前言
在 R3 下防护动态加载的模块不被意外卸载需要很多的策略,比如:LDR 断链、VAD 记录擦除、PE 头擦除、修改入口函数、内存注入等。文本我们将浅析模块静态化技术这一项技术。模块静态化是一个很常见的模块保护技术,它通过修改模块的引用计数为 -1,来使得模块不可被标准的 API 成功卸载。
系列文章:
- R3 下动态加载的模块的保护(一):分析模块伪静态化技术 [本文]
- R3 下动态加载的模块的保护(二):分析重映射擦除 VAD 信息[暂未发布]
- 更多 ... ...
1 关于 DLL 引用计数
DLL 的引用计数(或加载计数)是 DLL 被请求加载到进程中的次数记录。每次加载 DLL 时(通过 LoadLibrary) 添加到进程中,其引用计数递增 1 ,每次从进程中释放 DLL(通过 FreeLibrary)时, 引用计数递减 1。进程中初次加载模块时会将模块映射到地址空间中,当之后多次加载同一个模块时,并不会重新加载这个模块,而是只返回相同的地址。当引用计数达到 0 时, DLL 完全从进程中取消映射。并且规定,静态加载的模块,其引用计数为 -1,并且不能增加计数或通过 FreeLibrary / LdrUnLoadDll 等卸载模块。
Windows API 没有提供有关加载的 DLL 的大量信息。 Windows 提供 ToolHelp 库来检索加载到进程中的 DLL 的信息,但它只提供了非常基本的信息:例如模块名称、模块句柄等。为了获得更多信息,需要更深入地挖掘。
2 关于 uFlags 位域中的 Mask
另一种类似的技术是通过 uFlags 位域覆盖修改系统用于区别静态模块和动态模块的标志位,修改后系统会认为模块是静态的进而阻止模块的卸载。
修改前,动态加载的模块可以被 RemoteDll 等工具卸载:
修改后,按钮灰显,表明这个模块不可以被卸载:
这种修改不需要针对 R3 下哪种工具,只需要在加载了模块的进程内修改即可。
本文参考文献:
(1)The covert way to find the Reference Count of DLL - www.SecurityXploded.com
(2)Make Your Dynamic Module Unfreeable (Anti-FreeLibrary) | secrary[dot]com
3 原理和应用
3.1 获取结构体和模块的遍历
DLL 的引用计数存储在 PEB (Process Environment Block)中。PEB 包含 DLL 的链表,而链表中包含有关该特定 DLL 的结构化信息。
任何进程的 PEB 块通常位于地址 0x7ffdf000。 但是,有标准方法可以获取此地址。有 NTDLL.DLL 的无文档函数 NtQueryInformationProcess 可用于检索PROCESS_BASIC_INFORMATION 结构。PBI 结构如下:
struct _PROCESS_BASIC_INFORMATION
{PVOID Reserved1;PPEB PebBaseAddress;PVOID Reserved2[2];ULONG_PTR UniqueProcessId;PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
第二个成员 PebBaseAddress 是指向 PEB 结构体的指针,该结构体可用于获取已加载模块的信息列表。
也可以使用 fs/gs 寄存器偏移来获取,这是 MSVC 编译器支持的接口:
#ifdef _WIN64PPEB_LDR_DATA64 pPebLdrData = NULL;ULONGLONG ModuleSum = NULL;PPEB64 peb = (PPEB64)__readgsqword(0x60);
#elsePPEB_LDR_DATA32 pPebLdrData = NULL;ULONG ModuleSum = NULL;PPEB32 peb = (PPEB32)__readfsdword(0x30);
#endif
而对于 PEB 结构体,微软是没有公开文档的,需要自己进行重定义(原始结构体定义中缺少我们需要的部分),经查阅逆向文献,得到如下的结构体定义(部分不需要用到的成员已经被截断):
typedef struct _PEB_LDR_DATA32
{ULONG Length; // +0x00BOOLEAN Initialized; // +0x04PVOID SsHandle; // +0x08LIST_ENTRY InLoadOrderModuleList; // +0x0cLIST_ENTRY InMemoryOrderModuleList; // +0x14LIST_ENTRY InInitializationOrderModuleList;// +0x1c
} PEB_LDR_DATA32, * PPEB_LDR_DATA32; // +0x24typedef struct _PEB32
{UCHAR InheritedAddressSpace; //0x0UCHAR ReadImageFileExecOptions; //0x1UCHAR BeingDebugged; //0x2union{UCHAR BitField; //0x3struct{UCHAR ImageUsesLargePages : 1; //0x3UCHAR IsProtectedProcess : 1; //0x3UCHAR IsImageDynamicallyRelocated : 1; //0x3UCHAR SkipPatchingUser32Forwarders : 1; //0x3UCHAR IsPackagedProcess : 1; //0x3UCHAR IsAppContainer : 1; //0x3UCHAR IsProtectedProcessLight : 1; //0x3UCHAR IsLongPathAwareProcess : 1; //0x3};};PVOID Mutant; //0x4PVOID ImageBaseAddress; //0x8PEB_LDR_DATA32* Ldr; //0xcRTL_USER_PROCESS_PARAMETERS* ProcessParameters; //0x10PVOID SubSystemData; //0x14PVOID ProcessHeap; //0x18RTL_CRITICAL_SECTION* FastPebLock; //0x1cSLIST_HEADER* volatile AtlThunkSListPtr; //0x20PVOID IFEOKey; //0x24
} PEB32, * PPEB32;typedef struct _STRING64
{USHORT Length; //0x0USHORT MaximumLength; //0x2ULONGLONG Buffer; //0x8
}STRING64, * LPSTRING64;typedef struct _PEB_LDR_DATA64
{ULONG Length; //0x0UCHAR Initialized; //0x4PVOID SsHandle; //0x8LIST_ENTRY InLoadOrderModuleList; //0x10LIST_ENTRY InMemoryOrderModuleList; //0x20LIST_ENTRY InInitializationOrderModuleList; //0x30PVOID EntryInProgress; //0x40UCHAR ShutdownInProgress; //0x48PVOID ShutdownThreadId; //0x50
}PEB_LDR_DATA64, *PPEB_LDR_DATA64;typedef struct _PEB64
{UCHAR InheritedAddressSpace; //0x0UCHAR ReadImageFileExecOptions; //0x1UCHAR BeingDebugged; //0x2union{UCHAR BitField; //0x3struct{UCHAR ImageUsesLargePages : 1; //0x3UCHAR IsProtectedProcess : 1; //0x3UCHAR IsImageDynamicallyRelocated : 1; //0x3UCHAR SkipPatchingUser32Forwarders : 1; //0x3UCHAR IsPackagedProcess : 1; //0x3UCHAR IsAppContainer : 1; //0x3UCHAR IsProtectedProcessLight : 1; //0x3UCHAR IsLongPathAwareProcess : 1; //0x3};};UCHAR Padding0[4]; //0x4ULONGLONG Mutant; //0x8ULONGLONG ImageBaseAddress; //0x10PEB_LDR_DATA64* Ldr; //0x18ULONGLONG ProcessParameters; //0x20ULONGLONG SubSystemData; //0x28ULONGLONG ProcessHeap; //0x30ULONGLONG FastPebLock; //0x38ULONGLONG AtlThunkSListPtr; //0x40ULONGLONG IFEOKey; //0x48
}PEB64, *PPEB64;
在 PEB 结构中,我们需要获取 PEB_LDR_DATA 结构,也就是这里的 Ldr 成员:
PPEB_LDR_DATA Ldr
它是指向 PEB_LDR_DATA 结构的指针。
PEB_LDR_DATA 包含我们感兴趣的加载器数据结构,它包含已加载模块的链表:
typedef struct _PEB_LDR_DATA64
{ULONG Length; //0x0UCHAR Initialized; //0x4PVOID SsHandle; //0x8LIST_ENTRY InLoadOrderModuleList; //0x10LIST_ENTRY InMemoryOrderModuleList; //0x20LIST_ENTRY InInitializationOrderModuleList; //0x30PVOID EntryInProgress; //0x40UCHAR ShutdownInProgress; //0x48PVOID ShutdownThreadId; //0x50
}PEB_LDR_DATA64, *PPEB_LDR_DATA64;
数据结构为 LIST_ENTRY 的三个链表分别为:InLoadOrderModuleList、 InMemoryOrderModuleList 和 InInitializationOrderModuleList。他们存储按照不同排序方式对模块排序的结果。
那么问题就转化为了如何解析链表来遍历每一个模块的信息。
具体遍历原理可以参考我的这篇文章:利用 PEB_LDR_DATA 结构枚举进程模块信息。就不再重复解释了。
3.2 修改的成员位置
这两个技术都通过 LDR_DATA_TABLE_ENTRY 中的成员来完成:
前者通过修改 DdagNode 结构中的 LoadCount 以及 LDR 中废弃的(旧系统用到) ObsoleteLoadCount 成员,将他们赋值为 -1,即可修改模块属性为静态:
pLdrDataEntry->DdagNode->LoadCount = 0xffffffff;
pLdrDataEntry->ObsoleteLoadCount = 0xffff;
后者通过修改位域 ProcessStaticImport 为 TRUE(1) 来实现的,该位域结构如下:
union
{
UCHAR FlagGroup[4]; //0x68
ULONG Flags; //0x68
struct
{
ULONG PackagedBinary : 1; //0x68
ULONG MarkedForRemoval : 1; //0x68
ULONG ImageDll : 1; //0x68
ULONG LoadNotificationsSent : 1; //0x68
ULONG TelemetryEntryProcessed : 1; //0x68
ULONG ProcessStaticImport : 1; //0x68
ULONG InLegacyLists : 1; //0x68
ULONG InIndexes : 1; //0x68
ULONG ShimDll : 1; //0x68
ULONG InExceptionTable : 1; //0x68
ULONG ReservedFlags1 : 2; //0x68
ULONG LoadInProgress : 1; //0x68
ULONG LoadConfigProcessed : 1; //0x68
ULONG EntryProcessed : 1; //0x68
ULONG ProtectDelayLoad : 1; //0x68
ULONG ReservedFlags3 : 2; //0x68
ULONG DontCallForThreads : 1; //0x68
ULONG ProcessAttachCalled : 1; //0x68
ULONG ProcessAttachFailed : 1; //0x68
ULONG CorDeferredValidate : 1; //0x68
ULONG CorImage : 1; //0x68
ULONG DontRelocate : 1; //0x68
ULONG CorILOnly : 1; //0x68
ULONG ChpeImage : 1; //0x68
ULONG ReservedFlags5 : 2; //0x68
ULONG Redirected : 1; //0x68
ULONG ReservedFlags6 : 2; //0x68
ULONG CompatDatabaseProcessed : 1; //0x68
}uFlags;
};
其实,开启 ProcessStaticImport 标志位保护模块的官方的方法是调用一次 GetModuleHandleEx 并指定 GET_MODULE_HANDLE_EX_FLAG_PIN 标志,但似乎通过官方方法并没法取消掉,我们通过编程方式枚举 LDR 信息的可以取消掉该机制。
HMODULE hTestModule = 0;
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, L"模块名称", &hTestModule);
开启该标志位后,无论使用多少次 FreeLibrary 都不会真正卸载模块。
3.3 完整代码
下面的代码实现上述所有功能,需要注意是,有三个链表都需要枚举并修改,关于这个结构枚举的原理可以看我的另一篇文章“利用 LDR_DATA_TABLE 枚举进程模块信息”,此外需要注意如果包含 winternl 头文件,它里面有 ldrp.h 部分结构的重复声明(微软给的结构体不完整)。
ldrp.h:
#pragma once
#include <winnt.h>
#include <WTypesbase.h>
//#include <winternl.h>// Kernels | x64 | Windows 10 | 2016 | 2210 22H2(May 2023 Update)//0x18 bytes (sizeof)
typedef struct _RTL_BALANCED_NODE
{union{_RTL_BALANCED_NODE* Children[2]; //0x0struct{_RTL_BALANCED_NODE* Left; //0x0_RTL_BALANCED_NODE* Right; //0x8};};union{struct{UCHAR Red : 1; //0x10UCHAR Balance : 2; //0x10};ULONGLONG ParentValue; //0x10};
}RTL_BALANCED_NODE, * PRTL_BALANCED_NODE, * LPRTL_BALANCED_NODE;//0x4 bytes (sizeof)
enum _LDR_DLL_LOAD_REASON
{LoadReasonStaticDependency = 0,LoadReasonStaticForwarderDependency = 1,LoadReasonDynamicForwarderDependency = 2,LoadReasonDelayloadDependency = 3,LoadReasonDynamicLoad = 4,LoadReasonAsImageLoad = 5,LoadReasonAsDataLoad = 6,LoadReasonEnclavePrimary = 7,LoadReasonEnclaveDependency = 8,LoadReasonUnknown = -1
};typedef _LDR_DLL_LOAD_REASON LDR_DLL_LOAD_REASON;//0x10 bytes (sizeof)
typedef struct _LDR_SERVICE_TAG_RECORD
{_LDR_SERVICE_TAG_RECORD* Next; //0x0ULONG ServiceTag; //0x8
}LDR_SERVICE_TAG_RECORD, * PLDR_SERVICE_TAG_RECORD;//0x8 bytes (sizeof)
typedef struct _LDRP_CSLIST
{SINGLE_LIST_ENTRY* Tail; //0x0
}LDRP_CSLIST;//0x4 bytes (sizeof)
enum _LDR_DDAG_STATE
{LdrModulesMerged = -5,LdrModulesInitError = -4,LdrModulesSnapError = -3,LdrModulesUnloaded = -2,LdrModulesUnloading = -1,LdrModulesPlaceHolder = 0,LdrModulesMapping = 1,LdrModulesMapped = 2,LdrModulesWaitingForDependencies = 3,LdrModulesSnapping = 4,LdrModulesSnapped = 5,LdrModulesCondensed = 6,LdrModulesReadyToInit = 7,LdrModulesInitializing = 8,LdrModulesReadyToRun = 9
};typedef _LDR_DDAG_STATE LDR_DDAG_STATE;//0x50 bytes (sizeof)
typedef struct _LDR_DDAG_NODE
{LIST_ENTRY Modules; //0x0PLDR_SERVICE_TAG_RECORD ServiceTagList; //0x10ULONG LoadCount; //0x18ULONG LoadWhileUnloadingCount; //0x1cULONG LowestLink; //0x20LDRP_CSLIST Dependencies; //0x28LDRP_CSLIST IncomingDependencies; //0x30LDR_DDAG_STATE State; //0x38SINGLE_LIST_ENTRY CondenseLink; //0x40ULONG PreorderNumber; //0x48
}LDR_DDAG_NODE, * PLDR_DDAG_NODE;typedef struct _UNICODE_STRING {USHORT Length;USHORT MaximumLength;PWSTR Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING* PUNICODE_STRING;
typedef const UNICODE_STRING* PCUNICODE_STRING;//0x120 bytes (sizeof)
typedef struct _LDR_DATA_TABLE_ENTRY
{LIST_ENTRY InLoadOrderLinks; //0x0LIST_ENTRY InMemoryOrderLinks; //0x10LIST_ENTRY InInitializationOrderLinks; //0x20VOID* DllBase; //0x30VOID* EntryPoint; //0x38ULONG SizeOfImage; //0x40UNICODE_STRING FullDllName; //0x48UNICODE_STRING BaseDllName; //0x58union{UCHAR FlagGroup[4]; //0x68ULONG Flags; //0x68struct{ULONG PackagedBinary : 1; //0x68ULONG MarkedForRemoval : 1; //0x68ULONG ImageDll : 1; //0x68ULONG LoadNotificationsSent : 1; //0x68ULONG TelemetryEntryProcessed : 1; //0x68ULONG ProcessStaticImport : 1; //0x68ULONG InLegacyLists : 1; //0x68ULONG InIndexes : 1; //0x68ULONG ShimDll : 1; //0x68ULONG InExceptionTable : 1; //0x68ULONG ReservedFlags1 : 2; //0x68ULONG LoadInProgress : 1; //0x68ULONG LoadConfigProcessed : 1; //0x68ULONG EntryProcessed : 1; //0x68ULONG ProtectDelayLoad : 1; //0x68ULONG ReservedFlags3 : 2; //0x68ULONG DontCallForThreads : 1; //0x68ULONG ProcessAttachCalled : 1; //0x68ULONG ProcessAttachFailed : 1; //0x68ULONG CorDeferredValidate : 1; //0x68ULONG CorImage : 1; //0x68ULONG DontRelocate : 1; //0x68ULONG CorILOnly : 1; //0x68ULONG ChpeImage : 1; //0x68ULONG ReservedFlags5 : 2; //0x68ULONG Redirected : 1; //0x68ULONG ReservedFlags6 : 2; //0x68ULONG CompatDatabaseProcessed : 1; //0x68}uFlags;};USHORT ObsoleteLoadCount; //0x6cUSHORT TlsIndex; //0x6eLIST_ENTRY HashLinks; //0x70ULONG TimeDateStamp; //0x80struct ACTIVATION_CONTEXT* EntryPointActivationContext; //0x88VOID* Lock; //0x90LDR_DDAG_NODE* DdagNode; //0x98LIST_ENTRY NodeModuleLink; //0xa0struct LDRP_LOAD_CONTEXT* LoadContext; //0xb0VOID* ParentDllBase; //0xb8VOID* SwitchBackContext; //0xc0RTL_BALANCED_NODE BaseAddressIndexNode; //0xc8RTL_BALANCED_NODE MappingInfoIndexNode; //0xe0ULONGLONG OriginalBase; //0xf8LARGE_INTEGER LoadTime; //0x100ULONG BaseNameHashValue; //0x108LDR_DLL_LOAD_REASON LoadReason; //0x10cULONG ImplicitPathOptions; //0x110ULONG ReferenceCount; //0x114ULONG DependentLoadFlags; //0x118UCHAR SigningLevel; //0x11c
}LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;//0x58 bytes (sizeof)
typedef struct _PEB_LDR_DATA32
{ULONG Length; // +0x00BOOLEAN Initialized; // +0x04PVOID SsHandle; // +0x08LIST_ENTRY InLoadOrderModuleList; // +0x0cLIST_ENTRY InMemoryOrderModuleList; // +0x14LIST_ENTRY InInitializationOrderModuleList;// +0x1c
} PEB_LDR_DATA32, * PPEB_LDR_DATA32; // +0x24typedef struct _PEB32
{UCHAR InheritedAddressSpace; //0x0UCHAR ReadImageFileExecOptions; //0x1UCHAR BeingDebugged; //0x2union{UCHAR BitField; //0x3struct{UCHAR ImageUsesLargePages : 1; //0x3UCHAR IsProtectedProcess : 1; //0x3UCHAR IsImageDynamicallyRelocated : 1; //0x3UCHAR SkipPatchingUser32Forwarders : 1; //0x3UCHAR IsPackagedProcess : 1; //0x3UCHAR IsAppContainer : 1; //0x3UCHAR IsProtectedProcessLight : 1; //0x3UCHAR IsLongPathAwareProcess : 1; //0x3};};PVOID Mutant; //0x4PVOID ImageBaseAddress; //0x8PEB_LDR_DATA32* Ldr; //0xcstruct RTL_USER_PROCESS_PARAMETERS* ProcessParameters; //0x10PVOID SubSystemData; //0x14PVOID ProcessHeap; //0x18RTL_CRITICAL_SECTION* FastPebLock; //0x1cSLIST_HEADER* volatile AtlThunkSListPtr; //0x20PVOID IFEOKey; //0x24
} PEB32, * PPEB32;typedef struct _STRING64
{USHORT Length; //0x0USHORT MaximumLength; //0x2ULONGLONG Buffer; //0x8
}STRING64, * LPSTRING64;typedef struct _PEB_LDR_DATA64
{ULONG Length; //0x0UCHAR Initialized; //0x4PVOID SsHandle; //0x8LIST_ENTRY InLoadOrderModuleList; //0x10LIST_ENTRY InMemoryOrderModuleList; //0x20LIST_ENTRY InInitializationOrderModuleList; //0x30PVOID EntryInProgress; //0x40UCHAR ShutdownInProgress; //0x48PVOID ShutdownThreadId; //0x50
}PEB_LDR_DATA64, * PPEB_LDR_DATA64;typedef struct _PEB64
{UCHAR InheritedAddressSpace; //0x0UCHAR ReadImageFileExecOptions; //0x1UCHAR BeingDebugged; //0x2union{UCHAR BitField; //0x3struct{UCHAR ImageUsesLargePages : 1; //0x3UCHAR IsProtectedProcess : 1; //0x3UCHAR IsImageDynamicallyRelocated : 1; //0x3UCHAR SkipPatchingUser32Forwarders : 1; //0x3UCHAR IsPackagedProcess : 1; //0x3UCHAR IsAppContainer : 1; //0x3UCHAR IsProtectedProcessLight : 1; //0x3UCHAR IsLongPathAwareProcess : 1; //0x3};};UCHAR Padding0[4]; //0x4ULONGLONG Mutant; //0x8ULONGLONG ImageBaseAddress; //0x10PEB_LDR_DATA64* Ldr; //0x18ULONGLONG ProcessParameters; //0x20ULONGLONG SubSystemData; //0x28ULONGLONG ProcessHeap; //0x30ULONGLONG FastPebLock; //0x38ULONGLONG AtlThunkSListPtr; //0x40ULONGLONG IFEOKey; //0x48
}PEB64, * PPEB64;#ifdef _WIN64
typedef PEB64 PEB;
typedef PPEB64 PPEB;
typedef PEB_LDR_DATA64 PEB_LDR_DATA;
typedef PPEB_LDR_DATA64 PPEB_LDR_DATA;
#else
typedef PEB32 PEB;
typedef PPEB32 PPEB;
typedef PEB_LDR_DATA32 PEB_LDR_DATA;
typedef PPEB_LDR_DATA32 PPEB_LDR_DATA;
#endif
main.cpp:
DWORD WINAPI EasyProtectLibrary(LPVOID lpThreadParameter)
{auto ldrpt = (LPLDR_PROTECT_STRUCT)lpThreadParameter;if (ldrpt == nullptr) return 0;BOOL bNewValue = ldrpt->bEnableProtect;BOOL bOldProtect = 0;DWORD index = 0;DWORD bResponse = 0;const WCHAR lpFileName[] = HOOK_MODULE_NAME;PPEB_LDR_DATA pPebLdrData = nullptr;PLDR_DATA_TABLE_ENTRY pLdrDataEntry = nullptr;PLIST_ENTRY pListEntryStart = nullptr;PLIST_ENTRY pListEntryEnd = nullptr;SIZE_T ulTestSize = 0;SIZE_T ulRealSize = wcsnlen_s(lpFileName, MAX_PATH);
#ifdef _WIN64ULONGLONG ModuleSum = NULL;PPEB peb = (PPEB)__readgsqword(0x60);
#elseULONG ModuleSum = NULL;PPEB32 peb = (PPEB32)__readfsdword(0x30);
#endif__try {pPebLdrData = peb->Ldr;// 以模块加载顺序排列的链表pListEntryStart = pPebLdrData->InLoadOrderModuleList.Flink;pListEntryEnd = pPebLdrData->InLoadOrderModuleList.Blink;for (index = 0; pListEntryStart != pListEntryEnd; index++){pLdrDataEntry = CONTAINING_RECORD(pListEntryStart,LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);ulTestSize = wcsnlen_s(pLdrDataEntry->BaseDllName.Buffer, MAX_PATH);if (ulTestSize != ulRealSize || ulTestSize == MAX_PATH){pListEntryStart = pListEntryStart->Flink;continue;}if (!_wcsicmp(pLdrDataEntry->BaseDllName.Buffer, lpFileName)){if (bNewValue == TRUE){// 引用计数主要有两个成员,引用计数为 -1 表示静态加载的模块,// 并且不允许卸载pLdrDataEntry->DdagNode->LoadCount = 0xffffffff;pLdrDataEntry->ObsoleteLoadCount = 0xffff;}else {// 引用计数主要有两个成员,引用计数为 -1 表示静态加载的模块,// 并且不允许卸载pLdrDataEntry->DdagNode->LoadCount = 1;pLdrDataEntry->ObsoleteLoadCount = 1;}// ProcessStaticImport 位域如果为 1, 则任何卸载调用都将直接返回 TRUE// 而不做任何资源释放操作pLdrDataEntry->uFlags.ProcessStaticImport = bNewValue;bResponse |= 0x1;break;}pListEntryStart = pListEntryStart->Flink;}// 以内存位置排列的模块链表pListEntryStart = pPebLdrData->InMemoryOrderModuleList.Flink;pListEntryEnd = pPebLdrData->InMemoryOrderModuleList.Blink;for (index = 0; pListEntryStart != pListEntryEnd; index++){pLdrDataEntry = CONTAINING_RECORD(pListEntryStart,LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);ulTestSize = wcsnlen_s(pLdrDataEntry->BaseDllName.Buffer, MAX_PATH);if (ulTestSize != ulRealSize || ulTestSize == MAX_PATH){pListEntryStart = pListEntryStart->Flink;continue;}if (!_wcsicmp(pLdrDataEntry->BaseDllName.Buffer, lpFileName)){if (bNewValue == TRUE){pLdrDataEntry->DdagNode->LoadCount = 0xffffffff;pLdrDataEntry->ObsoleteLoadCount = 0xffff;}else {pLdrDataEntry->DdagNode->LoadCount = 1;pLdrDataEntry->ObsoleteLoadCount = 1;}pLdrDataEntry->uFlags.ProcessStaticImport = bNewValue;bResponse |= 0x2;break;}pListEntryStart = pListEntryStart->Flink;}// 以初始化顺序加载的模块列表pListEntryStart = pPebLdrData->InInitializationOrderModuleList.Flink;pListEntryEnd = pPebLdrData->InInitializationOrderModuleList.Blink;for (index = 0; pListEntryStart != pListEntryEnd; index++){pLdrDataEntry = CONTAINING_RECORD(pListEntryStart,LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);ulTestSize = wcsnlen_s(pLdrDataEntry->BaseDllName.Buffer, MAX_PATH);if (ulTestSize != ulRealSize || ulTestSize == MAX_PATH){pListEntryStart = pListEntryStart->Flink;continue;}if (!_wcsicmp(pLdrDataEntry->BaseDllName.Buffer, lpFileName)){if (bNewValue == TRUE){pLdrDataEntry->DdagNode->LoadCount = 0xffffffff;pLdrDataEntry->ObsoleteLoadCount = 0xffff;}else {pLdrDataEntry->DdagNode->LoadCount = 1;pLdrDataEntry->ObsoleteLoadCount = 1;}pLdrDataEntry->uFlags.ProcessStaticImport = bNewValue;bResponse |= 0x4;break;}pListEntryStart = pListEntryStart->Flink;}}__except (EXCEPTION_EXECUTE_HANDLER) {OutputDebugStringW(L"Er:Exception occurred while accessing memory.\n");return FALSE;}return bResponse;
}
这样,我们只需要在模块初始化和脱钩时,调用该函数就可以在进程中简单地保护/脱保护钩子模块。
总结&后记
文本浅析模块静态化技术这一项技术。是一种有效的实践。
发布于:2024.02.03;更新于:2024.02.03