IDA Pro之xrefs的巧妙运用
数据交叉引用
首先我们要知道的xrefs其实的就是交叉引用
也即是CTRL+X就可以了
它会列出一些信息,如上。
流程图
视图——流程图
打开
就是一个类似于这样的图
函数调用
IDA提供了一项分析函数间依存关系(交叉参考)的功能。
可以看到上面图中,根据函数地址的属性,被区分为不同的颜色(如程序入口点,外部函数,库函数……),颜色规则与反汇编窗口中的分析结果有关。
IDA Pro 逆向训练
第一题
首先打开
这个软件说:注册失败.
现在就是要把这个软件注册成功。
先查看发现是Win32 然后用IDA打开
然后上面这个窗口的地方有:Registeration。【Registeration == 登记】
所以我们就去找含有这个字符串的地方
用之前学的搜索的功能对它进行搜索。
点过去,看一下伪代码。【F5或者TAB】
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
| INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { HMODULE ModuleHandleW; HICON IconW; HMODULE v7; HWND DlgItem; HCURSOR CursorW; CHAR String[256]; CHAR v11[256]; CHAR Text[256]; char Source[36]; char v14[24];
if ( a2 == 16 ) { EndDialog(hDlg, 0); return 0; } if ( a2 == 272 ) { ModuleHandleW = GetModuleHandleW(0); IconW = LoadIconW(ModuleHandleW, (LPCWSTR)0x67); SetClassLongA(hDlg, -14, (LONG)IconW); v7 = GetModuleHandleW(0); CursorW = LoadCursorW(v7, (LPCWSTR)0x66); DlgItem = GetDlgItem(hDlg, 1); SetClassLongA(DlgItem, -12, (LONG)CursorW); return 1; } if ( a2 != 273 || (unsigned __int16)a3 != 1 ) return 0; memset(String, (unsigned __int16)a3 - 1, sizeof(String)); memset(v11, 0, sizeof(v11)); memset(Text, 0, sizeof(Text)); GetDlgItemTextA(hDlg, 1001, String, 256); GetDlgItemTextA(hDlg, 1002, v11, 256); if ( strstr(String, "@") && strstr(String, ".") && strstr(String, ".")[1] && strstr(String, "@")[1] != '.' ) { strcpy(v14, "Registration failure."); strcpy(Source, "Registration Success!\nYour flag is:"); if ( strlen(v11) == 16 && v11[0] == 'C' && v11[15] == 88 && v11[1] == 90 && v11[14] == 65 && v11[2] == 57 && v11[13] == 98 && v11[3] == 100 && v11[12] == 55 && v11[4] == 109 && v11[11] == 71 && v11[5] == 113 && v11[10] == 57 && v11[6] == 52 && v11[9] == 103 && v11[7] == 99 && v11[8] == 56 ) { strcpy_s(Text, 0x100u, Source); strcat_s(Text, 0x100u, v11); } else { strcpy_s(Text, 0x100u, v14); } } else { strcpy_s(Text, 0x100u, "Your E-mail address in not valid."); } MessageBoxA(hDlg, Text, "Registeration", 0x40u); return 1; }
|
上面的,大概率是在定义东西吧。也不是很需要看懂。
然后看这个if语句。这个strcpy 就是字符串拷贝函数。把后面的copy到前面去。
最后调用了一个MessageBoxA的函数
通过快捷键把数字【ascii码】先转化为字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| if ( strlen(v11) == 16 && v11[0] == 'C' && v11[15] == 'X' && v11[1] == 'Z' && v11[14] == 'A' && v11[2] == '9' && v11[13] == 'b' && v11[3] == 'd' && v11[12] == '7' && v11[4] == 'm' && v11[11] == 'G' && v11[5] == 'q' && v11[10] == '9' && v11[6] == '4' && v11[9] == 'g' && v11[7] == 'c' && v11[8] == '8' )
|
最后组成:CZ9dmq4c8g9G7bAX
成功的通过第一关……
第二题
首先用用die查看一下
发现是一个ELF也就是linux下的一个文件。
然后我们用kali 来运行一下这个文件
首先看到的是:我们的权限不够
我用的都是root了..我也不知道为什么权限不够。。。我们百度一下
然后用chmod 这个命令来提高权限【也许是这个意思】
然后发现:有Please input flag:
随便输入一下,发现是Wrong。
这里我们用IDA打开看一看咯【由于之前看到的是一个64位的】所以我们用64位的打开。
还是一样:搜索一下这个flag的位置
点击下面这个Please input flag
过去过后稍微看一下流程图,然后就可以来看看伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int __cdecl main(int argc, const char **argv, const char **envp) { char s[24]; int v5; int i;
for ( i = 0; i <= 181; ++i ) judge[i] ^= 0xCu; printf("Please input flag:"); __isoc99_scanf("%20s", s); v5 = strlen(s); if ( v5 == 14 && (*(unsigned int (__fastcall **)(char *))judge)(s) ) puts("Right!"); else puts("Wrong!"); return 0; }
|
看到这个要put Right 要满足上面这个条件
v5的的值要等于14 ; v5=strlen(s) 所以这个s 的长度得是14
点击这个judge函数,点过去看看:
这里这个judge db 59h 和下面 超过了59h的单位,让我总觉得有问题。但是我又说不出来问题在哪里。…
由于之前的judge 函数是异或了181次后的,我们现在要把他还原回去,那也就是异或181次回去
也就是说:下面的东西 db 44h ; D 以后的东西,被加密了呗。
解密idc脚本 修复judge函数
1 2 3 4 5 6
| auto i; for(i=0;i<0xb5;i++) {PatchByte(0x600b00+i,Byte(0x600b00+i) ^ 0xc);}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from idautils import PatchByte from idc import Byte
for i in range(0xb5): current_byte = Byte(0x600b00 + i) new_byte = current_byte ^ 0xC PatchByte(0x600b00 + i, new_byte)
|
由于IDA在开始的时候会自己分析一手:这个分析对我们来说是错误的。所以就需要把这个judge删掉。也就是右键然后undefine
也可以用快捷键“u”。删去后,让他重新分析;按下“p”键。
ok 这样就是变回来后的,现在我们tab一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void __fastcall judge(__int64 a1) { char v1[5]; char v2[9]; int i;
qmemcpy(v1, "fmcd", 4); v1[4] = 127; qmemcpy(v2, "k7d;V`;np", sizeof(v2)); for ( i = 0; i <= 13; ++i ) *(_BYTE *)(i + a1) ^= i; for ( i = 0; i <= 13 && *(_BYTE *)(i + a1) == v1[i]; ++i ) ; __asm { iret }
|
1 2 3 4 5 6 7 8 9 10 11 12
| void __fastcall judge(__int64 a1) { char v1[28]; int i;
qmemcpy(v1, "fmcd\x7Fk7d;V`;np", 14); for ( i = 0; i <= 13; ++i ) *(_BYTE *)(i + a1) ^= i; for ( i = 0; i <= 13 && *(_BYTE *)(i + a1) == v1[i]; ++i ) ; __asm { iret } }
|
得到一个这样的伪代码
我也不知道为什么,2次弄出来的不一样….
但是看着一其实应该差不多。
qmemcpy()函数:C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。
fmcd\x7Fk7d;V`;np 这个里面的 \x7f 是7f所表示的16进制 对应10进制是127 对应的ascii码是:DEL 删除键 。无法对应成字符,所以就成这样了。
然后再异或回去就能得到flag..
这个题;这个伪代码看得我蒙蒙的。