最近上网找到了一个小软件TextDraw,写了个注册机,后来觉得算法挺好,于是就写了这篇破文与大家一起学习学习。TextDraw是一个简单易用且功能非常强大的文本图形制作工具。你可以像使用一般作图工具一样,在作图区绘制直线、椭圆、矩形、多边形、曲线等图形,但你使用的是文本,得到的是可以在记事本上显示的文本图形!不多说了,它的功能挺好,大家自己试试吧。
现在进入正题。先用PEiD查壳,运气不错,程序没有加壳,使用Borland C++ 1999编写。运行一下程序,在注册的地方输入“zjjtr”和“1234567890”注册,出现了一些奇怪的字符,如图1所示,提示“不是有效的整数”,我数了下它的位数,有十位,极有可能是由“1234567890”计算而来的。看来,注册码计算后的结果是整数才行。不管了,把它放到OD中去吧。查找那些字符,没找到,却发现了“注册失败,请检查你的输入是否有误”,我想那些字符可能会在附近,于是双击“注册失败,请检查你的输入是否有误”,来到下面的地方。
view plainprint?
00415829 |> \66:C745 A4 D4>MOV WORD PTR SS:[EBP-5C],0D4
0041582F |. BA ADEC4900 MOV EDX,TextDraw.0049ECAD
; 注册失败,请检查你的输入是否有误
00415834 |. 8D45 B8 LEA EAX,DWORD PTR SS:[EBP-48]
在00415829处,信息窗口显示“跳转来自004154ED”,那我们就到004154ED看看吧。
view plainprint?
004154EA |. 83F8 64 CMP EAX,64
004154ED |. 0F85 36030000 JNZ TextDraw.00415829
004154F3 |. 66:C745 A4 44>MOV WORD PTR SS:[EBP-5C],44
004154F9 |. BA 88EC4900 MOV EDX,TextDraw.0049EC88
; 注册成功,谢谢您的支持
将EAX与0x64比较,不等就跳向注册失败的地方。在这里应该就可以爆破了,将JNZ改为JE即可,但我们是分析算法,那就接着往下看。在后面的分析中可以看到,这里的爆破还不行,因为由注册码算出的结果不是整数,是不会运行到这里来的。我们往前看,来到算法的入口处,一般它的前面有一个 RETN。我们在004152B0出下断点,F9运行,填好注册码,确定,程序便停了下来。
view plainprint?
004152B0 /. 55 PUSH EBP ;断在这里
004152B1 |. 8BEC MOV EBP,ESP
004152B3 |. 81C4 6CF7FFFF ADD ESP,-894
004152B9 |. 53 PUSH EBX
004152BA |. 8955 8C MOV DWORD PTR SS:[EBP-74],EDX
004152BD |. 8945 90 MOV DWORD PTR SS:[EBP-70],EAX
004152C0 |. B8 14EE4900 MOV EAX,TextDraw.0049EE14
004152C5 |. E8 864E0600 CALL TextDraw.0047A150
004152CA |. 66:C745 A4 08>MOV WORD PTR SS:[EBP-5C],8
004152D0 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
004152D3 |. E8 44C4FEFF CALL TextDraw.0040171C
004152D8 |. FF45 B0 INC DWORD PTR SS:[EBP-50]
004152DB |. 66:C745 A4 14>MOV WORD PTR SS:[EBP-5C],14
004152E1 |. 66:C745 A4 20>MOV WORD PTR SS:[EBP-5C],20
004152E7 |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
004152EA |. E8 2DC4FEFF CALL TextDraw.0040171C
004152EF |. 8BD0 MOV EDX,EAX
004152F1 |. FF45 B0 INC DWORD PTR SS:[EBP-50]
004152F4 |. 8B4D 90 MOV ECX,DWORD PTR SS:[EBP-70]
004152F7 |. 8B81 DC020000 MOV EAX,DWORD PTR DS:[ECX+2DC]
004152FD |. E8 8A570300 CALL TextDraw.0044AA8C;用户名长度进入EAX
00415302 |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
00415305 |. E8 A2D1FEFF CALL TextDraw.004024AC;用户名进入EAX
0041530A |. 50 PUSH EAX; /Arg2
0041530B |. 8D95 74FBFFFF LEA EDX,DWORD PTR SS:[EBP-48C]; |
00415311 |. 52 PUSH EDX; |Arg1
00415312 |. E8 CD4B0600 CALL TextDraw.00479EE4; \TextDraw.00479EE4
00415317 |. 83C4 08 ADD ESP,8
0041531A |. FF4D B0 DEC DWORD PTR SS:[EBP-50]
0041531D |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
00415320 |. BA 02000000 MOV EDX,2
00415325 |. E8 12F70600 CALL TextDraw.00484A3C
0041532A |. 8D8D 74FBFFFF LEA ECX,DWORD PTR SS:[EBP-48C]
00415330 |. 51 PUSH ECX
00415331 |. E8 DE4B0600 CALL TextDraw.00479F14
00415336 |. 59 POP ECX
00415337 |. 8945 80 MOV DWORD PTR SS:[EBP-80],EAX
0041533A |. C785 7CFFFFFF>MOV DWORD PTR SS:[EBP-84],-64
;寄存器EBP初始化存入-0x64
00415344 |. 33C0 XOR EAX,EAX
00415346 |. 8945 84 MOV DWORD PTR SS:[EBP-7C],EAX
00415349 |. 8B55 84 MOV EDX,DWORD PTR SS:[EBP-7C]
0041534C |. 3B55 80 CMP EDX,DWORD PTR SS:[EBP-80]
0041534F |. 7D 23 JGE SHORT TextDraw.00415374
00415351 |> 8B4D 84 /MOV ECX,DWORD PTR SS:[EBP-7C]
00415354 |. 8A840D 74FBFF>|MOV AL,BYTE PTR SS:[EBP+ECX-48C];用户名每一位进入AL
0041535B |. 8845 8B |MOV BYTE PTR SS:[EBP-75],AL
0041535E |. 33D2 |XOR EDX,EDX
00415360 |. 8A55 8B |MOV DL,BYTE PTR SS:[EBP-75]
00415363 |. 0195 7CFFFFFF |ADD DWORD PTR SS:[EBP-84],EDX;加到[EBP-84]中
00415369 |. FF45 84 |INC DWORD PTR SS:[EBP-7C]
0041536C |. 8B4D 84 |MOV ECX,DWORD PTR SS:[EBP-7C]
0041536F |. 3B4D 80 |CMP ECX,DWORD PTR SS:[EBP-80]
00415372 |.^ 7C DD \JL SHORT TextDraw.00415351;用户名没取完往回跳
到这里将用户名的ASCII码相加减去十进制的100,有什么用呢?我们接着往下看。
view plainprint?
00415374 |> 8B85 7CFFFFFF MOV EAX,DWORD PTR SS:[EBP-84];结果放到EAX中,记为s1
0041537A |. 8985 6CF7FFFF MOV DWORD PTR SS:[EBP-894],EAX
00415380 |. 33D2 XOR EDX,EDX
00415382 |. 8995 70F7FFFF MOV DWORD PTR SS:[EBP-890],EDX
00415388 |. DFAD 6CF7FFFF FILD QWORD PTR SS:[EBP-894]
0041538E |. DB2D 80584100 FLD TBYTE PTR DS:[415880];浮点数“0.6480041472265422897”
00415394 |. DEC9 FMULP ST(1),ST ;s1×0.6480041472265422897
00415396 |. D805 8C584100 FADD DWORD PTR DS:[41588C] ;s1×0.6480041472265422897+1234,记为s2
0041539C |. E8 5F800600 CALL TextDraw.0047D400
;这个call转化为十六进制,其实就是取整
004153A1 |. 8985 7CFFFFFF MOV DWORD PTR SS:[EBP-84],EAX
004153A7 |. 8B95 7CFFFFFF MOV EDX,DWORD PTR SS:[EBP-84]
004153AD |. 8995 6CF7FFFF MOV DWORD PTR SS:[EBP-894],EDX
004153B3 |. 33C9 XOR ECX,ECX
004153B5 |. 898D 70F7FFFF MOV DWORD PTR SS:[EBP-890],ECX
004153BB |. DFAD 6CF7FFFF FILD QWORD PTR SS:[EBP-894]
004153C1 |. DC0D 90584100 FMUL QWORD PTR DS:[415890] ;s2×3121.141592600000
004153C7 |. E8 34800600 CALL TextDraw.0047D400;取整
004153CC |. 8985 7CFFFFFF MOV DWORD PTR SS:[EBP-84],EAX
004153D2 |. 66:C745 A4 2C>MOV WORD PTR SS:[EBP-5C],2C
004153D8 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
到这里,用户名的计算告一段落,下面再看看用户名是怎么处理的。
view plainprint?
004153DB |. E8 3CC3FEFF CALL TextDraw.0040171C
004153E0 |. 8BD0 MOV EDX,EAX
004153E2 |. FF45 B0 INC DWORD PTR SS:[EBP-50]
004153E5 |. 8B4D 90 MOV ECX,DWORD PTR SS:[EBP-70]
004153E8 |. 8B81 E4020000 MOV EAX,DWORD PTR DS:[ECX+2E4]
004153EE |. E8 99560300 CALL TextDraw.0044AA8C
004153F3 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
004153F6 |. E8 B1D0FEFF CALL TextDraw.004024AC;注册码进入EAX
004153FB |. 50 PUSH EAX ; /Arg2
004153FC |. 8D95 74FBFFFF LEA EDX,DWORD PTR SS:[EBP-48C] ; |
00415402 |. 52 PUSH EDX; |Arg1
00415403 |. E8 DC4A0600 CALL TextDraw.00479EE4; \TextDraw.00479EE4
00415408 |. 83C4 08 ADD ESP,8
0041540B |. FF4D B0 DEC DWORD PTR SS:[EBP-50]
0041540E |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
00415411 |. BA 02000000 MOV EDX,2
00415416 |. E8 21F60600 CALL TextDraw.00484A3C
0041541B |. 8D8D 74FBFFFF LEA ECX,DWORD PTR SS:[EBP-48C]
00415421 |. 51 PUSH ECX
00415422 |. E8 ED4A0600 CALL TextDraw.00479F14
00415427 |. 59 POP ECX
00415428 |. 8945 80 MOV DWORD PTR SS:[EBP-80],EAX
0041542B |. 33C0 XOR EAX,EAX
0041542D |. 8945 84 MOV DWORD PTR SS:[EBP-7C],EAX
00415430 |. 8B55 84 MOV EDX,DWORD PTR SS:[EBP-7C]
00415433 |. 3B55 80 CMP EDX,DWORD PTR SS:[EBP-80]
00415436 |. 7D 46 JGE SHORT TextDraw.0041547E
00415438 |> 8B45 84 /MOV EAX,DWORD PTR SS:[EBP-7C]
0041543B |. B9 03000000 |MOV ECX,3
00415440 |. 99 |CDQ
00415441 |. F7F9 |IDIV ECX;模3
00415443 |. 8B55 84 |MOV EDX,DWORD PTR SS:[EBP-7C]
00415446 |. 8A8C15 74FBFF>|MOV CL,BYTE PTR SS:[EBP+EDX-48C];注册码每一位进入CL
0041544D |. 80C1 EC |ADD CL,0EC;CL+0xEC
00415450 |. 8B55 84 |MOV EDX,DWORD PTR SS:[EBP-7C]
00415453 |. 81E2 01000080 |AND EDX,80000001;判断EDX奇偶性
00415459 |. 79 05 |JNS SHORT TextDraw.00415460;奇数跳转
0041545B |. 4A |DEC EDX
0041545C |. 83CA FE |OR EDX,FFFFFFFE
0041545F |. 42 |INC EDX;EDX+1
00415460 |> 03D2 |ADD EDX,EDX;EDX×2
00415462 |. 8D1492 |LEA EDX,DWORD PTR DS:[EDX+EDX*4] ;EDX×5,始终为10
00415465 |. 2ACA |SUB CL,DL;CL=CL-DL
00415467 |. 02C1 |ADD AL,CL;AL=AL+CL
00415469 |. 8B4D 84 |MOV ECX,DWORD PTR SS:[EBP-7C]
0041546C |. 88840D 74FBFF>|MOV BYTE PTR SS:[EBP+ECX-48C],AL
00415473 |. FF45 84 |INC DWORD PTR SS:[EBP-7C] ;计数器加1
00415476 |. 8B45 84 |MOV EAX,DWORD PTR SS:[EBP-7C]
00415479 |. 3B45 80 |CMP EAX,DWORD PTR SS:[EBP-80]
0041547C |.^ 7C BA \JL SHORT TextDraw.00415438;小于注册码长度,跳转
大家可能看得一头雾水,这里在干什么呢?我来小结一下,这里的循环就是把每一位注册码变成另外的字符,从开头的错误信息推测,只有当这些字符是数字时,才有可能注册成功。
那么它是怎样计算的呢?首先取得一位注册码,加上0xEC,再加上(它的位数-1)mod 3,若是偶数为还得加上0xA,然后求得对应的ASCII码,组合在一起,这样就将注册码计算好了。我们继续往下看。
view plainprint?
0041547E |> 8D85 74FBFFFF LEA EAX,DWORD PTR SS:[EBP-48C]
00415484 |. 50 PUSH EAX; /Arg2
00415485 |. 8D95 74F7FFFF LEA EDX,DWORD PTR SS:[EBP-88C]; |
0041548B |. 52 PUSH EDX; |Arg1
0041548C |. E8 534A0600 CALL TextDraw.00479EE4; \TextDraw.00479EE4
00415491 |. 83C4 08 ADD ESP,8
00415494 |. 66:C745 A4 38>MOV WORD PTR SS:[EBP-5C],38
0041549A |. 8D95 74F7FFFF LEA EDX,DWORD PTR SS:[EBP-88C]
004154A0 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10]
004154A3 |. E8 DCF40600 CALL TextDraw.00484984
004154A8 |. 8BD0 MOV EDX,EAX
004154AA |. FF45 B0 INC DWORD PTR SS:[EBP-50]
004154AD |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
004154B0 |. E8 B7F50600 CALL TextDraw.00484A6C
004154B5 |. FF4D B0 DEC DWORD PTR SS:[EBP-50]
004154B8 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10]
004154BB |. BA 02000000 MOV EDX,2
004154C0 |. E8 77F50600 CALL TextDraw.00484A3C
004154C5 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
004154C8 |. E8 E7F60600 CALL TextDraw.00484BB4
;这里就是出错的地方,后来跟踪发现就是将上面得到的一串字符转化成十六进制,如果不是数字,当然是异常了。于是我不断试验,发现每一位的“0123456789”分别对应“DEFGHIJKLM”,我输了个E,经过上面的计算结果为整数1,接着调试下去
view plainprint?
004154CD |. B9 7B000000 MOV ECX,7B
004154D2 |. 99 CDQ
004154D3 |. F7F9 IDIV ECX;整数部分进入EAX
004154D5 |. 83C0 64 ADD EAX,64
004154D8 |. 8985 78FFFFFF MOV DWORD PTR SS:[EBP-88],EAX
004154DE |. 8B85 78FFFFFF MOV EAX,DWORD PTR SS:[EBP-88]
004154E4 |. 2B85 7CFFFFFF SUB EAX,DWORD PTR SS:[EBP-84]
;[EBP-84]中存放的是用户名计算结果
004154EA |. 83F8 64 CMP EAX,64
004154ED |. 0F85 36030000 JNZ TextDraw.00415829
004154F3 |. 66:C745 A4 44>MOV WORD PTR SS:[EBP-5C],44
004154F9 |. BA 88EC4900 MOV EDX,TextDraw.0049EC88; 注册成功,谢谢您的支持
004154FE |. 8D45 EC LEA EAX,DWORD PTR SS:[EBP-14]
00415501 |. E8 7EF40600 CALL TextDraw.00484984
注册码转换后的结果除以0x7B得到的整数部分,如果和用户名计算的结果相等,就注册成功。
到这里就分析完了,我们再总结一下。算法主要用了F(用户名)?=G(注册码)的思路。F的过程为用户名的ASCII码求和-0x64,记为 s1,s1*0.6480041472265422897+1234取整得s2,s2×3121.141592600000取整得s3。G的过程为首先取得一位注册码,加上0xEC,再加上(它的位数-1)mod 3,若是偶数为还得加上0xA,然后求得对应的ASCII码,组合在一起,得到t1,t1除以0x7B得到t2。若s3=t2,则注册成功。
这个软件不能做内存注册机,但我写了一个VB注册机,源码如下。
view plainprint?
Private Sub Command1_Click()
t = Text1.Text
For i = 1 To Len(t) Step 1
a = a + Asc(Mid(t, i, 1)) ‘用户名ASCII码求和
Next i
a = a - 100
b = Int(Int(a * 0.648004147226542 + 1234) * 3121.1415926)
b = b * 123
c = ""
Do While (b > 0)
c = Chr(b Mod 10 + 48) & c
b = Int(b / 10)
Loop ‘转化为字符串,当然这里可以直接用VB的函数Cstr()
d = ""
For j = 1 To Len(c) Step 1
If j Mod 2 = 1 Then
d = d & Chr(Asc(Mid(c, j, 1)) + 20 - Int((j - 1) / 3))
Else
d = d & Chr(Asc(Mid(c, j, 1)) + 30 - Int((j - 1) / 3))
End If ‘上面的逆运算
Next j
Text2.Text = d
End Sub
用这个注册机注册成功的界面如图2所示。到这里,细心的读者可能看出来了,如果用户名ASCII码和小于100,会不会有问题呢?的确,如果用户名ASCII码和小于100,用这个注册机注册是不会成功的,我后来又跟了一遍,发现当s1为十六进制负数时,转化为十进制时会变成一个大的正数,然后相乘时会溢出,在VB中就运行不下去了。
图2
这个软件的算法还可以,但是留了太多的错误信息,也许作者想到给用户方便,但同样给Crack找到了破解的机会,建议最好不要留错误信息,或者将信息加密,也许能更好的保护软件。
阅读(1531) | 评论(0) | 转发(0) |