【文章标题】: ty123的实用crackme- CPN Augur (新手飘过~~) 破解详情
【文章作者】: atomy
【作者邮箱】: http://2lin.net
--------------------------------------------------------------------------------
【详细过程】
偶还是一个新手. 看到一个新手飘过的字样 不由的心痒痒想试一试.
这个CrackMe 分析花了我好几天的时间
第一次只破解了前四位 后来不甘心 最终被偶破解下来了.使我学到了不少东西 下面讲一下分析过程
作者使用的软件防爆破方法真的不错. 以后可以多学习一下了
这个CrackMe里面加了很多防爆破
举个例
一般大家爆破使用的方法就是修改爆破点. 但是作者使用内存动态解密的方法
使用爆破点的数据进行加密 如果爆破点的数据改了 那解密出来的数据就是错误的 造成执行程序错误
这种方法对OD的中断也有效 如果在爆破点设置断点 同样会发生异常
好了 知道了这些 调试的时候只要不对爆破点下断点就可以了
首先 试练码
USER:ABCDEFG
SN: 123456
点击注册 提示重启验证
重启 输入命令 bp RegQueryValueExA 运行
被断后 一直按ALT + F9 或F9 直到进入 用户代码
一直跟到下面代码
004013BC 6A 00 push 0
004013BE 8F45 88 pop dword ptr [ebp-78]
004013C1 68 E4304000 push 004030E4 ; ASCII "BOY"
004013C6 68 C3304000 push 004030C3 ; ASCII "Software\CPN Augur\Licence\"
004013CB 8D45 88 lea eax, dword ptr [ebp-78]
004013CE 50 push eax
004013CF E8 8C050000 call 00401960
004013D4 8B4D 88 mov ecx, dword ptr [ebp-78]
004013D7 85C9 test ecx, ecx
004013D9 0F84 8E020000 je 0040166D
004013DF 68 13304000 push 00403013
004013E4 68 AA204000 push 004020AA ; ASCII "Serial Number"
004013E9 68 C3304000 push 004030C3 ; ASCII "Software\CPN Augur\Licence\"
004013EE 8D45 DB lea eax, dword ptr [ebp-25]
004013F1 50 push eax
004013F2 E8 BF040000 call 004018B6
004013F7 68 DF304000 push 004030DF ; ASCII "PLAY"
004013FC 68 C3304000 push 004030C3 ; ASCII "Software\CPN Augur\Licence\"
00401401 8D45 8C lea eax, dword ptr [ebp-74]
00401404 50 push eax
00401405 E8 56050000 call 00401960
0040140A 68 13304000 push 00403013
0040140F 68 A0204000 push 004020A0 ; ASCII "User Name"
00401414 68 A6304000 push 004030A6 ; ASCII "Software\CPN Augur\User\"
00401419 8D45 9B lea eax, dword ptr [ebp-65]
0040141C 50 push eax
0040141D E8 94040000 call 004018B6
竟然有读四个值 PLAY BOY UserName SerialNumber
继续往下看
00401422 6A 00 push 0
00401424 6A 00 push 0
00401426 6A 00 push 0
00401428 6A 00 push 0
0040142A 8D45 FC lea eax, dword ptr [ebp-4]
0040142D 50 push eax
0040142E 6A 00 push 0
00401430 6A 00 push 0
00401432 68 EE304000 push 004030EE ; ASCII "c:\"
00401437 E8 90060000 call <jmp.&kernel32.GetVolumeInformationA> ;取磁盘序号
0040143C FF75 9B push dword ptr [ebp-65]
0040143F 58 pop eax ; 用户名 前四位
00401440 C1C0 08 rol eax, 8 ; 循环左移8位
00401443 3345 FC xor eax, dword ptr [ebp-4] ; 再异或C盘序列号
00401446 2E:3305 7514400>xor eax, dword ptr cs:[401475] ; 再异或850F073A
0040144D 8945 90 mov dword ptr [ebp-70], eax
00401450 8D75 90 lea esi, dword ptr [ebp-70]
00401453 8B45 DB mov eax, dword ptr [ebp-25] ; 序列号
00401456 0FC8 bswap eax ; 交换顺序
00401458 C1C8 08 ror eax, 8 ; 循环右移8位
0040145B 8945 DB mov dword ptr [ebp-25], eax
0040145E 8D7D DB lea edi, dword ptr [ebp-25]
00401461 6A 04 push 4
00401463 59 pop ecx
00401464 6A 10 push 10
00401466 5A pop edx
00401467 8D1D 00304000 lea ebx, dword ptr [403000] ; 字符 CodedByTy123-China
0040146D 33C0 xor eax, eax
0040146F AC lods byte ptr [esi] ; 取用户名算出来的字符第一个字节到al
00401470 F6F2 div dl ; 将值 / 10
00401472 86C4 xchg ah, al ; 交换 ah, al
00401474 D7 xlat byte ptr [ebx+al] ; 从字符 CodedByTy123-China 中取值
00401475 3A07 cmp al, byte ptr [edi] ; 对比
00401477 0F85 F0010000 jnz 0040166D ; 不对 出错
0040147D 47 inc edi
0040147E ^ E2 ED loopd short 0040146D
上面代码可以看出 这是对第一组序列号四个字符对比
可以利用反推方法得出第一组序号
关键在第二次对比 这个东东偶分析了好久的时间 下面看第二个对比
00401498 8B45 88 mov eax, dword ptr [ebp-78] ; BOY
0040149B 2E:3305 7514400>xor eax, dword ptr cs:[401475] ; 异或 850F073A
004014A2 3345 8C xor eax, dword ptr [ebp-74] ; 异或 PLAY
004014A5 F7D0 not eax ; 取反
004014A7 35 CA158B7D xor eax, 7D8B15CA ; 异或 7D8B15CA
004014AC 0F85 BB010000 jnz 0040166D ; !=0 Over
上面有两个数 一个PLAY BOY 可是不知道这两个数字是怎么来的.
这就需要跟踪到点击注册确定的时候做了些什么事情了.
用上面的方法 下断 bp RegCreateKeyExA 按 ALT + F9 直到返回到用户代码 一直跟到下面代码
00401072 50 push eax
00401073 68 D5070000 push 7D5
00401078 FF75 08 push dword ptr [ebp+8]
0040107B E8 DA090000 call <jmp.&user32.GetDlgItemTextA>
00401080 D1E0 shl eax, 1 ; 序列号个数左移1位
00401082 8945 C4 mov dword ptr [ebp-3C], eax ; 放入内存
00401085 DB45 C4 fild dword ptr [ebp-3C] ; 放入st(0)
00401088 D9EB fldpi ; 放入st(1) pi
0040108A DEC9 fmulp st(1), st ; st(1) * st(0)
0040108C D95D CC fstp dword ptr [ebp-34] ; 放入变量
0040108F 8D75 D4 lea esi, dword ptr [ebp-2C] ; 跳过前四位 取序列号后面的字符
00401092 8D7D C8 lea edi, dword ptr [ebp-38]
00401095 6A 03 push 3
00401097 59 pop ecx ; 3次
00401098 A4 movs byte ptr es:[edi], byte ptr [esi]
00401099 83C6 04 add esi, 4 ; 间隔4位字符取3个字符作序列号
0040109C ^ E2 FA loopd short 00401098
0040109E B8 47434644 mov eax, 44464347
004010A3 3145 C8 xor dword ptr [ebp-38], eax ; 将挑出来的字符异或44464347
004010A6 68 E8304000 push 004030E8 ; ASCII "E-Mag"
004010AB 68 C3304000 push 004030C3 ; ASCII "Software\CPN Augur\Licence\"
004010B0 68 6B304000 push 0040306B
004010B5 E8 A6080000 call 00401960 ; 获取 E-Mag 的值
004010BA 60 pushad
004010BB 8D05 D7104000 lea eax, dword ptr [4010D7] ;
004010C1 B9 2C000000 mov ecx, 2C
004010C6 8B15 06114000 mov edx, dword ptr [401106]
004010CC 3110 xor dword ptr [eax], edx ; 动态解密
004010CE 83C0 04 add eax, 4
004010D1 83E9 04 sub ecx, 4
004010D4 ^ 75 F6 jnz short 004010CC
上面代码可以看出 一花算出了两个值
一个是 将 SN shl 1 * pi 放入 ebp-34
第二个是 将 序列号隔四位取一个字符 然后 xor 44464347H 放入 ebp-38 再动态解密一段代码 看看解出来的代码是什么样的
004010D7 A1 6B304000 mov eax, dword ptr [40306B] ; E-Mag 的值
004010DC 85C0 test eax, eax ; 为空跳走
004010DE 74 32 je short 00401112
004010E0 35 71FF2CD7 xor eax, D72CFF71 ; EAX xor D72CFF71
004010E5 C1E8 04 shr eax, 4 ; 右移4位
004010E8 8B35 06114000 mov esi, dword ptr [401106] ; 4376073C
004010EE 3335 03114000 xor esi, dword ptr [401103] ; 3CE08A40
004010F4 3335 0D114000 xor esi, dword ptr [40110D] ; EBCC7531
004010FA 3335 0A114000 xor esi, dword ptr [40110A] ; 31C85531
00401100 90 nop
00401101 90 nop
00401102 90 nop
00401103 40 inc eax ; EAX ++
00401104 8AE0 mov ah, al
00401106 3C 07 cmp al, 7 ; AL > 7
00401108 76 43 jbe short 0040114D ; 转移
0040110A 3155 C8 xor dword ptr [ebp-38], edx ; EDX = 7C95ED54
0040110D 3175 CC xor dword ptr [ebp-34], esi ; ESI = xor 31C85531 xir EBCC7531 xor 3CE08A40 xor 4376073C
00401110 EB 3B jmp short 0040114D
00401113 8D05 2F114000 lea eax, dword ptr [40112F]
00401119 B9 1C000000 mov ecx, 1C
0040111E 8B15 03114000 mov edx, dword ptr [401103]
00401124 3110 xor dword ptr [eax], edx ;防爆破 解密
00401126 83C0 04 add eax, 4
00401129 83E9 04 sub ecx, 4
0040112C ^ 75 F6 jnz short 00401124
0040112E 61 popad
0040112F 40 inc eax ;
00401130 8AE0 mov ah, al ;
00401132 C1E0 04 shl eax, 4 ; eax = 1010H
00401135 2E:3305 0311400>xor eax, dword ptr cs:[401103] ; 3CE08A40
0040113C 2E:3305 0D11400>xor eax, dword ptr cs:[40110D] ; EBCC7531
00401143 A3 6B304000 mov dword ptr [40306B], eax ; E-mag
这段代码大概意思就是将 E-Mag的值 进行一些计算 最后再看 al的值是否大于 7 如果大于就将
上面计算的两个数 分别 xor 0A592AD7CH 和 7C95ED54H
E-Mag的初始值是 0D72CEF61H 继续跟踪代码
00401151 8D05 69114000 lea eax, dword ptr [401169]
00401157 B9 14000000 mov ecx, 14
0040115C 8BD6 mov edx, esi ;
0040115E 3110 xor dword ptr [eax], edx
00401160 83C0 04 add eax, 4
00401163 83E9 04 sub ecx, 4
00401166 ^ 75 F6 jnz short 0040115E
00401168 61 popad
00401169 2E:3305 0311400>xor eax, dword ptr cs:[401103] ; 3CE08A40
00401170 2E:3305 0D11400>xor eax, dword ptr cs:[40110D] ; EBCC7531
00401177 A3 6B304000 mov dword ptr [40306B], eax ; 重新给E-Mag 定值
0040117C 90 nop
0040117D 68 E8304000 push 004030E8 ; ASCII "E-Mag"
00401182 68 C3304000 push 004030C3 ; ASCII "Software\CPN Augur\Licence\"
00401187 68 6B304000 push 0040306B
0040118C E8 83070000 call 00401914 ; 写入E-Bag
00401191 6A 18 push 18
00401193 8D45 E8 lea eax, dword ptr [ebp-18]
00401196 50 push eax
00401197 68 D3070000 push 7D3
0040119C FF75 08 push dword ptr [ebp+8]
0040119F E8 B6080000 call <jmp.&user32.GetDlgItemTextA>
004011A4 83F8 04 cmp eax, 4
004011A7 72 05 jb short 004011AE
004011A9 83F8 10 cmp eax, 10
004011AC 76 02 jbe short 004011B0
004011AE EB 50 jmp short 00401200
004011B0 6A 18 push 18
004011B2 68 A0204000 push 004020A0 ; ASCII "User Name"
004011B7 68 A6304000 push 004030A6 ; ASCII "Software\CPN Augur\User\"
004011BC 8D45 E8 lea eax, dword ptr [ebp-18]
004011BF 50 push eax
004011C0 E8 A4060000 call 00401869
004011C5 6A 18 push 18
004011C7 68 AA204000 push 004020AA ; ASCII "Serial Number"
004011CC 68 C3304000 push 004030C3 ; ASCII "Software\CPN Augur\Licence\"
004011D1 8D45 D0 lea eax, dword ptr [ebp-30]
004011D4 50 push eax
004011D5 E8 8F060000 call 00401869
004011DA 68 DF304000 push 004030DF ; ASCII "PLAY"
004011DF 68 C3304000 push 004030C3 ; ASCII "Software\CPN Augur\Licence\"
004011E4 8D45 CC lea eax, dword ptr [ebp-34]
004011E7 50 push eax
004011E8 E8 27070000 call 00401914
004011ED 68 E4304000 push 004030E4 ; ASCII "BOY"
004011F2 68 C3304000 push 004030C3 ; ASCII "Software\CPN Augur\Licence\"
004011F7 8D45 C8 lea eax, dword ptr [ebp-38]
004011FA 50 push eax
004011FB E8 14070000 call 00401914
可以看出 PLAY的值 = Count shl 1 * pi
而 Boy 的值 就是序列号 每隔四个字符的值 再 xor 44464347H
如果 E-Mag 算出的值 <= 7 还会 将这两个数字 再 xor 0A592AD7CH 和 7C95ED54H
也就是说 第一次注册 是不会 xor 0A592AD7CH 和 7C95ED54H 的 所以调试的时候 每次都把 E-Mag这个键值删掉再重新注册
而且 PLAY 的值 等于 Count shl 1 * pi 那么这是一个常数 现在的问题是怎么知道序列号是多少位的呢.
利用反推法.
首先反推第二个对比
mov eax, 7D8B15CAH
not eax ;先将 7D8B15CAH 取反 得到 8274EA35H
xor eax, PLAY ;再 xor PLAY
xor eax, 850F073AH ;得到BOY的值
BOY 是 三个字符串 xor 44464347H 这么说 要得到正确的BOY 应该 第一个数字应该得到 44******H 这种数字才可以得到真正的 BOY 也就是三个字符
最后一个 xor 的数字是 850F073AH 那么 就是说 PLAY 的值 应该是 850F073AH xor 44******H = 43******H
于是写了下面一个过程 先假设 注册码为 16 位
.data?
p dd ?
.CODE
START:
mov eax, 0FH
shl eax, 1
R:
shr eax, 1
inc eax
shl eax, 1
mov
, eax
fild DWORD PTR
fldpi
fmulp st(1), st
fstp DWORD PTR
and DWORD PTR
,0FF000000H
cmp DWORD PTR
,43000000H
jnz R
shr eax, 1
这样 得出 eax 的值 = 21 就是 注册码的个数 然后再反推 BOY的值 为 /\>
哈 其实这是错误的 真正的注册是23位的 追到后面看就知道了 但是这个数字可以通过第二关
继续跟踪第三关
004014B2 8D75 E0 lea esi, dword ptr [ebp-20] ; 继续
004014B5 8B06 mov eax, dword ptr [esi] ; 取四位放入eax
004014B7 3345 DB xor eax, dword ptr [ebp-25] ; 和序列号生成的前四位数异或
004014BA 8906 mov dword ptr [esi], eax
004014BC 33C0 xor eax, eax
004014BE 33D2 xor edx, edx
004014C0 6A 04 push 4
004014C2 59 pop ecx
004014C3 AC lods byte ptr [esi] ; 放入al
004014C4 3203 xor al, byte ptr [ebx] ; xor Code
004014C6 03D0 add edx, eax ; edx += eax
004014C8 43 inc ebx
004014C9 ^ E2 F8 loopd short 004014C3
004014CB 52 push edx ; edx
004014CC 8D75 9B lea esi, dword ptr [ebp-65] ; esi = 用户名
004014CF 33C0 xor eax, eax
004014D1 33D2 xor edx, edx
004014D3 6A 04 push 4
004014D5 59 pop ecx
004014D6 AC lods byte ptr [esi]
004014D7 3203 xor al, byte ptr [ebx] ; xor dByT
004014D9 03D0 add edx, eax ; edx += eax
004014DB 43 inc ebx
004014DC ^ E2 F8 loopd short 004014D6
004014DE 87CA xchg edx, ecx
004014E0 5A pop edx
004014E1 33CA xor ecx, edx ; edx1 != edx2 序列号不对 edx 要用到后面解压
004014E3 0F85 84010000 jnz 0040166D
这个算法把偶给搞了好久才明白
其实就是 将 用户名前四位 xor 'dByT' 然后 再 xor 'Code' 就是第二组序列号了
继续往下看
00401506 A1 75144000 mov eax, dword ptr [401475] ; 内存指定住不能下断点
0040150B 3305 E1144000 xor eax, dword ptr [4014E1]
00401511 3305 AC144000 xor eax, dword ptr [4014AC]
00401517 8BF8 mov edi, eax
00401519 8945 90 mov dword ptr [ebp-70], eax
0040151C 60 pushad
0040151D 8D05 35154000 lea eax, dword ptr [401535]
00401523 B9 34000000 mov ecx, 34
00401528 8BD7 mov edx, edi
0040152A 3110 xor dword ptr [eax], edx
0040152C 83C0 04 add eax, 4
0040152F 83E9 04 sub ecx, 4
00401532 ^ 75 F6 jnz short 0040152A
00401534 61 popad
00401535 8D75 E5 lea esi, dword ptr [ebp-1B] ; 继续计算第三组
00401538 8D1D EB144000 lea ebx, dword ptr [4014EB] ; nothing special, right? :)
0040153E 6A 04 push 4
00401540 59 pop ecx
00401541 33C0 xor eax, eax
00401543 AC lods byte ptr [esi]
00401544 3203 xor al, byte ptr [ebx]
00401546 C1C0 08 rol eax, 8
00401549 43 inc ebx
0040154A ^ E2 F7 loopd short 00401543
0040154C 50 push eax ; 保存Eax
0040154D 8D75 9B lea esi, dword ptr [ebp-65] ; 用户名
00401550 6A 04 push 4
00401552 59 pop ecx
00401553 03D9 add ebx, ecx ; special, right? :)
00401555 33C0 xor eax, eax
00401557 AC lods byte ptr [esi]
00401558 3203 xor al, byte ptr [ebx]
0040155A C1C0 08 rol eax, 8
0040155D 43 inc ebx
0040155E ^ E2 F7 loopd short 00401557
00401560 0FC8 bswap eax ; 交换 eax
00401562 C1C8 08 ror eax, 8 ; 循环右移
00401565 91 xchg eax, ecx
00401566 58 pop eax
00401567 33C8 xor ecx, eax ; 计算出来的值必须相等
00401569 0F85 FE000000 jnz 0040166D
第三组的算法也很是简单 不过也把偶的头搞的晕晕的.
试了N次才得到这样一个算法
mov eax, 'spec'
xor eax, DWORD PTR [sUserName]
rol eax, 8H
bswap eax
xor eax, 'noth'
eax 就是 第三组序列号了
走到这里 可以说真是费了偶的九牛二虎之力 不容易呀..
继续看最后一组吧.
004015A7 8D75 FC lea esi, dword ptr [ebp-4] ; 硬盘序号
004015AA 6A 04 push 4
004015AC 59 pop ecx
004015AD 33C0 xor eax, eax
004015AF 33D2 xor edx, edx
004015B1 AC lods byte ptr [esi]
004015B2 03D0 add edx, eax ; 四个字节的和
004015B4 ^ E2 FB loopd short 004015B1
004015B6 8955 90 mov dword ptr [ebp-70], edx
004015B9 DB45 90 fild dword ptr [ebp-70]
004015BC 8D75 9B lea esi, dword ptr [ebp-65] ; 用户名
004015BF 8D45 9B lea eax, dword ptr [ebp-65]
004015C2 50 push eax
004015C3 E8 78050000 call 00401B40 ; 取用户名的长度
004015C8 91 xchg eax, ecx
004015C9 33D2 xor edx, edx
004015CB AC lods byte ptr [esi]
004015CC 03D0 add edx, eax ; 用户名 ASCII 和
004015CE ^ E2 FB loopd short 004015CB
004015D0 0FAFD2 imul edx, edx ; edx * edx
004015D3 8955 90 mov dword ptr [ebp-70], edx
004015D6 DB45 90 fild dword ptr [ebp-70]
004015D9 DEC9 fmulp st(1), st ;
004015DB D9EB fldpi
004015DD DEC9 fmulp st(1), st ; * pi
004015DF D9FC frndint ; 四舍五入
004015E1 8D45 EA lea eax, dword ptr [ebp-16] ; 最后的序列号
004015E4 50 push eax
004015E5 E8 FA040000 call 00401AE4 ; 哈哈 和Crackme 5的算法一样 将字符串转换成数值
004015EA 3345 88 xor eax, dword ptr [ebp-78] ; xor boy 的值
004015ED 8945 90 mov dword ptr [ebp-70], eax
004015F0 DB45 90 fild dword ptr [ebp-70]
004015F3 DB45 E5 fild dword ptr [ebp-1B] ; 第三组序列号
004015F6 DEE9 fsubp st(1), st ; [ebp-70] - 第三组序列号的值
004015F8 D8D9 fcomp st(1) ; 比较
004015FA 9B wait
004015FB DFE0 fstsw ax
004015FD 9E sahf ; ah 是否为 0
004015FE 75 6D jnz short 0040166D ; 最后一次对比
由于上次分析过 Crackme 5 发现这里竟然和那个一样 于是就猜测到最后一组的序列号应该是 8位
所以注册码总数 = 23
算法是根据用户名计算出一个值 然后再 将最后一组的值计算出一个数字 相等 就ok
--------------------------------------------------------------------------------
【经验总结】
破解分析完后 感受颇深 使我更坚信,只要你有足够的耐心 没有什么事能难到你. 当然前提是你有充足的时间
下面是注册机代码 汇编写的 偶汇编不太好 大家将就着看吧.
如果有什么错误 请大家指正~ 谢谢!
.486
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
include gdi32.inc
include advapi32.inc
includelib gdi32.lib
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
includelib advapi32.lib
include macro.asm
.data
sMsg db "请输入用户名:",0
sDriver db "C:\", 0
sFormat db "序列号是:%s",0
sFormat1 db "%08X",0
sKey db "CodedByTy123-China", 0
sKey1 db "nothing special, right? :)", 0
sKEYPath db "SOFTWARE\CPN Augur\Licence\", 0
dBoy dd 446B6E6AH
.data?
sUserName db MAX_PATH dup(?)
sRegKey db MAX_PATH dup(?)
sShowKey db MAX_PATH dup(?)
dSerial dd ?
dPlay dd ?
p dd ?
.CODE
START:
;删除注册表的键
invoke RegDeleteKey, HKEY_LOCAL_MACHINE, addr sKEYPath
invoke StdOut,offset sMsg
invoke StdIn, addr sUserName, sizeof sUserName
;获取硬盘序列号
invoke GetVolumeInformation, addr sDriver, 0, 0, addr dSerial, 0, 0, 0, 0
;计算第一组序列号
mov eax, DWORD PTR [sUserName]
rol eax, 8 ;
xor eax, DWORD PTR [dSerial] ; eax xor 硬盘序列号
xor eax, 850F073AH
mov
, eax
lea esi,
mov ecx, 4H
mov edx, 10H
lea ebx, [sKey]
lea edi,
R:
xor eax, eax
lods BYTE PTR [esi]
div dl
xchg ah, al
xlat
stosb
loopd R
mov eax, DWORD PTR
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课