接触逆向也算是小半年了,一直都在搞游戏分析。觉得大牛都看不上我们这些小虾。于是决定看一下破解的。
话说着,在看雪看到一篇文章,写着自己写的CrackMe,算法一般,但是有点ANTI代码,建议新手。
有点手痒,看到ANTI 很好奇的。就拿来试了试。先是爆破了一下。觉得着基本上人人都会的。于是写了一下注册机。
一 先看爆破的:
bp MessageBoxA
随便输入用户名和key点击OK ,断下,堆栈回朔
73D883E3 >/$ 8B4424 08 MOV EAX,DWORD PTR SS:[ESP+8] ; EAX message
004015D6 83FF 0A CMP EDI,0A
004015D9 ^ 7C E9 JL SHORT CrackMe.004015C4
004015DB EB 19 JMP SHORT CrackMe.004015F6
004015DD 33FF XOR EDI,EDI
004015DF 8A543C 30 MOV DL,BYTE PTR SS:[ESP+EDI+30]
004015E3 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+10]
004015E7 80F2 AA XOR DL,0AA ; 这几个地方随便下断点都被检测到
int 3 断点 不能下,下硬件执行断点
没发现什么东西,往上看
0040154B 8B46 64 MOV EAX,DWORD PTR DS:[ESI+64]
0040154E 8B2D D4314000 MOV EBP,DWORD PTR DS:[<&MSVCRT._mbscmp>] ; msvcrt._mbscmp
00401554 68 EC404000 PUSH CrackMe.004040EC
00401559 50 PUSH EAX
0040155A FFD5 CALL EBP
0040155C 83C4 08 ADD ESP,8 ; EAX返回为1
发现有比较,看一下是什么
0040155C 83C4 08 ADD ESP,8 ; EAX返回为1
00401554 68 EC404000 PUSH CrackMe.004040EC
常量:004040EC是空字符串指针 是判断用户名和regkey 是否为空的函数
00401546 E8 D9070000 CALL <JMP.&MFC42.#?UpdateData@CWnd@@QAEH>
0040154B 8B46 64 MOV EAX,DWORD PTR DS:[ESI+64] ; 取regkey
0040154E 8B2D D4314000 MOV EBP,DWORD PTR DS:[<&MSVCRT._mbscmp>] ; msvcrt._mbscmp
00401554 68 EC404000 PUSH CrackMe.004040EC
00401559 50 PUSH EAX
0040155A FFD5 CALL EBP ; 判断regkey是否为空
0040155C 83C4 08 ADD ESP,8 ; EAX返回为1
0040155F 85C0 TEST EAX,EAX
00401561 74 7A JE SHORT CrackMe.004015DD
00401563 8B46 60 MOV EAX,DWORD PTR DS:[ESI+60] ; 取用户名
00401566 8D5E 60 LEA EBX,DWORD PTR DS:[ESI+60]
00401569 68 EC404000 PUSH CrackMe.004040EC
0040156E 50 PUSH EAX
0040156F FFD5 CALL EBP ; 判断用户名是否为空
00401571 83C4 08 ADD ESP,8
00401574 85C0 TEST EAX,EAX
00401578 . 8B4E 64 MOV ECX,DWORD PTR DS:[ESI+64] ; 既然上面都是判断是否为空,那从这里开始
0040157B . 33C0 XOR EAX,EAX
0040159F . E8 8C030000 CALL CrackMe.00401930 ; 计算并判断是否通过(算法)
004015A4 . 85C0 TEST EAX,EAX
进入CALL
Code:
004019D3 |. B8 01000000 MOV EAX,1 正确走过的
004019D8 |. 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C]
004019DC |. 64:890D 00000>MOV DWORD PTR FS:[0],ECX
004019E3 |. 83C4 18 ADD ESP,18
004019E6 |. C2 0800 RETN 8
004019E9 |> E8 1C020000 CALL <JMP.&MFC42.#??1CString@@QAE@XZ_800>
004019EE |. 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C]
004019F2 |. 33C0 XOR EAX,EAX 错误的EAX=0
004019F4 |. 64:890D 00000>MOV DWORD PTR FS:[0],ECX
004019FB |. 83C4 18 ADD ESP,18
004019FE \. C2 0800 RETN 8
最后返回EAX,改成1. OK爆破 成功
二 算法分析,注册机代码
00401578 . 8B4E 64 MOV ECX,DWORD PTR DS:[ESI+64] ; ECX为自己输入的Regkey
0040157B . 33C0 XOR EAX,EAX ; EAX=0;
0040157D > 0FBE1401 MOVSX EDX,BYTE PTR DS:[ECX+EAX] ; 计算自己输入的regkey 异或相加的和。
00401581 . 81F2 AA000000 XOR EDX,0AA ; 每个字符都与0aa 异或然后相加
00401587 . 03FA ADD EDI,EDX
00401589 . 40 INC EAX ; 计算9次跟使用用户名是一样的
0040158A . 83F8 09 CMP EAX,9 ; 计算9次运算
0040158D .^ 7C EE JL SHORT CrackMe.0040157D
0040158F . 57 PUSH EDI ; 计算key 后的值
00401590 . 51 PUSH ECX ; push 进入key 进行运算
0040159D . 8BCE MOV ECX,ESI ; 已经产生了key
0040159F . E8 8C030000 CALL CrackMe.00401930 ; 此处 计算并判断是否通过(算法)
进入 00401930
是根据输入的用户名计算输入的regkey是否正确。
用到字符串char *KeyConst="KEY-KANON";
0040196A |. 33C0 XOR EAX,EAX
0040196C |. C64424 0D 45 MOV BYTE PTR SS:[ESP+D],45 ; $ ==> >KEY-KANON
00401971 |. 85C9 TEST ECX,ECX
00401973 |. C64424 0E 59 MOV BYTE PTR SS:[ESP+E],59
00401978 |. C64424 0F 2D MOV BYTE PTR SS:[ESP+F],2D
0040197D |. C64424 11 41 MOV BYTE PTR SS:[ESP+11],41
00401982 |. C64424 13 4F MOV BYTE PTR SS:[ESP+13],4F
00401987 |. 7E 0B JLE SHORT CrackMe.00401994
00401989 |> 0FBE1C10 /MOVSX EBX,BYTE PTR DS:[EAX+EDX] ; 用户名
0040198D |. 03F3 |ADD ESI,EBX
0040198F |. 40 |INC EAX
00401990 |. 3BC1 |CMP EAX,ECX ; 根据用户名计算出esi 长度
00401992 |.^ 7C F5 \JL SHORT CrackMe.00401989 ; 计算出esi,下面使用
00401994 |> 33C9 XOR ECX,ECX
00401996 |> 0FBE440C 0C /MOVSX EAX,BYTE PTR SS:[ESP+ECX+C] ; 拿出KEY-KANON每个字符跟上面算出的ESI相乘
0040199B |. 0FAFC6 |IMUL EAX,ESI ; eax*esi
0040199E |. 99 |CDQ ; EDX=0了
0040199F |. BB 1A000000 |MOV EBX,1A
004019A4 |. F7FB |IDIV EBX ; ESI 的值除于ebx 的值,商在EAX,余数在EDX
004019A6 |. 83C2 61 |ADD EDX,61 ; EDX=EDX+0x61
004019A9 |. 81F2 AA000000 |XOR EDX,0AA
004019AF |. 03FA |ADD EDI,EDX ; 计算后加到EDI,要看每个EDX怎么来的
004019B1 |. 41 |INC ECX
004019B2 |. 83F9 09 |CMP ECX,9
004019B5 |.^ 7C DF \JL SHORT CrackMe.00401996 ; 计算算法
004019B7 |. 8B4424 2C MOV EAX,DWORD PTR SS:[ESP+2C]
004019BB |. C74424 20 FFF>MOV DWORD PTR SS:[ESP+20],-1
004019C3 |. 3BF8 CMP EDI,EAX ; 比较一下是否相等
通过算法算出的key,可以有很多种组合,只要key 的字符串不变,每个字符串的顺序可以变动。
注册算法代码:
//根据用户名计算出来的数值
int UserNum=0;//根据用户名计算的长度
char *UserName="asdfgh";
int charLength=strlen(UserName);
int x=0;
do
{
UserNum=UserNum+(int)(UserName[x]);
x++;
}while(x<charLength);
printf("用户名计算出来的数值: \r\n%d,0x%X \r\n",UserNum,UserNum);
int _EDI=0;//存放最后结果
char *KeyConst="KEY-KANON";
int _EAX=0;
int n=0;
int _ESI=UserNum;
int _EDX=0;//存放求余数
int _EBX=0;
char RealkeyStr[10]={0};
do
{
_EAX=(int)(KeyConst[n]);
_EAX=_EAX*_ESI;
_EDX=0;
_EBX=0x1A;
_EDX=_EAX%_EBX;
_EDX=_EDX+0x61;
printf("_EDX=%d,%x \r\n",_EDX,_EDX);
//保留一下这里的edx的值
RealkeyStr[n]=_EDX;
__asm
{
mov edx,_EDX
xor edx,0xAA
mov _EDX,edx
}
_EDI=_EDI+_EDX;
n++;
}while(n<9);
printf("计算出来Key数值: \r\n%d,0x%X ,%s\r\n",_EDI,_EDI,RealkeyStr);
代码用的都是跟寄存器名称差不多的,基本像我一样的新手,一看就明白。
具体代码看附件
CrackMe下载地址:http://bbs.pediy.com/showthread.php?t=12375
[培训]科锐逆向工程师培训第53期2025年7月8日开班!