-
-
[原创]KCTF2022秋季赛 第八题 商贸往来 题解
-
2022-12-3 20:16 12105
-
开头包装的一层调用可以手动清理出来,他调用了sub_4026D2
作为窗口回调,在WM_COMMAND
里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | v21 = ( * ( int (__stdcall * * )( int , int ))(dword_4ABE44 + 92 ))(a1, 1001 ); / / GetDlgItem if ( v21 ) { for ( i = 0 ; i < 0x100 ; + + i ) v7[i] = 0 ; v42 = ( * ( int (__stdcall * * )( int ))(v35 + 96 ))(v21); / / GetWindowTextLengthA if ( v42 < = 210 && v42 > = 1 ) { ( * (void (__stdcall * * )( int , char * , int ))(v35 + 100 ))(v21, v7, 255 ); / / GetWindowTextA v42 = ( * ( int (__stdcall * * )(char * ))(v35 + 24 ))(v7); / / lstrlenA if ( v42 > = 1 && v42 < = 128 ) { for ( j = v42; j < 128 ; + + j ) { if ( j % 2 ) v7[j] = 0x20 ; else v7[j] = 0x7F ; } v34 = 1 ; } else { v34 = 0 ; } } else { v34 = 0 ; } } else { v34 = 0 ; } if ( v34 ) { v43 = dword_4ABE44; if ( ( * ( int (__stdcall * * )(_DWORD, char * , int ))(dword_4ABE44 + 56 ))( 0 , v5, 255 ) ) { strcpy(v27, "h" ); v27[ 2 ] = 0 ; v27[ 3 ] = 0 ; v27[ 4 ] = 0 ; v27[ 5 ] = 0xB8 ; v27[ 6 ] = 0 ; v27[ 7 ] = 0 ; v27[ 8 ] = 0 ; v27[ 9 ] = 0 ; v27[ 10 ] = 0xFF ; v27[ 11 ] = 0xD0 ; Eax = 0 ; v31 = 0 ; v8[ 17 ] = 0xFFFFFFFF ; for ( k = 0 ; k < 0x44 ; + + k ) * ((_BYTE * )v8 + k) = 0 ; v8[ 0 ] = 68 ; for ( m = 0 ; m < 0x10 ; + + m ) * ((_BYTE * )&v37 + m) = 0 ; if ( ( * ( int (__stdcall * * )(char * , _DWORD, _DWORD, _DWORD, _DWORD, int , _DWORD, _DWORD, int * , int * ))(v43 + 28 ))( / / CreateProcessW v5, 0 , 0 , 0 , 0 , 4 , 0 , 0 , v8, &v37) ) { v6.ContextFlags = 0x10007 ; if ( !( * ( int (__stdcall * * )( int , CONTEXT * ))(v43 + 32 ))(v38, &v6) ) / / GetThreadContext goto LABEL_69; Eax = v6.Eax; v31 = ( * ( int (__stdcall * * )( int , _DWORD, int , int , int ))(v43 + 44 ))(v37, 0 , 128 , 4096 , 4 ); if ( !v31 ) goto LABEL_69; for ( n = 0 ; n < 0x80 ; n + = v17 ) { v17 = 0 ; if ( !( * ( int (__stdcall * * )( int , unsigned int , char * , unsigned int , int * ))(v43 + 0x30 ))( / / WriteProcessMemory v37, n + v31, &v7[n], 128 - n, &v17) ) { v16 = 0 ; goto LABEL_45; } } v16 = 1 ; if ( !v16 ) goto LABEL_69; LABEL_45: v20 = (PIMAGE_DOS_HEADER)( * ( int (__stdcall * * )(_DWORD))(v43 + 20 ))( 0 ); / / GetModuleHandleW v10 = ( int )v20 + v20 - >e_lfanew; v9 = Eax - * (_DWORD * )(v10 + 40 ); v11 = (char * )sub_401000 - (char * )v20; * (_DWORD * )&v27[ 1 ] = v31; * (_DWORD * )&v27[ 6 ] = (char * )sub_401000 - (char * )v20 + v9; for ( ii = 0 ; ii < 0xC ; ii + = v15 ) { v15 = 0 ; if ( !( * ( int (__stdcall * * )( int , unsigned int , char * , unsigned int , int * ))(v43 + 48 ))( v37, ii + Eax, &v27[ii], 12 - ii, &v15) ) { v14 = 0 ; goto LABEL_52; } } v14 = 1 ; LABEL_52: if ( v14 ) { ( * (void (__stdcall * * )( int ))(v43 + 36 ))(v38); / / ResumeThread v30 = 2 ; if ( ( * ( int (__stdcall * * )( int , int ))(v43 + 60 ))(v37, 30000 ) ) / / WaitForSingleObject { ( * (void (__stdcall * * )( int , int ))(v43 + 64 ))(v37, 2 ); / / TerminateProcess } else { v18 = 0 ; if ( ( * ( int (__stdcall * * )( int , int * ))(v43 + 52 ))(v37, &v18) && v18 ! = 2 ) / / GetExitCodeProcess v30 = v18; } |
会再执行一次crackme
,将入口点改为
1 2 3 | push input mov eax, 0x401000 call eax |
0x401000通过调用Decompress
函数,解压数据
类似格式是
1 2 3 4 | struct CodeData{ uint32_t CodeSize; uint8_t code[CodeSize]; }; |
在这里进行调用,v47
用于加密,v45
用于最后的验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | if ( v38 ) { v90 = 0 ; v29[ 0 ] = 5 ; v29[ 1 ] = 0 ; v29[ 2 ] = 4 ; v29[ 3 ] = 3 ; v29[ 4 ] = 2 ; v29[ 5 ] = 1 ; for ( ii = 0 ; ii < 6 ; + + ii ) { v32 = v29[ii]; v92 = 0 ; v47 = 0 ; for ( jj = 0 ; jj < = v32; + + jj ) { v47 = ( int (__stdcall * )(_DWORD, _DWORD, _DWORD, _DWORD))(v108[ 30 ] + v92 + 4 ); v46 = * (_DWORD * )(v108[ 30 ] + v92); v92 + = v46 + 4 ; } v90 = v47; if ( !v47( * v108, v108[ 1 ], v108[ 2 ], a1) ) goto LABEL_134; } v56 = 1 ; v91 = 0 ; v45 = 0 ; for ( kk = 0 ; kk < = 6 ; + + kk ) { v45 = ( int (__stdcall * )(_DWORD, _DWORD, _DWORD, _DWORD))(v108[ 30 ] + v91 + 4 ); v48 = * (_DWORD * )(v108[ 30 ] + v91); v91 + = v48 + 4 ; } v90 = v45; if ( !v45( * v108, v108[ 1 ], v108[ 2 ], a1) ) v56 = 0 ; } |
通过强制F5了几个函数发现,对应输入只进行了基于字节的异或加密、交换、查表,修改其中一个字节,只会对加密结果产生一个字节的影响。
这些代码花式调用了大量API
,拖慢了计算速度,同时也有反调试。
其实根据附带的题目描述我感觉是叫你硬看,但我就偏要硬爆
将最后一个函数F5
找到比对逻辑,将其导出。
将原始文件patch 入口点,push 0x402d4c call 0x401000
后 跟一个int3
,然后nop
掉0x04026C8
的ExitProcess
,到达int3
后读取和重写flag的值,然后更改Eip
为入口点进行下次爆破。
需要用到ScyllaHide
,爆的时候执行一下InjectorCLIx86.exe sb.exe HookLibraryx86.dll nowait
加载一下反反调试,配置文件选Themida x86/x64
。
预计时间是(128 + 94) * 10 / 60 = 37
分钟,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | #include <windows.h> #include <TlHelp32.h> #include <stdint.h> #include <stdio.h> char trueflag[ 0x81 ] = { 0 }; / / char flag[ 0x81 ] = { 0x3a , 0x2a , 0x44 , 0x23 , 0x4f , 0x2b , 0x5f , 0x49 , 0x33 , 0x3b , 0x60 , 0x7d , 0x30 , 0x4e , 0x66 , 0x50 , / / 0x2d , 0x3d , 0x32 , 0x2f , 0x2b , 0x59 , 0x22 , 0x5f , 0x3e , 0x41 , 0x38 , 0x53 , 0x36 , 0x5d , 0x4c , 0x7c , / / 0x34 , 0x47 , 0x3b , 0x55 , 0x48 , 0x69 , 0x41 , 0x35 , 0x6d , 0x6e , 0x6f , 0x6c , 0x5e , 0x6b , 0x3b , 0x23 , / / 0x4f , 0x68 , 0x57 , 0x32 , 0x21 , 0x55 , 0x45 , 0x4a , 0x66 , 0x30 , 0x22 , 0x37 , 0x3f , 0x44 , 0x74 , 0x35 , / / 0x6d , 0x7b , 0x43 , 0x71 , 0x45 , 0x2a , 0x41 , 0x5a , 0x72 , 0x7e , 0x24 , 0x31 , 0x28 , 0x7a , 0x57 , 0x40 , / / 0x54 , 0x42 , 0x58 , 0x4b , 0x4c , 0x26 , 0x32 , 0x72 , 0x3f , 0x2b , 0x33 , 0x6b , 0x77 , 0x78 , 0x43 , 0x39 , / / 0x30 , 0x4f , 0x27 , 0x25 , 0x26 , 0x50 , 0x79 , 0x56 , 0x6f , 0x7e , 0x29 , 0x27 , 0x51 , 0x25 , 0x5a , 0x40 , / / 0x36 , 0x62 , 0x7d , 0x52 , 0x45 , 0x4b , 0x46 , 0x5b , 0x63 , 0x67 , 0x46 , 0x65 , 0x2f , 0x2d , 0x3f , 0x49 }; char flag[ 0x81 ] = { 0 }; int flagcount = 0 ; int _current = 0 ; uint8_t encrelative[ 0x80 ] = { 0 }; uint8_t enctable[ 0x80 ] = { 0 }; / / uint8_t enctable[ 0x80 ] = { 0x09 , 0x0a , 0x07 , 0x08 , 0x05 , 0x06 , 0x03 , 0x04 , 0x01 , 0x02 , 0x40 , 0x00 , 0x42 , 0x41 , 0x44 , 0x43 , / / 0x46 , 0x45 , 0x48 , 0x47 , 0x4a , 0x49 , 0x4c , 0x4b , 0x4e , 0x4d , 0x50 , 0x4f , 0x52 , 0x51 , 0x54 , 0x53 , / / 0x56 , 0x55 , 0x58 , 0x57 , 0x5a , 0x59 , 0x5c , 0x5b , 0x5e , 0x5d , 0x60 , 0x5f , 0x62 , 0x61 , 0x64 , 0x63 , / / 0x66 , 0x65 , 0x68 , 0x67 , 0x6a , 0x69 , 0x6c , 0x6b , 0x6e , 0x6d , 0x70 , 0x6f , 0x72 , 0x71 , 0x74 , 0x73 , / / 0x76 , 0x75 , 0x78 , 0x77 , 0x7a , 0x79 , 0x7c , 0x7b , 0x7e , 0x7d , 0x3f , 0x7f , 0x3d , 0x3e , 0x3b , 0x3c , / / 0x39 , 0x3a , 0x37 , 0x38 , 0x35 , 0x36 , 0x33 , 0x34 , 0x31 , 0x32 , 0x2f , 0x30 , 0x2d , 0x2e , 0x2b , 0x2c , / / 0x29 , 0x2a , 0x27 , 0x28 , 0x25 , 0x26 , 0x23 , 0x24 , 0x21 , 0x22 , 0x1f , 0x20 , 0x1d , 0x1e , 0x1b , 0x1c , / / 0x19 , 0x1a , 0x17 , 0x18 , 0x15 , 0x16 , 0x13 , 0x14 , 0x11 , 0x12 , 0x0f , 0x10 , 0x0d , 0x0e , 0x0b , 0x0c }; int stage = 1 ; int guess = 33 ; uint8_t enc[ 0x80 ] = { 121 , 23 , 66 , 107 , 59 , 80 , 122 , 227 , 70 , 208 , 222 , 78 , 36 , 167 , 138 , 106 , 105 , 208 , 2 , 6 , 240 , 39 , 36 , 189 , 192 , 187 , 227 , 30 , 9 , 163 , 151 , 48 , 60 , 182 , 235 , 104 , 144 , 9 , 208 , 234 , 17 , 242 , 196 , 96 , 165 , 203 , 195 , 252 , 69 , 251 , 92 , 83 , 192 , 128 , 58 , 153 , 89 , 111 , 47 , 84 , 74 , 217 , 14 , 106 , 52 , 222 , 210 , 236 , 175 , 74 , 11 , 164 , 138 , 182 , 250 , 147 , 31 , 4 , 16 , 68 , 238 , 228 , 214 , 158 , 244 , 69 , 18 , 77 , 55 , 60 , 240 , 17 , 248 , 200 , 68 , 118 , 99 , 16 , 115 , 45 , 104 , 215 , 157 , 47 , 195 , 132 , 42 , 182 , 204 , 181 , 55 , 97 , 79 , 15 , 22 , 188 , 187 , 140 , 83 , 39 , 238 , 119 , 170 , 31 , 156 , 194 , 24 , 222 }; uint8_t tmp[ 0x80 ] = { 0 }; int main(void) { STARTUPINFOA si = { sizeof(si) }; PROCESS_INFORMATION pi = { sizeof(pi) }; DWORD ret = CreateProcessA( "D:/Users/CShi/Desktop/sb.exe" , "", NULL, NULL, FALSE, DEBUG_PROCESS | CREATE_SUSPENDED, NULL, NULL, &si, &pi); DWORD __sb = 0 ; uint8_t original = 0 ; uint8_t int3 = 0xcc ; ReadProcessMemory(pi.hProcess, 0x004041B5 , &original, 1 , &__sb); WriteProcessMemory(pi.hProcess, 0x004041B5 , &int3, 1 , &__sb); ResumeThread(pi.hThread); DEBUG_EVENT de = { 0 }; CONTEXT ThreadContext = { 0 }; ThreadContext.ContextFlags = 0x10007 ; while ( 1 ){ WaitForDebugEvent(&de, INFINITE); if (de.dwDebugEventCode = = EXCEPTION_DEBUG_EVENT){ if (de.u.Exception.ExceptionRecord.ExceptionCode = = 0x80000003 ){ if (de.u.Exception.ExceptionRecord.ExceptionAddress = = (LPVOID) 0x004041B5 ){ puts( "InjectorCLIx86.exe sb.exe HookLibraryx86.dll nowait" ); system( "pause" ); WriteProcessMemory(pi.hProcess, 0x4041b5 , &original, 1 , &__sb); HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, de.dwThreadId); GetThreadContext(hThread, &ThreadContext); WriteProcessMemory(pi.hProcess, 0x402d4c , &flag, 0x80 , &__sb); ThreadContext.Eip = 0x4041b5 ; SetThreadContext(hThread, &ThreadContext); CloseHandle(hThread); } else if (de.u.Exception.ExceptionRecord.ExceptionAddress = = (LPVOID) 0x04041BF ){ if (stage = = 1 ){ if (encrelative[ 0 ] = = 0 ){ ReadProcessMemory(pi.hProcess, 0x402d4c , &encrelative, 0x80 , &__sb); } else { ReadProcessMemory(pi.hProcess, 0x402d4c , &tmp, 0x80 , &__sb); for ( int i = 0 ;i< 0x80 ;i + + ){ if (tmp[i] ! = encrelative[i]){ enctable[_current - 1 ] = i; break ; } } } memset(flag, 0 , sizeof(flag)); if (_current = = 0x81 ) { memset(flag, 0 , sizeof(flag)); stage = 2 ; _current = 0 ; flag[_current] = guess; } else { flag[_current] = 1 ; _current + = 1 ; } puts( "enctable debug:" ); for ( int i = 0 ; i < 128 ; i + + ) { printf( "0x%02x," , enctable[i]); if (i % 16 = = 15 ) { puts(""); } } } else { ReadProcessMemory(pi.hProcess, 0x402d4c , &tmp, 0x80 , &__sb); for ( int i = 0 ;i< 0x80 ;i + + ){ if (tmp[i] = = enc[i]) { for ( int j = 0 ; j < 0x80 ; j + + ) { if (enctable[j] = = i){ printf( "%x: %c OK!\n" , j, flag[j]); flagcount + = 1 ; trueflag[j] = flag[j]; if (flagcount = = 0x80 ) { printf( "%s\n" , trueflag); system( "pause" ); } break ; } } } } puts(""); memset(flag, guess, 128 ); guess + = 1 ; printf( "%x: %c current\n" , _current, flag[_current]); puts( "flag debug:" ); for ( int i = 0 ; i < 128 ; i + + ) { printf( "0x%02x," , trueflag[i]); if (i % 16 = = 15 ) { puts(""); } } if (guess = = 128 ) { puts( "No Solve!" ); } } HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, de.dwThreadId); GetThreadContext(hThread, &ThreadContext); WriteProcessMemory(pi.hProcess, 0x402d4c , &flag, 0x80 , &__sb); ThreadContext.Eip = 0x4041b5 ; SetThreadContext(hThread, &ThreadContext); CloseHandle(hThread); } } ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); } else { ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); } } } |
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2022-12-3 20:23
被mb_xxgcvcih编辑
,原因:
赞赏
他的文章
看原图