2018网鼎杯Give_a_try WP
0x0
记录一次某Crackme的分析过程,大致分为算法和反调试两部分。
0x1
[测试环境]win10 64
[使用工具]Ollydbg丶IDA
0x2 算法部分
应该是将反调试部分写在前面的,但是由于这个CM的算法部分相对与反调试部分的意义较小,所以先写在前面,重点写在后面。以下都是在过了反调试的情况下的分析。
将程序拖入IDA后 shift+F12打开字符串窗口
可以看到作者给我们的提示
pizza:0040210A 0000001D C The flag begins with “flag{”
告知了flag开头的格式
还有验证提示的字符串
通过交叉引用可以定位到关键代码段
F5可以将汇编代码转换为伪代码
整体算法比较简单,其中涉及到了随机数,在这里我们可以猜测他是一个伪随机数,不然我们是无法逆向出他原来的结果的,当随机种子相同时,rand()函数的返回值也相同。
还有可以确定的一点是要解出这题需要通过枚举来得到答案,因为他进行了很多次取余,原数值已经逆向不出来了。
至此,静态分析到这大致已经结束了。我们需要得知 丶
中的值才能进行代码编写。
打开OD进行动态调试,来到关键位置后下个断点输入一串假码(长度满足42位)后断下。
F8单步往下
ds:[0040406C]=31333359 p.s:如果没有过反调试这里的值会不一样,就解不出
edi=00000976
每个字符加密后的对应的是内存中的四个字节,所以我们需要复制4*42=162个字节。
至此所需的数据已经有了,下面是代码编写,与0x31333359异或的是原flag各字符之和,这我们无从得知,所以需要通过枚举来得到。
已知条件:flag的第一位是‘f’ 加密后的值是 0x63B25AF1
为图方便原加密算法我直接引用他的会汇编代码,没有转化成C语言形式
如果直接复制IDA的伪代码会发现,少做了一次取余emmmm。挺坑的。
代码如下
原flag各字符之和为e64,
Flag为flag{[email protected]w111-th3r3_i5@_w4y}
0x3 反调试
反调试在这个程序中比较关键,如果没有过掉反调试,就得不到与flag各字符之和异或的那个正确的值,也就无法解出题目。
不过我开始没有发现,还是解出来了,全仰仗大佬写的sharpOD的插件
能过掉很多反调试。
从IDA的函数窗口可以看到三个可疑函数,
前面两个是系统API用来检测调试状态,后面的是TLS的回调函数
TLS全称线程局部存储(Thread Local Storage,TLS),它先于程序入口点(OEP)执行就行了。
我们可以可以用PE工具在数据表中找到它。
查看TLS表,它占了24个字节
32位中TLs结构体如下:
typedef struct _IMAGE_TLS_DIRECTORY32 {
DWORD StartAddressOfRawData; /* tls节区的起始地址 */
DWORD EndAddressOfRawData; /* tls节区的最终地址 */
DWORD AddressOfIndex; /* tls节区的索引 */
DWORD AddressOfCallBacks; /* 指向回调函数的指针 */
DWORD SizeOfZeroFill;
DWORD Characteristics;
} IMAGE_TLS_DIRECTORY32;
第4项为TLS回调函数指针数组,在这个程序中为00404032
在OD中可以看到
第一个回调函数地址为:00402000 跟IDA上是一样的
OD载入程序在该地址下断点,重载程序就会断下。
代码加了花指令,无法正常阅读,IDA的F5功能也是失效的,
00402006 E8 00000000 call 0040200B
0040200B 810424 17000000 add dword ptr [esp], 0x17
00402012 C3 retn
看下这三句指令,call到了0040200B,也就是call的下一行位置,此时栈顶的值应该为call的下一行也就是0040200B 然后加0x17就是0x402022 然后ret 这三句代码的实际效果就是jmp 402022也就是说 在0040200B-402021这之间的指令都是没用的,那么我们就可以把它直接nop掉,经过调试发现,后面还有许多类似的花指令,其机器码格式都是E8 01 00 00 00 ?? ?? ?? ?? ?? C3
,那么可以写一个OD脚本来除去这些花指令。
去除花指令后另存为能正常运行,直接转到IDA看伪代码
作者在这里动态的将第二个回调函数地址写入,如果我们用OD调试,ReturnLength就为0xFFFFFFFF也就是-1,那么第二个TLS的回调函数将不会被执行,进而在算法中需要的地址40406C也就不会被赋值。
来到第二个回调函数,看下40406C如何被赋值
经过这个函数,地址40406C就为0x31333359了。然后整个分析到这里就结束了。
0x2 总结
在分析这个程序的时候我们会发现IDA的F5功能并不是很准确,有时会成为解题的阻碍,比如,在IDA显示的算法伪代码中少做了一次取余,如果不去看汇编代码就发现不了,所以看下程序本身的汇编代码还是挺重要的。