恩,对,就是这段代码了.很明显哪个是用户名哪个是注册码,再看一下他们的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,正是我们想要的注册码在里面!!!!