###### tags: `程安` # CS 2019 Fall - Homework 0x02 ### [0x02] IDAmudamudamuda 一樣 IDA 起手式 ```cpp= int __cdecl main(int argc, const char **argv, const char **envp) { int input_seed; // [esp+0h] [ebp-2Ch] char input_flag; // [esp+4h] [ebp-28h] sub_D71000(); puts("Oh, it's another ez Reversing Challenge"); puts("Leverage all you learned in class to solve this one"); puts("2 step to get the flag: \n\n\n"); puts("First, give me the seed: "); scanf("%d", &input_seed); sub_D71070(input_seed); puts("\n\n\nOK then whats the flag ?"); scanf("%s", &input_flag); if ( sub_D71270(&input_flag) ) { puts("OH yeah, you got the flag\n\n\n"); } else { puts("That's not right," " go back to review the slides on https://edu-ctf.csie.org"); puts("Hint: file format, calling convention," " shellcode, stack frame !!\n\n\n\n"); } system("pause"); return 0; } ``` 我們來看一下關鍵的 3 個部份︰ * `sub_D71000()` * `sub_D71070(input_seed)` * `sub_D71270(&input_flag)` --- **Part 1** ```cpp= FARPROC sub_D71000() { HMODULE v0; // eax FARPROC result; // eax HMODULE hModule; // [esp+4h] [ebp-4h] hModule = LoadLibraryA("msvcrt.dll"); puts = GetProcAddress(hModule, "puts"); scanf = GetProcAddress(hModule, "scanf"); v0 = LoadLibraryA("Kernel32.dll"); result = GetProcAddress(v0, "GetModuleHandleA"); GetModuleHandleA = result; return result; } ``` 這邊的重點在於 ```cpp=11 result = GetProcAddress(v0, "GetModuleHandleA"); GetModuleHandleA = result; ``` --- **Part 2** ```cpp= int __cdecl sub_D71070(char input_int) { char *handle; // eax int result; // eax int v3; // [esp+4h] [ebp-28h] char *v4; // [esp+8h] [ebp-24h] int m; // [esp+14h] [ebp-18h] int i; // [esp+18h] [ebp-14h] int k; // [esp+1Ch] [ebp-10h] int handle_var_2; // [esp+20h] [ebp-Ch] int j; // [esp+24h] [ebp-8h] int l; // [esp+24h] [ebp-8h] handle = GetModuleHandleA(0); handle_var = handle; result = *handle; if ( result == 'M' ) { result = *(handle_var + 1); if ( result == 'Z' ) { v4 = (*(handle_var + 60) + handle_var); result = *v4 if ( result == 'P' ) { result = v4[1]; if ( result == 'E' ) { for ( i = (v4 + 248); ; i += 40 ) { v3 = strcmp(i, ".data"); if ( v3 ) v3 = v3 < 0 ? -1 : 1; if ( !v3 ) break; } handle_var_2 = *(i + 12) + handle_var; for ( j = 0; ; ++j ) { result = i; if ( j >= *(i + 8) ) break; result = *(j + handle_var_2); if ( result == 15 ) { for ( k = 0; k < 32; ++k ) { result = j + handle_var_2; *(j + handle_var_2 + k) += *(j + handle_var_2 + k + 32); } break; } } for ( l = j + 33; l < *(i + 8); ++l ) { if ( *(l + handle_var_2) == 69 ) { for ( m = 0; ; ++m ) { result = l + handle_var_2; if ( !*(l + handle_var_2 + m) ) break; *(l + handle_var_2 + m) += input_int; } return result; } result = l + 1; } } } } } return result; } ``` 這部份有點長 簡單來說,就是他靠 **Part 1** 那個 function 來拿到自己這個 process 的當前位置,然後對`.data`的某個位置做與我們 input 進去的`seed`有關的計算 (第63行) --- **Part 3** ```cpp= int __cdecl sub_D71270(const char *input_str) { void *v2; // eax if ( strlen(input_str) != 32 ) return 0; v2 = VirtualAlloc(0, 0xC8u, 0x1000u, 0x40u); qmemcpy(v2, &source_str, 0xC8u); return (v2)(input_str, &unk_D74018); } ``` 這邊我們可以先簡單看出 FLAG 長度為 32,後面則是將一段未知內容的字串`source_str` copy 到`v2`,然後`v2`把當作 function 去 call 他,並把我們 input 的字串跟一個未知的字串當作參數傳給他 既然`v2`的位置是動態要出來的,我們就只能用 x64dbg 來動態一下 --- **Part 4** 我們先輸入`seed=0`和`flag="12341234123412341234123412341234"` 我們先找到`v2`的位置 ![](https://i.imgur.com/JGBzsz1.png) 我們繼續跟下去 ![](https://i.imgur.com/afB8rgn.png) 長的完全不像一個 function (例如最後結尾不是`pop ebp; ret`之類的) 我們換成`seed=1`試試看 ![](https://i.imgur.com/53aHw4C.png) 內容果然變了,而且每個 byte 都跟`seed=0`的時候差 1。 也就是說,在 **Part 2** 中`.data`的某個位置被做了與`seed`有關的計算,其實就是在更改這個部份 那既然這個字串應該要長的像一個 function,那我們就大膽猜測最後一個 byte 應該要是`c3 (ret)`,也就是`seed=16` ![](https://i.imgur.com/hyJhMFv.png) 看起來是猜中了,我們再來借助一下 IDA 的 decompiler 吧 ```cpp= int __cdecl sub_8F0000(int input_str, int arg2) { int i; // [esp+0h] [ebp-4h] for ( i = 0; *(i + arg2); ++i ) { if ( ((*(i + input_str) + 35) ^ 102) != *(i + arg2) ) return 0; } return 1; } ``` 這個 function 其實就是一個 flag checker,將我們 input 的字串每個 byte `+ 35`再`& 102`之後與`arg2`做比對,也就是說我們直接將`(arg[i] ^ 102) - 35`即為 flag 那`arg2`再哪呢?我們在 **Part 3** 時可以看到 ```cpp=9 return (v2)(input_str, &unk_D74018); ``` `unk_D74018`即為`arg2` ![](https://i.imgur.com/ojfYLzU.png) `unk_D74018 = "\x0F\x09\x02\x0C ... \x22\x22\xC6\x00"` 然後我們寫個簡單的 script 就可以拿到 flag 了 :::success FLAG{y3s!!y3s!!y3s!!0h_my_g0d!!} :::