【文章标题】: 一次菜鸟的破解学习过程
【文章作者】: 混世魔王
【作者邮箱】: 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
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)