让软件死而复生-程序员折腾笔记

  • A+
所属分类:安全闲碎


author: anhkgg
date: 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+0x13c
02 0019f7a0 6992b4f2 ffffffff 00001003 00000001 LordPE+0x5fb6
03 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 0xfffffffe
06 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的位置还不只一个。

让软件死而复生-程序员折腾笔记

更多想法:

  1. dwProcessId通过malloc分配,但得修改所有引用位置的代码,从dwProcessId[index]换成(*dwProcess)[index]

  2. 劫持所有procs.dll接口,把参数PID换成我需要dump的进程,同样也需要替换模块地址。

  3. 或者重写一个…(额)

觉得都挺麻烦的。

此时,去百度搜索了一下,发现已经有前人做过相关工作了。

LordPE只显示60个进程 fix

他是在PE中找到空白位置,用做新的dwProcessId地址,然后把所有引用dwProcessId的位置换成这个新地址,还挺简单,不过最多只能存256个进程PID,将就可以用了。

然后procs.dll接口也存在问题,居然还有硬编码F0来EnumProcess获取进程(几乎所有接口)。

让软件死而复生-程序员折腾笔记

不过我前面已经修改了Is_xxx_200024FC,所以不会用enumprocess,全部使用的tlhelp32的ProcessNext接口,不会存在这个问题。

所以暂时确定方案:

  1. 找到新位置用作dwProcessId,并修改引用位置

  2. 修改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。或者我孤陋寡闻,目前已经有类似程序,有知情大佬,请不吝告知。

如果觉得文章不错,请不吝点赞在看。

本文始发于微信公众号(汉客儿):让软件死而复生-程序员折腾笔记

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: