基于明码的典型diy注册机
很久没写文章了,最近也没干什么,就整理了一些经验。
看题目,也就是说程序算法比较必须是明码,我们要把源程序部份改成注册机。当然, CrackMe和普通的软件就不太一样!!我用一个明码CrackMe来说明,其他的举一反三就行了。
另外,我打包的这个CrackMe有多层壳吧,把图标都压没了!是Delphi写的程序。
用DEDE找到注册按钮事件代码,在00457344处下断:(一路按F8,直到看到真码)
00457344 /. 55 push ebp
00457345 |. 8BEC mov ebp, esp
00457347 |.
0045734B |. 56 push esi
0045734D |.
00457352 |. 894D F0 mov dword ptr [ebp-10], ecx
00457355 |. 8945 FC mov dword ptr [ebp-4], eax
00457358 |.
0045735B |. 68 B4744500 push 004574B4
00457360 |. 64:FF30 push dword ptr fs:[eax]
00457363 |. 64:8920 mov dword ptr fs:[eax], esp
00457366 |. E8 15FBFFFF call 00456E80
0045736B |. 8B45 FC mov eax, dword ptr [ebp-4]
0045736E |. 83B8 FC020000>cmp dword ptr [eax+2FC], 1
00457375 |.
0045737B |. BF 12020000 mov edi, 212
00457380 |> 47 /inc edi
00457381 |. 83EF 02 |sub edi, 2
00457384 |. 81FB 94000000 |cmp ebx, 94
0045738D |. 81FB 94000000 ||cmp ebx, 94
00457393 |.^ 7E F7 |\jle short
00457395 |> 81FF F0000000 |cmp edi,
0045739B |.^
0045739D |. 8D
004573AE |. 837D F4 00 cmp dword ptr [ebp-C], 0
004573B2 |. 75 11 jnz short
004573B4 |. A1
004573B9 |. 8B00 mov eax, dword ptr [eax]
004573BB |. E8 0864FEFF call 0043D
004573CB |. 8B
004573D1 |. E8 4ED6FCFF call
004573D6 |. 837D F4 00 cmp dword ptr [ebp-C], 0
004573DA |.
004573E0 |. C
004573E7 |. 8B
004573EA |> 03DB /add ebx, ebx
004573EC |. 81FB EE000000 |cmp ebx, 0EE
004573FA |.
004573FC |>
004573FF |. 43 ||inc ebx
00457400 |.
00457403 |. 4B ||dec ebx
00457404 |. 83EF 31 ||sub edi, 31
00457407 |. 81FF 26020000 ||cmp edi, 226
0045740D |.^ 7E ED |\jle short 004573FC
00457411 |. 8D
00457414 |. 8BC3 |mov eax, ebx
00457416 |. E8 2D04FBFF |call 00407848
0045741B |. 8B
0045741E |. E8 8DC6FAFF |call 00403AB0
00457423 |.
00457427 |. 33DB |xor ebx, ebx
00457429 |. 8BFB |mov edi, ebx
0045742B |. 836D F8 02 |sub dword ptr [ebp-8], 2
00457435 |.
00457437 |> BE 01000000 |/mov esi, 1
00457442 |.^ 7D F3 |\jge short 00457437
00457444 |> 817D F8 D0070>|cmp dword ptr [ebp-8], 7D0
0045744B |.^
0045744D |. E8 AEFAFFFF call
00457452 |. 8D
00457455 |. 8B45 FC mov eax, dword ptr [ebp-4]
00457458 |. 8B
0045745E |. E
00457463 |. 8B
00457466 |. 8B55 FC mov edx, dword ptr [ebp-4]
00457469 |. 8B
可以看出00d6aeec是真码地址
00457474 |. 74 0E je short 00457484 //是否注册成功
记下地址;
接下来我们要把这串东西显示出来,当然,我们要diy一个似模似样的注册机,如果以MessageBox形式输入,太没趣,而且不能复制!
我们看一下程序的界面:
我想我们最好是把真码显示到Serial框,哈哈,这样才像真正的注册机!
要在对话框的编辑框上显示字符串,当然是用SetWindowText,或者SetDlgItemText
至于用哪个,我们看一下这们的参数:
BOOL SetWindowText(
HWND hWnd, // handle to window or control
LPCTSTR lpString // title or text
);
一个窗口句柄和要显示的字符串
BOOL SetDlgItemText(
HWND hDlg, // handle to dialog box
int nIDDlgItem, // control identifier
LPCTSTR lpString // text to set
);
一个对话框句,位于对话框的控件ID,和要显示的字符串。
当然,我们就选用SetWindowText这个函数。
OK,看程序界面,初始化时我们已经可以看到两个对话框中已经有内容了,所以姑且判断程序有调用SetWindowText这个函数,我们用现成的,就不用再添加一个了,至于程序如果没调用此函数,我们又该怎么办!这个问题,后续再讲。
Ctrl+f2重新在OD中载入程序,Ctrl+n打开程序函数列表,找一下SetWindowText函数,发现有一个,在上面回车来查找参考,发现一个都没有,汗!!
我们用PE Load用打程序:
点击“目录”按钮,我们可以看到有导出表和导入表,也就是导入函数的意思,程序使用函数都是导入后的函数,关于导入表知识,大家可以参看相关PE教程。
我们点击导入表后面的那个“。。”按钮,如下图:
在dll名称中找到user32.dll,下面列表框就会出现程序调用user32.dll里的函数列表,我们找到SetWindowTextA!
ThunkRVA值就是我们要的,关于RVA这个关键字的概念,大家可以去看CCDebuger的那篇《浅淡脱壳后的优化》,里面有介绍!
我们就可以 call dword ptr[0045b42c]这样来调用SetWindowTextA这个函数了!
好了,知道怎么调用,也知道程序原有的SetWindowText函数了,现在要着手的是该函数的参数,我们知道该函数有两个参数,第二个字符串我们用真码地址,已经有了,第一个是窗口的句柄,就是我们要把该字符串设置到哪一个窗口的,该窗口的句柄!
找窗口的句柄有很多种方法,我们知道每一个按钮,第一个编辑框都是一个窗口,在我们屏幕上看到的都是一个个大小形态不同的窗口!创建窗口,无论你在编程时是画上一个按钮还是什么,系统都会调用函数去创建,比如CreateWindow或CreateWindowEx,程序当然也会用到!!
我们就Ctrl+f2重新载入,清除所有断点,ctrl+n打开程序函数列表,看到有一个CreateWindowExA。呵,在命令行上下 bp CreateWindowExA,F9运行会多次中断,这是当然,因为程序的窗口控件不只一个
我们中断之后看堆栈,因为是断在函数开头,参数还未被使用,所以在进入call前所压入栈内的参数还在,所以我们在堆栈中看到的是最准确的值。
第一次中断(堆栈):
这些都是该函数的参数,我们要关注的就是Class窗口类别,WindowName窗口名,和其返回值。
Class,知道编辑框类别为Edit,我们就F9直到Class参数为Edit关键字为止。
F9中断7次后看到Class为”TEdit”类别,不过WindowName却是”2Sweeet”,显然是第一个编辑框,不管它,继续f9。
第8次终于看到我们想要的了,Class为”TEdit”,WindowName为“Serial”,接下来我们Alt+f9,返回调用语句的下一条语句!
来到这里:
00427D44 8986 40010000 mov dword ptr [esi+140], eax ; 句柄传[esi+140]
我前面说过要关注该函数的返回值的,该函数创建窗口成功之后会返回窗口的句柄,而汇编中函数的返回值都会先放在eax里,所以这里就是把句柄传到[esi+140]这个内存地址中。
看一下信息窗口:
得知句柄为0x80322,当然我们不能直接使用0x80322,句柄是系统分配的,每次运行程序都会不一样,所以,记住地址才是最有用的。记下esi+140=00d65654。
要补丁的话还是用全0的地方比较安全,下面找全0:
我们用PEid找到全0处代码,好打入我们的补丁,Peid载入,点击EP区段右边的“>”按钮,出现如下图:
在区段查看器上右键,搜索全0,出现下图:
呃,upx1这个区都有,汗,这就是脱壳后没优化的结果,再次推荐看一下CCDebuger的那篇文章哈!!好了,我选择”SuckMe!!”吧,看起来实在点!^-^ 记住偏移00070cef加上基址400000!
嘿嘿,找到全0处了!
我们所具备的条件,就是这些:
1、
真码地址00d6aeec
2、
编辑框句柄地址00d65654
3、
全0地址00470cef
OK,所要的条件已具备,下面开始打注册机补丁!
CTrl+f2重新载入,Ctrl+g来到457344处,也就是注册按钮点击事件代码:
00457344 /. 55 push ebp //断在这里
…………………….
省略N行代码
……………………
0045744D |. E8 AEFAFFFF call
…………………..
00457469 |. 8B
//[edx+
Ps:这里可以利用一下,我们直接传参数为edx就行了!地址就不用记了!况且地址中esi会变动!— —|||
//比较的call,为了不把上面的真码指针edx破坏掉,这里我们nop★
00457474 /74 0E je short 00457484
//是个决定注册是否成功的跳转
Ps:这里也利用起来,就跳转到我们的全0处,打补丁去吧!
改为jmp 00470cef,记住把“用nop填补”给选上!
00470cef处,我们写入如下代码:
00470CEF 90 nop //留个空吧
00470CF0 90 nop //留个空吧
00470CF1 60 pushad //保护现场
00470CF2 90 nop //补个空
00470CF3 52 push edx //函数的第二个参数,把真码指针压进栈
00470CF4 FF35 5456D600 push dword ptr [D65654] //第一个参数,把句柄压进栈
00470CFA FF15 2CB44500 call dword ptr [<&USER32.SetWindowTex>; //调用SetWindowText函数,.前面说了怎么调用的,只要call dword ptr[0045b
00470D00 61 popad //恢复现场
00470D01 - E9 7367FEFF jmp 00457479 //跳回原来的代码执行
跳回到这里:
00457479 90 nop //这是补空用的
0045747B . 8B00 mov eax, dword ptr [eax]
0045747D E8 4663FEFF call 0043D
OK,补丁完毕,输入key的那个框变灰不能用,这还不完美,搞得只能通过一个key来算注册码,我们还要再改一下:
直接下bp EnableWindow函数断点,断不下来,看来创建该窗口时已经决定变灰了!我们干脆自己调用EnableWindow函数算了!
看一下该函数的定义:
BOOL EnableWindow(
HWND hWnd, // handle to window
BOOL bEnable // enable or disable input
);
一个窗口句柄,和一个bool值,真假变量,为0就为假,非0为真,再看下面那句:
bEnable
[in] Specifies whether to enable or disable the window. If this parameter is TRUE, the window is enabled. If the parameter is FALSE, the window is disabled.
如果这个参数为真,这个窗口就激活,如果为假,就禁止!
我们只要传递一个非0值就行了!
下面打补丁。
下断,bp ShowWindow,在程序显示的时候断下:
77D1D
77D1D
77D1D8AE FF12 call dword ptr [edx]
77D1D8B
Alt+F9返回程序领空:
0043D3D1 50 push eax //ShowWindow函数的参数
0043D3D2 E8 ED90FCFF call <jmp.&USER32.ShowWindow>//调用ShowWindow
0043D3D7 E9 05010000 jmp 0043D4E1 //无条件跳转,Ps:这里利用一下,先记下原跳转的目标地址,也就是0043d4e1!然后我们通过用peid找全0位置,我找的是00470d
Ctrl+g到达00470d
00470D
00470D10
00470D12 FF35
00470D18 FF
00470D1E 61 popad //恢复现场
00470D
00470D24 90 nop //补一个空]
OK,打完补丁,右键->复制可执行文件->所有修改(如果没有所有修改的话,用鼠标先中上面我们打进的补丁代码,右键->复制可执行文件->选择->出现的新窗口再右键->保存文件,这样只是把上面的补丁码给保存了,程序压根就没运行到这里,所以,我们再用OD载入保存后的文件,把0043d3d7处的跳转再改为jmp 00470d
哟嘿,程序有注册机的内涵了,界面也改一下,用eXe或才Res去改就行了,不过程序含有非标准资源,改的时候注册别改变原本资源的大小,比如我把name框的“2Sweeet”,总共7个字节,改为“大菜一号”的话,就不行了!改为“大菜1号”倒可以,哈!
因为那个机器码的框,在本机上注册的话要本机的机器码,所以可以不清空,注册码输入框,程序会调用SetWindowText把真码显示出来,所以也不用清空了,注册名框的话,为了宣传宣传自己,所以改为“大菜1号”啦``哈哈哈哈哈^0^ !!
下面请看两个程序的截图:
最后请看胜利截图:
呀哈哈哈哈,终于,,终于,完成啦!!!!,
想想第二篇要写什么哈???…….想到再说啦!!
