zoukankan      html  css  js  c++  java
  • <转>挣扎的菜鸟 当OD不能装载也不能附加程序时

    原方转自 http://www.unpack.cn/thread-65647-1-1.html

    【文章标题】: 挣扎的菜鸟 - 当OD不能装载也不能附加程序时
    【文章作者】: justlovemm
    【作者邮箱】: 无
    【作者主页】: 无
    【作者QQ号】: 无
    【下载地址】: 自己搜索下载
    【保护方式】: VMP2.07
    【使用工具】: OD,LoadPE,CE,Exception Monitor
    【作者声明】: 只是感兴趣,没有其他目的。只是一个菜鸟对几年前大牛们就搞定的问题的一次练习,请大牛们无视本文。
    ------------------------------------------------------------------------------------------------------------------------------------------

    前几天拿到一个程序X,用PEiD查不到任何信息,用exeinfope说是VMP2.07。于是先用OD载入,结果OD立即直接被关闭。开始认为TLS在作怪,用LoadPE,删除掉TLS,保存。再用od 载入,还是一样。下来先直接运行程序,然后用OD附加,结果OD也是立即直接被关闭。
    检查OD的选项,first pause是在system breakpoint处(其实自TMD利用那个浮点漏洞关闭OD以后,我的OD一直是启动时停在system breakpoint的)。打开StrongOD的选项,break On TLS也是打上了勾的。这时仔细一想,不对啊,现在的设置应该能截获TLS的运行,这说明不是TLS的问题。
    下来考虑是否plugin有问题,于是删除了plugin目录下的所有文件,结果还是一样。
    现在菜鸟有点失望了,于是开始在论坛里找关于VMP2.07的资料,无果。查找OD被关闭,基本上就2条参考意见,一个是删除plugin试试,另一个是删除掉OD目录下的dbghelp.dll文件。于是直接试第二个方法,删除掉了OD目录下修改时间为2001年11月12日的dbghelp.dll文件,测试,结果还是一样。于是又把system32目录下的修改时间为2005年5月26日的dbghelp.dll拷贝到OD目录下,其实菜鸟心里也很清楚,这和刚试过的方法没有什么不同的,不过这个时候菜鸟已经有点绝望了,所以这样明知道不会有任何作用的方法菜鸟也要去试试。结果就不说了。
    也许是这个时候命不好,菜鸟竟然没有搜索到海风大牛关于dbghelp.dll文件的那个原帖,如果当时看到那个帖子,直接下载帖子里的dbghelp.dll,就不会有这些问题了。
    接着菜鸟在UPK发了一个帖子求助,热心人很多,不过菜鸟太菜,没能搞定。
    下来改用CE装载,OK,可以装载。然后运行,提示发现调试器。菜鸟据此判断,此anti一定是针对OD的。不过菜鸟不会用CE调试程序,至少是不会象用OD那样去用CE调试程序。
    现在,菜鸟已经绝望了。以前TMD不能加载的时候,菜鸟只能等待,不过很快,大牛们就给出了解决方法,菜鸟只是照着去做就OK了。可是现在菜鸟觉得很无助,不知道去哪里寻找帮助,觉得四周一片漆黑。绝望的菜鸟只能一个人在那儿苦苦思索,过了几个小时,菜鸟突然想到一个方法,可以用OD来调试OD,然后用被调试的OD去装载程序X,这样应该就能知道OD是怎么被关闭的了。菜鸟当时心里还有点激动,心想,也许一个新的anti OD的方法就要让本菜鸟给搞定了,哈哈。
    立即动手,用OllyICE加载一个OllyDbg,用OllyDbg加载程序X,OllyDbg立即被关闭,去OllyICE中查看OllyDbg退出时的栈,没有得到任何有用的线索。
    再试,用OllyICE加载一个OllyDbg,然后在CreateProcessA和ResumeThread处下断,用OllyDbg加载程序X,断在CreateProcessA处,F8过去,OllyDbg正常,再Shift+F9,断到ResumeThread处,再F8过去,然后调出任务管理器,看到进程X已经有一点CPU的占用率了,这时OllyDbg还未被关闭,再Shift+F9,OllyDbg直接被关闭,查看退出的栈,还是没有任何线索。
    这时候先推理到,OllyDbg当时是一被调试的进程,除了调试进程以外,其它进程是无法关闭OllyDbg的,菜鸟猜想是否给OllyDbg窗口发送了WM_QUIT或者WM_CLOSE消息。于是在OD中查找GetMessage,未发现,查找PeekMessage,找到好几个,根据传入的消息的上下限,找到了OllyDbg的窗口过程中使用的PeekMessage,在PeekMessage返回后的一个地方下条件断点,当消息ID是WM_QUIT或者WM_CLOSE时触发断点。再次载入程序X,OllyDbg同样被关掉,并未触发任何条件断点。
    这样就排除了程序X发送消息给OllyDbug窗口的可能性。这时菜鸟认定OllyDbg在装入程序X的时候本身产生了什么不可捕获的异常,导致程序直接被关闭了。问题是怎么才能知道这个异常发生在什么地方呢?
    此时的菜鸟又一次陷入了绝望,又觉得四周一片漆黑。
    在黑暗中孤独的思索了几个小时后,菜鸟突然想起以前用过的Exception Monitor,是M$的产品,当时是为了调试服务进程而推出的东东。用这个东西能捕获最后一次异常发生时的线程信息,包括各个寄存器和栈数据。上网搜索,还是命不好,竟然找不到MS的Exception Monitor的下载地点。不过,也意外的发现还有好几个类似的产品,一个叫EMon.exe的还是开源的,于是下载了这个EMon.exe。
    打开OllyDbg,用EMon.exe去attach,在进程列表里没有发现OllyDbg。呵呵,是StrongOD隐藏了OllyDbg进程,删除掉SOD,OK,用EMon.exe attach OllyDbg,再用OllyDbg载入程序X,然后看到EMon.exe的Log窗口哗哗哗的闪,计算机不停的叫"叭嗒叭嗒",过了有2、3分钟,停了下来,OllyDbg已经不见踪影了。

    EMon.exe最后的Log是这样的:

    下午 04:00:09: Process terminated with exit code 3221225477
    下午 04:00:09: End of Process: 4076 - OllyDBG.EXE
    下午 04:00:09: End of Process: 2380 - X.exe
    

      接着往上看,最后出错信息是这样的:

    下午 04:00:09: ACCESS_VIOLATION at address 7C92EDDD
    ** The thread tried to read from or write to a virtual address
       for which it does not have the appropriate access.
    ** Thread ID=00000F34
    ** Access violation writing address 00030FFC
    ** First chance
    ** Register Dump:
        EAX=0000000C
        EBX=7C920000 : 00905A4D 00000003 00000004 0000FFFF 
        ECX=7C930833 : 900004C2 FFFFFF90 95C5FEFF 95C6077C 
        EDX=000000E0
        EDI=7C9237D8 : 04244C8B 060441F7 B8000000 00000001 
        ESI=7C920000 : 00905A4D 00000003 00000004 0000FFFF 
        ESP=00031000 : 7C920000 00000000 00000000 00000000 
        EBP=00031020 : 00031030 7C93086E 7C920000 00031400 
        EIP=7C92EDDD : 458B5756 E86589F8 FC458B50 FFFC45C7 
    ** Stack Dump:
        00031000: 7C920000 : 00905A4D 00000003 00000004 0000FFFF 
        00031004: 00000000
        00031008: 00000000
        0003100C: 00000000
        00031010: 00031464 : 00031834 7C9237D8 0012B060 00031520 
        00031014: 7C92EE18 : 83EC8B55 565308EC 8BFC5557 458B0C5D 
        00031018: 7C9307F5 : 4D8BC033 74C98508 FFF98330 45212B74 
        0003101C: 7C930838 : FFFFFFFF 7C95C5FE 7C95C607 90909090 
        00031020: 00031030 : 0003104C 7C9579F0 7C920000 00000001 
        00031024: 7C93086E : 840FC085 000025BC 18488B66 0BF98166 
        00031028: 7C920000 : 00905A4D 00000003 00000004 0000FFFF 
        0003102C: 00031400 : C0000034 00000000 00000018 00E8DAA0 
        00031030: 0003104C : 00031080 7C95799C 7C920000 0003107C 
        00031034: 7C9579F0 : 840FC085 000001D8 85FC4D8B CD840FC9 
        00031038: 7C920000 : 00905A4D 00000003 00000004 0000FFFF 
        0003103C: 00000001
    ** Disassembly listing
        7C92EDDD: 56                   push                esi
        7C92EDDE: 57                   push                edi
        7C92EDDF: 8B45F8               mov                 eax, [ebp-0x08]
        7C92EDE2: 8965E8               mov                 [ebp-0x18], esp
        7C92EDE5: 50                   push                eax
        7C92EDE6: 8B45FC               mov                 eax, [ebp-0x04]
        7C92EDE9: C745FCFFFFFFFF       mov                 [ebp-0x04], 0xFFFFFFFF
        7C92EDF0: 8945F8               mov                 [ebp-0x08], eax
        7C92EDF3: 8D45F0               lea                 eax, [ebp-0x10]
        7C92EDF6: 64A300000000         mov                 0x00000000, eax
    ** End of exception report
    

      7C92EDDD是在ntdll中的,菜鸟不知道这个是怎么调用来的。不过在OllyICE中看了一下fs:[8],是00031000,而上面的出错信息的ESP也是这个值,这说明线程栈已经已经用光了,程序无法再运行了。

    再往上看,下来的出错信息好像都一样,都是下面这个样子的:

    下午 04:00:09: ACCESS_VIOLATION at address 32C21FAE
    ** The thread tried to read from or write to a virtual address
       for which it does not have the appropriate access.
    ** Thread ID=00000F34
    ** Access violation reading address 32C21FAE
    ** First chance
    ** Register Dump:
        EAX=00000000
        EBX=00000000
        ECX=32C21FAE
        EDX=7C9237D8 : 04244C8B 060441F7 B8000000 00000001 
        EDI=00000000
        ESI=00000000
        ESP=00031450 : 7C9237BF 00031538 0012B060 00031554 
        EBP=00031470 : 00031520 7C92378B 00031538 0012B060 
        EIP=32C21FAE
    ** Stack Dump:
        00031450: 7C9237BF : 00258B64 64000000 0000058F E58B0000 
        00031454: 00031538 : C0000005 00000010 00000000 32C21FAE 
        00031458: 0012B060 : 8525521F 32C21FAE 1D2F676B ABC87504 
        0003145C: 00031554 : 0001003F 00000000 00000000 00000000 
        00031460: 0003150C : 0012B060 00000000 00130000 00031000 
        00031464: 00031834 : 00031C04 7C9237D8 0012B060 000318F0 
        00031468: 7C9237D8 : 04244C8B 060441F7 B8000000 00000001 
        0003146C: 0012B060 : 8525521F 32C21FAE 1D2F676B ABC87504 
        00031470: 00031520 : 00031840 7C92EAFA 0012B060 00031554 
        00031474: 7C92378B : C25B5E5F 8B900014 909090FF 8B559090 
        00031478: 00031538 : C0000005 00000010 00000000 32C21FAE 
        0003147C: 0012B060 : 8525521F 32C21FAE 1D2F676B ABC87504 
        00031480: 00031554 : 0001003F 00000000 00000000 00000000 
        00031484: 0003150C : 0012B060 00000000 00130000 00031000 
        00031488: 32C21FAE
        0003148C: 00000002
    ** End of exception report
    

      每次出错的地址都是32C21FAE,用上面的OllyICE调试OllyDbg并断在ResumeThread之后,查看,这个地址是空的。菜鸟觉得很怪异。

    继续向上看,都是32C21FAE。于是直接翻到到最上面的Log,才发现只有第一个不是32C21FAE,第一个出错的地址是68D808BF,信息如下:

    下午 03:57:58: ACCESS_VIOLATION at address 68D808BF
    ** The thread tried to read from or write to a virtual address
       for which it does not have the appropriate access.
    ** Thread ID=00000F34
    ** Access violation reading address 8C699B73
    ** First chance
    ** Register Dump:
        EAX=8C699B73
        EBX=023FBF58 : 00000000 00000000 00000000 0040B987 
        ECX=8C291638
        EDX=73A90925
        EDI=023F9160 : 00000000 00000000 00400000 00000000 
        ESI=023FA090 : 023FAA48 00000000 00400000 00000000 
        ESP=0012A460 : 023F9160 80000000 023FA090 023FC3E4 
        EBP=0012ACAC : A1A8ECCE E2B7A856 9C91972D C09558D3 
        EIP=68D808BF : 0C88088A C9844002 8D38F675 FFFFF7EC 
    ** Stack Dump:
        0012A460: 023F9160 : 00000000 00000000 00400000 00000000 
        0012A464: 80000000
        0012A468: 023FA090 : 023FAA48 00000000 00400000 00000000 
        0012A46C: 023FC3E4 : 000A0118 00040006 00020008 001A000F 
        0012A470: 023FC616 : 0040791E 0040853B 0040855D 00408581 
        0012A474: 023FBF58 : 00000000 00000000 00000000 0040B987 
        0012A478: 023FBF80 : 0000158D 00001F0C 0000D640 0000D778 
        0012A47C: 023FBF58 : 00000000 00000000 00000000 0040B987 
        0012A480: 00343158 : 00580058 0070002E 00620064 00000000 
        0012A484: 00000124
        0012A488: 02400AF8 : 00000000 00000000 00000000 00000000 
        0012A48C: 000000B8
        0012A490: 00000001
        0012A494: 00000001
        0012A498: 7EA7BC00
        0012A49C: F11FC1BF
    ** Disassembly listing
        68D808BF: 8A08                 mov                 cl, [eax]
        68D808C1: 880C02               mov                 [edx+eax], cl
        68D808C4: 40                   inc                 eax
        68D808C5: 84C9                 test                cl, cl
        68D808C7: 75F6                 jnz                 +0x000000F6
        68D808C9: 388DECF7FFFF         cmp                 [ebp-0x00000814]
        68D808CF: 7473                 jz                  +0x00000073
        68D808D1: F6059804DF6802       test                0x68DF0498, 0x00000002
        68D808D8: 8D85ECF7FFFF         lea                 eax, [ebp-0x00000814]
        68D808DE: 8D5001               lea                 edx, [eax+0x01]
    ** End of exception report
    

      在OllyICE中查看了一下68D808BF,在DbgHelp.dll中。
    OK,重新用OllyICE装载OllyDbg,在68D808BF处下断,然后装载程序X,成功断下。在数据窗口跳到eax,eax地址有效,看了一下代码,这个应该是一个字符串拷贝的循环,删除68D808BF处的断点,在循环结束后的68D808C9下断,F9正常运行到68D808C9,然后再F9,就跑飞了。
    为了捕获异常不让OllyDbg跑飞,再重新来一次,在68D808BF断下后,取消断点,跳到fs:[0],对当前SEH的handler 68D90888 下硬件断点,F9,还是跑飞了。跑飞的时候好像还提示了那个不存在的地址32C21FAE,一看log,是"32C21FAE|访问违规: 正在执行 [32C21FAE]",很奇怪,为什么在跳到这个不存在的地址之前没有去执行SEH的hander 68D90888。
    无奈,再来,再次断到68D808BF处,F9了几次,每次都又断到68D808BF,这时查看了一下后面一行代码中的edx+eax竟然等于12A498,哈哈字符串拷贝的目标地址在当前栈上,在数据窗口跳到EAX(02363102),看一下,没有发现00,二进制搜索00,在02363D1E,原来EAX指向的字符串长达0xC1C,就是3100字节长,而根据前面的代码
    68D808B7    8D95 ECF7FFFF   lea     edx, dword ptr [ebp-814]
    edx在栈上最大的可用空间也只能是0x814,这肯定是把线程的栈数据给覆盖了。重新测试一下,当断到68D808BF处时,在数据窗口跳去fs:[0],然后F4到68D808C9,这时数据窗口的数据已经完全改变了,就是说SEH的链和hander已经被覆盖了,而hander就是被修改为那个不存在的32C21FAE。
    这时,菜鸟已经明白了,那个字符串拷贝的循环应该就是一个inline化的strcpy,由于没有限制拷贝长度,造成栈数据被覆盖掉了,而新生成的Exception Handler是无效的,结果就又触发了新的异常,进入了一个异常循环,直到栈被用光,OD就结束了,连错误提示都没有,让人以为OD是被正常关闭了。
    搞清楚这个以后,菜鸟又在想,这个分明就是一个异常,为什么用OllyICE调试OllyDbg时没有捕获这个异常呢,查看了一下OD的设置,发现是忽略了非法的内存访问异常。设置成不忽略非法的内存访问,用OllyICE装载OllyDbg,然后OllyDbg装载程序X,在OllyICE中就断到了68D808BF,OK,确定了就是这个异常。
    分析到这一步,本来应该再分析一下DbgHelp.dll,看看是在拷贝什么信息的时候造成的栈溢出,可是这个时候菜鸟又去搜索了一下DbgHelp.dll,找到了海风大牛的那个帖子,下载了那个DbgHelp.dll,用OD加载程序X,正常的停到了系统入口。这时菜鸟才发现自己的确成不了大牛,因为菜鸟这个时候已经不愿意再去分析DbgHelp.dll了。

    最后再说一下,菜鸟因为自己在OD不能装载和附加时,经过思考发现了如何去寻找不能装载和附加的方法,菜鸟自己非常高兴,所以写了此文,为自己庆贺一下!

    对DbgHelp.dll溢出时的分析在25楼,请大家指正。

    本人新博客网址为:http://www.hizds.com
    本博客注有“转”字样的为转载文章,其余为本人原创文章,转载请务必注明出处或保存此段。c++/lua/windows逆向交流群:69148232
  • 相关阅读:
    ArcSDE 10.1安装、配置、连接 (SQL Server 2008)
    ASP.NET MVC 音乐商店
    ASP.NET MVC 音乐商店
    一些Web开发工具
    Apache 2 频率限制模块
    零起步高性能PHP框架 Phalcon 实战
    零配置Ubuntu下Wordpress安装
    零起步的Hadoop实践日记(hbase in action)
    零起步的Hadoop实践日记(hive in action)
    零起步的Hadoop实践日记(内存设置调整)
  • 原文地址:https://www.cnblogs.com/zhangdongsheng/p/2973412.html
Copyright © 2011-2022 走看看