分析KeygenMe(KM)2014#001——山重水复疑无路,柳暗花明又一村。 【上篇】
本帖最后由 tree_fly 于 2015-8-19 23:11 编辑评委:GGLHY、月之精灵
观战:飘云
特此声明:
A.不得利用CM自身任何BUG绕过注册机
B.算法程序。请勿爆破
C.分析好的文章评优秀、精华,奖励PYB
D.记住:没什么值得炫耀的!
1.请提交一组合法KEY信息[设置阅读权限]
2.请提交胜利截图[部分信息隐藏]
3.请提交算法分析[另外开贴,设置阅读权限]
4.请提交注册机及源码详细内容,跳转:https://www.chinapyg.com/thread-72326-1-1.html
分析KeygenMe(KM)2014#001——山重水复疑无路,柳暗花明又一村。 【上篇】
链接 https://www.chinapyg.com/thread-74486-1-1.html]分析KeygenMe2014#001——山重水复疑无路,柳暗花明又一村 【下篇】 算法注册机源码
今天我们来分析KeygenMe2014#001,这款软件破解难度略高,不过各位如果仔细、认真的分析代码,问题均会迎刃而解。
让我想起陆游的一首《游西山村》,可谓是:山重水复疑无路,柳暗花明又一村!
下面进入主题:
0x01 基础篇*****************************************************************************************************
PEiD检测Keygenme001.exe,被识别加壳软件:ASPack 2.12 -> Alexey Solodovnikov.
为了调试方便,这里我们脱壳后保存程序:KG_Unpack.exe.
0x02 机器码篇**************************************************************************************************
很容易,我们来到这里
004042D0/$81EC 4C020000 SUB ESP, 24C
004042D6|.A1 78244100 MOV EAX, DWORD PTR DS:
004042DB|.53 PUSH EBX
004042DC|.55 PUSH EBP
004042DD|.56 PUSH ESI
004042DE|.57 PUSH EDI ;ntdll.7C930228
004042DF|.6A 68 PUSH 68 ; /RsrcName = 104.
004042E1|.50 PUSH EAX ; |hInst = NULL
004042E2|.FF15 8C914000 CALL NEAR DWORD PTR DS:[<&USER32.Load>; \LoadIconA
004042E8|.8BB424 600200>MOV ESI, DWORD PTR SS:
004042EF|.50 PUSH EAX ; /lParam = 0
004042F0|.6A 01 PUSH 1 ; |wParam = 1
004042F2|.68 80000000 PUSH 80 ; |Message = WM_SETICON
004042F7|.56 PUSH ESI ; |hWnd = FFFFFFFF
004042F8|.FF15 80914000 CALL NEAR DWORD PTR DS:[<&USER32.Send>; \SendMessageA
004042FE|.8B0D 681E4100 MOV ECX, DWORD PTR DS: ;C:\
00404304|.8D5424 34 LEA EDX, DWORD PTR SS:
00404308|.894C24 28 MOV DWORD PTR SS:, ECX
0040430C|.68 FF000000 PUSH 0FF ; /pFileSystemNameSize = 000000FF
00404311|.8D4424 34 LEA EAX, DWORD PTR SS: ; |
00404315|.52 PUSH EDX ; |pFileSystemNameBuffer = ntdll.KiFastSystemCallRet
00404316|.8D4C24 34 LEA ECX, DWORD PTR SS: ; |
0040431A|.50 PUSH EAX ; |pFileSystemFlags = NULL
0040431B|.8D5424 2C LEA EDX, DWORD PTR SS: ; |
0040431F|.51 PUSH ECX ; |pMaxFilenameLength =
00404320|.52 PUSH EDX ; |pVolumeSerialNumber = ntdll.KiFastSystemCallRet
00404321|.8D4424 54 LEA EAX, DWORD PTR SS: ; |
00404325|.68 FF000000 PUSH 0FF ; |MaxVolumeNameSize = FF (255.)
0040432A|.8D4C24 40 LEA ECX, DWORD PTR SS: ; |
0040432E|.50 PUSH EAX ; |VolumeNameBuffer = NULL
0040432F|.51 PUSH ECX ; |RootPathName
00404330|.FF15 7C904000 CALL NEAR DWORD PTR DS:[<&KERNEL32.Ge>; \GetVolumeInformationA
00404336|.B9 40000000 MOV ECX, 40 ;获取C盘卷的序列号
0040433B|.33C0 XOR EAX, EAX
0040433D|.8D7C24 55 LEA EDI, DWORD PTR SS:
00404341|.B3 34 MOV BL, 34
00404343|.F3:AB REP STOS DWORD PTR ES:
00404345|.66:AB STOS WORD PTR ES:
00404347|.AA STOS BYTE PTR ES:
00404348|.8B4424 20 MOV EAX, DWORD PTR SS: ;
0040434C|.C64424 54 50MOV BYTE PTR SS:, 50
00404351|.C1E0 29 SHL EAX, 29
00404354|.99 CDQ
00404355|.33C2 XOR EAX, EDX ;ntdll.KiFastSystemCallRet
00404357|.C64424 55 59MOV BYTE PTR SS:, 59
0040435C|.2BC2 SUB EAX, EDX ;ntdll.KiFastSystemCallRet
0040435E|.8D5424 5B LEA EDX, DWORD PTR SS:
00404362|.50 PUSH EAX ; /<%d> = 0
00404363|.68 641E4100 PUSH KG_Unpac.00411E64 ; |%d
00404368|.52 PUSH EDX ; |s = ntdll.KiFastSystemCallRet
00404369|.C64424 62 47MOV BYTE PTR SS:, 47 ; |
0040436E|.C64424 63 32MOV BYTE PTR SS:, 32 ; |
00404373|.C64424 64 30MOV BYTE PTR SS:, 30 ; |
00404378|.C64424 65 31MOV BYTE PTR SS:, 31 ; |
0040437D|.885C24 66 MOV BYTE PTR SS:, BL ; |
00404381|.FF15 9C914000 CALL NEAR DWORD PTR DS:[<&USER32.wspr>; \wsprintfA
00404387|.8B2D 84914000 MOV EBP, DWORD PTR DS:[<&USER32.SetD>;USER32.SetDlgItemTextA
这里使用了这个函数,GetVolumeInformationA 函数解释如下:
RootPathName String,欲获取信息的那个卷的根路径,KM提供的是C:\
VolumeNameBuffer String,用于装载卷名(卷标)的一个字串
VolumeNameSize Long,lpVolumeNameBuffer字串的长度
VolumeSerialNumber Long,用于装载磁盘卷序列号的变量
MaximumComponentLength Long,指定一个变量,用于装载文件名每一部分的长度。
堆栈 SS:=FC2363B9 ,这里就是C盘的序列号
EAX=00000001
注意这里
00404348|.8B4424 20 MOV EAX, DWORD PTR SS: ;
0040434C|.C64424 54 50MOV BYTE PTR SS:, 50
00404351|.C1E0 29 SHL EAX, 29
C盘卷标被再次读取给EAX,SHL 0x29 = SHL 0x9
0xFC2363B9 * 2^0x9 = 0x46C77200(1187475968) ;这个就是机器码的后部分。 PYG2014 + 1187475968
0012F9EC50 59 47 32 30 31 34 31 31 38 37 34 37 35 39 36PYG2014118747596
0012F9FC38 8
0x03 文件篇******************************************************************************************************
函数原型:FILE * fopen(const char * path,const char * mode);
1.程序查找目录内是否有 PYG2014.dat文件,如果不存在,随机生成一串字符写入内存,文件存在即读取。
004043E7|.68 5C1E4100 PUSH KG_Unpac.00411E5C ; /rb
004043EC|.50 PUSH EAX ; |path = ".\\PYG2014.dat"
004043ED|.C64424 1C 59MOV BYTE PTR SS:, 59 ; |
004043F2|.C64424 1D 47MOV BYTE PTR SS:, 47 ; |
004043F7|.C64424 1E 32MOV BYTE PTR SS:, 32 ; |
004043FC|.C64424 1F 30MOV BYTE PTR SS:, 30 ; |
00404401|.C64424 20 31MOV BYTE PTR SS:, 31 ; |
00404406|.885C24 21 MOV BYTE PTR SS:, BL ; |
0040440A|.884C24 22 MOV BYTE PTR SS:, CL ; |
0040440E|.C64424 23 64MOV BYTE PTR SS:, 64 ; |
00404413|.C64424 24 61MOV BYTE PTR SS:, 61 ; |
00404418|.C64424 25 74MOV BYTE PTR SS:, 74 ; |
0040441D|.885424 26 MOV BYTE PTR SS:, DL ; |
00404421|.FF15 E4904000 CALL NEAR DWORD PTR DS:[<&msvcrt.fope>; \fopen
00404427|.8BD8 MOV EBX, EAX
00404429|.83C4 08 ADD ESP, 8
0040442C|.85DB TEST EBX, EBX
2.文件流内存地址:77C2FCE0
向地址:004123F4 写入文件内容
对地址:004123FF 写入字节0结束符,提示将读取 F4->FE,这0xB个字符。
00404475|.C605 FF234100>MOV BYTE PTR DS:, 0
读文件:
0040442E|.74 1C JE SHORT KG_Unpac.0040444C
00404430|.53 PUSH EBX ; /stream = 00050234
00404431|.6A 0A PUSH 0A ; |n = A (10.)
00404433|.6A 01 PUSH 1 ; |size = 1
00404435|.68 F4234100 PUSH KG_Unpac.004123F4 ; |ptr = KG_Unpac.004123F4
0040443A|.FF15 EC904000 CALL NEAR DWORD PTR DS:[<&msvcrt.frea>; \fread
00404440|.53 PUSH EBX ; /stream = 00050234
00404441|.FF15 F0904000 CALL NEAR DWORD PTR DS:[<&msvcrt.fclo>; \fclose
否则随机生成0xB字节数据:
00404447|.83C4 14 ADD ESP, 14
0040444A|.EB 1A JMP SHORT KG_Unpac.00404466
0040444C|>33DB XOR EBX, EBX
0040444E|>FF15 00914000 /CALL NEAR DWORD PTR DS:[<&msvcrt.ran>; [rand
00404454|.02C0 |ADD AL, AL
00404456|.B1 01 |MOV CL, 1
00404458|.2AC8 |SUB CL, AL
0040445A|.888B F4234100 |MOV BYTE PTR DS:, CL
00404460|.43 |INC EBX
00404461|.83FB 0B |CMP EBX, 0B
00404464|.^ 72 E8 \JB SHORT KG_Unpac.0040444E
3.获取当前文件的完整路径,存放在地址:12FAF0
kernel32.GetModuleFileNameA
00404466|>8D9424 580100>LEA EDX, DWORD PTR SS:
0040446D|.68 04010000 PUSH 104 ; /BufSize =
00404472|.52 PUSH EDX ; |PathBuffer = NULL
00404473|.6A 00 PUSH 0 ; |hModule = NULL
00404475|.C605 FF234100>MOV BYTE PTR DS:, 0 ; |
0040447C|.FF15 78904000 CALL NEAR DWORD PTR DS:[<&KERNEL32.Ge>; \GetModuleFileNameA
4.打开当前文件,执行READ操作
kernel32.CreateFileA
00404482|.6A 00 PUSH 0 ; /hTemplateFile = NULL
00404484|.6A 00 PUSH 0 ; |Attributes = 0
00404486|.6A 03 PUSH 3 ; |Mode = OPEN_EXISTING
00404488|.6A 00 PUSH 0 ; |pSecurity = NULL
0040448A|.6A 01 PUSH 1 ; |ShareMode = FILE_SHARE_READ
0040448C|.8D8424 6C0100>LEA EAX, DWORD PTR SS: ; |
00404493|.6A 08 PUSH 8 ; |Access = 8
00404495|.50 PUSH EAX ; |FileName =
00404496|.FF15 74904000 CALL NEAR DWORD PTR DS:[<&KERNEL32.Cr>; \CreateFileA
0040449C|.8BD8 MOV EBX, EAX
0040449E|.83FB FF CMP EBX, -1
004044A1|.74 3C JE SHORT KG_Unpac.004044DF
5.获取文件大小,以字节为单位 294912(0x48000)
kernel32.GetFileSize
004044A3|.6A 00 PUSH 0 ; /pFileSizeHigh = NULL
004044A5|.53 PUSH EBX ; |hFile =
004044A6|.FF15 70904000 CALL NEAR DWORD PTR DS:[<&KERNEL32.Ge>; \GetFileSize
6.向地址: 0012FAF0 写入当前文件大小,且十进制表示,如:ASCII "294912"
USER32.wsprintfA
004044AC|.50 PUSH EAX ; /<%d> =
004044AD|.8D8C24 5C0100>LEA ECX, DWORD PTR SS: ; |
004044B4|.68 641E4100 PUSH KG_Unpac.00411E64 ; |%d
004044B9|.51 PUSH ECX ; |s =
004044BA|.894424 30 MOV DWORD PTR SS:, EAX ; |
004044BE|.FF15 9C914000 CALL NEAR DWORD PTR DS:[<&USER32.wspr>; \wsprintfA
004044C4|.83C4 0C ADD ESP, 0C
004044C7|.53 PUSH EBX ; /hObject = 00050234
004044C8|.FF15 6C904000 CALL NEAR DWORD PTR DS:[<&KERNEL32.Cl>; \CloseHandle
7.这里比较文件大小,是否小于等于 0x11170,校验是否被脱壳,并对全局变量值修改,这里很关键,关系到后面算法分析:
004044CE|.817C24 24 701>CMP DWORD PTR SS:, 11170 ;比较文件大小断点
004044D6|.77 07 JA SHORT KG_Unpac.004044DF
004044D8|.C605 10A04000>MOV BYTE PTR DS:, 7E
*.为了我们伟大的胜利,修改一下吧。
004044CE 817C24 24 701>CMP DWORD PTR SS:, 11170
004044D6 76 07 JBE SHORT KG_Unpac.004044DF
修改成大于跳转,即JA(76改77),并另存为新文件:KG_Unpack_Patch.exe
分析KeygenMe2014#001——山重水复疑无路,柳暗花明又一村 【下篇】 算法注册机源码
沙发。。。终于坐到了 这篇分析分析的很详细透彻,学习了
页:
[1]