好友
阅读权限40
听众
最后登录1970-1-1
|
本帖最后由 missviola 于 2009-10-20 20:29 编辑
【破文标题】zaas crackme算法分析+注册机
【破文作者】missviola[LCG]
【破解工具】PEID OD SmartCheck
【破解平台】Windows XP
【原版下载】http://bbs.pediy.com/showthread.php?t=99360
【破解声明】只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
------------------------------------------------------------------------
【破解过程】某日,小菜我正在看雪上闲逛,发现zaas大侠发了一个初级的crackme。小菜我下载下来分析学习了一下,偶有心得,
不敢独享,发出来和大家共同分享一下。
首先我们用PEID查壳,显示为Microsoft Visual Basic 5.0 / 6.0。VB编写的东西,如果我等小菜直接用OD载入分析的话,可能为因
为代码的可读性不是特别好,而给cm搞得晕头转向的。所以我选择先用smartcheck总体看下cm的流程,然后再用OD载入去具体分析算
法细节。
我们用smartcheck载入cm,F5运行程序,输入注册名:viola,注册码:12345678,点击“试试手气”。选择下面的Events选项卡,
我们就可以看到cm的事件了,点击旁边的加号就可以进去具体分析了。我们选择最后一个Text2_Change进行分析。由于smartcheck不
能像OD那样那么方便的贴代码,还请大家多多见谅。
Asc(String:"v") returns Integer:118
Arguments
--------------------
String string = 0015DBA4
= "v"
首先获取注册名的第一位ASCII码值
Double (86) --> String ("86")
Double 86
String "86"
这里ASCII码对应的字符是“V”,也就是说将注册名第一位转换成为了大写字母。后面几位也是相同的。我们接着往下看。
Integer (65) --> Long (65)
Integer 65
Long 65
Chr(Integer:65)
Arguments
--------------------
Integer charcode = 65 0x0041
Integer (0) --> Long (0)
Integer 0
Long 0
65对应的字符为A,往下看,我们可以看到cm好像在这里写入了26英文的大写字母。那么这个有什么用呢?我们现在还不知道。带着
疑问,我们接着看。
Len(String:"78563412") returns LONG:8
Arguments
--------------------
String string1 = 0015DE8C
= "78563412"
这里我们非常明显的看到,cm将我们输入的注册码颠倒了过来。(这里要注意一下,如果你的注册码中有小写字母的话,cm会把它转
换为大写字母的。由于我这里输入的是纯数字的注册码,所以看不出来,大家可以自行分析一下的。小菜我这里就小小偷下懒了 -_
-|||||)
Val(String:"&h78") returns double:120 (displayed as single-precision floating point)
Arguments
--------------------
String string1 = 0015DDD4
= "&h78"
Val(String:"&h56") returns double:86 (displayed as single-precision floating point)
Arguments
--------------------
String string1 = 0015DDD4
= "&h56"
Val(String:"&h34") returns double:52 (displayed as single-precision floating point)
Arguments
--------------------
String string1 = 0015DDD4
= "&h34"
Val(String:"&h12") returns double:18 (displayed as single-precision floating point)
Arguments
--------------------
String string1 = 0015DDD4
= "&h12"
这里cm将我们的注册码取两个为一组,并且转换为了十六进制的形式。
Double (18) --> Integer (18)
Double 18
Integer 18
Double (95) --> Integer (95)
Double 95
Integer 95
Asc(String:"K") returns Integer:75
Arguments
--------------------
String string = 0015DE44
= "K"
String ("86") --> Double (86)
String "86"
Double 86
这里的18为12的十进制,95的十六进制为5F,这里返回的ASCII码值为75,对应为“K”,86就是我们注册名第一位v的大写形式的
ASCII码值。到了这里cm就跳出了失败信息。所以我们可以猜测,如果返回的ASCII值如果也为86的话,那么就会比较下一位了,以此
类推,如果每位都相等的话,就证明我们注册成功了。但是这只是我们的猜测而已,到这里我们已经大致了解了cm的流程。下面我们
就用OD载入分析,来解开我们的疑问吧。
OD载入以后,我们选择在403310处下断点,由于这个cm会监测Text_Change,所以有时候我们还没输完注册码,cm就断下来了。为了
避免这个,我们可以直接把注册码粘贴进去,就不会有这个问题了。这里我就不贴出我们smartcheck看出来的对应部分代码了,大家
可以自行分析一下。我这里直接给出能回答我们疑问的代码:
00404262 . 66:8B143A MOV DX,WORD PTR DS:[EDX+EDI] 这里第一次运算时为0x5B,第二次运算时为0x5C,最后一次为
0x5F。也就是说这里异或的数字第一次为0x5F减去注册名长度加上1,之后每次加上1。
00404266 . 66:33140B XOR DX,WORD PTR DS:[EBX+ECX] 注册码的最后二位组成的十六进制同0x5B异或
0040426A . 66:891408 MOV WORD PTR DS:[EAX+ECX],DX
0040426E . 8B45 C8 MOV EAX,DWORD PTR SS:[EBP-38]
00404271 . 85C0 TEST EAX,EAX
00404273 . 74 2E JE SHORT CrackMe.004042A3
00404275 . 66:8338 01 CMP WORD PTR DS:[EAX],1
00404279 . 75 28 JNZ SHORT CrackMe.004042A3
0040427B . 8D45 A8 LEA EAX,DWORD PTR SS:[EBP-58]
0040427E . 50 PUSH EAX
0040427F . FF15 E0104000 CALL DWORD PTR DS:[<&MSVBVM60.__vbaI4Var>; MSVBVM60.__vbaI4Var
00404285 . 8BF0 MOV ESI,EAX
00404287 . 8B45 C8 MOV EAX,DWORD PTR SS:[EBP-38]
0040428A . 8B1D 68104000 MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaGe>; MSVBVM60.__vbaGenerateBoundsError
00404290 . 8B50 14 MOV EDX,DWORD PTR DS:[EAX+14]
00404293 . 8B48 10 MOV ECX,DWORD PTR DS:[EAX+10]
00404296 . 2BF2 SUB ESI,EDX
00404298 . 3BF1 CMP ESI,ECX
0040429A . 72 02 JB SHORT CrackMe.0040429E
0040429C . FFD3 CALL EBX ; <&MSVBVM60.__vbaGenerateBoundsError>
0040429E > 8D0436 LEA EAX,DWORD PTR DS:[ESI+ESI]
004042A1 . EB 0C JMP SHORT CrackMe.004042AF
004042A3 > FF15 68104000 CALL DWORD PTR DS:[<&MSVBVM60.__vbaGener>; MSVBVM60.__vbaGenerateBoundsError
004042A9 . 8B1D 68104000 MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaGe>; MSVBVM60.__vbaGenerateBoundsError
004042AF > 8B4D C8 MOV ECX,DWORD PTR SS:[EBP-38]
004042B2 . 8B51 0C MOV EDX,DWORD PTR DS:[ECX+C]
004042B5 . 66:B9 1A00 MOV CX,1A
004042B9 . 66:8B0402 MOV AX,WORD PTR DS:[EDX+EAX] ; 异或结果送AX
004042BD . 66:99 CWD ; 清零
004042BF . 66:F7F9 IDIV CX ; 异或结果idiv 0x1A
004042C2 . 0FBFFA MOVSX EDI,DX ; 余数送EDI
004042C5 . 83FF 1A CMP EDI,1A ; 余数同0x1A比较
004042C8 . 72 02 JB SHORT CrackMe.004042CC ; 小于就跳走
004042CA . FFD3 CALL EBX
004042CC > 8B45 D0 MOV EAX,DWORD PTR SS:[EBP-30]
004042CF . 85C0 TEST EAX,EAX
004042D1 . 74 2C JE SHORT CrackMe.004042FF
004042D3 . 66:8338 01 CMP WORD PTR DS:[EAX],1
004042D7 . 75 26 JNZ SHORT CrackMe.004042FF
004042D9 . 8D55 A8 LEA EDX,DWORD PTR SS:[EBP-58]
004042DC . 52 PUSH EDX
004042DD . FF15 E0104000 CALL DWORD PTR DS:[<&MSVBVM60.__vbaI4Var>; MSVBVM60.__vbaI4Var
004042E3 . 8BF0 MOV ESI,EAX
004042E5 . 8B45 D0 MOV EAX,DWORD PTR SS:[EBP-30]
004042E8 . 8B50 14 MOV EDX,DWORD PTR DS:[EAX+14]
004042EB . 8B48 10 MOV ECX,DWORD PTR DS:[EAX+10]
004042EE . 2BF2 SUB ESI,EDX
004042F0 . 3BF1 CMP ESI,ECX
004042F2 . 72 02 JB SHORT CrackMe.004042F6
004042F4 . FFD3 CALL EBX
004042F6 > 8D04B5 0000000>LEA EAX,DWORD PTR DS:[ESI*4]
004042FD . EB 02 JMP SHORT CrackMe.00404301
004042FF > FFD3 CALL EBX
00404301 > 8B4D 8C MOV ECX,DWORD PTR SS:[EBP-74] 这里的ECX的地址我们d过去看一下
00404304 . 8B14B9 MOV EDX,DWORD PTR DS:[ECX+EDI*4] ; EDX中的值为ECX加上余数乘以4以后的地址
00404307 . 8B4D D0 MOV ECX,DWORD PTR SS:[EBP-30]
0040430A . 8B49 0C MOV ECX,DWORD PTR DS:[ECX+C]
0040430D . 03C8 ADD ECX,EAX
0040430F . FF15 C8104000 CALL DWORD PTR DS:[<&MSVBVM60.__vbaStrCo>; MSVBVM60.__vbaStrCopy
我们这里看一下404301处地址那边的内容:
0015D3F0 64 D5 15 00 8C 83 15 00 4C D5 15 00 7C D5 15 00 d?.寖.L?.|?.
0015D400 94 D5 15 00 AC D5 15 00 C4 D5 15 00 DC D5 15 00 斦..恼.苷.
0015D410 F4 D5 15 00 0C D6 15 00 24 D6 15 00 3C D6 15 00 粽..?.$?.<?.
0015D420 54 D6 15 00 6C D6 15 00 84 D6 15 00 9C D6 15 00 T?.l?.勚.溨.
0015D430 B4 D6 15 00 CC D6 15 00 E4 D6 15 00 FC D6 15 00 粗.讨.渲..
0015D440 14 D7 15 00 2C D7 15 00 44 D7 15 00 5C D7 15 00 ?.,?.D?.\?.
0015D450 74 D7 15 00 8C D7 15 00 t?.屪..
我们来看看这里的这些地址对应的内容是什么,我们d 15D564看下,发现为大写字母A,15838C为字母B,依次类推。原来这里的地址
对应的是26个大写字母。还记得刚才我们在smartcheck中的第一个疑问吗?也就是说cm通过刚才的那个余数,来取出对应地址的大写
字母。如果这里取出的大写字母同你注册名对应位置的字母相同时,就证明你注册通过了。
00404304 . 8B14B9 MOV EDX,DWORD PTR DS:[ECX+EDI*4] 根据这一句我们可以知道余数应该就是字母在26个大写英文字
母中的位置,比如A为0,B为1,依次类推。比如我这里的注册名viola,那么对应的大写字母形式就是VIOLA,这几个字母在26个字母
中的位置分别为21,8,14,11,0。那么我这里余数也应该为21,8,14,11,0。为了方便运算,我们可以假设商为0。由于异或运
算是可逆的,所以我们可以推算出对应位置的注册码应该为4e 54 53 55 5f,由于这里的异或运算是将注册码倒过来取的,所以我们
还得把它颠倒一次,最终的注册码为5f5553544e。
------------------------------------------------------------------------
【破解总结】最后我们再来总结一下这个cm的算法:
1.首先将注册名各位转换为大写字母。
2.将注册码颠倒过来,两位为一组,转换成为十六进制形式。
3.各组注册码同中间数进行异或运算,异或的结果再idiv 0x1A,取其余数。中间数第一次为0x5F减去注册码长度加上1,随后每次运
算都加上1。
4.用余数作为下标,来确定对应下标在26个大写字母中对应的字母。比如0为A,1为B,以此类推。
5.如果对应各位余数的返回的字符同注册名中的各位都相同的话,则认为注册成功。
最后给出我用python写的注册机,在windows xp+python 2.5下编译通过:
regname = raw_input('please input your regname:')
regstring = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
sn = ''
regname = regname[::-1]
for i in range(0, len(regname)):
temp = regstring.index(regname.upper())
temp = hex(temp ^ (95-i))
temp = temp.split("0x")[1]
sn = sn + temp
print "Your registrion key is:%s" % sn
print "Press Enter key to exit"
raw_input()
------------------------------------------------------------------------
【版权声明】本文原创于52pojie技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
|
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|