author: anhkggdate: 2021年6月19日
最近在分析某个软件时,提示错误。赶紧挂上windbg看看调用栈,看能不能找到问题。
一看应该能够解决,需要结合IDA静态分析。
通过任务管理器进程转到文件,发现文件已经不存在了,咋办?
还好,进程还在,可以把主程序dump下来,就可以静态分析了。
如何dump呢?简单的可以通过windbg的.writemem把内存写入文件,但是文件不是合法(可运行)的PE,虽然此时文件和内存中数据完全相同(IDA可以将就分析)。
PE文件的文件结构和内存结构是不完全相同的,最重要的原因是文件对齐和内存对齐不同。
所以windbg的.writemem是不支持把内存dump生成合法的PE文件,除非自己再进行文件修复。
此时,不知道有没有人想起来逆向中脱壳,是不是也有类似操作,我这里不是脱壳,但需要做的确和脱壳类似。
所以我想到了LordPE(没用OD),它可以把内存dump之后生成正确的PE文件,然后再ImportREC修复输入表即可。
这活脱脱的就是脱壳啊,哈哈,无所谓啦。
好久不使LordPE,赶紧找出来,运行之后,发现不行。咋回事?该版本不支持枚举高权限进程?不至于啊。
连着换了多个版本,还是不行,LordPE枚举到的进程中没有我的目标进程,而且很多进程名都是[System Process]。
LordPE不至于这么弱吧?!算了,祭出windbg分析一下吧。
windbg启动LordPE,对枚举进程API下断,bp kernel32!ProcessNext,居然没断下来。
WTF?
那断ntdll的API总行了吧,bp ntdll!NtQuerySystemInformation。可以,发现用的是kernel32!EnumProcess。
0:000> kv # ChildEBP RetAddr Args to Child 00 0019f5e0 200013fc 004a0010 00000400 0019f600 KERNELBASE!K32EnumProcesses (FPO: [Non-Fpo])01 0019f74c 00405fb6 004a0010 00000400 69970c70 procs!GetProcessIDList+0x13c02 0019f7a0 6992b4f2 ffffffff 00001003 00000001 LordPE+0x5fb603 0019f7c4 69929edb 00040426 00001003 00000001 COMCTL32!FlatSB_SubclassWndProc+0x22 (FPO: [6,0,0])04 0019f820 fffffffe 0019f874 69929e20 00040426 COMCTL32!CallNextSubclassProc+0x69 (FPO: [Non-Fpo])05 0019f844 7789c79c 00000000 00559420 00000000 0xfffffffe06 0019f920 766760bf 00000000 00000000 004911c8 ntdll!RtlDeactivateActivationContextUnsafeFast+0x9c (FPO: [Non-Fpo])
然后发现procs!GetProcessIDList,看名字明显就是获取所有进程PID。
IDA打开procs.dll一看,这个DLL提供了所有进程和模块管理的接口。
可以看到,他根据Is_xxx_200024FC(系统版本)分两类API来获取信息,第二种才是我前面没成功下断的ProcessNext。
这不是重点,上面的枚举代码没什么问题,不过我没怎么用过EnumProcess接口,不确定是否有问题,所以我把Is_xxx_200024FC强制改为0,然后所有接口都通过tlhelp32接口来获取进程和模块信息。
再往上层回溯,进入LordPE,发现神奇的东西。
长度传的0xF0,也就是240 / 4 = 60,也就是说LordPE只能获取60个进程。
DWORD dwProcessId[60];
而在win10上,动不动就是上百个进程,所以没有枚举到我要看的目标进程太正常了。
只想吐槽,LordPE作者怎么会写出这样的代码,这就算在xp、win7,进程超过60个也歇菜了。
问题找到了,现在该想想如何修改让LordPE能够正常用起来。
首先想到的是,既然枚举进程不全,我可以自己枚举进程插入到进程列表中。
但需要确认点击某个进程选dump是怎么处理的?
获取到选择的进程行,让后dwProcessId[index]拿到进程PID,然后调用dump函数。
这,index超了60,dwProcessId[index]就不行了啊,这个PID不合法啊。
此路不通。
那把dwProcessId扩大呢?
dwProcessId大小60个,后面马上接着其他变量,连对齐空间都没有。
不可行。
可以看到,引用dwProcessId的位置还不只一个。
更多想法:
dwProcessId通过malloc分配,但得修改所有引用位置的代码,从dwProcessId[index]换成(*dwProcess)[index]
劫持所有procs.dll接口,把参数PID换成我需要dump的进程,同样也需要替换模块地址。
或者重写一个…(额)
觉得都挺麻烦的。
此时,去百度搜索了一下,发现已经有前人做过相关工作了。
LordPE只显示60个进程 fix
他是在PE中找到空白位置,用做新的dwProcessId地址,然后把所有引用dwProcessId的位置换成这个新地址,还挺简单,不过最多只能存256个进程PID,将就可以用了。
然后procs.dll接口也存在问题,居然还有硬编码F0来EnumProcess获取进程(几乎所有接口)。
不过我前面已经修改了Is_xxx_200024FC,所以不会用enumprocess,全部使用的tlhelp32的ProcessNext接口,不会存在这个问题。
所以暂时确定方案:
找到新位置用作dwProcessId,并修改引用位置
修改procs.dll的Is_xxx_200024FC为0
在结尾看到800h的对齐位置。
0x800/4=0x200=512字节,那么可以枚举到512个进程。
把所有dwProcessId换成41EA88,大小F0换成800h。
现在可以正常枚举到进程。
经过一番折腾,目前满足我当前需求,可以正常dump出错的软件,但是LordPE不支持64进程,所有可能某些情况下还是鸡肋。
很少这么手工修改软件,思路还是挺重要的,要不是搜到那篇帖子,我可能就会采用勾上procs.dll的导出接口和dump函数,但随便几点某个进程,选择dump时,会弹出一个我的界面选择真实的目标进程,然后返回调用dump函数,也同样是可以同样的功能。
最后立个flag,有时间还是想写个支持64进程的增强版LordPE。或者我孤陋寡闻,目前已经有类似程序,有知情大佬,请不吝告知。