生活随笔
收集整理的這篇文章主要介紹了
REVERSE-PRACTICE-JarvisOJ-2
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
REVERSE-PRACTICE-JarvisOJ-2 DD - Hello APK_500 DebugMe FindPass
DD - Hello
macos文件,無殼,ida分析 start函數(shù)和sub_100000C90函數(shù)沒什么作用 主要的邏輯在sub_100000CE0函數(shù),反調(diào)試檢測(cè)和byte_100001040數(shù)組的循環(huán)變換,最后打印flag 按sub_100000CE0函數(shù)的邏輯寫腳本,即可得到flag
byte_100001040
= [ 0x41 , 0x10 , 0x11 , 0x11 , 0x1B , 0x0A , 0x64 , 0x67 , 0x6A , 0x68 , 0x62 , 0x68 , 0x6E , 0x67 , 0x68 , 0x6B , 0x62 , 0x3D , 0x65 , 0x6A , 0x6A , 0x3D , 0x68 , 0x04 , 0x05 , 0x08 , 0x03 , 0x02 , 0x02 , 0x55 , 0x08 , 0x5D , 0x61 , 0x55 , 0x0A , 0x5F , 0x0D , 0x5D , 0x61 , 0x32 , 0x17 , 0x1D , 0x19 , 0x1F , 0x18 , 0x20 , 0x04 , 0x02 , 0x12 , 0x16 , 0x1E , 0x54 , 0x20 , 0x13 , 0x14 ]
start
= ( 0x0000000100000CB0 ) & 0xff
sub_100000C90
= ( 0x0000000100000C90 ) & 0xff
v2
= ( ( start
- sub_100000C90
) >> 2 ) ^ byte_100001040
[ 0 ]
v1
= 0
while v1
< 55 : byte_100001040
[ v1
] -= 2 byte_100001040
[ v1
] ^ = v2v1
+= 1 v2
+= 1
print ( '' . join
( chr ( byte_100001040
[ i
] ) for i
in range ( 1 , len ( byte_100001040
) ) ) )
APK_500
apk文件,jadx-gui打開 在com.ctf.test.android_ctf_500_test.MainActivity中看到,靜態(tài)加載了easy庫(kù),輸入password后,調(diào)用easy庫(kù)中的helloworld函數(shù),驗(yàn)證輸入 ApkToolBox反編譯apk文件后,ida打開CTF_500\lib\armeabi-v7a\libeasy.so 沒有直接在左側(cè)函數(shù)窗找到helloworld函數(shù),來到JNI_OnLoad函數(shù) 解出三段字符串,分別為函數(shù)名,函數(shù)的參數(shù),以及函數(shù)所在的類 往下走,sub_1198函數(shù)為驗(yàn)證輸入的password 對(duì)輸入的password有以下幾步變換: 輸入的字符轉(zhuǎn)成了十六進(jìn)制數(shù) input[i]^=i,輸入和其下標(biāo)異或 input[i]+=1,i∈[0,3],前4個(gè)字節(jié)加1 input的前7個(gè)字節(jié)按原來的順序放到最后7個(gè)位置上,其余的字節(jié)依次向前移動(dòng) 變換位置后的input與byte_4004異或 input再轉(zhuǎn)成十六進(jìn)制數(shù),但是不會(huì)填充兩位,例如 “0x0c”->“0xc”,有一個(gè)0被忽略了 最后input和v50比較
bool __fastcall
sub_1198 ( JNIEnv
* a1
)
{ const char * input
; __pid_t v2
; int v3
; int v4
; char * v5
; int * v6
; int v7
; int v8
; _BYTE
* v9
; __pid_t v10
; int v11
; const char * input_
; size_t v13
; signed int input_len
; size_t v15
; const char * v16
; int v17
; int v18
; int v19
; const char * v20
; char * v21
; signed int v22
; char v23
; int v24
; signed int v25
; const char * v26
; int v27
; char v28
; char * v29
; char v30
; int v31
; char * v32
; char v33
; signed int i
; const char * v35
; signed int v36
; int v37
; char * v38
; int * v39
; int v40
; int v41
; __pid_t v43
; int v44
; char v45
; char v46
; int v47
; __int16 v48
; char v49
; char v50
; char v51
[ 128 ] ; char v52
[ 512 ] ; input
= ( const char * ) ( ( int ( * ) ( void ) ) ( * a1
) -> GetStringUTFChars
) ( ) ; v2
= getppid ( ) ; v3
= 0 ; v43
= v2
; do v52
[ v3
++ ] = 0 ; while ( v3
!= 64 ) ; v4
= 0 ; do v51
[ v4
++ ] = 0 ; while ( v4
!= 32 ) ; v5
= & v50
; v6
= & dword_2C6F
; do { v7
= * v6
; v6
+ = 2 ; v8
= * ( v6
- 1 ) ; * ( _DWORD
* ) v5
= v7
; * ( ( _DWORD
* ) v5
+ 1 ) = v8
; v9
= v5
+ 8 ; v5
+ = 8 ; } while ( v6
!= ( int * ) & unk_2C7F
) ; * v9
= * ( _BYTE
* ) v6
; sub_1064 ( & v50
, 17 , 65 ) ; v47
= 0x9021D19 ; v48
= 0xD13 ; v49
= 0x69 ; sub_1064 ( & v47
, 7 , 99 ) ; v10
= getppid ( ) ; snprintf ( v51
, 32u , & v50
, v10
, v43
) ; v11
= open ( v51
, 0 ) ; read ( v11
, v52
, 64u ) ; sub_107E ( v52
) ; close ( v11
) ; if ( ! strstr ( v52
, ( const char * ) & v47
) ) exit ( - 1 ) ; input_
= input
; v13
= strlen ( input
) ; BYTE2 ( v47
) = 0 ; v52
[ 0 ] = 0 ; input_len
= v13
; v15
= strlen ( input
) ; v16
= ( const char * ) & unk_2CF7
; v17
= v15
; while ( input_
- input
< v17
) { v18
= * ( unsigned __int8
* ) input_
++ ; v19
= v17
; v20
= v16
; sprintf ( ( char * ) & v47
, v16
, v18
) ; strcat ( v52
, ( const char * ) & v47
) ; v17
= v19
; v16
= v20
; } v21
= ( char * ) input
; v22
= 0 ; while ( v22
< input_len
) { v23
= * v21
^ v22
++ ; * v21
++ = v23
; } v24
= sub_10A4 ( ) ; if ( v24
) { v26
= input
; v27
= 0 ; v47
= v24
- v44
+ 0x1010101 ; do { v28
= * ( ( _BYTE
* ) & v47
+ v27
++ ) ; * v26
++ + = v28
; } while ( v27
!= 4 ) ; } if ( input_len
> 7 ) { v25
= 7 ; do { v29
= & v51
[ v25
] ; v30
= input
[ v25
++ ] ; * ( v29
- 7 ) = v30
; } while ( v25
!= input_len
) ; v31
= ( int ) ( input
- 1 ) ; v32
= & v51
[ input_len
- 8 ] ; do { v33
= * ( _BYTE
* ) ( v31
++ + 1 ) ; ( v32
++ ) [ 1 ] = v33
; } while ( ( const char * ) v31
!= input
+ 6 ) ; v51
[ input_len
] = 0 ; } for ( i
= 0 ; i
< input_len
; ++ i
) input
[ i
] = v51
[ i
] ^ byte_4004
[ i
] ; v52
[ 0 ] = 0 ; v46
= 0 ; v35
= input
; v36
= strlen ( input
) ; while ( v35
- input
< v36
) { v37
= * ( unsigned __int8
* ) v35
++ ; sprintf ( & v45
, ( const char * ) & unk_2CF7
, v37
) ; strcat ( v52
, & v45
) ; } v38
= & v50
; v39
= & dword_2C87
; do { v40
= * v39
; v39
+ = 2 ; v41
= * ( v39
- 1 ) ; * ( _DWORD
* ) v38
= v40
; * ( ( _DWORD
* ) v38
+ 1 ) = v41
; v38
+ = 8 ; } while ( v39
!= & dword_2CA7
) ; sub_1064 ( & v50
, 32 , 57 ) ; return strcmp ( & v50
, v52
) == 0 ;
}
需要注意的地方有兩點(diǎn): 1、在解最后要去比較的v50時(shí),只能得到31個(gè)可見字符"ddedd4ea2e7bef168491a6cae2bc660",原因是使用"%x"做參數(shù)轉(zhuǎn)成十六進(jìn)制數(shù)時(shí),某個(gè)字節(jié)的1個(gè)0被忽略,但是并不知道是哪個(gè)字節(jié)轉(zhuǎn)十六進(jìn)制時(shí)忽略了0,因此需要爆破0的位置 2、byte_4004數(shù)組,在ida中直接可見16個(gè)字節(jié) 其中dword_4007在程序運(yùn)行時(shí)被賦了新值,交叉引用過去就能看到 寫逆運(yùn)算腳本,打印的字符串中有可讀意義的即為flag
from Crypto
. Util
. number
import long_to_bytes
byte_4004
= [ 0x85 , 0x8B , 0xEC , 0x83 , 0xEC , 0x14 , 0x83 , 0x8D , 0x0C , 0x01 , 0x75 , 0x5F , 0xC6 , 0x45 , 0xF3 , 0x50 ]
byte_4004
[ 3 ] = 0x83
byte_4004
[ 4 ] = 0x6c
byte_4004
[ 5 ] = 0x9c
byte_4004
[ 6 ] = 0x83 v50
= "ddedd4ea2e7bef168491a6cae2bc660"
flags
= [ ]
for i
in range ( 32 ) : p
= v50
[ : i
] + '0' + v50
[ i
: ] flags
. append
( long_to_bytes
( int ( '0x' + p
, 16 ) ) )
for s
in flags
: flag
= [ ] for i
in range ( 16 ) : p
= ord ( s
[ i
] ) ^ byte_4004
[ i
] flag
. append
( p
) flag
= flag
[ - 7 : ] + flag
[ : - 7 ] for i
in range ( 4 ) : flag
[ i
] -= 1 for i
in range ( 16 ) : flag
[ i
] ^ = i
print ( '' . join
( chr ( i
) for i
in flag
) )
DebugMe
elf文件,無殼,ida分析 main函數(shù),主要邏輯為 命令行輸入password,sub_A30函數(shù)中有個(gè)j_fork,不太明白什么作用 往下走,輸入和下標(biāo)循環(huán)異或,進(jìn)入sub_D90->sub_C14驗(yàn)證輸入,第二個(gè)參數(shù)為0 繼續(xù)向下,輸入和數(shù)字1循環(huán)異或,進(jìn)入sub_C14驗(yàn)證輸入,第二個(gè)參數(shù)為7
int __cdecl
main ( int argc
, const char * * argv
, const char * * envp
)
{ int v3
; size_t i
; int v5
; int v6
; int v7
; int v8
; size_t j
; const char * v10
; char * input_
; void ( __noreturn
* v13
) ( ) ; int v14
; char v15
; char v16
; char v17
; char v18
; char v19
[ 20 ] ; char v20
[ 64 ] ; if ( argc
!= 2 ) { j_puts ( "Usage:\t program_name password" ) ; j_exit ( 0 ) ; } input_
= ( char * ) argv
[ 1 ] ; if ( sub_A30 ( 2u , ( int ) argv
) ) { for ( i
= 0 ; i
< j_strlen ( input_
) ; ++ i
) input
[ i
] = input_
[ i
] ^ i
; } v3
= 0 ; v13
= sub_D90
; v14
= 0 ; j_sigaction ( 7 , ( int ) & v13
, 0 ) ; j_sigaction ( 11 , ( int ) & v13
, 0 ) ; do v20
[ v3
++ ] = 0 ; while ( v3
!= 64 ) ; v5
= 0 ; do v19
[ v5
++ ] = 0 ; while ( v5
!= 32 ) ; j_memcpy ( & v18
, & unk_213D
, 17u ) ; sub_AE4 ( ( int ) & v18
, 17 , 65 ) ; v15
= 36 ; v16
= 61 ; v17
= 83 ; v6
= sub_AE4 ( ( int ) & v15
, 3 , 87 ) ; v7
= j_getppid ( v6
) ; j_snprintf ( v19
, 32 , & v18
, v7
) ; v8
= j_open ( v19
, 0 ) ; j_read ( ) ; sub_A0C ( v20
) ; j_close ( v8
) ; if ( ! j_strstr ( v20
, & v15
) ) { for ( j
= 0 ; j
< j_strlen ( input_
) ; ++ j
) input
[ j
] = input_
[ j
] ^ 1 ; } if ( ! sub_B1C ( ) ) __breakpoint ( 0 ) ; if ( sub_C14 ( input
, 7 ) ) v10
= "you win!\nFlag is your password!" ; else v10
= "The password you input is wrong!" ; j_puts ( v10
) ; return 0 ;
}
進(jìn)入sub_C14函數(shù),重要的邏輯在switch case語句中按照v3的值,驗(yàn)證輸入的內(nèi)容,LABEL_26的代碼,是變換v3的值,實(shí)際上v3 = 7 * (v3 + 1) - 11*sub_E14(7 * (v3 + 1), 11) 把sub_E14函數(shù)的代碼摳出來,編寫c程序 兩次調(diào)用sub_C14函數(shù)時(shí),第二個(gè)參數(shù)(也就是v3的初始值)分別為0和7,于是驗(yàn)證順序分別為 v3初始為0:0 7 1 3 6 5 9 4 2 v3初始為7:7 1 3 6 5 9 4 2 當(dāng)v3為2時(shí),sub_C14函數(shù)返回1 可以看到,v3初始為7時(shí),比v3初始為0時(shí),前者少驗(yàn)證了1位,其他的驗(yàn)證順序是一致的
int __fastcall
sub_C14 ( _BYTE
* a1
, int a2
)
{ _BYTE
* input
; int v3
; int v4
; int v5
; int v6
; int v7
; int v8
; int result
; int v10
; char v11
; char v12
; char v13
; char v14
[ 20 ] ; char v15
[ 64 ] ; input
= a1
; v3
= a2
; while ( 2 ) { v4
= 0 ; do v15
[ v4
++ ] = 0 ; while ( v4
!= 64 ) ; v5
= 0 ; do v14
[ v5
++ ] = 0 ; while ( v5
!= 32 ) ; j_memcpy ( & v12
, & unk_2113
, 0xFu ) ; sub_BF8 ( ( int ) & v12
, 15 , 107 ) ; j_memcpy ( & v13
, & unk_2122
, 0xFu ) ; sub_BF8 ( ( int ) & v13
, 15 , 116 ) ; j_memcpy ( & v11
, & unk_2131
, 0xCu ) ; v6
= sub_BF8 ( ( int ) & v11
, 12 , 114 ) ; v7
= j_getppid ( v6
) ; j_snprintf ( v14
, 32 , & v12
, v7
) ; v8
= j_open ( v14
, 0 ) ; j_read ( ) ; sub_A0C ( v15
) ; j_close ( v8
) ; if ( j_strstr ( v15
, & v13
) ) return - 1 ; result
= - ( ( unsigned int ) j_strstr ( v15
, & v11
) >= 1 ) ; if ( result
== - 1 ) return result
; switch ( v3
) { case 0 : if ( * input
== 105 ) goto LABEL_26
; return 0 ; case 1 : if ( * input
!= 101 ) return 0 ; goto LABEL_26
; case 3 : if ( * input
!= 110 ) return 0 ; goto LABEL_26
; case 4 : if ( * input
!= 100 ) return 0 ; goto LABEL_26
; case 5 : if ( * input
!= 97 ) return 0 ; goto LABEL_26
; case 6 : if ( * input
!= 103 ) return 0 ; goto LABEL_26
; case 7 : if ( * input
!= 115 ) return 0 ; goto LABEL_26
; case 9 : if ( * input
== 114 ) {
LABEL_26
: sub_EAC ( 7 * ( v3
+ 1 ) , 11 ) ; ++ input
; v3
= v10
; continue ; } return 0 ; default : return 1 ; } }
}
由于v3初始為0時(shí),sub_C14函數(shù)驗(yàn)證了8位,在調(diào)用sub_C14函數(shù)前,輸入的變換是,input[i]^i 于是寫逆運(yùn)算腳本即可得到8位小寫字母,即為flag
a
= [ 105 , 115 , 101 , 110 , 103 , 97 , 114 , 100 ]
print ( '' . join
( chr ( a
[ i
] ^ i
) for i
in range ( len ( a
) ) ) )
FindPass
apk文件,jadx-gui打開 在com.example.findpass.MainActivity中,GetKey方法的邏輯為 獲取輸入的fkey,已知的ekey做變換,fkey和變換后的ekey比較,驗(yàn)證輸入fkey 按照GetKey方法的邏輯寫腳本即可得到flag
ekey
= "Tr43Fla92Ch4n93"
ekey_data
= [ ord ( ekey
[ i
] ) for i
in range ( len ( ekey
) ) ]
f
= open ( "D:\\ctfdownloadfiles\\src.jpg" , "rb" )
cha
= f
. read
( 1024 )
f
. close
( )
for i
in range ( len ( ekey
) ) : if ord ( cha
[ ord ( ekey
[ i
] ) ] ) < 128 : tmp2
= ord ( cha
[ ord ( ekey
[ i
] ) ] ) % 10 else : tmp2
= ( - ( ord ( cha
[ ord ( ekey
[ i
] ) ] ) & 0x7f ) ) % 10 if i
% 2 == 1 : ekey_data
[ i
] += tmp2
else : ekey_data
[ i
] -= tmp2
print ( '' . join
( chr ( i
) for i
in ekey_data
) )
總結(jié)
以上是生活随笔 為你收集整理的REVERSE-PRACTICE-JarvisOJ-2 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。