【文章标题】: 一次菜鸟的破解学习过程
【文章作者】: 混世魔王
【作者邮箱】: hsmw26836659@hotmail.com
【编写语言】: delphi
【使用工具】: OllyDbg 
【操作平台】: Windows2003
【作者声明】: 最近在写学习汇编方面的东西,先声明此文高手就可以略过了,我还比较菜此文也只能给和我同一等级的菜鸟作为技术交流吧,硬盘里丢了几个月了。有不足的地方还请多多指教。
【正文】
程序是里诺客户管理软件2.0单机版。一般基础用于我这样的菜鸟学习软件,一般是没有壳的,不过我们还是先用PEID查一下壳。
Borland Delphi 6.0 - 7.0 果然不出我所料,Delphi写的。
先去他注册地方看看,注册提示信息,提示“软件注册失败”接下来,我们直接用OD载入,可以用OD的插件查找他的“ASCII”字符.查找有关信息.
这里功能和W32asm的字符串参考功能一般,不过比W32asm更方便,我用W32asm载入速度n慢,有时候还死机,汗!电脑配置差不能怪别人.
我们搜索“注册”,就可以找到我们的信息。我们在“提示注册成功,本程序所有能限制下次启动…..”这句地方,回车进入代码处,因为程序是重上面往下运行,所以我们分析要重下往上看.
0060FFCE   . 55         PUSH EBP
0060FFCF   . 68 0D016100   PUSH EasyCRM.0061010D
0060FFD4   . 64:FF30     PUSH DWORD PTR FS:[EAX]
0060FFD7   . 64:8920     MOV DWORD PTR FS:[EAX],ESP
0060FFDA   . 8B45 FC     MOV EAX,DWORD PTR SS:[EBP-4]
0060FFDD   . E8 AE020000   CALL EasyCRM.00610290     //调用算法
0060FFE2   . 84C0       TEST AL,AL             //比较
0060FFE4   0F84 DB000000 JE EasyCRM.006100C5     //相等跳006100C5
0060FFEA   . 33C0       XOR EAX,EAX           

我们来看看006100C5处
006100C5   > 6A 40       PUSH 40   
006100C7   . 68 58016100   PUSH EasyCRM.00610158   //软件注册   
006100CC   . 68 B4016100   PUSH EasyCRM.006101B4   //注册成功

经过,本菜鸟的简单分析,
0060FFDD   . E8 AE020000   CALL EasyCRM.00610290 //这句就是他的关键CALL
0060FFE4   0F84 DB000000 JE EasyCRM.006100C5   //这句就是他的关键跳
那我们在他关键CALL 下断点,那我们输入假注册码,他是否会和真注册进行比较呢?下个断点试下就知道了。在0060FFDD 处F2下断点.接着F9运行程序,进行注册,

在注册的用户名我们就添入我们黑客防线的网站地址吧。在注册码随便输入些数字。点击注册,程序停止运行,有点假死的味道,我们来看看F7步入F8下走来看看OD的反映。
00610298 6A00             push 00000000 
:0061029A 6A00             push 00000000
:0061029C 49               dec ecx 
:0061029D 75F9             jne 00610298   // 回跳在610298
:0061029F 51               push ecx       //F4
进入之后在0061029D处有个回跳,我们直接在0061029F F4运行到所选,继续F8慢慢下看。经过n个F8后,我们在OD的下面看到一写类似的注册的ASCII的友情提示。

Stack SS:[0012EC0C]=01976030, (ASCII "CRM4-E63656ei8-E2D6")
EDX=019764A4, (ASCII "www.hacker.com.cn")
我们刚才输入的用户名就是:www.hacker.com.cn 那CRM4-E63656ei8-E2D6 会不会是我们的注册码呢,我们来输入看看吧。

看图,提示“提示注册成功,本程序所有能限制下次启动…..”对于程序就破接ok了。接着我们就写我们的内存注册机了。对于内存注册就断在 006102f5的 edx上,因为这里是我们追出注册码的地方,

中断地址:6102f8
中断次数:1
第一字节:58
指令长度:1
对于程序的算法,我特别差,这里要感谢诗人的鼎立帮忙.
我们可以在
0060FFDD   . E8 AE020000   CALL EasyCRM.00610290     //调用算法
进去看看他的算法分析,尝试写个算法注册机.
006103FD   6A 00           push 0       //初始化
006103FF   6A 00           push 0
00610401   49             dec ecx
00610402 ^ 75 F9           jnz short EasyCRM.006103FD
00610404   51             push ecx
00610405   874D FC         xchg dword ptr ss:[ebp-4],ecx
00610408   53             push ebx
00610409   56             push esi
0061040A   57             push edi
0061040B   8BF9           mov edi,ecx
0061040D   8955 FC         mov dword ptr ss:[ebp-4],edx
00610410   8B45 FC         mov eax,dword ptr ss:[ebp-4]
00610413   E8 C84CDFFF       call EasyCRM.004050E0
00610418   33C0           xor eax,eax
0061041A   55             push ebp
0061041B   68 B5056100       push EasyCRM.006105B5
00610420   64:FF30         push dword ptr fs:[eax]
00610423   64:8920         mov dword ptr fs:[eax],esp
00610426   8BC7           mov eax,edi
00610428   E8 0348DFFF       call EasyCRM.00404C30   //取用户名
0061042D   8B45 FC         mov eax,dword ptr ss:[ebp-4]
00610430   E8 BB4ADFFF       call EasyCRM.00404EF0   //取用户名长度
00610435   8BF0           mov esi,eax
00610437   85F6           test esi,esi
00610439   7E 26           jle short EasyCRM.00610461
0061043B   BB 01000000       mov ebx,1
00610440   8D4D EC         lea ecx,dword ptr ss:[ebp-14]
00610443   8B45 FC         mov eax,dword ptr ss:[ebp-4]
00610446   0FB64418 FF   movzx eax,byte ptr ds:[eax+ebx-1]   //循环 ebx作计数器
0061044B   33D2         xor edx,edx
0061044D   E8 3A9FDFFF     call EasyCRM.0040A38C     //取 ascii码值的函数
00610452   8B55 EC         mov edx,dword ptr ss:[ebp-14]
00610455   8D45 F8         lea eax,dword ptr ss:[ebp-8]
00610458   E8 9B4ADFFF       call EasyCRM.00404EF8 // 保存在寄存器中,dd eax
0061045D   43             inc ebx
0061045E   4E             dec esi
0061045F ^ 75 DF           jnz short EasyCRM.00610440
00610461   8B45 F8         mov eax,dword ptr ss:[ebp-8]
00610464   E8 874ADFFF   call EasyCRM.00404EF0 //取长度函数,相当于vb中的 len
00610469   8BF0           mov esi,eax
0061046B   85F6           test esi,esi
0061046D   7E 2C           jle short EasyCRM.0061049B
0061046F   BB 01000000       mov ebx,1
00610474   8B45 F8         mov eax,dword ptr ss:[ebp-8]   //ebp-8中存的就是用户名的asc值
00610477   E8 744ADFFF       call EasyCRM.00404EF0
0061047C   2BC3           sub eax,ebx
0061047E   8B55 F8         mov edx,dword ptr ss:[ebp-8]
00610481   8A1402         mov dl,byte ptr ds:[edx+eax]
00610484   8D45 E8         lea eax,dword ptr ss:[ebp-18]
00610487   E8 8C49DFFF       call EasyCRM.00404E18
0061048C   8B55 E8         mov edx,dword ptr ss:[ebp-18] // 这一段处理的就是将asc反转,
0061048F   8D45 F4         lea eax,dword ptr ss:[ebp-C] //比如12asc码是 3132反转后变为2313
00610492   E8 614ADFFF       call EasyCRM.00404EF8   // 相当于vb函数中的 StrReverse
00610497   43             inc ebx     // 结果保存在 [ebp-c] 寄存器里
00610498   4E             dec esi
00610499 ^ 75 D9           jnz short EasyCRM.00610474
0061049B   8D45 F8         lea eax,dword ptr ss:[ebp-8]
0061049E   50             push eax
0061049F   B9 04000000       mov ecx,4
006104A4   BA 01000000       mov edx,1
006104A9   8B45 F4         mov eax,dword ptr ss:[ebp-C]
006104AC   E8 9F4CDFFF       call EasyCRM.00405150   // 取反序后的1-4位
006104B1   8D45 F4         lea eax,dword ptr ss:[ebp-C]
006104B4   50             push eax
006104B5   B9 04000000       mov ecx,4
006104BA   BA 05000000       mov edx,5
006104BF   8B45 F4         mov eax,dword ptr ss:[ebp-C]
006104C2   E8 894CDFFF       call EasyCRM.00405150   // 取反序后的5-8位
006104C7   8B45 F8     mov eax,dword ptr ss:[ebp-8] // 取出来的1-4为赋给eax
006104CA   E8 214ADFFF       call EasyCRM.00404EF0
006104CF   83F8 04     cmp eax,4     // 比较长度是否够4位
006104D2   7D 2F           jge short EasyCRM.00610503   // 够则跳 继续处理,否则进行以下操作
006104D4   8B45 F8         mov eax,dword ptr ss:[ebp-8]
006104D7   E8 144ADFFF       call EasyCRM.00404EF0
006104DC   8BD8           mov ebx,eax
006104DE   83FB 03         cmp ebx,3
006104E1   7F 20           jg short EasyCRM.00610503
006104E3   8D4D E4         lea ecx,dword ptr ss:[ebp-1C]
006104E6   8BC3           mov eax,ebx
006104E8   C1E0 02         shl eax,2     // 左移两位 也就是 乘以4
006104EB   33D2           xor edx,edx
006104ED   E8 9A9EDFFF       call EasyCRM.0040A38C
006104F2   8B55 E4         mov edx,dword ptr ss:[ebp-1C]   // 不足4位就填充 长度*2*2的数字字符
006104F5   8D45 F8         lea eax,dword ptr ss:[ebp-8]
006104F8   E8 FB49DFFF       call EasyCRM.00404EF8
006104FD   43             inc ebx
006104FE   83FB 04         cmp ebx,4
00610501 ^ 75 E0           jnz short EasyCRM.006104E3
00610503   8B45 F4         mov eax,dword ptr ss:[ebp-C]
00610506   E8 E549DFFF       call EasyCRM.00404EF0
0061050B   83F8 04     cmp eax,4   // 5-8为空 也就是长度为0,则像前面一样处理
0061050E   7D 2F           jge short EasyCRM.0061053F
00610510   8B45 F4         mov eax,dword ptr ss:[ebp-C]
00610513   E8 D849DFFF       call EasyCRM.00404EF0
00610518   8BD8           mov ebx,eax
0061051A   83FB 03         cmp ebx,3     // 这里都是进行这样的处理
0061051D   7F 20       jg short EasyCRM.0061053F   // 写成 vb的程序就是
0061051F   8D4D E0     lea ecx,dword ptr ss:[ebp-20] // for i=0 to 3 m=m&str(I*4)
00610522   8BC3           mov eax,ebx
00610524   C1E0 02         shl eax,2
00610527   33D2           xor edx,edx
00610529   E8 5E9EDFFF       call EasyCRM.0040A38C
0061052E   8B55 E0         mov edx,dword ptr ss:[ebp-20]
00610531   8D45 F4         lea eax,dword ptr ss:[ebp-C]
00610534   E8 BF49DFFF       call EasyCRM.00404EF8
00610539   43             inc ebx
0061053A   83FB 04         cmp ebx,4
0061053D ^ 75 E0           jnz short EasyCRM.0061051F
0061053F   8D45 F0         lea eax,dword ptr ss:[ebp-10]
00610542   BA CC056100       mov edx,EasyCRM.006105CC           ; ASCII "CRM456ei878"
00610547   E8 7C47DFFF       call EasyCRM.00404CC8
0061054C   8D45 DC         lea eax,dword ptr ss:[ebp-24] // 特定字符串
0061054F   50             push eax
00610550   B9 04000000       mov ecx,4
00610555   BA 01000000       mov edx,1
0061055A   8B45 F0         mov eax,dword ptr ss:[ebp-10]
0061055D   E8 EE4BDFFF       call EasyCRM.00405150   // 取特定字符串1-4为也就是 CRM4
00610562   FF75 DC         push dword ptr ss:[ebp-24]
00610565   68 E0056100       push EasyCRM.006105E0
0061056A   FF75 F8         push dword ptr ss:[ebp-8]
0061056D   8D45 D8         lea eax,dword ptr ss:[ebp-28]
00610570   50             push eax     // 将 算出来的 M1,M2分别插到特定字符串的具体位置
00610571   B9 05000000       mov ecx,5
00610576   BA 05000000       mov edx,5       // 就得出真正的注册码了
0061057B   8B45 F0         mov eax,dword ptr ss:[ebp-10]
0061057E   E8 CD4BDFFF       call EasyCRM.00405150
00610583   FF75 D8         push dword ptr ss:[ebp-28]
00610586   68 E0056100       push EasyCRM.006105E0
0061058B   FF75 F4         push dword ptr ss:[ebp-C]
0061058E   8BC7           mov eax,edi
00610590   BA 06000000       mov edx,6
00610595   E8 164ADFFF       call EasyCRM.00404FB0
0061059A   33C0           xor eax,eax
0061059C   5A             pop edx
0061059D   59             pop ecx
0061059E   59             pop ecx
0061059F   64:8910         mov dword ptr fs:[eax],edx
006105A2   68 BC056100       push EasyCRM.006105BC
006105A7   8D45 D8         lea eax,dword ptr ss:[ebp-28]
006105AA   BA 0A000000       mov edx,0A
006105AF   E8 A046DFFF       call EasyCRM.00404C54
006105B4   C3             retn
006105B5 ^ E9 163FDFFF       jmp EasyCRM.004044D0
006105BA ^ EB EB           jmp short EasyCRM.006105A7
006105BC   5F             pop edi
006105BD   5E             pop esi
006105BE   5B             pop ebx
006105BF   8BE5           mov esp,ebp
006105C1   5D             pop ebp
006105C2   C3             retn
例如,我们输入注册用户名字是1,那1 转换为 16进制的ASCII码是“31”,“31”不足八位,需要补全补为 318c048c ,翻转为 C840 C831 x1=c840 x2=C831 填到   CRM4-(x1)-56ei8-(x2) 得到的注册码就是:CRM4-138C56ei8-048C ,算法分析大概就是这样,知道了原理,我们就来写我们的算法注册机(编写语言VB)。
代码如下:
Private Sub Command1_Click()
Dim LenText1, i As Integer
Dim str, ValueText1 As String

ValueText1 = Text1.Text
LenText1 = Len(ValueText1)
If LenText1 = 0 Then
MsgBox "注册名总不会为空吧", , "提示"
Exit Sub
End If
For i = 1 To LenText1
  str = str & Hex(Asc(Mid$(ValueText1, i, 1)))
Next
str = StrReverse(str)
If LenText1 = 3 Then
  str = str & "8C"
ElseIf LenText1 = 2 Then
  str = str & "048C"
ElseIf LenText1 = 1 Then
str = str & "8C048C"
End If
Text2.Text = "CRM4-" & Left$(str, 4) & "56ei8-" & Right$(str, 4)
End Sub