【文章标题】: 菜鸟就吃个软柿子
【文章作者】: benbentaiyang
【作者邮箱】: **
【作者主页】: **
【作者QQ号】: 40597503
【软件名称】: KeyGenMe.exe
【软件大小】: 14.5
【下载地址】: 看雪crackeme专区
【加壳方式】: 无
【保护方式】: 无
【编写语言】: Win32汇编
【使用工具】: OD,WinHex,peid,reshacker,Stud_PE
【操作平台】: xp
【软件介绍】: 一个CrackeMe,使用远线程,MD5算法,但明文比较.
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
菜鸟级破文,只求能看懂.属入门级,高手飘过!废话不说了,开始正题.
下载这个CrackeMe,作者自己介绍无壳,无Anti,等等.
用Peid查看,无壳,情况属实.
然后用OD载入,无加密提示,也说明了没有加壳.F9,运行,无退出,死机,异常,检查结束,作者比较厚道,所述情况属实.
主进程如下:
131416D9 >/$ 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
恩,对,就是这段代码了.很明显哪个是用户名哪个是注册码,再看一下他们的hMenu,呵呵,这个不久是我们要找的ControlID吗? yeah! 一个3 一个4,正合我意. 回到前面我们的猜测,呵呵,原来真的是第一种A的猜测啊!!
到目前,我们还没有调试这个程序!但是我们却知道了这么多,是不是很有成就感啊!!哈哈!
还不能太高兴了,因为我们还没找到注册码.不过既然我们知道是A种情况了,那就是程序处理后的结果跟注册码比较了,也就是说程序用用户名做参数计算出来一个结果,然后跟注册码比较.这个结果???这个结果跟注册码比较???? 晕倒,这个结果不就是真正的注册码吗!!!
呵呵,我们找到注册码了!!!
可是我们只是这样分析,还不能给自己的名字一个注册码?怎么样才能得到它呢? 调试吧? 可是OD 一打开就结束了.你说编程读这个地址?晕,别给我说这个,我是菜鸟,不会这个.那怎么办呢?
静下心来想想,到嘴的肥肉不能只在嘴边舔舔而吃不下. 既然是明码,也计算出来了,但是因为我不能调试却看不到.可能作者用远线程就是这个目的,让我们干着急.看来他的目的达到了.我们可不能束手就擒.再想想,恩,程序里面计算出来了,已经有了,哈哈,对,那运行的时候内存里也有这个明码了.去内存里面找去!!yeah!!
打开我们的好助手winhex,找这个线程,不爽,没找到.不管它,那我就打开整个内存.因为真的注册码跟假的比较,那他们应该在内存中离的不远,搜索---假的注册码
呵呵,找到了,就在它的附近它的兄弟真注册码乖乖的躺在那里:
哈哈,我们找到了自己的注册码了!!
文章似乎结束了,但是总感觉有点不是很痛快.作者不让我调试,MD我就很乖很听话地没调试,不爽.
但是现在还没什么思路该怎么调试.去论坛看看吧:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)