如何在没有源代码的情况下将 Vista 程序反向移植到 XP?

逆向工程 拆卸 视窗
2021-06-15 22:09:48

通常当我有 Vista 应用程序时,它会从 kernel32.dll 升级一些功能

最常见的是 InitializeCriticalSection -> InitializeCriticalSectionEx

有可能向后移植吗?除了更改链接器 OSVersion。

编辑:只是为了冗长,这里是例子

.text:0048CE4D                 xor     esi, esi
.text:0048CE4F                 push    esi             ; Flags
.text:0048CE50                 push    esi             ; dwSpinCount
.text:0048CE51                 push    ecx             ; lpCriticalSection
.text:0048CE52                 call    ds:InitializeCriticalSectionEx
.text:0048CE58                 test    eax, eax

十六进制转储: 33 F6 56 56 51 FF 15 F0 C1 4A 00 85 C0

3个回答

一种方法是创建具有相似名称的“填充”DLL,以便它们易于识别。这种技术可以增量使用(即可以随时向 DLL 添加附加功能,用于其他具有类似要求的程序,而不是每次都使用全新的 DLL)。

最初的问题是您不能简单地替换函数名称(即CriticalSectionEx -> CriticalSection),因为需要额外的参数。

填充技术要求您仅更改 exe 文件中导入的 DLL 的名称,例如从“kernel32.dll”更改为“kernel31.dll”(以保留名称的长度并保持数据对齐)。然后你创建一个“kernel31.dll”,它和exe文件放在同一个目录下。这个“kernel31.dll”文件的内容将是一个导出表、一个导入表和一些函数的包装器。

要创建导入表,您需要另一个程序来读取原始 exe 的导入表,并对每个条目执行 GetProcAddress。对于返回有效地址的每个条目,“kernel31.dll”导出表将直接添加该条目,并将指向“kernel31.dll”导入表,以便将该导入的名称转发到原始 DLL。此功能没有兼容性问题。

对于为地址返回零的每个条目,“kernel31.dll”导出表将指向“kernel31.dll”内的包装器,您必须自己编写该包装器。

对原始 exe 中的每个 DLL 重复此过程(因此“ntdll.dll”可能会变成“ntdl1.​​dll”,“user32.dll”可能会变成“user31.dll”,等等)。

但是有两种特殊情况:LoadLibrary 及其变体(及其在 ntdll.dll 中的等效项),以及 GetModuleHandle 及其变体(及其在 ntdll.dll 中的等效项)。它们需要“kernel31.dll”中的包装器,因为它们可能会尝试动态访问也存在兼容性问题的 DLL 或函数。不幸的是,您无法通过静态分析真正确定这一点。

这两个包装器将调用kernel32.dll(或ntdll.dll)中的原始函数,然后检查结果。如果 DLL 不存在,则需要自己创建该 DLL,以防在更高版本的 Windows 中引入,或者如果 DLL 确实是可选的,则返回此结果。如果该函数不存在,则需要查找对 DLL 的引用并重命名它,然后为该 DLL 的新版本编写函数包装器。

这是一个非常长的答案,可能听起来更难实现它的真实性,但需要细节。

不是一个简单的修复,但你可以修补导入表来代替InitializeCriticalSectionExInitializeCriticalSection(只需更换E一个空字节字符),然后打补丁最初将所有来电InitializeCriticalSectionEx,而不是仅仅通过lpCriticalSection论证,而不是dwSpinCountFlags参数。如果对该函数的其他调用不依赖于静态导入,则您需要做一些额外的工作。

甚至还有更丑陋的解决方案,例如挂钩 Windows 的 PE 加载程序以动态重定向事物,但我不推荐该路线。

也许其他人可以想到一个更简单的解决方案......?

它很容易做馅饼。

                33 F6 56 56 51 FF 15 F0 C1 4A 00 85 C0
changed into -> 33 F6 90 90 51 FF 15 F0 C1 4A 00 85 C0
                      ^^ ^^

并更改导入表中的字符串

49 6E 69 74 69 61 6C 69 7A 65 43 72 69 74 69 63 61 6C 53 65 63 74 69 6F 6E 45 78 00 // InitializeCriticalSectionEx
49 6E 69 74 69 61 6C 69 7A 65 43 72 69 74 69 63 61 6C 53 65 63 74 69 6F 6E 00 00 00  // InitializeCriticalSection 
                                                                           ^^ ^^