闲言碎语
最近开始学习windows逆向,所学尚浅,因此以Crackme160作为练习对象,督促自己学习的同时也能取悦自己,学海无涯,希望自己能够不忘初心。
正文
预测
本次练习对象为Crackme的第一个 Acid burn.exe。首先直接打开该程序,看看本次的目标是什么。
运行程序首先弹窗,给了一些欢迎信息和作者信息,点击确定后会出现程序的主界面
分别点击两侧的button,可知该程序有两部分:
第一部分Serial/Name需要分别输入Name和Serial,推测程序将通过输入的Name通过本身的加密生成Serial,然后和我们输入的Serial做字符串比较,此处先尝试输入几个随意值,并且点击checkit,得到错误提示如下:
第二部分Serial需要输入Serial,推测程序内置或者会生成一个字符串,与输入的serial做字符串比较。此处仍尝试输入值,得到错误提示如下:
Crack
由上述预测可以得到本次目标如下:
-
1.跳过程序启动时的弹窗neg(顺手而为,并非本次主要目标)
-
2.serial部分点击check it 的button显示正确提示。
-
3.serial/name部分点击check it的button时显示正确提示。
1.跳过弹窗neg
(1)搜索字符串方法
由于程序并未字符串加密,因此可以通过右键->search for->all reference strings方式查找相应字符串
字符串内容是程序启动时,弹窗内显示的字符串,搜索可以看到如下
选中双击或者enter键可以进入到调用的地方,如下图所示,该字符串的存储地址作为函数参数传入
其实在图中call处enter进入之后往下拉可以看到MessageBoxA的调用,这是第二种crack方式所需要谈到的。
接上述,在Call处F2断点,F9运行到该处,从栈区可以看到该函数调用的返回值,同样enter可以到达调用处。
如果需要跳过弹窗,直接将该处call干掉即可,但需注意栈平衡以及返回值,这里eax返回值在MessageBox按下确定后应该为1,则我们可以将call 替换为mov eax,1,剩余的空间用nop填充即可。
(2)搜索内部方法调用
windows的弹窗一般为MessageBox的windows API调用,因此可以搜索该调用,从而找到弹窗的调用点。
在MessageBox处右键选中图中选项,即在所有的调用点出打断点。然后F9继续运行,接下来的步骤就和方法(1)一样了。
(3)暂停查栈方法
在无任何断点情况下,直接ollydbg运行程序,在弹窗弹出后F11暂停程序,如下图
此时程序运行于windows主循环中,循环等待消息。需要在栈区中往下翻,因为messagebox为阻塞程序,无消息进入而挂起时,该函数调用的堆栈应该会被保存,因此往下翻可以找到messagebox的栈调用信息,如下图:
之后的步骤也就和方法(1)中所述一致。
2.serial部分
使用上述任一方法可以定位到输入任意字符串后按下checkit button后messagebox调用的位置,如下
可以看到该位置同时有成功和错误的提示,往上翻,将断点打在栈帧开始位置
push ebp
mov ebp, esp
F8单步运行,同时观察栈区信息,可以分析到如下图中中文注释内容。由此分析该程序目标字符串为Hello Dude!。
程序中输入该字符串,即可得到正确提示如下:
3.serial/name部分
同样方法找到messagebox调用的位置。
同样地往上翻查,找到字符串比较跳转的代码位置,如下:
可以看到这里已经生成了目标结果,因此需要往上查找生成该字符串的代码。逐行运行且关注dump和stack区,可以分析出如注释区中文注释内容,即程序将读取输入字符串的第一个字符,乘以29乘以2之后作为参数输入到一个函数从而生成中间段serial,然后再做字符串拼。了解到这一点后需要进入生成中间serial的函数进一步分析。
在上图生成中间serial的call中,发现有下一级的call,查看传入参数,发现传入了上述第一个字符*0x29*2的值以及“%d”,结合printf的格式输入,猜测这里将输入的值做了十六进制转十进制再字符串化输出,于是根据猜想实验如下,结果表示猜想正确
这里先假装不知道这个意图继续往下级call找。在一段对%d字符处理的操作后(包含读取前导码%,根据%后为d或者x等格式输入进入不同处理分支),进入了核心的计算代码段:
将该段写成C语言即为如下:
#include <cstdio>
#include <cstdint>
int main()
{
const uint8_t kEcx = 0xA;
char input_char = 0;
input_char = getchar();
uint32_t source;
source = input_char * 0x29 * 2;
uint32_t mod;
char result[16] = { 0 };
uint32_t i = sizeof(result) - 2;//留一个\0
do{
mod = source % kEcx;
source /= kEcx;
mod += '0'; //add dl,30
if (mod >= ':') //cmp dl,3A
{
mod += 7;
}
result[i--] = mod;
//putchar(mod);
} while (source);
i = 0;
while (result[i] == 0) ++i;
printf("%s\n", &result[i]);
return 0;
}
在上述程序基础上,增加"CW-" "-CRACKED"字符串连接的程序,即可完成注册机程序。如下,任意输入,使用上述注册机得到结果如下图:
至此,整个crackme结束。
终言
整个crackme下来感觉自己还需要多加练习,需要学习的还有很多,希望之后能够坚持下去,将基础知识打牢,同时掌握技巧,并由此增加对其他方面知识的认知,总之不忘初心。