【文章标题】: 一个字节搞定12Ghost版NotePad
【文章作者】: jackozoo
【作者邮箱】: [email]jackozoo@163.com[/email]
【软件名称】: 12Ghost Notepad
【下载地址】: 自己搜索下载
【保护方式】: NAG加序列号
【编写语言】: C++/ VS2005
【使用工具】: OD
【软件介绍】: 一款看起来很清爽的增强版记事本,生成rtf文档。
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
没什么技术含量,希望对菜鸟朋友能有一些帮助,因此截了不少图。
安装好软件后, 到目录中看看, 里面有很多文件, 打开运行看看, 结果提示如下的窗口。
我们点击输入注册码看看, 随便输入一个,提示出错。如图:
我们现在想,从哪里下手了? 先不慌。 看看启动代码。
004141B7 > E8 25630000 call 12notepa.0041A4E1 //ep
004141BC ^ E9 16FEFFFF jmp 12notepa.00413FD7
004141C1 55 push ebp
004141C2 8BEC mov ebp, esp
004141C4 81EC 28030000 sub esp, 328
// 。。。
//。。。
00414140 51 push ecx
00414141 50 push eax
00414142 6A 00 push 0
00414144 68 00004000 push 12notepa.00400000
00414149 E8 325BFFFF call 12notepa.00409C80
//好的, 这里就是WinMain了。 (怎么确定?GetCommandLine之后,再加至少3个push压参就到了(Win)Main了)
// ...
看看这里WinMain进去的东西:
00409CDD 56 push esi
00409CDE 68 FC2B4200 push 12notepa.00422BFC ; ASCII "unused"
00409CE3 68 D42B4200 push 12notepa.00422BD4 ; ASCII "http://12Ghosts.com/ghosts/notepad.htm"
00409CE8 6A 47 push 47
00409CEA 6A 4E push 4E
00409CEC 56 push esi
00409CED 56 push esi
00409CEE 56 push esi
00409CEF 56 push esi
00409CF0 68 C42B4200 push 12notepa.00422BC4 ; ASCII "12notepad.exe"
00409CF5 68 B82B4200 push 12notepa.00422BB8 ; ASCII "notepad.htm"
00409CFA 68 A82B4200 push 12notepa.00422BA8 ; ASCII "12Ghosts.hlp"
00409CFF 68 F8244200 push 12notepa.004224F8 ; ASCII "Software\12Ghosts\NotePad"
00409D04 68 A02B4200 push 12notepa.00422BA0 ; ASCII "NotePad"
00409D09 68 A02B4200 push 12notepa.00422BA0 ; ASCII "NotePad"
00409D0E 68 942B4200 push 12notepa.00422B94 ; ASCII "PactNotepad"
00409D13 68 A02B4200 push 12notepa.00422BA0 ; ASCII "NotePad"
00409D18 68 B0254200 push 12notepa.004225B0 ; ASCII "12Ghosts NotePad"
00409D1D 50 push eax
00409D1E E8 C78D0000 call <jmp.&12Ghosts.#312> ; 写入数据到dll变量中。
00409D23 6A 32 push 32
00409D25 6A 06 push 6
00409D27 E8 B88D0000 call <jmp.&12Ghosts.#11>
00409D2C 83C4 54 add esp, 54
调用的是dll中以序号导出的函数, 其中第一个函数有19个参数, 真是第一次见到这么奇怪的函数。
看看这个巨型函数中的一部分代码:
// ... ...
// 巨大一堆strcpy、、、
// ... ...
10002961 . 50 push eax ; /String2
10002962 . 68 10F70210 push 12Ghosts.1002F710 ; |String1 = 12Ghosts.1002F710
10002967 . 880D 08F70210 mov [1002F708], cl ; |
1000296D . 8815 09F70210 mov [1002F709], dl ; |
10002973 . FFD6 call esi ; \lstrcpyA
注意这一句: mov [1002F708], cl 。这一句的cl是参数4的末字节的值。先在这打住。
从下至上的思路:
我们按OK的时候程序要读取Edit控件的文本,那就下相关API试试,bp GetWindowTextW ,
bp GetDlgItemTextW(某菜鸟问:为什么后面都是W了? 因为如果软件在编码时定义了UNICODE,就会直接执行以W结尾的函数,
而不会去执行以A结尾的外壳函数)。 OK, 对SetWindowTextW下好断,再按OK。 滴-- 还是弹窗了。看来没断下。 原因太多。
那我们换种思路,用IsDialogMessageW条件加代码断点大法来确定OK按钮的事件地址。
如下:
10018BFE . 0FB78424 7802>movzx eax, word ptr [esp+278] ; Case 111 (WM_COMMAND) of switch 10018BDB
10018C06 . 3D 0F040000 cmp eax, 40F ; Switch (cases 1..410)
10018C0B . 0F8F F9000000 jg 12Ghosts.10018D0A
10018C11 . 74 63 je short 12Ghosts.10018C76
10018C13 . 83E8 01 sub eax, 1
10018C16 . 74 21 je short 12Ghosts.10018C39
10018C18 . 83E8 01 sub eax, 1
10018C1B . 74 68 je short 12Ghosts.10018C85
10018C1D > 5F pop edi ; Default case of switch 10018C06
10018C1E . 5B pop ebx
10018C1F > 8B8C24 600200>mov ecx, [esp+260]
10018C26 . 5E pop esi
10018C27 . 33CC xor ecx, esp
10018C29 . 33C0 xor eax, eax
10018C2B . E8 CE370000 call 12Ghosts.1001C3FE
10018C30 . 81C4 60020000 add esp, 260
10018C36 . C2 1000 ret 10
10018C39 > 68 F3010000 push 1F3 ; Case 1 of switch 10018C06
10018C3E . 8D4424 79 lea eax, [esp+79]
10018C42 . 6A 00 push 0
10018C44 . 50 push eax
10018C45 . C68424 800000>mov byte ptr [esp+80], 0
10018C4D . E8 BE370000 call 12Ghosts.1001C410
10018C52 . 83C4 0C add esp, 0C
10018C55 . 6A 64 push 64 ; /Count = 64 (100.)
10018C57 . 8D4C24 78 lea ecx, [esp+78] ; |
10018C5B . 51 push ecx ; |Buffer
10018C5C . 68 29040000 push 429 ; |ControlID = 429 (1065.)
10018C61 . 56 push esi ; |hWnd
10018C62 . FF15 4C730210 call [<&USER32.GetDlgItemTextA>] ; \GetDlgItemTextA
看到了吗? 上面竟然用的是GetDlgItemTextA来取的文本, 但是为什么我刚才用GetWindowTextW没断下来了, 真是奇了怪了,
GetDlgItemText(X)都是先GetDlgItem再GetWindowText(X)的啊, 可能我第一次键盘操作失误吧,不管了。
现在断下来, 我们看一下是不是我们的Edit控件, 看一下Buffer, 嗯, 执行完call后,有了我们的数据, 然后我们对
Buffer来个内存读或者硬件读断点。 看看程序对我们的注册码打算咋处理。
OK, 如图,第一次断到了lstrlen的里面, 这是在求长度。Alt+F9. 来到这里:
10016FB2 |. 56 push esi ; /String
10016FB3 |. 884424 0A mov [esp+A], al ; |
10016FB7 |. 884424 0B mov [esp+B], al ; |
10016FBB |. 884424 09 mov [esp+9], al ; |
10016FBF |. C74424 0C 000>mov dword ptr [esp+C], 0 ; |
10016FC7 |. FF15 1C720210 call [<&KERNEL32.lstrlenA>] ; \lstrlenA
10016FCD |. 83F8 40 cmp eax, 40
10016FD0 |. 75 25 jnz short 12Ghosts.10016FF7
长度不是64,则玩完, 其实上面那个图都说了是64位注册码。
我们改一下ZF,继续。
10016FE7 |. 50 push eax
10016FE8 |. 6A 00 push 0
10016FEA |. 56 push esi
10016FEB |. E8 50EFFFFF call 12Ghosts.10015F40
10016FF0 |. 83C4 1C add esp, 1C
10016FF3 |. 85C0 test eax, eax
10016FF5 |. 75 68 jnz short 12Ghosts.1001705F
10016FF7 |> 6A 00 push 0
10016FF9 |. 68 D8AE0210 push 12Ghosts.1002AED8 ; ASCII "The code you entered is not a valid license. Please double-click the file ::attached to your license e-mail.::::Or select the line with the code (64 characters) from your registration ::notification by dragging the mouse over it. Then se"...
10016FFE |. E8 5D56FFFF call 12Ghosts.1000C660
10017003 |. 83C4 08 add esp, 8
10017006 |. 50 push eax ; /String2
10017007 |. 8D8C24 300300>lea ecx, [esp+330] ; |
1001700E |. 51 push ecx ; |String1
1001700F |. FF15 14720210 call [<&KERNEL32.lstrcpyA>] ; \lstrcpyA
10017015 |. A1 880D0310 mov eax, [10030D88]
1001701A |. 68 41000500 push 50041 ; /Style = MB_OKCANCEL|MB_ICONASTERISK|MB_APPLMODAL|50000
1001701F |. 68 00F00210 push 12Ghosts.1002F000 ; |Title = "12Ghosts NotePad"
10017024 |. 8D9424 340300>lea edx, [esp+334] ; |
1001702B |. 52 push edx ; |Text
1001702C |. 50 push eax ; |hOwner => 002F1096 ('12Ghosts NotePad',class='#32770',parent=000910BE)
1001702D |. FF15 E0730210 call [<&USER32.MessageBoxA>] ; \MessageBoxA
所以12Ghosts.10015F40这个是我们目前认为的关键call了。 进去看一下,它在干什么了:
// ... ...
10015FB9 |. 6A 06 push 6 ; /maxlen = 6
10015FBB |. 68 04AD0210 push 12Ghosts.1002AD04 ; |s2 = "YmUbRe"
10015FC0 |. 56 push esi ; |s1
10015FC1 |. E8 84760000 call <12Ghosts._strncmp> ; \_strncmp
10015FC6 |. 83C4 0C add esp, 0C
10015FC9 |. 85C0 test eax, eax
10015FCB |. 0F84 F70E0000 je <12Ghosts.完蛋了>
10015FD1 |. 6A 06 push 6 ; /maxlen = 6
10015FD3 |. 68 FCAC0210 push 12Ghosts.1002ACFC ; |s2 = "QBowyN"
10015FD8 |. 56 push esi ; |s1
10015FD9 |. E8 6C760000 call <12Ghosts._strncmp> ; \_strncmp
10015FDE |. 83C4 0C add esp, 0C
10015FE1 |. 85C0 test eax, eax
10015FE3 |. 0F84 DF0E0000 je <12Ghosts.完蛋了>
10015FE9 |. 6A 06 push 6 ; /maxlen = 6
10015FEB |. 68 F4AC0210 push 12Ghosts.1002ACF4 ; |s2 = "EJ2kgA"
10015FF0 |. 56 push esi ; |s1
10015FF1 |. E8 54760000 call <12Ghosts._strncmp> ; \_strncmp
10015FF6 |. 83C4 0C add esp, 0C
10015FF9 |. 85C0 test eax, eax
10015FFB |. 0F84 C70E0000 je <12Ghosts.完蛋了>
// ... ...
为了不占版面, 我省了很多代码, 这个函数里面全部是是strncmp(注册码,“xxxxxx”,6)的比较。 很长的一大路,
就像那个我命名的lable“完蛋了”一样,其实是程序在检验黑名单。 只要你的注册码的前面6位和上述的黑名单的是一样的话,
就会调到惩罚你的入口, 因为12Ghost出品的软件有很多, 它只要发现你用黑名单中的注册码来注册这个notepad的话,它会把
你机器的注册表里面的其他的所有只要是它公司的软件的键值都删掉。
所以上面那个call根本就不是所谓的关键call。那这个时候我们暂时先不去管算法了。
我们看你弹错误窗口后,要干啥。 你总得把注册信息保存下吧。
看看这里:
100170A1 |. 68 00F00210 push 12Ghosts.1002F000 ; ASCII "12Ghosts NotePad"
100170A6 |. 6A 00 push 0
100170A8 |. 68 B0AE0210 push 12Ghosts.1002AEB0 ; ASCII "Valid! Thank you for registering %s!"
100170AD |. E8 AE55FFFF call 12Ghosts.1000C660
100170B2 |. 83C4 08 add esp, 8
100170B5 |. 50 push eax
100170B6 |. 8D8C24 400300>lea ecx, [esp+340]
100170BD |. 51 push ecx
100170BE |. EB 1D jmp short 12Ghosts.100170DD
100170C0 |> 68 9CAE0210 push 12Ghosts.1002AE9C ; ASCII "12Ghosts software"
100170C5 |. 6A 00 push 0
100170C7 |. 68 B0AE0210 push 12Ghosts.1002AEB0 ; ASCII "Valid! Thank you for registering %s!"
我们强行调到注册成功的MessageBoxA的, 然后往下跟。
下面都是调用的12Ghost.dll中的函数, 你会发现, 它在里面一会打开注册表HKEY,一会关闭注册表的,大家可以跟
的试一下, 它并没有写入任何信息到注册表中。
那我想, 你这么喜欢用注册表,(其实从dll的一些函数的代码的代码里面都可以看出注册信息肯定在注册表中的)
那我们用RegMon来监视一下(或者直接下端Reg相关函数)。
重启程序。
bp RegQueryValueExW, F9 . 断下来了, 不过是些垃圾注册表信息, shift+F9。 几次之后终于到了我们所要的。
程序要读取 HKCU/SoftWare/12Ghost/NotePad/RegCode的字符串值。 好的, 我们就从这出发,在注册表中建立这个项,
其值就填写为“AAAAAAAA”吧,按从上倒下的思路搞、对buffer下访问断, 结果发现,断是断了几次了,不过基本没用
到我们的注册码。NAG还是出现了。 不要气馁, NAG是吧, 我们断下DialogBoxParamW看看。 嗯:
好,断下来了。 继续往上拉拉代码, 会发现这些东西:
1001BA40 . 68 E8030000 push 3E8
1001BA45 . 6A 01 push 1
1001BA47 . E8 6473FEFF call 12Ghosts.10002DB0
1001BA4C . 83C4 08 add esp, 8
1001BA4F . 3D B6030000 cmp eax, 3B6
1001BA54 . A0 08F70210 mov al, [1002F708]
1001BA59 . 0F8F 86000000 jg 12Ghosts.1001BAE5
1001BA5F . 3C 4D cmp al, 4D
1001BA61 . 0F84 C4000000 je 12Ghosts.1001BB2B
1001BA67 . 3C 6D cmp al, 6D
1001BA69 . 74 7A je short 12Ghosts.1001BAE5
1001BA6B . 3C 77 cmp al, 77
1001BA6D . 74 76 je short 12Ghosts.1001BAE5
1001BA6F . 3C 70 cmp al, 70
1001BA71 . 74 72 je short 12Ghosts.1001BAE5
1001BA73 . 3C 59 cmp al, 59
1001BA75 . 74 6E je short 12Ghosts.1001BAE5
1001BA77 . 3C 79 cmp al, 79
1001BA79 . 74 6A je short 12Ghosts.1001BAE5
1001BA7B . 3C 6B cmp al, 6B
1001BA7D . 74 66 je short 12Ghosts.1001BAE5
1001BA7F . 3C 4B cmp al, 4B
1001BA81 . 74 62 je short 12Ghosts.1001BAE5
1001BA83 . 3C 65 cmp al, 65
1001BA85 . 74 5E je short 12Ghosts.1001BAE5
1001BA87 . 8B15 64090310 mov edx, [10030964] ; 12Ghosts.10000000
1001BA8D . 6A 00 push 0 ; /lParam = NULL
1001BA8F . 68 90990110 push 12Ghosts.10019990 ; |DlgProc = 12Ghosts.10019990
1001BA94 . 6A 00 push 0 ; |hOwner = NULL
1001BA96 . 6A 7A push 7A ; |pTemplate = 7A
1001BA98 . 52 push edx ; |hInst => 10000000
1001BA99 . C705 A4F80210>mov dword ptr [1002F8A4], 0 ; |
1001BAA3 . FF15 C8720210 call [<&USER32.DialogBoxParamA>] ; \DialogBoxParamA
试了一下, 这个DialoagBoxParam就是弹NAG的,看前面的比较。 一堆单字节的比较。 而al = 什么了?
答案在这里:1001BA54 . A0 08F70210 mov al, [1002F708] 。
在回过头去看那个巨型函数。 呵呵, 找到最最关键的地方了吧.
对。 就是这个参数:
00409CEA 6A 4E push 4E
把这个4E改为4D来试试 。
NAG没有了。 是否感觉被忽悠了 ?。。。。 的确我当时也觉得被忽悠了。
既然无论输入什么注册码都不能成功还让我们输个P的注册码啊, 真是的。。 不过先别生气。
我们来体验体验下消NAG后的软件, 打开, 点菜单栏的选项--一般选项, 怎么没反应了? 这时别点“一般选项”
选择“Option”就可以了 。 一个一个标签的看啊看。。 翻到了关于标签:
这么几个大字弄的我郁闷了N久 : 仅供评估的测试版,点击这里获得完全版。 晕怪不得啊。 原来是Demo版。
看来我眼睛真的是不行了, 或者是太粗心了。。 到此打住。
这个Demo版的里面有很多乱七八糟的信息, 来看看部分:
1.
1002A8AC 57 65 20 61 72 65 20 6E 6F 77 20 65 78 61 6D 69 We are now exami
1002A8BC 6E 69 6E 67 20 79 6F 75 72 20 64 69 73 6B 20 66 ning your disk f
1002A8CC 6F 72 20 66 75 72 74 68 65 72 20 73 74 6F 6C 65 or further stole
1002A8DC 6E 20 69 6E 66 6F 72 6D 61 74 69 6F 6E n information
2、
1002A8F0 57 65 20 61 72 65 20 63 6F 6E 74 61 63 74 69 6E We are contactin
1002A900 67 20 57 65 62 20 50 6F 6C 69 63 65 20 4F 72 67 g Web Police Org
1002A910 61 6E 69 73 61 74 69 6F 6E 20 77 69 74 68 20 79 anisation with y
1002A920 6F 75 72 20 49 50 20 6E 75 6D 62 65 72 20 6E 6F our IP number no
1002A930 77 2E 2E 2E w...
3.
1002A930 59 6F 75 20 75 6E 6C 61 You unla
1002A940 77 66 75 6C 6C 79 20 75 73 65 64 20 74 68 69 73 wfully used this
1002A950 20 73 6F 66 74 77 61 72 65 20 77 69 74 68 6F 75 software withou
1002A960 74 20 61 20 76 61 6C 69 64 20 6C 69 63 65 6E 73 t a valid licens
1002A970 65 2E e.
4.
1002A970 59 6F 75 20 66 72 61 75 You frau
1002A980 64 75 6C 65 6E 74 6C 79 20 75 73 65 64 20 61 20 dulently used a
1002A990 73 74 6F 6C 65 6E 20 63 72 65 64 69 74 20 63 61 stolen credit ca
1002A9A0 72 64 20 74 6F 20 70 75 72 63 68 61 73 65 20 74 rd to purchase t
1002A9B0 68 69 73 20 73 6F 66 74 77 61 72 65 2E his software.
5.
1002A9C0 59 6F 75 20 73 74 6F 6C 65 20 61 20 63 72 65 64 You stole a cred
1002A9D0 69 74 20 63 61 72 64 20 6F 72 20 61 72 65 20 61 it card or are a
1002A9E0 20 72 65 63 65 69 76 65 72 20 6F 66 20 73 74 6F receiver of sto
1002A9F0 6C 65 6E 20 67 6F 6F 64 73 2E len goods.
非常搞笑的一些字符串,呵呵。 有兴趣的朋友可以深究一下。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年04月26日 PM 10:19:12
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)