【文章标题】:【原创】对happytown老大的KeyGenMe_08的分析
【文章作者】: rageliu
【破解日期】: 2007_02_07 17:29
【下载地址】:
【作者声明】: 兴趣,无它。
--------------------------------------------------------------------------------
【详细过程】
壳分析:目前happytown的系列KeyGenMe都没加壳,适合偶们新手练习。
运行KeyGenMe_08.exe,什么都不输入直接点击“Check”,没反映。输入用户名:rageliu,注册码:12345后点“Check”,一样没有什么反映。看来happytown延续了他的一惯风格,只有注册码正确了才会有提示出现。
老规矩,当然是OD出马了。
运行OD,加载KeyGenMe_08.exe,先看看字符串参考,哈哈,看到什么了“Good job,man”,就从这里入手。多说一点,这里不知道你有没有注意到,居然还有一个“C:\”,想到什么了吗?没想到也没关系,偶们后面要说。双击“Good job,man”来到下面这一行:
0040116A . 56 PUSH ESI ;
看看附近代码:
00401160 . 33C0 XOR EAX,EAX
00401162 . 5E POP ESI
00401163 . C2 1000 RETN 10 ;这个RETN说明上面是其他函数的代码了。
00401166 > 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+8] ; Case 3EC of switch 00401145
0040116A . 56 PUSH ESI ; 参数入栈
0040116B . E8 90FEFFFF CALL KeyGenMe.00401000 ; 关键call
00401170 . 83C4 04 ADD ESP,4 ; 平栈
00401173 . 85C0 TEST EAX,EAX ; 关键跳,跳就完蛋
00401175 0F84 C7000000 JE KeyGenMe.00401242
0040117B . 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
0040117D . 68 A8D04000 PUSH KeyGenMe.0040D0A8 ; |Title = "Congratulations"
00401182 . 68 98D04000 PUSH KeyGenMe.0040D098 ; |Text = "Good job,man!"
00401187 . 56 PUSH ESI ; |hOwner
00401188 . FF15 C8C04000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
这里我们下关键call
0040116B . E8 90FEFFFF CALL KeyGenMe.00401000
的断点,然后F7跟进去开始分析算法,算法如下:
00401000 /$ 81EC DC050000 SUB ESP,5DC ; 给局部变量分配空间
00401006 |. 53 PUSH EBX
00401007 |. 55 PUSH EBP
00401008 |. 56 PUSH ESI
00401009 |. 57 PUSH EDI
0040100A |. 33DB XOR EBX,EBX ; EBX=0,CF=0
0040100C |. B9 7C000000 MOV ECX,7C
00401011 |. 33C0 XOR EAX,EAX ; EAX=0,CF=0
00401013 |. 8DBC24 F90300>LEA EDI,DWORD PTR SS:[ESP+3F9]
0040101A |. 889C24 F80300>MOV BYTE PTR SS:[ESP+3F8],BL
00401021 |. 889C24 040200>MOV BYTE PTR SS:[ESP+204],BL
00401028 |. F3:AB REP STOS DWORD PTR ES:[EDI]
0040102A |. 66:AB STOS WORD PTR ES:[EDI]
0040102C |. AA STOS BYTE PTR ES:[EDI]
0040102D |. B9 7C000000 MOV ECX,7C
00401032 |. 33C0 XOR EAX,EAX
00401034 |. 8DBC24 050200>LEA EDI,DWORD PTR SS:[ESP+205]
0040103B |. 885C24 10 MOV BYTE PTR SS:[ESP+10],BL
0040103F |. F3:AB REP STOS DWORD PTR ES:[EDI]
00401041 |. 66:AB STOS WORD PTR ES:[EDI]
00401043 |. AA STOS BYTE PTR ES:[EDI]
00401044 |. B9 7C000000 MOV ECX,7C
00401049 |. 33C0 XOR EAX,EAX
0040104B |. 8D7C24 11 LEA EDI,DWORD PTR SS:[ESP+11]
0040104F |. 8BB424 F00500>MOV ESI,DWORD PTR SS:[ESP+5F0]
00401056 |. F3:AB REP STOS DWORD PTR ES:[EDI]
00401058 |. 66:AB STOS WORD PTR ES:[EDI]
0040105A |. 8B2D D8C04000 MOV EBP,DWORD PTR DS:[<&USER32.GetDlgIte>; USER32.GetDlgItemTextA
00401060 |. 68 F5010000 PUSH 1F5 ; /Count = 1F5 (501.)
00401065 |. AA STOS BYTE PTR ES:[EDI] ; |
00401066 |. 8D8424 FC0300>LEA EAX,DWORD PTR SS:[ESP+3FC] ; |返回串在这里!!名字
0040106D |. 50 PUSH EAX ; |Buffer
0040106E |. 68 EA030000 PUSH 3EA ; |ControlID = 3EA (1002.)
00401073 |. 56 PUSH ESI ; |hWnd
00401074 |. FFD5 CALL EBP ; \GetDlgItemTextA
00401076 |. 8BF8 MOV EDI,EAX ; EAX返回名字长度
00401078 |. 83FF 02 CMP EDI,2 ; 名字长度必须大于2,不然就Over
0040107B |. 7D 0D JGE SHORT KeyGenMe.0040108A
0040107D |. 5F POP EDI
0040107E |. 5E POP ESI
0040107F |. 5D POP EBP
00401080 |. 33C0 XOR EAX,EAX
00401082 |. 5B POP EBX
00401083 |. 81C4 DC050000 ADD ESP,5DC
00401089 |. C3 RETN
0040108A |> 8D8C24 040200>LEA ECX,DWORD PTR SS:[ESP+204] ; 返回串在这里!!偶们随便填的注册码
00401091 |. 68 F5010000 PUSH 1F5
00401096 |. 51 PUSH ECX
00401097 |. 68 EB030000 PUSH 3EB
0040109C |. 56 PUSH ESI
0040109D |. FFD5 CALL EBP
0040109F |. 8BF0 MOV ESI,EAX ; EAX返回假注册码长度
004010A1 |. 3BF3 CMP ESI,EBX ; 注册码不能为空,不然就Over
004010A3 |. 75 0D JNZ SHORT KeyGenMe.004010B2
004010A5 |. 5F POP EDI
004010A6 |. 5E POP ESI
004010A7 |. 5D POP EBP
004010A8 |. 33C0 XOR EAX,EAX
004010AA |. 5B POP EBX
004010AB |. 81C4 DC050000 ADD ESP,5DC
004010B1 |. C3 RETN
004010B2 |> 33C9 XOR ECX,ECX ; ECX=0,CF=0
004010B4 |. 3BF3 CMP ESI,EBX ; 为什么又判断注册码是否为空??
004010B6 |. 7E 22 JLE SHORT KeyGenMe.004010DA
004010B8 |> 33C0 /XOR EAX,EAX ; EAX=0,CF=0
004010BA |. BB 1A000000 |MOV EBX,1A ; EBX=1A
004010BF |. 8A840C 040200>|MOV AL,BYTE PTR SS:[ESP+ECX+204] ; 依次按Byte取注册码
004010C6 |. 03C7 |ADD EAX,EDI ; EAX=AL+EDI,EDI为名字长度
004010C8 |. 99 |CDQ ; 把EAX中的字的符号扩展到EDX中去
004010C9 |. F7FB |IDIV EBX ; EAX=EAX/EBX
004010CB |. 41 |INC ECX ; ECX+=1
004010CC |. 3BCE |CMP ECX,ESI ; ECX和注册码长度比较
004010CE |. 8A92 30D04000 |MOV DL,BYTE PTR DS:[EDX+40D030] ; 取得一个字符
004010D4 |. 88540C 0F |MOV BYTE PTR SS:[ESP+ECX+F],DL
004010D8 |.^ 7C DE \JL SHORT KeyGenMe.004010B8 ; 循环注册码长度次
004010DA |> 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10]
004010DE |. 68 C8FB4000 PUSH KeyGenMe.0040FBC8 ; /String2 = "JUYZZILVYICSONESXHC"
004010E3 |. 50 PUSH EAX ; |String1
004010E4 |. FF15 00C04000 CALL DWORD PTR DS:[<&KERNEL32.lstrcmpA>] ; \lstrcmpA
004010EA |. F7D8 NEG EAX
004010EC |. 5F POP EDI
004010ED |. 5E POP ESI
004010EE |. 1BC0 SBB EAX,EAX
004010F0 |. 5D POP EBP
004010F1 |. 40 INC EAX
004010F2 |. 5B POP EBX
004010F3 |. 81C4 DC050000 ADD ESP,5DC
004010F9 \. C3 RETN
这里一直分析到:
004010DA |> 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10]
都是好理解的,不过接下来的:
004010DE |. 68 C8FB4000 PUSH KeyGenMe.0040FBC8
这句让我迷惑了,上面算出来的东东居然是和它比较,那么0040FBC8地址的东西到底是什么呢?动态调试到这里显示是一串字符串,这个字符串是什么时候生成的呢,再看看上面也没有对0040FBC8地址的操作啊。看来是一早就生成在那里了,下面偶们来看看它是什么时候生成的。
Ctrl+F2,重新开始,输入DB 0040FBC8,来到这个地址,我们看到还是空的。对该地址下字节方式的硬件写入断点。F9运行,OD断在下面这个地方:
00401218 . B8 ABAAAAAA MOV EAX,AAAAAAAB
我们看看这句上面都有些什么代码:
004011D6 . 83C4 04 ADD ESP,4
004011D9 > 6A 00 PUSH 0 ; /pFileSystemNameSize = NULL
004011DB . 6A 00 PUSH 0 ; |pFileSystemNameBuffer = NULL
004011DD . 6A 00 PUSH 0 ; |pFileSystemFlags = NULL
004011DF . 6A 00 PUSH 0 ; |pMaxFilenameLength = NULL
004011E1 . 68 C4FB4000 PUSH KeyGenMe.0040FBC4 ; |pVolumeSerialNumber = KeyGenMe.0040FBC4
004011E6 . 6A 00 PUSH 0 ; |MaxVolumeNameSize = 0
004011E8 . 6A 00 PUSH 0 ; |VolumeNameBuffer = NULL
004011EA . 68 94D04000 PUSH KeyGenMe.0040D094 ; |RootPathName = "c:\"
004011EF . FF15 04C04000 CALL DWORD PTR DS:[<&KERNEL32.GetVolumeI>; \GetVolumeInformationA
004011F5 . 8B0D C4FB4000 MOV ECX,DWORD PTR DS:[40FBC4]
004011FB . 85C9 TEST ECX,ECX
004011FD . 76 43 JBE SHORT KeyGenMe.00401242
004011FF . 57 PUSH EDI
00401200 . BE C8FB4000 MOV ESI,KeyGenMe.0040FBC8
00401205 > 8BC1 MOV EAX,ECX
00401207 . 33D2 XOR EDX,EDX
00401209 . BF 1A000000 MOV EDI,1A
0040120E . F7F7 DIV EDI
00401210 . 8A82 30D04000 MOV AL,BYTE PTR DS:[EDX+40D030]
00401216 . 8806 MOV BYTE PTR DS:[ESI],AL
00401218 . B8 ABAAAAAA MOV EAX,AAAAAAAB
哈哈,看到了吗?开始说的那个串“C:\”,还有函数GetVolumeInformationA(),原来是取C盘的逻辑序列号。
其实偶们要先看看引入的函数有GetVolumeInformationA(),也会有些想法的。
到这里2个比较串的来源都清楚了,接下来应该是写注册机。该下班了,偶找时间补上来,你也可以自己先练练写。呵呵
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)