这次进行CrackMe002的逆向分析 AfKayAs
(本系列的CrackMe资源均来自我爱破解网).
1. 运行程序,随机输入,进行弹窗:
两种思路:
3. 分析:发现字符串 “You Get Wrong”是由另一个地址进行跳转得到:
4. 进行溯源,发现跳转来自 je short 004025E5
5. 发现其中正确的字符串显示 “You Get it”;je前面的语句即是判断语句,序列号正确时继续往下执行,序列号错误时就跳转到 “You Get Wrong“字符串(地址为004025E5)处进行执行。
6. 破解程序,只需要用两个nop 指令替换je short 004025E5指令即可:
9. 从je short 004025E5处往前查看,它的前几条语句都没有能够改变ZF的值,继续往前发现有一个带有cmp的函数,那么下意识怀疑它是一个字符串比较函数,上网对该函数进行搜索,果然是一个字符串比较函数,那么它就极可能是进行序列号判断的函数,对它下断,:
10. 发现好多可疑信息,不要激动,一步一步来;入栈的eax应该是正确的序列号为 “AKA-1853138“ ,至于这个序列号怎么来的,我们从00402510开始分析,因为此处为有一个跳转,往往是一个新的逻辑开始的地方,下端后F7单步调试,查看堆栈,发现 [ebp-1C] 为序列号的数字 “1853138“ ,[ebp-18] 为用户输入的序列号”333333333333333“
11. 继续进行分析,发现一个库函数调用 vbaStrCat,搜索后发现该函数为字符拼接函数,在 00402523处对该函数进行间接调用(利用edi),其中的参数有一个固定字符串(00401B70内存中)“AKA-“ 和ecx (在00402513处进行了赋值,为序列号中间的数字”1853138“),此时该函数的返回值存放在eax中,其中 ”AKA-1853138“ 这就是我们的正确序列号。
12. 所以我们的序列号是由固定字符串“AKA-“和”1853138“拼接而来;那么”1833138“又是怎么得到的呢?我们继续往前看,刚刚说过,带有跳转的部分极有可能是新的逻辑开始的地方,这次我们从 004024DD开始分析,进行 F8调试;因为在上面的分析中我们发现字符串”1853138“字符串是保存在 [ebp-1C] 中的,我们在内存中查找 EBP-1C,在调试的时候需要对该内存进行观察。进行调试后发现,在执行到 004024FA处该内存内容发生了变化,变成了”1853138“,而次地址的前面正好是一个函数调用,那么真相只有一个:该字符串是由这个函数生成的 。
13. 然后我们需要对该函数进行分析,跟踪后会发现,完全迷失了自我;冷静一番后有了以下思路进行函数回溯:(大神如果知道别的更快的方法请一定要告诉我)
14. 序列号首次出现在栈中是在 00402456处:
15. 字符串保存在 eax中,则在前面找一处断点单步执行,继续观察 eax的值;发现在 0040243F处的函数调用返回值就算序列号的中间值(此处为“1853138“),也就是说该函数为序列号产生的最后一步,接下来我们需要理清整个序列号产生算法的逻辑。
16. 我们从 00402409开始分析,至于为什么从这里开始分析,一方面00402409是有一个跳转语句进行跳转的,那么从它开始很大程度上就是一个新的逻辑开始的地方;另一方面,在用F7进行单步调试时,在 0040240F处发现用户输入的用户名出现,而用户名在栈中的地址正好是 [ebp-1C],
17. 从 00402409开始分析:查看 [ebp-B0],并不知道它是什么,先不管他,继续往下:
18. 在 00402415处有一处函数调用 MSVBVN50.__vbaLenBstr(),其中用户的输入(被传入eax)和[ebp-B0](被传入ebx)作为该函数的参数参与计算,上网搜索该函数为函数,该函数的作用是计算字符串的长度。
19. 继续往下执行,得到输入用户名的长度,被保存在eax中(此处为0x13,数值为19)
20. 继续往下执行,出现 [ebp-18],进行堆栈查看,还是存放的还是用户输入的用户名"1111111111111111111"
21. 继续执行,进行乘法运算:edi=edi*17CFB,刚刚 edi 存放的是字符串的长度(此处为0x13,数值为19),则此时的 edi 的数据为 ”001C46A1”
22. 继续执行,将ecx入栈(此时的ecx还是用户是输入用户名“1111111111111“)做下一个函数的参数,然后是一个溢出跳转指令 jo 004026BE,应该是针对刚刚的 edi 乘法进行检查;接下来是一个函数调用,该函数的作用的计算输入参数的 首字符ASCII值。
23. 因为我们这里没有溢出,所以先不考虑溢出的部分;继续往下执行,用户名的首字符为“1“,ASCII值为”31“,所以eax的值是 0x00000031
24. 继续往下执行,edx=0x00000031,(只取了eax的ax), edi=edi+edx=001C46A1+00000031=001C46D2, 然后进行溢出检查(此处不存在,先不进行考虑),将 edi 入栈作为参数传递给 vabStrI4函数,该函数的作用是 将16进制转换成10进制:
25. 到此,整个序列号生成函数的逻辑就分析完了,整个序列号生成函数的逻辑如下: