原方转自 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楼,请大家指正。