查找可执行文件的正确输入以打印标志。国际开发协会 7

逆向工程 艾达 拆卸 部件 快手
2021-06-28 02:39:11

我试图了解下面代码的行为,以便我可以确定哪些输入会触发“你做到了!~!” 字符串(在程序指令的末尾):

.text:00C21034 Buf= 字节 ptr -6Ch
.text:00C21034 var_68= 字节 ptr -68h
.text:00C21034 var_4= dword ptr -4
.text:00C21034
.text:00C21034 推送 ebp
.text:00C21035 mov ebp, esp
.text:00C21037 sub esp, 6Ch
.text:00C2103A mov eax, ___security_cookie
.text:00C2103F xor eax, ebp
.text:00C21041 mov [ebp+var_4], eax
.text:00C21044 推送 ebx
.text:00C21045 push offset aPleaseEnterThe ; "请输入密码:"
.text:00C2104A 调用 sub_C21006
.text:00C2104F 异或 ebx, ebx
.text:00C21051 推送 ebx
.text:00C21052 调用 ds:__acrt_iob_func
.text:00C21058 推送 eax ; 文件
.text:00C21059 lea eax, [ebp+Buf]
.text:00C2105C 推送 64h ;最大计数
.text:00C2105E 推送 eax ; 缓冲
.text:00C2105F 调用 ds:fgets
.text:00C21065 lea ecx, [ebp+Buf]
.text:00C21068 添加 esp, 14h
.text:00C2106B lea edx, [ecx+1]
.text:00C2106E
.text:00C2106E loc_C2106E: ; 代码外部参照:sub_C21034+3F↓j
.text:00C2106E mov al, [ecx]
.text:00C21070 inc ecx
.text:00C21071 测试 al, al
.text:00C21073 jnz 短 loc_C2106E
.text:00C21075 sub ecx, edx
.text:00C21077 cmp ecx, 5
.text:00C2107A jnz 短 loc_C210C3
.text:00C2107C mov [ebp+var_68], bl
.text:00C2107F
.text:00C2107F loc_C2107F: ; 代码外部参照:sub_C21034+5E↓j
.text:00C2107F mov eax, ebx
.text:00C21081 和 eax, 3
.text:00C21084 mov al, [ebp+eax+Buf]
.text:00C21088 xor byte_C23018[ebx], al
.text:00C2108E inc ebx
.text:00C2108F cmp ebx, 0Ah
.text:00C21092 jb 短 loc_C2107F
.text:00C21094 mov ecx,偏移字节_C23018
.text:00C21099 mov edx,偏移loc_C23024
.text:00C2109E mov eax, [ecx]
.text:00C210A0 cmp eax, [edx]
.text:00C210A2 jnz 短 loc_C210C3
.text:00C210A4 mov eax, [ecx+4]
.text:00C210A7 cmp eax, [edx+4]
.text:00C210AA jnz 短 loc_C210C3
.text:00C210AC movzx eax, 字节 ptr [ecx+8]
.text:00C210B0 cmp al, [edx+8]
.text:00C210B3 jnz 短 loc_C210C3
.text:00C210B5 推送偏移量 aYouDidIt ; “你做到了!~!\r\n”
.text:00C210BA 调用 sub_C21006
.text:00C210BF xor eax, eax
.text:00C210C1 jmp short loc_C210D0
.text:00C210C3 ; -------------------------------------------------- -------------------------
.text:00C210C3
.text:00C210C3 loc_C210C3: ; 代码外部参照:sub_C21034+46↑j
.text:00C210C3 ; sub_C21034+6E↑j ...
.text:00C210C3 推送偏移 aOhhhhNooTryAga ; “哦不……再试一次。\r\n”
.text:00C210C8 调用 sub_C21006
.text:00C210CD xor eax, eax
.text:00C210CF inc eax


注意:
这里的目标是找到正确的输入。我知道我可以把 IP 放在我想要的地方,然后让程序打印出来。


到目前为止我的理解:

该程序要求在此指令中输入:

.text:00C2105F 调用 ds:fgets

之后,它运行一个循环来计算输入中有多少个字符,包括末尾的“新行”字符(当用户输入并按下“输入”时):

.text:00C2106E loc_C2106E: ; 代码外部参照:sub_C21034+3F↓j
.text:00C2106E mov al, [ecx]
.text:00C21070 inc ecx
.text:00C21071 测试 al, al
.text:00C21073 jnz 短 loc_C2106E

然后,它减去最后一个输入字符的地址和第一个输入字符的地址来确定输入的长度:

.text:00C21075 sub ecx, edx
.text:00C21077 cmp ecx, 5
.text:00C2107A jnz 短 loc_C210C3

如果输入长度不同于 5(包括“换行”字符),则它会跳转到打印出“Ohhhh noo... try again.”的标签。并终止程序:

.text:00C210C3 推送偏移 aOhhhhNooTryAga ; “哦不……再试一次。\r\n”
.text:00C210C8 调用 sub_C21006

如果输入长度正好是 5(包括“新行”字符),那么它继续执行这条指令,从输入字符串的末尾删除“新行”字符,这样,而不是 'A' hexa,将有是 '0' hexa(bl 最初的值为 0):

.text:00C2107C mov [ebp+var_68], bl

因此,如果输入的长度为 5(包括换行符),则应继续执行以下代码。这是一个运行 10 次的循环。ebx 最初为 0,它一直运行直到 ebx = 0A hexa = 10 十进制:

.text:00C2107F loc_C2107F: ; 代码外部参照:sub_C21034+5E↓j
.text:00C2107F mov eax, ebx
.text:00C21081 和 eax, 3
.text:00C21084 mov al, [ebp+eax+Buf]
.text:00C21088 xor byte_C23018[ebx], al
.text:00C2108E inc ebx
.text:00C2108F cmp ebx, 0Ah
.text:00C21092 jb 短 loc_C2107F

现在,关于这个循环的事情是以下指令保证 eax 将始终具有 0-3 范围内的值:

.text:00C21081 和 eax, 3

因此,假设我输入了输入“G00D”,该循环会将输入字符串的每个字符与字符串“G00D 作业!”的每个字符进行异或运算。(XOR指令中出现的byte_C23018存储这个字符串,见文末“PS”),这里是这个循环的演示('20h'是“空格”字符的ascii值):

  eax = 0 | eax = 1 | eax = 2 | eax = 3 | eax = 0 | eax = 1 |等
G 异或 G = 0|0 异或 0 = 0| 0 XOR 0 = 0|D XOR D = 0|G XOR '20h' = g|0 XOR j = z|etc

在那个循环之后,我开始挣扎。
下面代码中的 2 个标签彼此相距 6 个地址:

.text:00C21094 mov ecx,偏移字节_C23018
.text:00C21099 mov edx,偏移loc_C23024

但是它们必须指向完全相同的地址,因此后面的“cmp”指令会成功:

.text:00C210A0 cmp eax, [edx]

否则 - 满足下面“jnz”指令的条件,并跳转到打印“oh no try again”字符串的标签:

.text:00C210A2 jnz 短 loc_C210C3
.text:00C210C3 推送偏移 aOhhhhNooTryAga ; “哦不……再试一次。\r\n”
.text:00C210C8 调用 sub_C21006

有什么建议或想法吗?我理解错了吗?

提前致谢!


PS:
这里是《G00D作业!》被储存了。请注意,“G”是“47h”

.data:00C23018 byte_C23018 db 47h ; 数据外部参照:sub_C21034+54↑w
.data:00C23018 ; sub_C21034+60↑o
.data:00C23019 a00dJob db '00D job!',0
.data:00C23022 对齐 4
.data:00C23024
.data:00C23024 loc_C23024: ; 数据外部参照:sub_C21034+65↑o
.data:00C23024 添加 eax, 62657D71h
.data:00C23029 sub esp, [edx]
.data:00C2302B inc ebx
.data:00C2302C arpl [eax], ax

如果我输入“G00D”,它会存储在这里:

debug007:00BBF8A0 db 47h;G
debug007:00BBF8A1 db 30h;0
debug007:00BBF8A2 db 30h;0
debug007:00BBF8A3 db 44h;D
1个回答

你快到了。

但是它们必须指向完全相同的地址,因此后面的“cmp”指令会成功

这种说法是不正确的。比较的不是地址,而是每个地址的数据。代码,从开始.text:00C21094比较13后续字节 atbyte_C23018与其对应的字节loc_C23024

因此,要获得正确的密码,我们必须对其进行调查。很容易看出,在程序开始时,它们并不相同,因此必须在某个时候对其进行修改。它发生的唯一地方是 处的循环loc_C2107Fxor是您密码的后续字母,带有“ G00D job!”字符串的字母正如您所指出的,密码必须具有长度5,包括\n字符,因此循环仅使用密码的前四个字节是有意义的。

而是xor可逆操作;换句话说,如果A xor B = C,则A = C xor B,因为B xor B = 0A xor 0 = A

在您的情况下,A是您提供的密码,B是“ G00d job!”字符串,Cloc_C23024. 因此,要找到相关内容,A您只需要xor B使用C.