标 题: 一个简单的cm的注册分析及编写注册机
作 者: keheng
时 间: 2009年06月13日 10:46:50
链 接: http://bbs.pediy.com/showthread.php?t=91441
http://www.bt518.cn/Blog/article.asp?id=39
【文章标题】: 一个简单的cm的注册分析及编写注册机
【文章作者】: keheng
【作者邮箱】: keheng@163com
【软件名称】: d2k2_crackme01.exe
【下载地址】: 忘记在哪下载的了。
【使用工具】: ollydbg,peid
【作者声明】: 写的第一个cm注册机,还忘记大侠指教一下。
--------------------------------------------------------------------------------
第一次写破文和注册机,实话说,感触很多,尤其是写注册机的时候觉得很多的命令不知道用什么来表示,作为一个菜鸟,要学的东西太多
了。一个简单的cm,花了好几天的才时间才写出了注册机,不过这已经是一个好的开始,能走出第一步就行,希望很多像我一样的菜鸟能从这
篇破文中得到学习。谢谢红尘岁月大侠的指点。
--------------------------------------------------------------------------------
【详细过程】
同样,老方法开始,先用peid查壳,我用的是peid0.96,据说是非官方版,查无壳
od载入程序停在这里:
00401000 >/$ 6A 00 push 0 ; /pModule = NULL
00401002 |. E8 35040000 call <jmp.&KERNEL32.GetModuleHandleA> ; \GetModuleHandleA
00401007 |. A3 30314000 mov dword ptr [403130], eax
0040100C |. 6A 0A push 0A
0040100E |. 6A 00 push 0
00401010 |. 6A 00 push 0
00401012 |. FF35 30314000 push dword ptr [403130]
00401018 |. E8 07000000 call 00401024
0040101D |. 6A 00 push 0 ; /ExitCode = 0
同样是老方法,查找字符串,
Ultra String Reference, 条目 18
Address=004013A8
Disassembly=push 004030C2
Text String=good cracker
到这里后双击来到
004013A8 |. 68 C2304000 push 004030C2 ; |good cracker
向上找到
00401248 |. 6A 28 push 28 ; /Count = 28 (40.)
0040124A |. 68 8C314000 push 0040318C ; |Buffer = d2k2_cra.0040318C
0040124F |. 6A 02 push 2 ; |ControlID = 2
00401251 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
00401254 |. E8 8F010000 call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
00401259 |. 84C0 test al, al ; ZF=0 //0x8&0x8=0x8
0040125B |. 0F84 06010000 je 00401367 ; 不跳 //ZF=0;只有相等时,才跳
00401261 |. 3C 20 cmp al, 20 ; AL是否为空
00401263 |. 0F8F 13010000 jg 0040137C ; 不跳 //ZF=1;当比较结果是大于时,才跳
00401269 |. 3C 05 cmp al, 5 ; ZF=0 //AL=0x8
0040126B |. 0F8C 20010000 jl 00401391 ; 不跳 //ZF=0,当比较结果是小于时,才跳
00401271 |. 8D1D 8C314000 lea ebx, dword ptr [40318C]
在00401248处F2下断,然后F9运行程序停在断点。
00401248 |. 6A 28 push 28 ; /Count = 28 (40.)
0040124A |. 68 8C314000 push 0040318C ; |Buffer = d2k2_cra.0040318C
0040124F |. 6A 02 push 2 ; |ControlID = 2
00401251 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
00401254 |. E8 8F010000 call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
00401259 |. 84C0 test al, al ; ZF=0 //0x8&0x8=0x8
0040125B |. 0F84 06010000 je 00401367 ; 判断用户名是否为空
00401261 |. 3C 20 cmp al, 20 ; 判断用户名是否大于20位
00401263 |. 0F8F 13010000 jg 0040137C ; 不跳 //ZF=1;当比较结果是大于时,才跳
00401269 |. 3C 05 cmp al, 5 ; 判断用户名是否小于5位
0040126B |. 0F8C 20010000 jl 00401391 ; 不跳 //ZF=0,当比较结果是小于时,才跳
00401271 |. 8D1D 8C314000 lea ebx, dword ptr [40318C] ; 获取用户名
00401277 |. 33C9 xor ecx, ecx ; ECX清零,存放注册值
00401279 |. B0 05 mov al, 5 ; AL=0x5 计数器
0040127B |. 33D2 xor edx, edx ; EDX=0,CF=0 //自身xor运算结果为0,CF=0
0040127D |> 8A0C1A mov cl, byte ptr [edx+ebx] ; 取用户名的第一个字母开始计算
00401280 |. 80F1 29 xor cl, 29 ; CL=0x53 与29异或
00401283 |. 02C8 add cl, al ; CL=0x54 //CL=0x53+0x1
00401285 |. 80F9 41 cmp cl, 41 ; CL与'A'比较 小于A则跳
00401288 |. 7C 1C jl short 004012A6 ; 不跳 //ZF=0,当比较结果是小于时,才跳
0040128A |. 80F9 5A cmp cl, 5A ; CL与'Z'比较 大于Z则跳
0040128D |. 7F 17 jg short 004012A6 ; 不跳 //ZF=1;当比较结果是大于时,才跳
0040128F |> 888A 3C314000 mov byte ptr [edx+40313C], cl ; 保存算出的值
00401295 |. C682 3D314000>mov byte ptr [edx+40313D], 0
0040129C |. FEC2 inc dl ; DL=(0x4)++
0040129E |. FEC8 dec al ; AL=(0x1)-- //减1
004012A0 |. 3C 00 cmp al, 0 ; ZF=1 //AL=0x0
004012A2 |. 74 08 je short 004012AC ; 跳到004012AC //ZF=1,结果相等
004012A4 |.^ EB D7 jmp short 0040127D ; 跳转到0040127D
004012A6 |> B1 52 mov cl, 52 ; CL=0x52
004012A8 |. 02C8 add cl, al ; CL=0x54 //CL=0x52+0x2
004012AA |.^ EB E3 jmp short 0040128F ; 跳转到0040128F
004012AC |> 33D2 xor edx, edx ; EDX=0,CF=0 //自身xor运算结果为0,CF=0
004012AE |. B8 05000000 mov eax, 5 ; EAX=0x5
004012B3 |> 8A0C1A mov cl, byte ptr [edx+ebx]
004012B6 |. 80F1 27 xor cl, 27 ; CL=0x49 //CL=0x6E^0x27
004012B9 |. 02C8 add cl, al ; CL=0x44 //CL=0x42+0x2
004012BB |. 80C1 01 add cl, 1 ; CL=0x45 //CL=0x44+0x1
004012BE |. 80F9 41 cmp cl, 41 ; CL与'A'比较 //CL=0x45;ZF=0
004012C1 |. 7C 1C jl short 004012DF ; 不跳 //ZF=0,当比较结果是小于时,才跳
004012C3 |. 80F9 5A cmp cl, 5A ; CL与'Z'比较 //CL=0x45;ZF=0
004012C6 |. 7F 17 jg short 004012DF ; 不跳 //ZF=1;当比较结果是大于时,才跳
004012C8 |> 888A 41314000 mov byte ptr [edx+403141], cl
004012CE |. C682 42314000>mov byte ptr [edx+403142], 0
004012D5 |. FEC2 inc dl ; DL=(0x4)++
004012D7 |. FEC8 dec al ; AL=(0x1)-- //减1
004012D9 |. 3C 00 cmp al, 0 ; ZF=1 //AL=0x0
004012DB |. 74 08 je short 004012E5 ; 不跳 //ZF=0;只有相等时,才跳
004012DD |.^ EB D4 jmp short 004012B3 ; 跳转到004012B3
004012DF |> B1 4D mov cl, 4D ; CL=0x4D
004012E1 |. 02C8 add cl, al ; CL=0x52 //CL=0x4D+0x5
004012E3 |.^ EB E3 jmp short 004012C8 ; 跳转到004012C8
004012E5 |> 33C0 xor eax, eax
004012E7 |. 6A 28 push 28 ; /Count = 28 (40.)
004012E9 |. 68 B4314000 push 004031B4 ; |Buffer = d2k2_cra.004031B4
004012EE |. 6A 04 push 4 ; |ControlID = 4
004012F0 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
004012F3 |. E8 F0000000 call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
004012F8 |. 66:85C0 test ax, ax ; ZF=0 //0x9&0x9=0x9
004012FB |. 74 55 je short 00401352 ; 不跳 //ZF=0;只有相等时,才跳
004012FD |. 66:83F8 0A cmp ax, 0A ; ZF=0 //AX=0x9
00401301 |. 7F 4F jg short 00401352 ; 不跳 //ZF=1;当比较结果是大于时,才跳
00401303 |. 7C 4D jl short 00401352 ; 跳到00401352 //ZF=0,SF!=OF
00401305 |. 33C0 xor eax, eax
00401307 |. 33DB xor ebx, ebx
00401309 |. 33C9 xor ecx, ecx
0040130B |. 33D2 xor edx, edx
0040130D |. 8D05 B4314000 lea eax, dword ptr [4031B4] ; 获取假码
00401313 |> 8A1C01 mov bl, byte ptr [ecx+eax] ; 获取真码的第一个位
00401316 |. 8A91 3C314000 mov dl, byte ptr [ecx+40313C] ; 获取假码的第一位
0040131C |. 80FB 00 cmp bl, 0
0040131F |. 0F84 81000000 je 004013A6
00401325 |. 80C2 05 add dl, 5 ; dl=dl+5
00401328 |. 80FA 5A cmp dl, 5A ; 是否大于Z
0040132B |. 7F 14 jg short 00401341
0040132D |> 80F2 0C xor dl, 0C ; 异或比较
00401330 |. 80FA 41 cmp dl, 41 ; 是否小于A
00401333 |. 7C 11 jl short 00401346
00401335 |. 80FA 5A cmp dl, 5A
00401338 |. 7F 12 jg short 0040134C
0040133A |> 41 inc ecx
0040133B |. 38DA cmp dl, bl ; 比较真假
0040133D |.^ 74 D4 je short 00401313
0040133F |. EB 11 jmp short 00401352
00401341 |> 80EA 0D sub dl, 0D
00401344 |.^ EB E7 jmp short 0040132D
00401346 |> B2 4B mov dl, 4B
00401348 |. 02D1 add dl, cl
0040134A |.^ EB EE jmp short 0040133A
0040134C |> B2 4B mov dl, 4B
0040134E |. 2AD1 sub dl, cl
00401350 |.^ EB E8 jmp short 0040133A
00401352 |> 6A 00 push 0 ; /0x0进栈
00401354 |. 68 49304000 push 00403049 ; |dont give up...
00401359 |. 68 59304000 push 00403059 ; |wrong code!try again!
0040135E |. 6A 00 push 0 ; |hOwner = NULL
00401360 |. E8 A1000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00401365 |. EB 52 jmp short 004013B9
00401367 |> 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
00401369 |. 68 6F304000 push 0040306F ; |sorry...
0040136E |. 68 97304000 push 00403097 ; |enter name!
00401373 |. 6A 00 push 0 ; |hOwner = NULL
00401375 |. E8 8C000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
0040137A |. EB 3D jmp short 004013B9
0040137C |> 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
0040137E |. 68 6F304000 push 0040306F ; |sorry...
00401383 |. 68 A3304000 push 004030A3 ; |name can be max 32 chars long!
00401388 |. 6A 00 push 0 ; |hOwner = NULL
0040138A |. E8 77000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
0040138F |. EB 28 jmp short 004013B9
00401391 |> 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
00401393 |. 68 6F304000 push 0040306F ; |sorry...
00401398 |. 68 78304000 push 00403078 ; |name must be min 5 chars long!
0040139D |. 6A 00 push 0 ; |hOwner = NULL
0040139F |. E8 62000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004013A4 |. EB 13 jmp short 004013B9
004013A6 |> 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
004013A8 |. 68 C2304000 push 004030C2 ; |good cracker
004013AD |. 68 CF304000 push 004030CF ; |serial is correct! now write a keygen + tut and send it to: diablo2oo2@gmx.net !
004013B2 |. 6A 00 push 0 ; |hOwner = NULL
004013B4 |. E8 4D000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004013B9 |> EB 15 jmp short 004013D0
004013BB |> FF75 14 push dword ptr [ebp+14] ; /lParam
004013BE |. FF75 10 push dword ptr [ebp+10] ; |wParam
004013C1 |. FF75 0C push dword ptr [ebp+C] ; |Message
004013C4 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
004013C7 |. E8 10000000 call <jmp.&USER32.DefWindowProcA> ; \DefWindowProcA --------------------------------------------------------------------------------
【算法总结】
较简单,还需要深入学习
【注册机算法】 代码:
分析上面代码写出注册机
ebx = Text1.Text
ecx = 0
al = &H5
edx = 0
For i = 1 To 5
cl = Asc(Mid(ebx, i, 1))
cl = cl Xor &H29
cl = cl + al
If cl < &H41 Or cl > &H5A Then
cl = &H52
cl = cl + al
End If
CodeStr1 = CodeStr1 & Chr(cl)
Code1 = Code1 & al
dl = dl + 1
al = al - 1
'MsgBox CodeStr1
Next
edx = 0
eax = &H5
al = &H5
For i = 1 To 5
cl = Asc(Mid(ebx, i, 1))
cl = cl Xor &H27
cl = cl + al
cl = cl + 1
If cl < &H41 Or cl > &H5A Then
cl = &H4D
cl = cl + al
End If
CodeStr2 = CodeStr2 & Chr(cl)
Code2 = Code2 & al
dl = dl + 1
al = al - 1
Next
Text2.Text = CodeStr1 & CodeStr2
Code = Code1 & Code2
eax = 0
ebx = 0
ecx = 0
edx = 0
eax = Text2.Text
cl = 0
For i = 1 To 10
dl = Asc(Mid(Text2.Text, i, 1))
dl = dl + &H5
If dl > &H5A Then
dl = dl - &HD
End If
dl = dl Xor &HC
If dl < &H41 Then
dl = &H4B
dl = dl + cl
End If
If dl > &H5A Then
dl = &H4B
dl = dl - cl
End If
cl = cl + 1
AA = AA & Chr(dl)
Next
Text3.Text = AA 写的不好,大侠指点一下。。。
注册机和原始cm见附件。。。
--------------------------------------------------------------------------------
【经验总结】
需要有汇编基础,最少也要懂最基础的几个汇编命令,然后在写注册机的时候知道汇编与各种语言的转换函数
1、chr() 返回与指定字符代码相关联的字符。可将数字转换为字母
2、hex() 函数返回表示十六进制数字值的字符串
3、asc() 返回与字符串的第一个字母对应的 ANSI 字符代码。
4、汇编里面的16进制数在VB里面用&H表示,比如:mav al,5a 这里的5a在VB里面要写成&H5A
5、还有一个要感谢红尘岁月帮我解答的test al,al 判断al是否等于零
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年06月13日 10:46:50
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: