tree_fly 发表于 2014-9-10 22:29:15

分析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——山重水复疑无路,柳暗花明又一村 【下篇】 算法注册机源码




crackvip 发表于 2014-9-11 21:59:09

沙发。。。终于坐到了

一梦千年缘 发表于 2015-6-7 16:21:49

这篇分析分析的很详细透彻,学习了
页: [1]
查看完整版本: 分析KeygenMe(KM)2014#001——山重水复疑无路,柳暗花明又一村。 【上篇】