IDA Pro之xrefs的巧妙运用

数据交叉引用

首先我们要知道的xrefs其实的就是交叉引用

也即是CTRL+X就可以了

image-20230514142655787

它会列出一些信息,如上。

image-20230514142804678

流程图

视图——流程图

image-20230514143025158

打开

image-20230514143046828

就是一个类似于这样的图

函数调用

IDA提供了一项分析函数间依存关系(交叉参考)的功能。

image-20230514143334926

可以看到上面图中,根据函数地址的属性,被区分为不同的颜色(如程序入口点,外部函数,库函数……),颜色规则与反汇编窗口中的分析结果有关。

IDA Pro 逆向训练

image-20230514144723769

第一题

首先打开

image-20230514143822224

这个软件说:注册失败.

现在就是要把这个软件注册成功。

先查看发现是Win32 然后用IDA打开

然后上面这个窗口的地方有:Registeration。【Registeration == 登记】

所以我们就去找含有这个字符串的地方

用之前学的搜索的功能对它进行搜索。

image-20230514144056616

点过去,看一下伪代码。【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; // eax
HICON IconW; // eax
HMODULE v7; // eax
HWND DlgItem; // eax
HCURSOR CursorW; // [esp-4h] [ebp-34Ch]
CHAR String[256]; // [esp+8h] [ebp-340h] BYREF
CHAR v11[256]; // [esp+108h] [ebp-240h] BYREF
CHAR Text[256]; // [esp+208h] [ebp-140h] BYREF
char Source[36]; // [esp+308h] [ebp-40h] BYREF
char v14[24]; // [esp+32Ch] [ebp-1Ch] BYREF

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

image-20230514150215382

成功的通过第一关……

第二题

首先用用die查看一下

image-20230514152810417

发现是一个ELF也就是linux下的一个文件。

然后我们用kali 来运行一下这个文件

首先看到的是:我们的权限不够

我用的都是root了..我也不知道为什么权限不够。。。我们百度一下

然后用chmod 这个命令来提高权限【也许是这个意思】

image-20230514152919392

然后发现:有Please input flag:

随便输入一下,发现是Wrong。

这里我们用IDA打开看一看咯【由于之前看到的是一个64位的】所以我们用64位的打开。

还是一样:搜索一下这个flag的位置

image-20230514153855603

点击下面这个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]; // [rsp+0h] [rbp-20h] BYREF
int v5; // [rsp+18h] [rbp-8h]
int i; // [rsp+1Ch] [rbp-4h]

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函数,点过去看看:

image-20230514162926543

这里这个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);}

//patch 修补
//patchbyte 补丁字节
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 导入IDA Python模块
from idautils import PatchByte
from idc import Byte

# 循环从0到0xb4(与IDC脚本中的0xb5对应)
for i in range(0xb5):
# 获取地址0x600b00+i处的字节值
current_byte = Byte(0x600b00 + i)

# 对字节值进行异或操作
new_byte = current_byte ^ 0xC

# 使用PatchByte函数来写入新的字节值
PatchByte(0x600b00 + i, new_byte)

image-20230514165949130

由于IDA在开始的时候会自己分析一手:这个分析对我们来说是错误的。所以就需要把这个judge删掉。也就是右键然后undefine

也可以用快捷键“u”。删去后,让他重新分析;按下“p”键。

image-20230514170436170

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]; // [rsp+8h] [rbp-20h] BYREF
char v2[9]; // [rsp+Dh] [rbp-1Bh] BYREF
int i; // [rsp+24h] [rbp-4h]

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]; // [rsp+8h] [rbp-20h] BYREF
int i; // [rsp+24h] [rbp-4h]

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..

image-20230514171444446


这个题;这个伪代码看得我蒙蒙的。