瑞星卡卡安全论坛

首页 » 技术交流区 » 反病毒/反流氓软件论坛 » 菜鸟学堂 » KeyGenMe的菜鸟级解密技术(图)
流星陨落 - 2010-1-8 21:03:00
菜鸟级破文,只求能看懂.属入门级,高手飘过!废话不说了,开始正题.
  下载这个CrackeMe,作者自己介绍无壳,无Anti,等等.
  用Peid查看,无壳,情况属实.
  然后用OD载入,无加密提示,也说明了没有加壳.F9,运行,无退出,死机,异常,检查结束,作者比较厚道,所述情况属实.
  主进程如下:
  131416D9 >/$Content$nbsp; 6A 00        push    0                                ; /pModule = NULL
  131416DB  |.  FF15 20201413 call    dword ptr [<&kernel32.GetModuleH>; \GetModuleHandleA
  131416E1  |.  A3 E1361413  mov    dword ptr [131436E1], eax
  131416E6      8BF8          mov    edi, eax
  131416E8      037F 3C      add    edi, dword ptr [edi+3C]
  131416EB  |.  83C7 04      add    edi, 4
  131416EE  |.  83C7 14      add    edi, 14
  131416F1  |.  8B47 38      mov    eax, dword ptr [edi+38]
  131416F4      A3 ED361413  mov    dword ptr [131436ED], eax
  131416F9  |.  68 05010000  push    105                              ; /BufSize = 105 (261.)
  131416FE  |.  8D05 8C321413 lea    eax, dword ptr [1314328C]        ; |
  13141704  |.  50            push    eax                              ; |PathBuffer => KeyGenMe.1314328C
  13141705  |.  6A 00        push    0                                ; |hModule = NULL
  13141707  |.  FF15 28201413 call    dword ptr [<&kernel32.GetModuleF>; \GetModuleFileNameA
  1314170D  |.  68 28010000  push    128                              ; /Length = 128 (296.)
  13141712  |.  8D05 01371413 lea    eax, dword ptr [13143701]        ; |
  13141718  |.  50            push    eax                              ; |Destination => KeyGenMe.13143701
  13141719  |.  FF15 24201413 call    dword ptr [<&kernel32.RtlZeroMem>; \RtlZeroMemory
  1314171F  |.  C705 01371413>mov    dword ptr [13143701], 128
  13141729  |.  8D05 01371413 lea    eax, dword ptr [13143701]
  1314172F  |.  50            push    eax                              ; /ProcessID => 13143701
  13141730  |.  6A 02        push    2                                ; |Flags = TH32CS_SNAPPROCESS
  13141732  |.  FF15 2C201413 call    dword ptr [<&kernel32.CreateTool>; \CreateToolhelp32Snapshot
  13141738  |.  A3 FD361413  mov    dword ptr [131436FD], eax
  1314173D  |.  8D05 01371413 lea    eax, dword ptr [13143701]
  13141743  |.  50            push    eax                              ; /pProcessentry => KeyGenMe.13143701
  13141744  |.  FF35 FD361413 push    dword ptr [131436FD]            ; |hSnapshot = NULL
  1314174A  |.  FF15 30201413 call    dword ptr [<&kernel32.Process32F>; \Process32First
  13141750  |.  EB 44        jmp    short 13141796
  13141752  |>  8D05 25371413 /lea    eax, dword ptr [13143725]
  13141758  |.  50            |push    eax                            ; /StringOrChar => ""
  13141759  |.  FF15 A8201413 |call    dword ptr [<&user32.CharLowerA>>; \CharLowerA
  1314175F  |.  8D05 25371413 |lea    eax, dword ptr [13143725]
  13141765  |.  50            |push    eax                            ; /String2 => ""
  13141766  |.  8D05 51321413 |lea    eax, dword ptr [13143251]      ; |
  1314176C  |.  50            |push    eax                            ; |String1 => "explorer.exe"
  1314176D  |.  FF15 34201413 |call    dword ptr [<&kernel32.lstrcmpA>>; \lstrcmpA
  13141773  |.  0BC0          |or      eax, eax
  13141775  |.  75 0C        |jnz    short 13141783
  13141777  |.  FF35 09371413 |push    dword ptr [13143709]
  1314177D  |.  8F05 F1361413 |pop    dword ptr [131436F1]
  13141783  |>  8D05 01371413 |lea    eax, dword ptr [13143701]
  13141789  |.  50            |push    eax                            ; /pProcessentry => KeyGenMe.13143701
  1314178A  |.  FF35 FD361413 |push    dword ptr [131436FD]            ; |hSnapshot = NULL
  13141790  |.  FF15 38201413 |call    dword ptr [<&kernel32.Process32>; \Process32Next
  13141796  |>  0BC0          or      eax, eax
  13141798  |.^ 75 B8        \jnz    short 13141752
  1314179A  |.  FF35 F1361413 push    dword ptr [131436F1]            ; /ProcessId = 0
  131417A0  |.  6A 00        push    0                                ; |Inheritable = FALSE
  131417A2  |.  6A 2A        push    2A                              ; |Access = CREATE_THREAD|VM_OPERATION|VM_WRITE
  131417A4  |.  FF15 3C201413 call    dword ptr [<&kernel32.OpenProces>; \OpenProcess
  131417AA  |.  A3 E9361413  mov    dword ptr [131436E9], eax
  131417AF  |.  68 00800000  push    8000
  131417B4  |.  6A 00        push    0
  131417B6  |.  FF35 E1361413 push    dword ptr [131436E1]
  131417BC  |.  FF35 E9361413 push    dword ptr [131436E9]
  131417C2  |.  FF15 40201413 call    dword ptr [<&kernel32.VirtualFre>;  kernel32.VirtualFreeEx
  131417C8  |.  6A 40        push    40
  131417CA  |.  68 00300000  push    3000
  131417CF  |.  FF35 ED361413 push    dword ptr [131436ED]
  131417D5  |.  FF35 E1361413 push    dword ptr [131436E1]
  131417DB  |.  FF35 E9361413 push    dword ptr [131436E9]
  131417E1  |.  FF15 44201413 call    dword ptr [<&kernel32.VirtualAll>;  kernel32.VirtualAllocEx
  131417E7  |.  A3 E5361413  mov    dword ptr [131436E5], eax
  131417EC  |.  8D05 F5361413 lea    eax, dword ptr [131436F5]
  131417F2  |.  50            push    eax                              ; /pBytesWritten => KeyGenMe.131436F5
  131417F3  |.  FF35 ED361413 push    dword ptr [131436ED]            ; |BytesToWrite = 0
  131417F9  |.  FF35 E1361413 push    dword ptr [131436E1]            ; |Buffer = NULL
  131417FF  |.  FF35 E5361413 push    dword ptr [131436E5]            ; |Address = 0
  13141805  |.  FF35 E9361413 push    dword ptr [131436E9]            ; |hProcess = NULL
  1314180B  |.  FF15 48201413 call    dword ptr [<&kernel32.WriteProce>; \WriteProcessMemory
  13141811  |.  8D05 F9361413 lea    eax, dword ptr [131436F9]
  13141817  |.  50            push    eax
  13141818  |.  6A 00        push    0
  1314181A  |.  FF35 E1361413 push    dword ptr [131436E1]
  13141820  |.  8D05 94151413 lea    eax, dword ptr [13141594]
  13141826  |.  50            push    eax
  13141827  |.  6A 00        push    0
  13141829  |.  6A 00        push    0
  1314182B  |.  FF35 E9361413 push    dword ptr [131436E9]
  13141831  |.  FF15 4C201413 call    dword ptr [<&kernel32.CreateRemo>;  kernel32.CreateRemoteThread
  13141837  |.  6A 00        push    0                                ; /ExitCode = 0
  13141839  \.  FF15 50201413 call    dword ptr [<&kernel32.ExitProces>; \ExitProcess
 
 
  看以上代码,没有什么特别地方,大体意思是先获得本句柄,然后取得当前进程列表,接着查找explorer.exe进程,打开,从里面分配一些内存,给将来的线程使用.也就是说将来的线程是注入到explorer.exe进程中,这些我们暂且不用关心.我们主要看一下这个地方:
  13141820  |.  8D05 94151413 lea    eax, dword ptr [13141594]
  13141826  |.  50            push    eax
  13141827  |.  6A 00        push    0
  13141829  |.  6A 00        push    0
  1314182B  |.  FF35 E9361413 push    dword ptr [131436E9]
  13141831  |.  FF15 4C201413 call    dword ptr [<&kernel32.CreateRemo>;  kernel32.CreateRemoteThread
 
  这个是在程序退出之前的创建的远程线程,这个函数具体参数可以查API,因为谁也不可能背过所有的API函数,^_^. 查过函数之后我们可以知道,push eax压入的这个参数是远线程的入口地址,往上看,lea    eax, dword ptr [13141594],呵呵,eax原来就是13141594.
  也就是窗口,注册什么的那些乱七八糟的代码都是从那里开始执行的,而这里只是铺垫.
  开始我也是没办法用OD调试,只能看看静态的反汇编代码了.还好,因为是win32汇编写的,反汇编后几乎跟源码没有区别,高兴!
  先找错误提示,
  1314151E  . /75 1E        jnz    short 1314153E
  13141520  . |6A 40        push    40                              ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
  13141522  . |8D05 43341413 lea    eax, dword ptr [13143443]        ; |
  13141528  . |50            push    eax                              ; |Title => "Congratulation"
  13141529  . |8D05 52341413 lea    eax, dword ptr [13143452]        ; |
  1314152F  . |50            push    eax                              ; |Text => "yes...You Got It!!"
  13141530  . |FF35 ED341413 push    dword ptr [131434ED]            ; |hOwner = NULL
  13141536  . |FF15 70201413 call    dword ptr [<&user32.MessageBoxA>>; \MessageBoxA
  1314153C  . |EB 17        jmp    short 13141555
  1314153E  > \6A 00        push    0                                ; /Style = MB_OK|MB_APPLMODAL
  13141540  .  6A 00        push    0                                ; |Title = NULL
  13141542  .  8D05 65341413 lea    eax, dword ptr [13143465]        ; |
  13141548  .  50            push    eax                              ; |Text => "hmm..maybe something worry..try again...:)"
  13141549  .  FF35 ED341413 push    dword ptr [131434ED]            ; |hOwner = NULL
  1314154F  .  FF15 70201413 call    dword ptr [<&user32.MessageBoxA>>; \MessageBoxA
 
  呵呵,经典的错误和正确并列,真理跟缪误之间就差一个选择--跳转.呵呵,改掉这个
  1314151E  . /75 1E        jnz    short 1314153E
  就可以品尝到爆破的快乐,呵呵,这也太简单了,相信你不会就此停步,因为这样也太没意思了,人家作者说了没做什么防范的,人家厚的,你也得厚道点,那我们接着往下看.
  131414B3  .  FF15 B8201413 call    dword ptr [131420B8]            ;  KeyGenMe.13141215
  131414B9  .  68 00020000  push    200                              ; /Count = 200 (512.)
  131414BE  .  8D05 69351413 lea    eax, dword ptr [13143569]        ; |
  131414C4  .  50            push    eax                              ; |Buffer => KeyGenMe.13143569
  131414C5  .  6A 03        push    3                                ; |ControlID = 3
  131414C7  .  FF75 08      push    dword ptr [ebp+8]                ; |hWnd
  131414CA  .  FF15 74201413 call    dword ptr [<&user32.GetDlgItemTe>; \GetDlgItemTextA
  131414D0  .  50            push    eax                              ; /Arg2
  131414D1  .  8D05 69351413 lea    eax, dword ptr [13143569]        ; |
  131414D7  .  50            push    eax                              ; |Arg1 => 13143569
  131414D8  .  FF15 BC201413 call    dword ptr [131420BC]            ; \KeyGenMe.13141087
  131414DE  .  50            push    eax                              ; /<%s>
  131414DF  .  68 C0341413  push    131434C0                        ; |Format = "%s",CR,LF,""
  131414E4  .  68 DD351413  push    131435DD                        ; |s = KeyGenMe.131435DD
  131414E9  .  E8 64030000  call    <jmp.&user32.wsprintfA>          ; \wsprintfA
  131414EE  .  83C4 0C      add    esp, 0C
  131414F1  .  68 00020000  push    200                              ; /Count = 200 (512.)
  131414F6  .  8D05 05351413 lea    eax, dword ptr [13143505]        ; |
  131414FC  .  50            push    eax                              ; |Buffer => KeyGenMe.13143505
  131414FD  .  6A 04        push    4                                ; |ControlID = 4
  131414FF  .  FF75 08      push    dword ptr [ebp+8]                ; |hWnd
  13141502  .  FF15 74201413 call    dword ptr [<&user32.GetDlgItemTe>; \GetDlgItemTextA
  13141508  .  8D35 DD351413 lea    esi, dword ptr [131435DD]
  1314150E  .  8D3D 05351413 lea    edi, dword ptr [13143505]
  13141514  .  B9 21000000  mov    ecx, 21
  13141519  .  FC            cld
  1314151A  .  F3:A6        repe    cmps byte ptr es:[edi], byte ptr>
  1314151C  .  0BC9          or      ecx, ecx
 
  这是在关键跳转上面的那段代码,从调用的API函数分析,先是获得一个输入的文本,然后这个文本送进一个加工厂处理了一下,接着用wprintf函数把加工后的结果格式化包装一下,放傍边先不管.在然后呢就是又获得另一个输入文本,获得之后就是这段代码了:
  13141508  .  8D35 DD351413 lea    esi, dword ptr [131435DD]
  1314150E  .  8D3D 05351413 lea    edi, dword ptr [13143505]
  13141514  .  B9 21000000  mov    ecx, 21
  13141519  .  FC            cld
  1314151A  .  F3:A6        repe    cmps byte ptr es:[edi], byte ptr>
  1314151C  .  0BC9          or      ecx, ecx
  这不难理解,就是把处理后的结果跟获得的第二个文本进行比较了,呵呵.
  因为没有调试只是在这里瞎看,瞎看也有瞎看的原则和方法对不?呵呵,我们可以知道这两个文本一个是用户名,一个是注册码,到底是哪个进了工厂处理然后跟另一个比?目前为止可以猜一下:
  A:用户名->进加工厂->加工之后的结果  cmp  输入的注册码
  B:注册码->进加工厂->加工之后的结果  cmp  输入的用户名
  从这种加密的效果上看没什么太大区别,但是仔细想想,如果你是软件作者,你当然想一个用户名对应一个注册码,而不是一个注册码去让用户改名字哦.还有从一般人的写代码的思路来看这两个流程,当然A种情况比较合理也可能性最大.
  好了,上面我们是在看完了那些代码后的想入非非,呵呵,当然不能光靠幻想和猜测了,得来点有理有据的东西来啊,呵呵,现在这个情况下我想到了两个办法?你呢?
  第一个办法当然就是调试跟踪了,看看他们取得的值各是什么,就能确定是A还是B了.
  第二个办法就是看控件的ControlID号了,怎么看呢? OD里面是 3 和 4,怎么知道3和4对应那个输入框呢?  看资源首先想到就是资源查看工具了,我用的是ResHacker,兴奋,赶快拿来试试! 用reshacker打开!!! 郁闷!!! 除了图标什么都没有.
  怎么回事呢? 看来这些窗口按钮什么的是动态加入的了.那我们还得回到程序看代码了.感觉有点不爽,因为一个想法落空了,呵呵,没关系,我们又知道了更多的信息.
  动态加入,动态加入,嘴里念道一下,呵呵,我想你一定会想到CreateWindowEx这个函数了吧,赶快找!go!!
  在OD里我们找到了:
  13141374  .  6A 00        push    0                                ; /lParam = NULL
  13141376  .  FF35 E9341413 push    dword ptr [131434E9]            ; |hInst = NULL
  1314137C  .  6A 03        push    3                                ; |hMenu = 00000003
  1314137E  .  FF75 08      push    dword ptr [ebp+8]                ; |hParent
  13141381  .  6A 0F        push    0F                              ; |Height = F (15.)
  13141383  .  68 A0000000  push    0A0                              ; |Width = A0 (160.)
  13141388  .  6A 0F        push    0F                              ; |Y = F (15.)
  1314138A  .  6A 50        push    50                              ; |X = 50 (80.)
  1314138C  .  68 80008850  push    50880080                        ; |Style = WS_CHILD|WS_VISIBLE|WS_SYSMENU|WS_BORDER|80
  13141391  .  68 DA331413  push    131433DA                        ; |WindowName = "4stone"
  13141396  .  68 D5331413  push    131433D5                        ; |Class = "Edit"
  1314139B  .  6A 00        push    0                                ; |ExtStyle = 0
  1314139D  .  FF15 68201413 call    dword ptr [<&user32.CreateWindow>; \CreateWindowExA
  131413A3  .  A3 F1341413  mov    dword ptr [131434F1], eax
  131413A8  .  FF35 F1341413 push    dword ptr [131434F1]            ; /hWnd = NULL
  131413AE  .  FF15 6C201413 call    dword ptr [<&user32.SetFocus>]  ; \SetFocus
  131413B4  .  6A 00        push    0                                ; /lParam = NULL
  131413B6  .  FF35 E9341413 push    dword ptr [131434E9]            ; |hInst = NULL
  131413BC  .  6A 04        push    4                                ; |hMenu = 00000004
  131413BE  .  FF75 08      push    dword ptr [ebp+8]                ; |hParent
  131413C1  .  6A 0F        push    0F                              ; |Height = F (15.)
  131413C3  .  68 A0000000  push    0A0                              ; |Width = A0 (160.)
  131413C8  .  6A 2D        push    2D                              ; |Y = 2D (45.)
  131413CA  .  6A 50        push    50                              ; |X = 50 (80.)
  131413CC  .  68 80008850  push    50880080                        ; |Style = WS_CHILD|WS_VISIBLE|WS_SYSMENU|WS_BORDER|80
  131413D1  .  68 E1331413  push    131433E1                        ; |WindowName = "Put your code here.."
  131413D6  .  68 D5331413  push    131433D5                        ; |Class = "Edit"
  131413DB  .  6A 00        push    0                                ; |ExtStyle = 0
  131413DD  .  FF15 68201413 call    dword ptr [<&user32.CreateWindow>; \CreateWindowExA

用户系统信息:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; QQPinyin 685; QQPinyin 686; QQPinyin 689; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; 360SE)
流星陨落 - 2010-1-8 21:03:00
恩,对,就是这段代码了.很明显哪个是用户名哪个是注册码,再看一下他们的hMenu,呵呵,这个不久是我们要找的ControlID吗? yeah!  一个3  一个4,正合我意.  回到前面我们的猜测,呵呵,原来真的是第一种A的猜测啊!!
  到目前,我们还没有调试这个程序!但是我们却知道了这么多,是不是很有成就感啊!!哈哈!
  还不能太高兴了,因为我们还没找到注册码.不过既然我们知道是A种情况了,那就是程序处理后的结果跟注册码比较了,也就是说程序用用户名做参数计算出来一个结果,然后跟注册码比较.这个结果???这个结果跟注册码比较???? 晕倒,这个结果不就是真正的注册码吗!!!
  呵呵,我们找到注册码了!!!
  可是我们只是这样分析,还不能给自己的名字一个注册码?怎么样才能得到它呢? 调试吧? 可是OD 一打开就结束了.你说编程读这个地址?晕,别给我说这个,我是菜鸟,不会这个.那怎么办呢?
  静下心来想想,到嘴的肥肉不能只在嘴边舔舔而吃不下. 既然是明码,也计算出来了,但是因为我不能调试却看不到.可能作者用远线程就是这个目的,让我们干着急.看来他的目的达到了.我们可不能束手就擒.再想想,恩,程序里面计算出来了,已经有了,哈哈,对,那运行的时候内存里也有这个明码了.去内存里面找去!!yeah!!
  打开我们的好助手winhex,找这个线程,不爽,没找到.不管它,那我就打开整个内存.因为真的注册码跟假的比较,那他们应该在内存中离的不远,搜索---假的注册码
  呵呵,找到了,就在它的附近它的兄弟真注册码乖乖的躺在那里:
 
   
  哈哈,我们找到了自己的注册码了!!
  文章似乎结束了,但是总感觉有点不是很痛快.作者不让我调试,MD我就很乖很听话地没调试,不爽.
引用:
    找到线程代码的地址,直接修改程序开头为JMP,就可以调试了
 
  另外,既然是做远程线程,其实就是在线程代码脸上写着“我可以重定位”,所以直接把线程代码摘出来,稍做处理,就可以直接在其他程序里使用了。假如计算注册码的代码也在其中,……注册机
 
  配合其他一些手段,如管道、消息,做成跨进程的交互注册验证更有实用点

  呵呵,原来有人比我们想得还要好啊,我怎么没想到改代码呢?既然人家指点咱了,咱就照搬一下试试.
  131416D9 >/$Content$nbsp; 6A 00        push    0                                ; /pModule = NULL
  131416DB  |.  FF15 20201413 call    dword ptr [<&kernel32.GetModuleH>; \GetModuleHandleA
  131416E1  |.  A3 E1361413  mov    dword ptr [131436E1], eax
  131416E6      8BF8          mov    edi, eax
  131416E8      037F 3C      add    edi, dword ptr [edi+3C]
  131416EB  |.  83C7 04      add    edi, 4
  131416EE  |.  83C7 14      add    edi, 14
  131416F1  |.  8B47 38      mov    eax, dword ptr [edi+38]
 
 
  这个是程序的开始,当然也没必要把人家的GetModuleHandleA也不要了,说不定还能用到这个句柄,mov  edi, eax  从这句以下我们就不需要了,那就从这里改吧.
  在OD里,选中这条语句,然后点右键,选Assemble,然后改成跳转到刚才原来我们分析的13141594这个地址: JMP 13141594  .ok了,运行一下,恩,没问题!!
  这样我们就能用OD调试了,也就不用到内存再找这册码去了,呵呵,我们好像又进步了一点,不过是在大家的指点下进步的.再彻底一点,用Winhex打开文件,找对应的机器码8BF8037F,确认只找到一处,然后改成 JMP 13141594的机器码:E9A9FEFFFF ,保存,ok!
  解决了用OD不能调试的问题.不过又想想,既然已经分析到注册码了,改JMP只是单纯为了调试,可是我们调试能干什么?去分析那个加工厂算法?呵呵,笑话,这可不是我菜鸟干的事情.
  那我们就到此为止了??似乎还有点遗憾.
  对,让程序自己把注册码给显示出来,那样就不用调试,也不用到内存去找了,呵呵,这个想法不错.应该很难吧???不,一点不难,我们继续前进!!go go !!
  怎么显示呢?当然最先想到的就是MessageBoxA了,让对话框来告诉我们,因为这个容易嘛,哈哈,好那我们就找到注册码的地址,然后再找个合适的MessageBoxA.
  一想到MessageBoxA我们就想到了错误提示,呵呵,好,我们再来到这里:
  13141520  .  6A 40        push    40                              ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
  13141522  .  8D05 43341413 lea    eax, dword ptr [13143443]        ; |
  13141528  .  50            push    eax                              ; |Title => "Congratulation"
  13141529  .  8D05 52341413 lea    eax, dword ptr [13143452]        ; |
  1314152F  .  50            push    eax                              ; |Text => "yes...You Got It!!"
  13141530  .  FF35 ED341413 push    dword ptr [131434ED]            ; |hOwner = NULL
  13141536  .  FF15 70201413 call    dword ptr [<&user32.MessageBoxA>>; \MessageBoxA
  1314153C  .  EB 17        jmp    short 13141555
  1314153E  >  6A 00        push    0                                ; /Style = MB_OK|MB_APPLMODAL
  13141540  .  6A 00        push    0                                ; |Title = NULL
  13141542  .  8D05 65341413 lea    eax, dword ptr [13143465]        ; |
  13141548  .  50            push    eax                              ; |Text => "hmm..maybe something worry..try again...:)"
  13141549  .  FF35 ED341413&nbs, p;push    dword ptr [131434ED]            ; |hOwner = NULL
  1314154F  .  FF15 70201413 call    dword ptr [<&user32.MessageBoxA>>; \MessageBoxA
 
  程序提示成功或者失败,当然加工厂已经加工好了然后比较的,那加工的结果地址在那里呢?刚才分析了,是这里:
  131414D0  .  50            push    eax                              ; /Arg2
  131414D1  .  8D05 69351413 lea    eax, dword ptr [13143569]        ; |
  131414D7  .  50            push    eax                              ; |Arg1 => 13143569
  131414D8  .  FF15 BC201413 call    dword ptr [131420BC]            ; \KeyGenMe.13141087
  131414DE  .  50            push    eax                              ; /<%s>
  131414DF  .  68 C0341413  push    131434C0                        ; |Format = "%s",CR,LF,""
  131414E4  .  68 DD351413  push    131435DD                        ; |s = KeyGenMe.131435DD
  131414E9  .  E8 64030000  call    <jmp.&user32.wsprintfA>          ; \wsprintfA
 
  处理的结果eax直接又当了个参数进行了格式调整,Format这个格式,"%s",CR,LF,"",当个字符串,并后面加了换行回车,哈哈,我们要的就是字符串,作者真周到,连换行回车也给写好了,那我们就拿来用了.
  查一下wsprintf这个函数,恩,这个131435DD就是整理后的结果,好的,我们就把它拿过去用了.改掉错误提示,让它显示注册码,成功的那个提示嘛,还给他留着,嘿嘿,好试试我们的成果啊.
  13141542  .  8D05 65341413 lea    eax, dword ptr [13143465]        ; |
  13141548  .  50            push    eax                              ; |Text => "hmm..maybe something worry..try again...:)"
  看来不用动手术了,只来个小外科就行了.把 lea    eax, dword ptr [13143465] 改成 lea    eax, dword ptr [131435DD] ,同样彻底点,再到winhex里面把相应的机器码改过来.
  运行试试,随便填个或者不填,直接按Validate,Yeah,成功了,直接显示了真正的注册码!!!
  我们菜鸟也算做了个简易的注册机了.哈哈!!!爽!!
  到此,可以松口气了!!
 
  围着这个程序走两步,呵呵,感觉还是有点缺憾,别人的注册机都能复制代码,我的注册机只能给看看,没法复制啊,怎么办呢?不能看的时候用笔记下来然后再填吧,好原始,不能忍受.再想点招.
  对,把代码显示到填写注册码的文本框里,恩,这样就好点了.继续工作,呵呵,let's go!!!
  要把注册码写到文本框里,我们得用个函数SetDlgItemText,这个函数不会用,没关系,到MSDN上查一下,现学现用吧.
 
  BOOL SetDlgItemText(
    HWND hDlg,        // handle of dialog box
    int nIDDlgItem,    // identifier of control
    LPCTSTR lpString  // text to set
  );
  我们要用这个函数得先准备三个参数:
  第一个参数是对话框的句柄,也就是我们看到的这个CrackeMe的窗口句柄.
  第二个就是文本框控件的ID了
  第三个就是我们要显示的字串的地址.
  在OD里看看,里面有个GetDlgItemText,模样相似,一个取得文本,一个设置文本.看看它的参数:
 
  UINT GetDlgItemText(
    HWND hDlg,      // handle of dialog box
    int nIDDlgItem,  // identifier of control
    LPTSTR lpString, // address of buffer for text
    int nMaxCount    // maximum size of string
  );
 
  我们需要的东西这里面都有了,呵呵,不用费事了.
 
  代码里:
 
  131414F1  .  68 00020000  push    200                              ; /Count = 200 (512.)
  131414F6  .  8D05 05351413 lea    eax, dword ptr [13143505]        ; |
  131414FC  .  50            push    eax                              ; |Buffer => KeyGenMe.13143505
  131414FD  .  6A 04        push    4                                ; |ControlID = 4
  131414FF  .  FF75 08      push    dword ptr [ebp+8]                ; |hWnd
  13141502  .  FF15 74201413 call    dword ptr [<&user32.GetDlgItemTe>; \GetDlgItemTextA
 
  我们要的第一个参数 窗口句柄在dword ptr [ebp+8]这里
  第二个参数ID就是4,刚才也分析了,第三个参数文本地址也有了刚才的131435DD,好像我们可以完成这个工作了,呵呵
 
  万事具备!!还差点啥,晕倒,光知道用这个函数了,这个函数还不知道从哪里调用呢???
 
  让我想起来一句台词: 唉,年轻的时候有贼心没贼胆,到老了贼心贼胆都有了,贼没了!!
 
  先不急,整个程序搜一搜,看看作者用这个函数了吗,如果用的话,我们就可以直接用!没用呢??没用当然也有没用的法,我们再给他加上这个就是了!嘿嘿
  OD里查看了一下,没有用到SetDlgItemTextA这个函数,看来只能自己添加了.
  如何添加?如何添加才能不出错?这些问题可以去学一下有关PE文件的只是,看看输入表这部分内容,我们现在就不在这里复习了.不想看也没关系,介绍个工具Stud_PE,看雪这里就有下载.
  我们就使用工具,不在手动自己添加了,呵呵,图个方便快捷,当然你有兴趣自己手动添加也可以.
  打开Stud_PE,文件里面打开KeyGenMe.exe,然后选Functions选项卡,在右边的窗口里右击鼠标,选Add new Import,弹出来一个对话框,点击Dll Select,然后到你系统文件夹下(xp系统在windows\system32)找到user32.dll打开.接着点击Select Fuc.在列表里找到SetDlgItemTextA选中,再点击Add to list,这个函数就到列表中了,最后点击ADD,就添加好了.
  这是再看右边的Import Functions栏里,多了个user32.dll,里面有了刚才添加的函数.这个窗口先别关,因为还要用一下.
  添加完这个函数,接下来我们如何调用这个函数呢?呵呵,这里什么地址啊偏移啊如果你不想深入了解也不妨碍我们继续,因为我们只要依葫芦画瓢能用它就可以了.
  再用OD打开KeyGenMe.exe,找到GetDlgTextA这个函数,点中它.我们看看程序如何调用它的:
  FF15 74201413 call    dword ptr [<&user32.GetDlgItemTe>; \GetDlgItemTextA
  od里面代码下面紧接着的一个小提示窗口里显示:
  ds:[13142074]=77D6AC1E (USER32.GetDlgItemTextA)
  也就是说这句话就是 call 13142074 就等于调用了GetDlgItemTextA,呵呵,好,再切换到刚才没让你关掉的stud_PE窗口里,在Import Functions 栏里找到第一个user32.dll,然后展开找到里面的GetDlgItemTextA这个函数,看到:rva:00002074.这个东西是什么,有兴趣你可以深入研究一下PE结构,目前我们不管它究竟是什么.再回头看看刚才的call 13142074 ,聪明的你发现点什么问题了吧,哈哈,对它们的低位是一样的,只是高位不同.你可以同样的方法看看其他函数,也是这样情况,即:在程序中对系统函数调用时call的地址的地位就是rva这个值,而高位是一个常数,在这个程序里高位是1314.
  明白了这个就好办了,我们再在stud_PE里找到我们刚才加入的SetDlgItemTextA这个函数,看它的rva:00006083,高位再加上1314,也就是13146083,哈哈,你要调用你刚才加的函数直接call dword ptr [13146083] 就可以拉,简单吧!!!!(前提是你要把参数准备好,不然会出错哦,^_^)
  好了,一切都准备好了,现在开始动工.
  先在程序里找块地方,把我们完成的功能写在那里.当然可以是空地,也可以原来没有用的地方或者你不想要的地方随便改一下就可以了.来,咱们一起找个地,这比在城市里买房子容易多了,哈哈!!
  我们有很多地方放我们的代码,比如把刚才改的错误提示那块地放重写SetDlgItemTextA,这样都在一个函数里参数也好设置.可是我们刚才的成果还不想破坏,怎么办??
  你可能说给程序加个区块,恩,不错的一个办法,不过在加区块的时候代码转移什么的还需要设置一下,改动比较大,麻烦!!!懒人就用懒人的做法了,不是还有个提示信息吗?? 那就把成功提示信息那块地方给占了吧,哈哈,这样好,免去不少麻烦!!
  好了,现在在OD中从地址1314151C开始(当然你也可以再往前一点,把比较那几条语句也去掉)到1314153D这段代码用nop替代,机器码90,然后再用OD的右键Assemble功能,如下代码:
 
  push    131435DD
  push    4
  push    dword ptr [ebp+8]
  call    dword ptr [13146083] (这条写完之后会自动变成 call    dword ptr [<&user32.SetDlgItemTextA>] )
 
  然后然后选中这段代码复制到文件中,接下来就是看着这段代码的机器码在winhex相对应的地方在文件中改掉,保存.
  我改后的代码如下:
  ......
  1314151A  .  F3:A6        repe    cmps byte ptr es:[edi], byte ptr [esi]
  1314151C  .  90            nop
  1314151D  .  68 DD351413  push    131435DD
  13141522  .  6A 04        push    4
  13141524  .  FF75 08      push    dword ptr [ebp+8]
  13141527      FF15 83601413 call    dword ptr [<&user32.SetDlgItemTextA>]  ;  USER32.SetDlgItemTextA
  1314152D  .  90            nop
  1314152E  .  90            nop
  1314152F  .  90            nop
  13141530  .  90            nop
  13141531  .  90            nop
  13141532  .  90            nop
  13141533  .  90            nop
  13141534  .  90            nop
  13141535  .  90            nop
  13141536  .  90            nop
  13141537  .  90            nop
  13141538  .  90            nop
  13141539  .  90            nop
  1314153A  .  90            nop
  1314153B  .  90            nop
  1314153C  .  90            nop
  1314153D  .  90            nop
  1314153E  .  6A 00        push    0                                      ; /Style = MB_OK|MB_APPLMODAL
  13141540  .  6A 00        push    0                                      ; |Title = NULL
  13141542  .  8D05 DD351413 lea    eax, dword ptr [131435DD]              ; |
  ......
  大功告成!!!
 
  让我们来试试有没有问题
 
  激动人心的时刻.....
 
  运行!!
 
  随便填一个名字一个注册码,点击validate,先弹出来一个对话框,显示出了正确的注册码,然后看看注册码输入框里,Yeah,正是我们想要的注册码在里面!!!!
流星陨落 - 2010-1-8 21:03:00
安全中国里看到的,还是挺有意思的,分享下
zhonghuayizu - 2010-6-10 12:35:00
辛苦了楼主
1
查看完整版本: KeyGenMe的菜鸟级解密技术(图)