首页
社区
课程
招聘
[悬赏帖]使用OD时的两个奇怪的问题
发表于: 2010-2-5 19:11 3388

[悬赏帖]使用OD时的两个奇怪的问题

2010-2-5 19:11
3388
原帖在http://bbs.pediy.com/showthread.php?t=106605,我在用OD调试时遇到了两个奇怪的问题,我的解答在21L,为了让大家方便回答,我在这里再贴一份吧。

-------------------------------------------------------------------------------------------------------------------------

先运行一下,用户名输入”xiilin”,序列号输入”1234567”,点击Test,窗口刷的一下不见了……
用peid查一下壳吧,ASPack 2.001 -> Alexey Solodovnikov,直接拿出AspackDie脱掉,再查,MASM32 / TASM32,不过文件大了很多……36KB了,呵呵,运行一下,没问题,那就OD载入吧。
先Ctrl+N查看一下输入表,看到了熟悉的GetDlgItemTextA,哈哈,bp GetDlgItemTextA下断点,F9运行起来,输入用户名”xiilin”和序列号”1234567”,点Test,断下来了,本来想Alt+F9返回用户的领空却失败了……不知跳到哪儿去了……
汗,那换个方法吧,Alt+M打开内存窗口,对用户程序的.text区段下一个内存访问断点,然后F9让程序跑起来,断在了004010FA这里,这里就是我们要找的地方了,看一看:
004010E3  |.  68 FF000000   push    0FF
004010E8  |.  68 54304000   push    00403054
004010ED  |.  68 E9030000   push    3E9
004010F2  |.  FF75 08       push    dword ptr [ebp+8]
004010F5  |.  E8 18010000   call    <jmp.&user32.GetDlgItemTextA>      ;获取用户名
004010FA  |.  0BC0          or      eax, eax
004010FC  |.  75 16         jnz     short 00401114      ;用户名不为空就跳
004010FE  |.  68 00304000   push    00403000
00401103  |.  68 EA030000   push    3EA
00401108  |.  FF75 08       push    dword ptr [ebp+8]
0040110B  |.  E8 1A010000   call    <jmp.&user32.SetDlgItemTextA>  ;提示输入用户名,这里有个小bug,第二个参数应该是3E9而不是3EA
00401110  |.  C9            leave                                                ;可以试一下,如果你不输入用户名,那么提示将会出现在序列号输入框里 :-)
00401111  |.  C2 1000       retn    10
00401114  |>  68 FF000000   push    0FF
00401119  |.  68 58304000   push    00403058
0040111E  |.  68 EA030000   push    3EA
00401123  |.  FF75 08       push    dword ptr [ebp+8]
00401126  |.  E8 E7000000   call    <jmp.&user32.GetDlgItemTextA>  ;获取序列号
0040112B  |.  0BC0          or      eax, eax
0040112D  |.  75 16         jnz     short 00401145      ;序列号不为空则跳
0040112F  |.  68 11304000   push    00403011
00401134  |.  68 EA030000   push    3EA
00401139  |.  FF75 08       push    dword ptr [ebp+8]
0040113C  |.  E8 E9000000   call    <jmp.&user32.SetDlgItemTextA>  ;提示输入序列号
00401141  |.  C9            leave
00401142  |.  C2 1000       retn    10
00401145  |>  68 54304000   push    00403054
0040114A  |.  68 48304000   push    00403048
0040114F  |.  E8 A0000000   call    <jmp.&kernel32.lstrcatA>    ;用户名前面加上"pediy"字符串
00401154  |.  68 58304000   push    00403058
00401159  |.  68 48304000   push    00403048
0040115E  |.  E8 97000000   call    <jmp.&kernel32.lstrcmpA>    ;在这里进行比较
00401163  |.  0BC0          or      eax, eax
00401165  |.  75 1F         jnz     short 00401186      ;验证失败,跳走
00401167  |.  6A 00         push    0
00401169  |.  68 2B304000   push    0040302B
0040116E  |.  68 3A304000   push    0040303A
00401173  |.  6A 00         push    0
00401175  |.  E8 A4000000   call    <jmp.&user32.MessageBoxA>    ;成功
0040117A  |.  6A 00         push    0
0040117C  |.  FF75 08       push    dword ptr [ebp+8]
0040117F  |.  E8 88000000   call    <jmp.&user32.EndDialog>
00401184  |.  EB 59         jmp     short 004011DF
00401186  |>  6A 00         push    0
00401188  |.  FF75 08       push    dword ptr [ebp+8]
0040118B  |.  E8 7C000000   call    <jmp.&user32.EndDialog>    ;失败
00401190  |.  EB 4D         jmp     short 004011DF

如果爆破那就很简单了,将00401165处的jnz改成nop,程序就跳不走了,那么试着追一下注册码吧。

本来我还觉得很简单的,但是真仔细一想,我就蒙了,仔细看一下,00403048这个地址存放的是字符串'pediy'和一个代表结束的0,00403054存放我们输入的用户名,00403058存放我们输入的序列号,那么万一我们输入的用户名不止四个字节呢?例如我输入了xiilin,那么00403058和00403059两个字节就存放了‘i’和‘n’,然后再读取我们的密码,这两个字符就被覆盖掉了,画一下现在数据在内存中的布局吧:

00403044  6F 64 21 00 70 65 64 69 79 00 00 00 00 00 40 00     od!.pediy.....@.
00403054  78 69 69 6c 31 32 33 34 35 36 37 00 00 00 00 00      xiil1234567.....
00403064  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00      ................

当我们执行到0040114F这一句的lstrcatA的时候,事实上是将xiil1234567这个字符串0040304D这个地址之后,然后再最后添加一个0作为结束标志,那么内存中就变成了这样:

00403044  6F 64 21 00 70 65 64 69 79 78 69 69 6C 31 32 33     od!.pediyxiil123
00403054  34 35 36 37 00 32 33 34 35 36 37 00 00 00 00 00      4567.234567.....
00403064  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00      ................

也就是说在执行lstrcmpA之前,真正的注册码就已经变成了pediyxiil1234567,但是如果我们输入pediyxiil1234567呢?注册码就又变了……因为我们输入的注册码也参加了运算——在计算真正的注册码的时候需要使用我们输入的注册码,那么换一句话来说的话也就是我们永远不可能输入正确的注册码!!当然在某种情况下这样说是不准确的,例如我们的用户名不超过三个字节,那么我们输入的注册码变不参与运算了,那就简单了,例如用户名输入1,那么注册码就是pediy1,用户名输入123,注册码就是pediy123,用户名一旦大于三个字节,那么我们就得不到正确的注册码了……

看看源代码吧,作者在inc文件中是这样写的:

         .data
;……
serial              db    'pediy'

         .data?

hInstance      dd     ?
id                   dd     ?
code              dd     ?

这里就是越界的根源了,大概作者也没想到会出现这种诡异的情况吧?修改一下:
            .data
;……
serial              db    'pediy',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0           ;添加了21个0

                   .data?

hInstance      dd     ?
id                   db     21 dup(?)
code              dd     ?

这样再编译一下的话,用户名就可以达到20个字节了,试一下,用户名输入xiilin,序列号输入pediyxiilin,验证成功。

顺便总结一下遇到的问题,希望路过的高人给能解答一下:
1、程序停在GetDlgItemTextA的断点处后,用Alt+F9为什么回不到程序的领空了?一定要给.text区段下访问断点才行么?还有什么办法快速回到程序的领空?
2、为什么有些call必须F7跟进去,如果用F8跟过去的话,程序直接就跑丢了……我也不知道跑到哪儿去了,反正肯定不是正常情况时的下一行,例如本例中0040114F处的lstrcatA和下一个lstrcmpA,难道必须每一个call都F7跟进去么?还有什么别的办法可以跳过去这些call而且程序跟不丢?这些call为什么会这样?

-----------------------------------------------------------------------------------------------------------------

麻烦大家给我指点一下到底为什么会出上面这两个问题,谢谢!

补充:

关于第一个问题:我试了试,可以一直Ctrl+F9返回程序……寒一个,当我没说,第一个问题就算解决了吧。

关于第二个问题:我开始时用工具脱的壳,现在换手脱了一下,就没问题了……无语,是脱壳没脱干净的原因?哪位有过类似经历么?

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 424
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
第一个的话,还是个.text下断点吧,我有时候也碰到这种情况,某些dll不被认为是系统的领空,所以od会返回那些dll中
第二个的话,看起来比较诡异,你可以在函数后合适的地方按F4试试 (话说我怎么没见过这样的问题)
2010-2-5 20:16
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
没几个人愿意来这里回答问题……分全给你了,以后才不来问问题了。
2010-2-6 16:19
0
雪    币: 197
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
很神奇的问题,没碰到过
   楼主别生气 或者大家只是没有看到而已
2010-2-6 18:58
0
雪    币: 32
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
真的很神奇哦··嘿嘿
2010-2-6 20:10
0
雪    币: 8
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我就遇到过,许多问题无法正常解释
2010-2-11 14:10
0
游客
登录 | 注册 方可回帖
返回
//