首页
社区
课程
招聘
znkkeygenme#1简单分析
发表于: 2006-8-7 20:33 5323

znkkeygenme#1简单分析

2006-8-7 20:33
5323

【文章标题】: znkkeygenme#1简单分析
【文章作者】: ikki
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  这个keygenMe在crackme.de上已经有solution
  
  http://www.crackmes.de/users/znycuk/znycuks_1_crackme/solutions/red477/browse/solution_ZNKKeygenme%5E1_red477.txt
  
  先试着运行看看,随便输入一个注册码"1234",点那个serial me,keygenMe下面状态栏显示"Bad entry, sorry :-(",失败了?看来运气不是很好呀,呵呵:)
  
    那么用w32dasm看看有没有什么可以利用的信息。本人是菜鸟一只,当然是最喜欢看字符串参考了,如果有个
  "Bad entry, sorry :-(",
  "God job"
  什么的,那就最好了.
  
  字符串参考信息:
  --------------
  
  ""
  ""
  "button"
  "edit"
  "Key"
  "Menu"
  "MessageBoxA"
  "Serial me"
  "user32.dll"
  "U??uj"
  "WinClass"
  "ZNY"
  "Znycuk's #1 KeyGenmE"---------------------keygenMe的标题
  "??????临?芮谒?鳞?萘论谇晾??
  "煜?死谲??淋茏??"
  "? @"
  "?, @"
  "?P @"
  ------------
  就知道一个keygenMe的标题,下面都是乱码,收获不大,提示字符串应该是做了变换的吧.
  
  那再看看Imported functions吧:
  Imported functions:
  ---------
  advapi32.GetUserNameA
  comctl32.CreateStatusWindowA
  comctl32.InitCommonControls
  kernel32.ExitProcess
  kernel32.GetCommandLineA
  kernel32.GetComputerNameA
  kernel32.GetModuleHandleA
  kernel32.GetProcAddress
  user32.CreateWindowExA
  user32.DefWindowProcA
  user32.DestroyWindow
  user32.DispatchMessageA
  user32.GetMessageA
  user32.GetWindowTextA
  user32.LoadCursorA
  user32.LoadIconA
  user32.PostQuitMessage
  user32.RegisterClassExA
  user32.SendMessageA
  user32.SetFocus
  user32.SetWindowTextA
  user32.ShowWindow
  user32.TranslateMessage
  user32.UpdateWindow
  ---------------
  重点盯上了这个:
  user32.GetWindowTextA
  
  --------------
  
  GetWindowTextA引用的地方只有下面一处:
  
  * Reference To: user32.GetMessageA, Ord:0119h
                                    |
  :004016CE FF2558204000            Jmp dword ptr [00402058]
  
  * Reference To: user32.GetWindowTextA, Ord:014Ah
                                    |
  :004016D4 FF2550204000            Jmp dword ptr [00402050]
  
  上不着村下不着店的,有点奇怪.
  
  Olldbg载入,
  
  bp GetWindowTextA
  
  输入测试注册码"1234",点击Serial Me按钮之后就会断下来,ALT + F9返回用户程序之后来到这里
  :
  004012BF    68 00020000                push 200
  004012C4    68 D8304000                push ZNKKeyge.004030D8                      ; ASCII "1234"
  004012C9    FF35 CC304000              push dword ptr ds:[4030CC]
  004012CF    68 DA124000                push ZNKKeyge.004012DA
  004012D4    68 D4164000                push
  004012D9    C3                         retn
  004012DA    8BD8                       mov ebx,eax--------------------------------停在这里(EAX=4)
  004012DC    81FB FFFF0000              cmp ebx,0FFFF------------------------------没有输入注册码?
  004012E2    74 07                      je short ZNKKeyge.004012EB
  004012E4    BB EC124000                mov ebx,ZNKKeyge.004012EC
  004012E9    FFE3                       jmp ebx
  004012EB   |DBE8                       fucomi st,st
  004012ED    8803                       mov byte ptr ds:[ebx],al
  004012EF    0000                       add byte ptr ds:[eax],al
  004012F1    84E4                       test ah,ah
  004012F3    75 76                      jnz short ZNKKeyge.0040136B
  004012F5    E8 F1010000                call ZNKKeyge.004014EB
  004012FA    83F8 04                    cmp eax,4
  
  ------------
  keygenMe中很多对API函数的调用都是这样处理的:
  push param A
  push param B
  .....
  push
  retn
  xxxxx
  
  其实就是
  push param A
  push param B
  .....
  jmp.&user32.GetWindowTextA
  xxxx
   
  ---------------
  
  
  结合上面那个ASCII字符串,可以知道,这里是在用GetWindowsTextA读取输入的注册码.
  
  运行到
  004012E9    FFE3                       jmp ebx
  004012EB   |DBE8                       fucomi st,st
  时
  EBX=004012EC
  而接下来的指令地址却是
  004012EB
  应该是花指令吧,在
  004012EB   |DBE8                       fucomi st,st
  这一行点击右键->汇编,输入汇编指令NOP(注意不要选上汇编对话框中的"使用NOP填充"),调试过程中还会遇到几次这样的情况,处理方法是一样的.
  004012E9   /FFE3                       jmp ebx                                     ; ZNKKeyge.004012EC
  004012EB   |90                         nop
  004012EC    E8 88030000                call ZNKKeyge.00401679                      ; 注册码格式检查:xxx-xxx-xxx-xxx
  004012F1    84E4                       test ah,ah
  004012F3   /75 76                      jnz short ZNKKeyge.0040136B
  004012F5   |E8 F1010000                call ZNKKeyge.004014EB                      ; /用rdtsc指令读取处理器计数器
  004012FA   |83F8 04                    cmp eax,4                                   ; 通过一定的计算得到一个小于4的数字
  004012FD   |7C 02                      jl short ZNKKeyge.00401301                  ; 返回到EAX中用来做后面计算的参数
  004012FF  ^|EB F4                      jmp short ZNKKeyge.004012F5                 ; \循环直到得到符合条件的值(<4)
  00401301    8BD8                       mov ebx,eax                                 ; /
  00401303    B1 04                      mov cl,4
  00401305    F6E1                       mul cl                                      ; 1
  00401307    03C3                       add eax,ebx
  00401309    8BB0 D8304000              mov esi,dword ptr ds:[eax+4030D8]           ; \
  0040130F    53                         push ebx
  00401310    E8 D8020000                call ZNKKeyge.004015ED                      ; *重点*
  00401315    3BF2                       cmp esi,edx                                 ; 第1次结果比较(这次比较是随机选择4段数字之一)
  00401317    75 52                      jnz short ZNKKeyge.0040136B
  00401319    33C9                       xor ecx,ecx
  0040131B    83F9 04                    cmp ecx,4                                   ; /
  0040131E    74 1D                      je short ZNKKeyge.0040133D
  00401320    8BC1                       mov eax,ecx
  00401322    8BD8                       mov ebx,eax
  00401324    B2 04                      mov dl,4                                    ; 循环依次比较输入
  00401326    F6E2                       mul dl
  00401328    03C3                       add eax,ebx
  0040132A    8BB0 D8304000              mov esi,dword ptr ds:[eax+4030D8]
  00401330    53                         push ebx
  00401310    E8 D8020000                call ZNKKeyge.004015ED                      ; *重点*
  00401336    3BF2                       cmp esi,edx                                 ; 的注册码的4段数字
  00401338    75 31                      jnz short ZNKKeyge.0040136B
  0040133A    41                         inc ecx
  0040133B  ^ EB DE                      jmp short ZNKKeyge.0040131B                 ; \
  
  
  
  
  1处:
  此处代码的作用就是根据前面循环得到的随机数(<4),使ESI指向
  输入注册码
  xxxx-xxxx-xxxx-xxxx
  0/5/10/15这4个位置中的某个.
  
  
  004015ED    51                         push ecx
  004015EE    56                         push esi
  004015EF    55                         push ebp
  004015F0    8BEC                       mov ebp,esp
  004015F2    83C4 F8                    add esp,-8                                  ; 下面的是keygenMe显示的key
  004015F5    BB 1D344000                mov ebx,ZNKKeyge.0040341D                   ; ASCII "1IHW"
  004015FA    833B FF                    cmp dword ptr ds:[ebx],-1
  004015FD    74 07                      je short ZNKKeyge.00401606
  004015FF    B8 07164000                mov eax,ZNKKeyge.00401607
  00401604    FFE0                       jmp eax
  00401606    90                         nop
  00401607    33C0                       xor eax,eax
  00401609    8B75 10                    mov esi,dword ptr ss:[ebp+10]               ; 用前面得到的随机数字,取4位KEY中
  0040160C    8A041E                     mov al,byte ptr ds:[esi+ebx]                ; 某一位的ASCII码
  0040160F    33DB                       xor ebx,ebx
  00401611    50                         push eax
  00401612    E8 A8FEFFFF                call ZNKKeyge.004014BF                      ; 对A进行计算
  00401617    895D FC                    mov dword ptr ss:[ebp-4],ebx                ; 设结果为A1
  0040161A    E8 B6FEFFFF                call ZNKKeyge.004014D5                      ; 对A进行计算
  0040161F    895D F8                    mov dword ptr ss:[ebp-8],ebx                ; 设结果为A2
  00401622    6A 00                      push 0
  00401624    68 25344000                push ZNKKeyge.00403425
  00401629    FF75 FC                    push dword ptr ss:[ebp-4]
  0040162C    FF75 F8                    push dword ptr ss:[ebp-8]
  0040162F    E8 2DFFFFFF                call ZNKKeyge.00401561
  00401634    A1 25344000                mov eax,dword ptr ds:[403425]               ; EAX查表得到的结果
  00401639    C1C8 08                    ror eax,8
  0040163C    83F8 05                    cmp eax,5
  0040163F    74 08                      je short ZNKKeyge.00401649
  00401641    50                         push eax
  00401642    B8 4A164000                mov eax,ZNKKeyge.0040164A
  00401647    FFE0                       jmp eax
  00401649    90                         nop
  0040164A    58                         pop eax
  0040164B    3265 F4                    xor ah,byte ptr ss:[ebp-C]                  ; xor ah, A
  0040164E    3245 F4                    xor al,byte ptr ss:[ebp-C]                  ; xor al, A
  00401651    33D2                       xor edx,edx
  00401653    66:8BD8                    mov bx,ax
  00401656    B9 04000000                mov ecx,4
  0040165B    24 0F                      and al,0F                                   ; /
  0040165D    3C 09                      cmp al,9                                    ; 把EBX中的16进制数字转换成字符串
  0040165F    7E 02                      jle short ZNKKeyge.00401663
  00401661    04 07                      add al,7
  00401663    04 30                      add al,30
  00401665    8AD0                       mov dl,al
  00401667    C1CA 08                    ror edx,8
  0040166A    66:C1EB 04                 shr bx,4
  0040166E    8AC3                       mov al,bl
  00401670  ^ E2 E9                      loopd short ZNKKeyge.0040165B               ; \
  00401672    83C4 1C                    add esp,1C
  00401675    5D                         pop ebp
  00401676    5E                         pop esi
  00401677    59                         pop ecx
  00401678    C3                         retn
  
  
  
  
  
  
  
  
  
  
  
  --
  004014BF    55                         push ebp
  004014C0    8BEC                       mov ebp,esp
  004014C2    8A5D 08                    mov bl,byte ptr ss:[ebp+8]
  004014C5    80E3 F0                    and bl,0F0
  004014C8    C0C3 04                    rol bl,4
  004014CB    80FB 03                    cmp bl,3
  004014CE    74 03                      je short ZNKKeyge.004014D3
  004014D0    80EB 04                    sub bl,4
  004014D3    5D                         pop ebp
  004014D4    C3                         retn
  --
  
  --
  004014D5    55                         push ebp
  004014D6    8BEC                       mov ebp,esp
  004014D8    8A5D 08                    mov bl,byte ptr ss:[ebp+8]
  004014DB    80E3 0F                    and bl,0F
  004014DE    80FB 07                    cmp bl,7
  004014E1    77 04                      ja short ZNKKeyge.004014E7
  004014E3    32DB                       xor bl,bl
  004014E5    EB 02                      jmp short ZNKKeyge.004014E9
  004014E7    B3 01                      mov bl,1
  004014E9    5D                         pop ebp
  004014EA    C3                         retn
  
  --
  
  
  ----
  00401561    55                         push ebp
  00401562    8BEC                       mov ebp,esp
  00401564    B8 02000000                mov eax,2
  00401569    F665 08                    mul byte ptr ss:[ebp+8]                     ; MUL A2
  0040156C    0245 0C                    add al,byte ptr ss:[ebp+C]                  ; ADD A1
  0040156F    8B5D 10                    mov ebx,dword ptr ss:[ebp+10]
  00401572    8A55 14                    mov dl,byte ptr ss:[ebp+14]
  00401575    84D2                       test dl,dl
  00401577    74 09                      je short ZNKKeyge.00401582
  00401579    891C85 FD334000            mov dword ptr ds:[eax*4+4033FD],ebx
  00401580    EB 09                      jmp short ZNKKeyge.0040158B
  00401582    8B3485 FD334000            mov esi,dword ptr ds:[eax*4+4033FD]         ; 用EAX查表
  00401589    8933                       mov dword ptr ds:[ebx],esi
  0040158B    5D                         pop ebp
  0040158C    C3                         retn
  
  ---
  
  004033FD  C3 D4 DE F1 FF E8 8D FF FF 2B 21 0E FF 17 72 00  迷揆???!?r.
  0040340D  08 58 09 71 08 B8 90 03 00 AC 84 B8 00 5C C8 81  X.q?.??\?
  
  
  注册算法大概就是这样了,最后的一个问题是:这个表里面的数据是从哪里来的?
  
  对04033FD下硬件写入断点,重新运行程序
  00401561    55                         push ebp
  00401562    8BEC                       mov ebp,esp
  00401564    B8 02000000                mov eax,2
  00401569    F665 08                    mul byte ptr ss:[ebp+8]                 
  0040156C    0245 0C                    add al,byte ptr ss:[ebp+C]              
  0040156F    8B5D 10                    mov ebx,dword ptr ss:[ebp+10]
  00401572    8A55 14                    mov dl,byte ptr ss:[ebp+14]
  00401575    84D2                       test dl,dl
  00401577    74 09                      je short ZNKKeyge.00401582
  00401579    891C85 FD334000            mov dword ptr ds:[eax*4+4033FD],ebx     ; 断在这里
  00401580    EB 09                      jmp short ZNKKeyge.0040158B
  00401582    8B3485 FD334000            mov esi,dword ptr ds:[eax*4+4033FD]     
  00401589    8933                       mov dword ptr ds:[ebx],esi
  0040158B    5D                         pop ebp
  0040158C    C3                         retn
  
  
  一段熟悉的代码,呵呵,执行到返回:
  0040158D    55                         push ebp
  0040158E    8BEC                       mov ebp,esp
  00401590    33C9                       xor ecx,ecx
  00401592    66:BE 0000                 mov si,0
  00401596    80F9 02                    cmp cl,2                                ; /
  00401599    74 50                      je short ZNKKeyge.004015EB
  0040159B    84C9                       test cl,cl
  0040159D    74 05                      je short ZNKKeyge.004015A4
  0040159F    8B55 0C                    mov edx,dword ptr ss:[ebp+C]            ; (奇数时EDX的初始值)
  004015A2    EB 03                      jmp short ZNKKeyge.004015A7
  004015A4    8B55 08                    mov edx,dword ptr ss:[ebp+8]            ; (偶数时EDX的初始值)
  004015A7    66:83FE 04                 cmp si,4
  004015AB    74 37                      je short ZNKKeyge.004015E4
  004015AD    66:85F6                    test si,si
  004015B0    74 10                      je short ZNKKeyge.004015C2              ; 以si为计算器循环
  004015B2    66:83FE 01                 cmp si,1
  004015B6    74 12                      je short ZNKKeyge.004015CA              ; 用变换后的EDX的值
  004015B8    66:83FE 02                 cmp si,2
  004015BC    74 10                      je short ZNKKeyge.004015CE              ; 填充DWORD表格
  004015BE    D1CA                       ror edx,1
  004015C0    EB 11                      jmp short ZNKKeyge.004015D3             ; 先填充偶数位:0/2/4/6
  004015C2    81F2 ABADDEAB              xor edx,ABDEADAB
  004015C8    EB 09                      jmp short ZNKKeyge.004015D3             ; 再填充奇数位:1/3/5/7
  004015CA    F7DA                       neg edx
  004015CC    EB 05                      jmp short ZNKKeyge.004015D3
  004015CE    C1E2 03                    shl edx,3
  004015D1    EB 00                      jmp short ZNKKeyge.004015D3
  004015D3    6A 01                      push 1
  004015D5    52                         push edx
  004015D6    51                         push ecx
  004015D7    56                         push esi
  004015D8    E8 84FFFFFF                call ZNKKeyge.00401561                  ; 填充表格
  004015DD    66:46                      inc si
  004015DF    83C4 10                    add esp,10
  004015E2  ^ EB C3                      jmp short ZNKKeyge.004015A7             ; \
  
  看看这两个初始值怎么来的,执行到返回:
  0040122C    FF35 E9334000              push dword ptr ds:[4033E9]              ; 初始值压栈
  00401232    FF35 E8324000              push dword ptr ds:[4032E8]              ; 初始值压栈
  00401238    E8 50030000                call ZNKKeyge.0040158D
  0040123D    6A 01                      push 1
  0040123F    FF75 08                    push dword ptr ss:[ebp+8]
  
  
  
  
  对04033E9下内存写入断点,重新运行程序.
  断下后返回:
  
  0040141C    68 A2304000                push ZNKKeyge.004030A2
  00401421    68 E9334000                push ZNKKeyge.004033E9                  ; ASCII "TEST"
  00401426    68 31144000                push ZNKKeyge.00401431
  0040142B    68 22174000                push    ; 这个很明显吧GetComputerName
  00401430    C3                         retn
  00401431    833D A2304000 04           cmp dword ptr ds:[4030A2],4             ; 返回这里
  00401438    73 1D                      jnb short ZNKKeyge.00401457             ; /
  0040143A    B9 04000000                mov ecx,4                               ; 如果ComputerName长度不足4位
  0040143F    2B0D A2304000              sub ecx,dword ptr ds:[4030A2]           ; 后面依次填充"ZNY",使长度为4位
  00401445    BE AA304000                mov esi,ZNKKeyge.004030AA               ; ASCII "ZNY"
  0040144A    BF E9334000                mov edi,ZNKKeyge.004033E9               ; ASCII "TEST"
  0040144F    033D A2304000              add edi,dword ptr ds:[4030A2]
  00401455    F3:A4                      rep movs byte ptr es:[edi],byte ptr ds:>; \
  00401457    C3                         retn
  
  对04032E8下内存写入断点,重新运行程序.
  断下后返回:
  004013DF    68 A6304000                push ZNKKeyge.004030A6
  004013E4    68 E8324000                push ZNKKeyge.004032E8                  ; ASCII "hy"
  004013E9    68 F4134000                push ZNKKeyge.004013F4
  004013EE    68 34174000                push        ; 先GetUserName
  004013F3    C3                         retn
  004013F4    833D A6304000 04           cmp dword ptr ds:[4030A6],4             ; 返回这里
  004013FB   /73 1E                      jnb short ZNKKeyge.0040141B             ; 如果GetUserName返回的size(包括一个NULL字符)
  004013FD   |B9 04000000                mov ecx,4                               ; 不足4位
  00401402    2B0D A6304000              sub ecx,dword ptr ds:[4030A6]           ; 后面依次填充"ZNY",使长度为4位
  00401408    8D35 AA304000              lea esi,dword ptr ds:[4030AA]
  0040140E    BF E8324000                mov edi,ZNKKeyge.004032E8               ; ASCII "hy"
  00401413    033D A6304000              add edi,dword ptr ds:[4030A6]
  00401419    F3:A4                      rep movs byte ptr es:[edi],byte ptr ds:>
  0040141B    C3                         retn
  
  整个算法的过程大概就是这样了,说的不清楚的地方请参考注册机代码(c语言).

  
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2006年08月07日 20:14:31


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (3)
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
2
精彩,学习,很适合我们这样的菜鸟~
2006-8-7 21:00
0
雪    币: 333
活跃值: (11)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
3
谢谢!学习中!
2006-8-7 23:05
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢,我会好好学习的
2006-8-8 18:51
0
游客
登录 | 注册 方可回帖
返回
//