下面是网上的160个CrackMe的部分逆向笔记,包括逆向思路、注册机实现和逆向中常用的知识整理
注意:逆向前一定要先操作一下软件,熟悉软件的运行现象;逆向一定要自己操作一遍,看是很难看会的(高手除外)
文章目录
1.现象
运行软件,发现有2个地方需要破解,一个是序列号/用户名,另一个是单独的序列号
2.序列号逆向
step 1.错误提示
OD启动程序,F9,随机输入一个序列号,验证,出现错误对话框
step 2.关键字符串
根据错误提示的字符串Try Again!!
,在OD里搜索一下,看看能不能发现线索?
找到了一个可疑的字符串,在字符串的地址处设置断点
重新输入一下序列号,验证,断点命中,说明线索有效(注意:这个过程有时要找很多次才能找到,要有耐心)
step 3.关键跳转
命中断点(0x42F4F8
)后,简单分析一下命中前的部分代码,发现了正确提示和可疑的**关键跳转(0x42F4D5)
**指令
说明:详细分析可以看到,错误提示中的
call
调用的0x0042A170
应该是类似于MessageBox
的对话框函数
爆破:直接将关键跳转指令改成nop
,再次运行一下验证序列号流程(随便输入一个序列号),发现弹出正确提示框;如果不想继续查看,直接保存就可以得到序列号破解程序
step 4.正确的序列号
程序在关键跳转(0x42F4D5
)前面一定会有判断逻辑来验证序列号,通常都是离关键跳转很近的函数调用
OD重新加载程序,在关键跳转上面的第一个函数调用(0x42F4D0
)处设置断点,F9,执行;断点命中后,查看函数的可能参数
- eax里保存的是我随机输入的系列号
123
- edx里保存的是一个陌生的字符串
Hello Dude!
,这个字符串大概率就是正确的序列号
step 5.验证结果
经验证Hello Dude!
就是正确的序列号
这是一个很简单的Crack思路,主要是利用错误提示框中的信息找到破解点,这也是最常用的套路
缺点:后续软件增加反调试或者不弹出错误对话框,这个思路就失效了
3.序列号/用户名逆向
逆向软件前,最好熟悉一组字符串的ASCII码,这样会增加逆向的效率,下面是我常用的用户名和密码的ASCII码
注意:后续所有笔记基本使用的都是下面的用户名和序列号
字符串 | 对用的ASCII(十六进制) |
---|---|
test123 | 74 65 73 74 31 32 33 |
456 | 34 35 36 |
step 1.错误提示
输入一组序列号和用户名,点击验证发现出现错误对话框
提示:用上面的字符串思路直接可以爆破这个程序;为了分析出注册机,因此不采用爆破的方式
step 2.关键跳转
通过错误字符串Sorry,The serial is incorect!
,用上面的方法可以直接定位到关键跳转(0x42FB03
)
在关键跳转上面最近的函数调用(即call指令)处(0x42FAFE
)设置断点,重新运行程序,输入错误的用户名和序列号(test123/456
),断点命中后分析如下:
- 序列号:没有变化
- 用户名:输入
test123
,结果应该是CW-9512-CRACKED
,想要写注册机就要找到用户名处理逻辑
扩展:IDA查看Graph图
用IDA
加载程序,通过错误字符串Sorry,The serial is incorect!
找到对应处理函数,转换成graph
视图,可以看到CRACKED
应该是一个固定字符串,猜测最终结果后半部分应该是拼接CRACKED
字符串
提示:逆向小程序使用OD或者x64dbg就能应付,但是逆向大一点的程序最好结合IDA进行分析,尤其IDA产生的辅助MAP文件很有用,后面的CrackMe004会有介绍
step 3.分析用户名处理逻辑
直接在上面关键跳转的函数起始处设置断点,重新运行程序;输入用户名和密码,分析处理逻辑,实际上包括2个部分:
- 1.用户名长度大于等于4
下面是用户名处理逻辑的前半部分,处理用户名的前4个字符是结构类似的代码
提示:这部分对用户名的处理结果后面没有使用(分析了个寂寞),后续的CrackMe笔记中会看到,结合IDA分析可以很快识别出关键处理逻辑
扩展:使用repne scas byte ptr es:[edi]计算字符串长度
上面截图地址0042FA52
中调用的函数是计算字符串长度的函数,要熟悉这个函数的反汇编形式,逆向中经常看到;反汇编代码对应如下:
; 计算字符串长度
00406930 /$ 89FA mov edx, edi
00406932 |. 89C7 mov edi, eax ; edi存放字符串
00406934 |. B9 FFFFFFFF mov ecx, -1 ; mov ecx,0xFFFFFFFF
00406939 |. 30C0 xor al, al ; al存放字符x;al=0,将遍历整个字符串
0040693B |. F2:AE repne scas byte ptr es:[edi] ; 以字节为单位遍历字符串,每循环一次ecx-1,遇到字符x则停止
0040693D |. B8 FEFFFFFF mov eax, -2 ; mov eax,0xFFFFFFFE
00406942 |. 29C8 sub eax, ecx ; eax里面存储的就是字符串长度
00406944 |. 89D7 mov edi, edx
00406946 \. C3 retn
C++代码验证上面反汇编代码:
#include "StdAfx.h"
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "1234567";
int str_len = 0;
int record_ecx = 0;
_asm
{
mov edx, edi //使用edi前临时保存起来
lea edi, str //edi存放字符串
mov ecx, 0xFFFFFFFF
xor al, al //al存放字符x;al=0,将遍历整个字符串
repne scas byte ptr es:[edi] //以字节为单位遍历字符串,每循环一次ecx-1,遇到字符x则停止
mov eax, 0xFFFFFFFE
sub eax, ecx
mov record_ecx, ecx
mov str_len, eax
mov edi, edx
}
printf("record_ecx=%d, str_len=%d, strlen()=%d", record_ecx, str_len, strlen(str));
return 0;
}
运行程序可以看到上面汇编代码和strlen
计算的结果一致:
- 2.用户名处理
输入test123
,经过计算结果是CW-9512-CRACKED
,这个对应关系要时刻牢记;下面是分析的整体截图,详细计算:
首先,用户名test
,取第一个字符t
,乘以0x29
,再乘以2
,最终结果=0x74 * 0x29 * 2 = 0x2528 = 9215
其次,将9215
转换成字符串与CW
和CRACKED
进行拼接,得到有效序列号CW-9512-CRACKED
,即序列号是根据用户名动态生成的
至此,用户名处理逻辑分析完,注册机实现就很容易了
step 4.注册机
注意:没有考虑复杂的输入,仅仅是为了验证算法分析的是否正确用,后续笔记的注册机也都是这个目的
#include "StdAfx.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
char user_name[100] = {0}; //用户名
printf("请输入用户名(长度>=4):");
scanf_s("%s", user_name, 100);
//根据用户名(第一位)生成序列号
int user_serial = user_name[0] * 0x29 * 2; //乘以0x29再乘以2
//拼接
char serial[200] = {0};
char serial1[] = "CW";
char serial2[] = "CRACKED";
sprintf(serial, "%s-%d-%s", serial1, user_serial, serial2);
printf("用户名:%s, 对应的序列号:%s\n", user_name, serial);
system("pause");
return 0;
}
运行结果:
验证注册机通用性,简单的注册机符合要求
简单总结:这个逆向案例其实很简单,主要是想将利用关键字符串破解的思路写一个笔记
4.参考
- 1.VB程序逆向反汇编常见的函数 - 笨笨D幸福 - 博客园 (cnblogs.com)
- 2.常用软件可以在这里下载:爱盘 - 最新的在线破解工具包 (52pojie.cn)
- 3.【反汇编练习】160个CrackME索引目录1~160建议收藏备用
- 4.160个Crackme_鬼手56的博客-CSDN博客
- 5.《使用OllyDbg从零开始Cracking》系列的文章也不错