【破文标题】CRACKME算法分析
【破文作者】逍遥风
【破解工具】OD 计算器
【保护方式】anti-debugging
----------------------------------------------------------------------
菜鸟偶得一点心得与大家分享
----------------------------------------------------------------------
综合简单的anti-debugging和算法分析,希望对大家有帮助。
话不多说,直接开始
用OD载入这个CRACKME ,根据字符串提示里的注册成功的信息,来到关键代码处
00447FA5 |. E8 A2040000 call 0044844C ; 在这里下断点
00447FAA |. 84C0 test al, al
00447FAC |. 75 14 jnz short 00447FC2
00447FAE |. B8 FC7F4400 mov eax, 00447FFC ; error! incorrect serial!
00447FB3 |. E8 38DBFFFF call 00445AF0
00447FB8 |. 33C0 xor eax, eax
00447FBA |. 8983 34020000 mov [ebx+234], eax
00447FC0 |. EB 0A jmp short 00447FCC
00447FC2 |> B8 20804400 mov eax, 00448020 ; thanks for registering our product :)))!
下完断点后,F9运行程序,但是OD这时的反应却是“已经终止”
基本可以确定这个CRACKME有anti-debugging
重新载入程序,打开“当前模块中的名称”(Ctrl+N)
找到这个
名称位于 crackme2, 条目 213
地址=0044B500
区段=.idata
类型=输入 (已知)
名称=user32.IsDialogMessageA
1)解决它的
根据它来到这里:anti-debugging
0044833C . E8 5BFFFFFF call <jmp.&kernel32.IsDebuggerPresent>; [IsDebuggerPresent
00448341 . 85C0 test eax, eax
00448343 . 74 0C je short 00448351
将这里的跳转改为:
00448343 /EB 0C jmp short 00448351
保存修改后,重新载入修改后的CRACKME。此时crackme就可以正常运行了。
2)分析算法
根据错误提示来到关键代码处
00447FA5 |. E8 A2040000 call 0044844C ; 在这里下断点(关键CALL,跟进)
00447FAA |. 84C0 test al, al
00447FAC |. 75 14 jnz short 00447FC2
00447FAE |. B8 FC7F4400 mov eax, 00447FFC ; error! incorrect serial!
00447FB3 |. E8 38DBFFFF call 00445AF0
00447FB8 |. 33C0 xor eax, eax
00447FBA |. 8983 34020000 mov [ebx+234], eax
00447FC0 |. EB 0A jmp short 00447FCC
00447FC2 |> B8 20804400 mov eax, 00448020 ; thanks for registering our product :)))!
----------------------------------------------------------------------
跟进关键CALL
来到这里:
0044844C /$ 55 push ebp
0044844D |. 8BEC mov ebp, esp
省略一些代码。。。。。。
0044846D |. E8 6EB4FBFF call 004038E0
00448472 |. 80BF F4020000>cmp byte ptr [edi+2F4], 4 ; 注册名与4比较位数
00448479 |. 73 07 jnb short 00448482 ; 注册名必须大于4位
0044847B |. 33DB xor ebx, ebx
0044847D |. E9 42010000 jmp 004485C4
00448482 |> 80BF F9030000>cmp byte ptr [edi+3F9], 2D ; 取注册码的第5位与2D比较(即判断注册码的第5位是否为“-”)
00448489 |. 75 09 jnz short 00448494 ; 不相等就跳向失败
0044848B |. 80BF F4030000>cmp byte ptr [edi+3F4], 9 ; 注册码等于9位吗?
00448492 |. 74 07 je short 0044849B ; 注册码不为9位就失败
到这里,可以看出
1)注册名必须是大于4位
2)注册码必须是9位
且必须是1234-6789这样的形式
重新载入,将注册码按格式输入,继续分析
省略一些代码。。。。。。
004484B7 |> /33C9 /xor ecx, ecx
004484B9 |. |8A8C1>|mov cl, [edi+edx+2F>; 取注册名每一位的ASCII码
004484C0 |. |014D >|add [ebp-C], ecx ; 累加注册名每一位的ASCII码结果设为A
004484C3 |. |42 |inc edx ; 没计算一次EDX+1
004484C4 |. |48 |dec eax ; 每计算一次EAX-1
004484C5 |.^\75 F0 \jnz short 004484B7 ; 循环计算
这个循环计算的作用是累加注册名ASCII码的值
例如:注册名lovetc
累加结果为28D
累加完后来到这里:
004484CC |. BE 01>mov esi, 1 ; 使ESI=1
004484D1 |> 8A5D >/mov bl, [ebp-8]
004484D4 |. 8BCE |mov ecx, esi
004484D6 |. 81E1 >|and ecx, 80000001
004484DC |. 79 05 |jns short 004484E3
004484DE |. 49 |dec ecx
004484DF |. 83C9 >|or ecx, FFFFFFFE
004484E2 |. 41 |inc ecx
004484E3 |> B8 05>|mov eax, 5 ; 使EAX等于5
004484E8 |. 2BC6 |sub eax, esi ; EAX=EAX-ESI(结果设为B)
004484EA |. 8A840>|mov al, [edi+eax+2F>; 取B对应位数的注册名的ASCII码
004484F1 |. 0AD8 |or bl, al ; OR[第N-1次所取的注册码,Yn]
004484F3 |. D2E3 |shl bl, cl ; 如果是偶数位就用OR运算的结果乘以2的1次方
004484F5 |. 8BCE |mov ecx, esi ; 使ECX=ESI
004484F7 |. 8A45 >|mov al, [ebp-C] ; 取注册名ASCII码累加值的后两位
004484FA |. D2E0 |shl al, cl ; A的后两位乘以2的N次方(结果设为D)
004484FC |. 02D8 |add bl, al ; (C+D的后两位)得到E
004484FE |. 33C0 |xor eax, eax ; EAX清零
00448500 |. 8AC3 |mov al, bl ; 使AL等于计算结果E
00448502 |. B9 1A>|mov ecx, 1A ; 使ECX等于固定值0x1A
00448507 |. 33D2 |xor edx, edx ; EDX清零
00448509 |. F7F1 |div ecx ; EAX中的值除以ECX中的值,商放进EAX余数放进EDX
0044850B |. 80C2 >|add dl, 41 ; 所得的余数加上定值0x41,得到结果F
0044850E |. 8BDA |mov ebx, edx ; 使EBX=EDX(结果F放进EBX中)
00448510 |. 8A843>|mov al, [edi+esi+3F>; 取注册码第一位的ASCII码
00448517 |. 32D8 |xor bl, al ; 计算结果F与注册码第一位的ASCII码做XOR运算
00448519 |. 74 07 |je short 00448522
0044851B |. 33DB |xor ebx, ebx ; 不相等就将EBX清零
0044851D |. E9 A2>|jmp 004485C4 ; 跳向失败
00448524 |. 8A843>|mov al, [edi+esi+2F4] ; 按次取注册名每一位的ASCII码
0044852B |. F7EE |imul esi ; ASCII码乘以计算次数
0044852D |. 0145 >|add [ebp-8], eax ; 相乘后的积累加(作为Yn)
00448530 |. 46 |inc esi ; 每计算一次ESI中的值加1
00448531 |. 83FE >|cmp esi, 5 ; 计算5次就结束
00448534 |.^ 75 9B \jnz short 004484D1 ; 循环计算
由于注册码是1234-6789这样的形式,这段代码就是计算注册码的第一部分(即1234对应的部分)
计算的过程为:以注册名lovetc为例:
注意:由于计算过程奇偶有关,所以须分两种情况举例
1)先取定值5,减去计算次数1(第一次计算),得到结果4。
2)在注册名中取4对应的字符(注册名的第4位)e对应的ASCII码65,OR(65,0)=65
3)因为4是偶数,所以就用65 * 2 = CA ,取累加结果28D的后两位8D
4)8D乘以2的N=1次方等于11A,取后两位1A
5) CA + 1A = E4 ,E4/1A=8,余数为14,14+41=55,55对应的字母是U
所以注册码第1位就是U:
1)在一次取定值5,减去计算次数2(第二次计算),得到结果3。
2)在注册名中取3对应的字符(注册名的第3位)v对应的ASCII码76,OR(76,6C)=7E
|--------n=1,Y1=6C
3)因为3是奇数,取累加结果28D的后两位8D
4)8D乘以2的N=2次方等于234,取后两位34
5)34 + 7E = B2,B2/1A,余数为16,16+41=57,57对应的字母是W
所以注册码第2位是W
依次类推:注意累加部分Yn的变化
Y1=6C*1, Y2=6F*2+6C=14A(取后两位4A,就是Y2)
|--|-注册码第一位得ASCII码 |--|--|----------注册码第二位得ASCII码
|----计算次数 |--|-------------计算次数
|----------------Y1
最后:得到注册码第一部分是UWSG
开始计算第2部分
00448536 |. C745 >mov dword ptr [ebp-8],>; 取定值0xABCD作为一个字符串
0044853D |. BE 01>mov esi, 1 ; 使ESI等于1
00448542 |> 8A5D >/mov bl, [ebp-8] ; 取定值0xABCD中取后两位。设为Z(Z1=CD)
00448545 |. 8BCE |mov ecx, esi
00448547 |. 81E1 >|and ecx, 80000001
0044854D |. 79 05 |jns short 00448554
0044854F |. 49 |dec ecx
00448550 |. 83C9 >|or ecx, FFFFFFFE
00448553 |. 41 |inc ecx
00448554 |> 8B45 >|mov eax, [ebp-4] ; 使EAX等于注册名的位数
00448557 |. 2BC6 |sub eax, esi ; EAX=EAX-ESI
00448559 |. 8A840>|mov al, [edi+eax+2F4] ; 取所得的差对应的注册名的ASCII码
00448560 |. 0AD8 |or bl, al ; OR(注册名的ASCII码,Zn)
00448562 |. D2E3 |shl bl, cl ; 如果是奇数位就用OR运算结果乘以2的一次方(结果设为F)
00448564 |. 8BCE |mov ecx, esi
00448566 |. 8B45 >|mov eax, [ebp-C] ; 取注册名的累加值(即A)
00448569 |. D3E8 |shr eax, cl ; A除以2的n次方(商设为G)
0044856B |. 02D8 |add bl, al ; (F+G的后两位),结果设为H
0044856D |. 33C0 |xor eax, eax
0044856F |. 8AC3 |mov al, bl ; 使AL等于H的后两位
00448571 |. B9 1A>|mov ecx, 1A ; 使ECX等于定值0x1A
00448576 |. 33D2 |xor edx, edx
00448578 |. F7F1 |div ecx ; EAX中的值除以ECX中的值,商放进EAX余数放进EDX
0044857A |. 80C2 >|add dl, 41 ; 所得余数加上定值0x41。得到结果X
0044857D |. 8BDA |mov ebx, edx ; 使EBX等于结果X
0044857F |. 8D46 >|lea eax, [esi+5]
00448582 |. 8A840>|mov al, [edi+eax+3F4] ; 取注册码对应位数的字符
00448589 |. 32D8 |xor bl, al ; 比较结果X与对应位数的注册码
0044858B |. 74 04 |je short 00448591 ; 相等就继续比较下一位
0044858D |. 33DB |xor ebx, ebx
0044858F |. EB 33 |jmp short 004485C4
00448591 |> 8B45 >|mov eax, [ebp-4] ; 使EAX等于注册名位数
00448594 |. 83E8 >|sub eax, 4 ; EAX=EAX-4
00448597 |. 03C6 |add eax, esi ; 计算次数与(注册名-4)所得得差相加
00448599 |. 0FB68>|movzx eax, byte ptr [ed>; 在注册名中取对应位数得字符
004485A1 |. F7EE |imul esi ; 对应字符得ASCII码乘以计算次数
004485A3 |. 0145 >|add [ebp-8], eax ; 第N次计算得结果与第N-1次计算的结果相加(即得到Zn)
004485A6 |. 46 |inc esi ; 每计算1次ESI+1
004485A7 |. 83FE >|cmp esi, 5 ; 计算5次
004485AA |.^ 75 96 \jnz short 00448542 ; 循环计算
以注册名lovetc为例:
注意:由于计算过程奇偶有关,所以须分两种情况举例
1)取字符串ABCD,取后两位CD作为Z1。6-1=5(注册名位数减去计算次数),取注册名第5位t对应的ASCII码74, OR(74,CD)=FD
2)因为5是奇数,所以FD * 2 = 1FA ,取后两位FA,
3)取注册名累加值28D,除以2,商为146,取后两位46
4)46 + FA = 140,取后两位40,40/1A=2,余数是C,C+41=4D,4D对应的字母是M
所以注册码第2部分
第一位是M
注意Zn的变化:Z1=CD,
6-4+1=3,注册名第3位V对应ASCII码76乘以计算次数N=1,得76。76+ABCD=AB43,所以Z2=43
|-|-|----计算次数
| |
|-|-----定值4
|
|------计算次数
依次类推:得到Zn
计算第2位:
1)6-2=4(注册名位数减去计算次数),取注册名第4位e对应的ASCII码65,OR(65,43)= 67
2)因为4是偶数,所以取注册名累加值28D,除以2*2,商为A3。
3)A3 + 67 = 10A, 取后两位0A,A/1A,余数是A,A+41=4B,4D对应的字母是K
所以所以注册码第2部分
第二位是K
依次类推:
最后可以得出注册码第2部分是MKBV
所以
注册名lovetc
注册码UWSG-MKBV
----------------------------------------------------------------------
【版权声明】本文只位交流,转载清保留作者及文章完整性
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!