Wintel机器代码反反转练习(C/C++逆向)

文章目录

Wintel Machine Code Anti-Reversing Exercise Description of the
Exercise:

Apply the anti-reversing techniques Eliminating Symbolic Information
and Obfuscating the Program, both introduced in sections 6 and 7 of
the report, to the C/C++ source code of the Password Vault application
with the goal of making it more difficult to disable the trial
limitation. Rebuild the executable binary for the Password Vault
application from the modified sources using the GNU compiler
collection for Windows. Show that the Wintel Machine Code Reversing
and Patching Exercise can no longer be carried out as demonstrated.

Wintel机器代码反反转练习

活动描述: 将报告第6节和第7节中介绍的消除符号信息和模糊程序的反反转技术应用到密码库应用程序的C/
C++源代码中,目的是使禁用试用限制更加困难。使用Windows GNU编译器集合从修改过的源代码重新生成Password
Vault应用程序的可执行二进制文件。显示Wintel机器代码反转和修补练习不能再进行演示。

这次的密码库应用程序是实验四-java反编译那一节的程序用C/ C++写的,先打开PasswordVaultObfuscated.exe应用程序运行,添加5条账户密码记录之后,程序提示达到上限不能再添加记录了:
Wintel机器代码反反转练习(C/C++逆向)

我们的目标就是突破5条账户密码记录的限制。
先用IDA打开,查看字符串窗口:
Wintel机器代码反反转练习(C/C++逆向)

发现除了标题以及部分提示的字符串,关键的字符串都已经被AES256算法加密了:

标题的提示文字

找到输出标题的提示文字的代码,有两处调用了这个提示函数:
Wintel机器代码反反转练习(C/C++逆向)

之前运行过exe你就会知道,第一次调用是启动的时候最开始的提示,第二次调用是每次选择显示、创建、编辑、删除等功能都会先调用输出标题的提示文字。
找到第二次调用的位置在函数sub_4078B6()中:
Wintel机器代码反反转练习(C/C++逆向)

6个功能的提示文字

下一个函数sub_401C04()就是输出6个功能的提示文字的函数:
Wintel机器代码反反转练习(C/C++逆向)

在OD中给找到00401C04函数下断点,运行程序在显示完标题提示之后就会停在断点处:
Wintel机器代码反反转练习(C/C++逆向)

这里就是显示6个功能的函数开始的地方,其中sub_401F42就是获取都是AES256解密后的字符串,sub_550C68就是printf函数,在00401D36 call Password.00527664下断点,运行程序就会断在输出第二个功能的提示文字之后:
Wintel机器代码反反转练习(C/C++逆向)

00401C04函数就是负责输出6个功能的函数选项的提示文字,他们都包含在sub_4078B6()函数里:
Wintel机器代码反反转练习(C/C++逆向)

我们再往上找到调用sub_4078B6()的sub_407504函数:
Wintel机器代码反反转练习(C/C++逆向)

就可以发现功能实现的逻辑了,通过sub_4078B6()的返回1-6来跳转到6个不同的功能,其中控制添加账户密码记录的就是第二个功能sub_407CE6()。

功能2:添加记录

在OD中进入407CE6函数,往下我们可以找到一个判断跳转的地方,在00407D41下一个断点,输入数字2之后运行程序就会停在00407D41:
Wintel机器代码反反转练习(C/C++逆向)

这时候我们已经输入了5条账户密码记录,然后al的值是01,ZF标志位是0,跳转不成立,这个跳转就是用来跳过
00407D5F E9 36080000 jmp Password.0040859A; 跳转到返回retn
让程序返回退出的,继续运行之后就会跳转到返回:
Wintel机器代码反反转练习(C/C++逆向)

而跳转不成立则会 JMP到返回的位置
所以我们在这把ZF标志位改为1,就可以让跳转成立:
Wintel机器代码反反转练习(C/C++逆向)

运行,成功突破限制可以继续添加账户密码记录:
Wintel机器代码反反转练习(C/C++逆向)
Wintel机器代码反反转练习(C/C++逆向)

所以这个判断就是账户密码记录条数是否小于5的关键位置,如果小于于5就可以继续添加账户密码记录,如果不小于5就输出[Error]返回。

我们再重新打开一个没有账户密码记录的exe,下断点在

00407D3F . 84C0 test al,al

运行停在断点00407D3F处:
Wintel机器代码反反转练习(C/C++逆向)

这时候al的值为0,ZF的值为1,跳转成立,可以继续运行添加账户密码记录。

方法一:修改跳转

我们只需要保证跳转一直成立,这样就不会提前返回了。所以我们可以把je(等于0则跳转)修改成jmp(一直跳转),也就是把对应的机器码74改成EB,修改之前的代码如下图:
Wintel机器代码反反转练习(C/C++逆向)

修改之后的代码:
Wintel机器代码反反转练习(C/C++逆向)

复制到可执行文件,保存文件为 PasswordVaultObfuscated_crack_jmp.exe:
Wintel机器代码反反转练习(C/C++逆向)

运行PasswordVaultObfuscated_crack_jmp.exe,成功突破限制:
Wintel机器代码反反转练习(C/C++逆向)

方法二:修改返回值

因为test al,al在al为0时,al&al=0,ZF标志位置1;
je在ZF为1时跳转。
所以我们只需要让al始终为0即可实现一直添加账户密码记录,我们找到了返回eax的值位置:
Wintel机器代码反反转练习(C/C++逆向)

然后我们将
00407A5B |. 0FB6C0 movzx eax,al;
修改成如下4种对应的机器码和对应的汇编:

编号 机器码 汇编 是否合适
1 33C0 xor eax,eax 将eax置0,且运算速度比2快,且包含了movzx eax,al将eax除al以外的位置0的作用
2 B8 00000000 mov eax,0x0 将eax置0,但是长度太长,修改比较麻烦
3 32C0 xor al,al 将al置0,且运算速度比2快
4 B0 00 mov al,0x0 将al置0

第一种修改方式

第一种修改的既可以满足我们将al置0的目的,同时包含了源代码movzx eax,al将eax除al以外的位置0的作用,而且对CPU而言它的运算速度比mov eax,0x0快。
所以我们将源代码修改为33 C0 90,多的这一位一定要用90(nop)来代替,如果是00会被识别为代码影响后面的代码:
Wintel机器代码反反转练习(C/C++逆向)

修改之后的代码:
Wintel机器代码反反转练习(C/C++逆向)

复制修改到可执行文件,保存文件为PasswordVaultObfuscated_crack.exe,运行程序,成功突破限制:
Wintel机器代码反反转练习(C/C++逆向)

第三种修改方式

但实际上,在这里我们按照其他的修改方式也可以实现我们的目的,可能是因为在这个程序中,eax除了al以外的位是不是为0对程序没有太大的影响 ,例如按照第三种修改32C0 xor al,al把源代码修改为32 C0 90:
Wintel机器代码反反转练习(C/C++逆向)

复制修改到可执行文件,保存文件为PasswordVaultObfuscated_crack3.exe,运行程序,也可以成功突破限制:
Wintel机器代码反反转练习(C/C++逆向)

第四种修改方式

例如第四种也是可以的B0 00 mov al,0x0,把源代码修改为B0 00 90:
Wintel机器代码反反转练习(C/C++逆向)

复制修改到可执行文件,保存文件为PasswordVaultObfuscated_crack4.exe,运行程序,也可以成功突破限制:
Wintel机器代码反反转练习(C/C++逆向)

上一篇:OD入门笔记


下一篇:逆向入门(3)汇编篇-寄存器和内存的认识