15

Windows 能够将填充程序应用于行为不端的应用程序。垫片用于拦截 API 调用并对其进行更改。例如,垫片可用于:

  • 更改传入参数
  • 谎报返回值
  • 改变它来调用别的东西

应用程序兼容性工具包有很多现有的垫片,您可以将其应用于您自己的行为不端的应用程序。这是一个忽略您的 API 调用并改为调用完全不同的 API 的示例:

替代文字

我需要一个不是 Microsoft 已经编写的数百个 shim 之一的 shim。我需要一个定制的垫片

就我而言,我想拦截对以下内容的调用:

GetSystemMetrics(0x1000)

使其返回0。我找不到任何有关如何为 Windows 提供我自己的 DLL 的信息,该 DLL 将具有我需要的修复程序。我什至不知道您是否可以创建自定义垫片。

Windows 是否支持自定义垫片?

4

5 回答 5

8

我不知道除 Microsoft 以外的其他人实施 appcompat shim 的任何方式。

您可能想调查Detours,它可能会提供您想要的功能。

于 2009-11-11T06:14:19.637 回答
3

您必须从 Raymond Chen 的角度来考虑这一点。想象一下,如果 Microsoft 以外的其他人也可以编写兼容性填充程序。然后,每当 Microsoft 进行重大更改时,除了所有其他兼容性工作外,他们还必须为做错事的第 3 方 shim 编写 shim。保持向后兼容性已经够难的了。

于 2009-11-12T04:12:12.440 回答
3

可以创建与真实 shim 引擎一起应用的自定义真实应用程序兼容性 shim,但Microsoft 绝对不支持这样做。雷蒙德·陈会吓坏的。

创建垫片

Shim 模块是导出两个函数的 DLL:

// Called by the shim engine to request the installation of a shim.
// Returns an array of requested import hooks and provides its length in the pdwHookCount output parameter.
EXTERN_C PHOOKAPI WINAPI GetHookAPIs(LPSTR pszArgs, LPWSTR pwszShim, PDWORD pdwHookCount);

// Called by the shim engine at various points in the process's life cycle.
EXTERN_C VOID WINAPI NotifyShims(DWORD notification, PVOID data);

// Represents a request for an imported function to be redirected to one in this DLL.
// Definition based on information from the ReactOS project.
typedef struct tagHOOKAPI {
    PCSTR DllName;
    PCSTR FunctionName;
    PVOID HookFunction;
    PVOID NextFunction; // Populated by the shim engine
    PVOID Reserved[2];
} HOOKAPI, *PHOOKAPI;

对于只需要提供一个替换一个 Win32 函数的 shim 的简单 shim 模块,您的GetHookAPIs实现可以只检查pwszShim一个 shim 的名称,设置*pdwHookCount为 1,并返回一个指向HOOKAPI描述目标函数及其替换的结构的指针。您在HookFunction字段中输入地址的钩子函数将被调用而不是目标。它可以使用NextFunction由 shim 引擎设置的字段在适当的时候调用真实/原始函数。NotifyShims可以是无操作的。

或者,我在我的自定义 shim 开发工具包中提供了一些脚手架,如果您需要编写包含多个或更复杂 shim 的 shim 模块,这将特别有用。我将演示如何制作您想要的TSLie垫片。从那里的CustomShim项目开始,让我们Shim_TSLie.h为一个简单的 shim 创建一个类来声明一个类:

#pragma once
#include "Shim.h"

class Shim_TSLie : public Shim {
public:
    Shim_TSLie();
protected:
    virtual void RegisterHooks();
private:
    static int WINAPI Hook_GetSystemMetrics(int nIndex);
};

Shim_TSLie.cpp中,让我们实现该类,添加一个钩子GetSystemMetricsMSDN 说是在 中User32.dll),检查请求的度量并返回零SM_REMOTESESSION

#include "Shim_TSLie.h"

SHIM_INSTANCE(TSLie)

void Shim_TSLie::RegisterHooks() {
    ADD_HOOK("USER32.DLL", "GetSystemMetrics", Hook_GetSystemMetrics);
}

int WINAPI Shim_TSLie::Hook_GetSystemMetrics(int nIndex) {
    if (nIndex == SM_REMOTESESSION) {
        ASL_PRINTF(ASL_LEVEL_TRACE, "Lie: returning 0 for SM_REMOTESESSION");
        return 0;
    } else {
        // Get and call the real GetSystemMetrics
        DEFINE_NEXT(Hook_GetSystemMetrics);
        return next(nIndex);
    }
}

编辑shimlist.cpp以包含和实例化Shim_TSLie,可能删除其他示例垫片,并在 Release x86 配置中编译。

安装垫片模块

在 Windows 10 上,shim 引擎将仅加载具有特定名称的 shim 模块。我建议重命名 DLL AcRes.dll,因为这是一个可接受的名称,不用于现有的 shim 模块。进行任何必要的重命名后,将 DLL 复制到C:\Windows\SysWOW64文件夹中。

应用垫片

现在是困难的部分。兼容性管理员不允许您定义 shim,也不会在非系统数据库中查找 shim,因此声明和使用自定义 shim 的 SDB 文件必须通过其他方式创建。

方法一:ShimDBC

如果您掌握了 ShimDBC,您可以像这样编写 XML,EXE适当地更改属性并添加您需要的任何其他匹配信息属性...

<?xml version="1.0" encoding="utf-8"?>
<DATABASE NAME="Custom Database">
    <LIBRARY>
        <SHIM NAME="TSLie" FILE="AcRes.dll" RUNTIME_PLATFORM="X86_ANY"/>
    </LIBRARY>
    <APP NAME="Some App">
        <EXE NAME="SomeApp.exe" PRODUCT_NAME="Some Product" RUNTIME_PLATFORM="X86_ANY">
            <SHIM NAME="TSLie"/>
        </EXE>
    </APP>
</DATABASE>

...并像这样编译它,根据需要更改YourXml.xmlYourDatabase.sdb文件名:

shimdbc Custom YourXml.xml YourDatabase.sdb -op X86_ANY

方法二:AppHelp API

或者,您可以使用apphelp.dll. 不幸的是,没有针对它的公共 LIB,因此链接它会很困难。您可以使用我的SprintDLL实用程序的脚本调用这些函数来构建 SDB ...

call apphelp.dll!SdbCreateDatabase /return native /into pdb (lpwstr "YourDatabase.sdb", int 0)
call apphelp.dll!SdbBeginWriteListTag /return int /into tDatabase (slotdata pdb, int 0x7001)
call apphelp.dll!SdbWriteDWORDTag (slotdata pdb, int 0x4023, int 1)
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6001, lpwstr "Custom Database")
call apphelp.dll!SdbWriteBinaryTag (slotdata pdb, int 0x9007, blockptr(guid {5FB8C914-168C-4B9B-8256-DF8A0F384E3E}), int 0x10)
call apphelp.dll!SdbWriteQWORDTag (slotdata pdb, int 0x5001, long 0)
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6022, lpwstr "3.0.0.9")
call apphelp.dll!SdbWriteDWORDTag (slotdata pdb, int 0x4021, int 37)
call apphelp.dll!SdbWriteDWORDTag (slotdata pdb, int 0x4055, int 0)
call apphelp.dll!SdbBeginWriteListTag /return int /into tLibrary (slotdata pdb, int 0x7002)
call apphelp.dll!SdbBeginWriteListTag /return int /into tShim (slotdata pdb, int 0x7004)
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6001, lpwstr "TSLie")
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x600A, lpwstr "AcRes.dll")
call apphelp.dll!SdbWriteBinaryTag (slotdata pdb, int 0x9010, blockptr(guid {77F84F43-0675-4B79-99EE-E70E0CE45BFC}), int 0x10)
call apphelp.dll!SdbWriteDWORDTag (slotdata pdb, int 0x4021, int 37)
call apphelp.dll!SdbEndWriteListTag (slotdata pdb, slotdata tShim)
call apphelp.dll!SdbEndWriteListTag (slotdata pdb, slotdata tLibrary)
call apphelp.dll!SdbBeginWriteListTag /return int /into tExe (slotdata pdb, int 0x7007)

// TODO: Change EXE attributes appropriately
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6001, lpwstr "SomeApp.exe")
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6006, lpwstr "Some App")
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6005, lpwstr "Some Vendor")

call apphelp.dll!SdbWriteBinaryTag (slotdata pdb, int 0x9004, blockptr(guid {BB751D03-9792-4208-886A-AFDBC5AA0EBE}), int 0x10)
call apphelp.dll!SdbWriteBinaryTag (slotdata pdb, int 0x9011, blockptr(guid {59CCFEAA-0A4B-4578-8B20-261A48D19E16}), int 0x10)
call apphelp.dll!SdbBeginWriteListTag /return int /into tMatching (slotdata pdb, int 0x7008)

// TODO: Change or add matching information as needed
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6001, lpwstr "*")
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6010, lpwstr "Some Product")

call apphelp.dll!SdbEndWriteListTag (slotdata pdb, slotdata tMatching)
call apphelp.dll!SdbBeginWriteListTag /return int /into tShimref (slotdata pdb, int 0x7009)
call apphelp.dll!SdbWriteStringTag (slotdata pdb, int 0x6001, lpwstr "TSLie")
call apphelp.dll!SdbEndWriteListTag (slotdata pdb, slotdata tShimref)
call apphelp.dll!SdbEndWriteListTag (slotdata pdb, slotdata tExe)
call apphelp.dll!SdbEndWriteListTag (slotdata pdb, slotdata tDatabase)
call apphelp.dll!SdbCloseDatabaseWrite (slotdata pdb)

...可以像这样调用:

sprintdll run YourScript.sprint

安装 SDB

最后,无论您如何生成 SDB,您都可以使用标准sdbinst实用程序安装它:

sdbinst YourDatabase.sdb
于 2020-12-23T00:07:16.773 回答
1

这是可能的,但需要一些工作。

您使用自己的启动程序生成应用程序,该程序将应用 shim。您可以通过让您的启动器创建具有足够权限来编辑其内存的进程来做到这一点。大多数 API 函数都以两个字节的 nop 开头,然后是更多的 nop。您可以将两个字节的 nop 更改为短跳转,并将前面的 nop 更改为您想去的任何地方的长跳转。

我过去使用的另一种解决方案是将可执行文件作为 DLL 加载,但这可能会导致更多工作,因为这取决于应用程序的挑剔程度。在我的情况下,我必须将可执行文件作为纯数据 DLL 加载并进行所有我自己的导入,但不幸的是,以前的解决方案不适合我。

我也曾经编写过一个使用类似原理的挂钩 DLL,但这只是一个选项,如果您可以修改源以加载 DLL,或者如果进程支持 DLL 插件。

于 2012-04-24T10:22:22.887 回答
-1

你总是可以使用逆向工程来修复它。

于 2009-12-28T17:27:57.433 回答