可以创建与真实 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
中,让我们实现该类,添加一个钩子GetSystemMetrics
(MSDN 说是在 中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.xml
和YourDatabase.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