R3 下动态加载的模块的保护(一)

前言

在 R3 下防护动态加载的模块不被意外卸载需要很多的策略,比如:LDR 断链、VAD 记录擦除、PE 头擦除、修改入口函数、内存注入等。文本我们将浅析模块静态化技术这一项技术。模块静态化是一个很常见的模块保护技术,它通过修改模块的引用计数为 -1,来使得模块不可被标准的 API 成功卸载。

系列文章:

  1. R3 下动态加载的模块的保护(一):分析模块伪静态化技术 [本文]
  2. R3 下动态加载的模块的保护(二):分析重映射擦除 VAD 信息[暂未发布]
  3. 更多  ... ... 

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 _WIN64
    PPEB_LDR_DATA64 pPebLdrData = NULL;
    ULONGLONG ModuleSum = NULL;
    PPEB64 peb = (PPEB64)__readgsqword(0x60);
#else
    PPEB_LDR_DATA32 pPebLdrData = NULL;
    ULONG ModuleSum = NULL;
    PPEB32 peb = (PPEB32)__readfsdword(0x30);
#endif

而对于 PEB 结构体,微软是没有公开文档的,需要自己进行重定义(原始结构体定义中缺少我们需要的部分),经查阅逆向文献,得到如下的结构体定义(部分不需要用到的成员已经被截断):

typedef struct _PEB_LDR_DATA32
{
    ULONG Length; // +0x00
    BOOLEAN Initialized; // +0x04
    PVOID SsHandle; // +0x08
    LIST_ENTRY InLoadOrderModuleList; // +0x0c
    LIST_ENTRY InMemoryOrderModuleList; // +0x14
    LIST_ENTRY InInitializationOrderModuleList;// +0x1c
} PEB_LDR_DATA32, * PPEB_LDR_DATA32; // +0x24


typedef struct _PEB32
{
    UCHAR InheritedAddressSpace;                                            //0x0
    UCHAR ReadImageFileExecOptions;                                         //0x1
    UCHAR BeingDebugged;                                                    //0x2
    union
    {
        UCHAR BitField;                                                     //0x3
        struct
        {
            UCHAR ImageUsesLargePages : 1;                                    //0x3
            UCHAR IsProtectedProcess : 1;                                     //0x3
            UCHAR IsImageDynamicallyRelocated : 1;                            //0x3
            UCHAR SkipPatchingUser32Forwarders : 1;                           //0x3
            UCHAR IsPackagedProcess : 1;                                      //0x3
            UCHAR IsAppContainer : 1;                                         //0x3
            UCHAR IsProtectedProcessLight : 1;                                //0x3
            UCHAR IsLongPathAwareProcess : 1;                                 //0x3
        };
    };
    PVOID Mutant;                                                           //0x4
    PVOID ImageBaseAddress;                                                 //0x8
    PEB_LDR_DATA32* Ldr;                                              //0xc
    RTL_USER_PROCESS_PARAMETERS* ProcessParameters;                 //0x10
    PVOID SubSystemData;                                                    //0x14
    PVOID ProcessHeap;                                                      //0x18
    RTL_CRITICAL_SECTION* FastPebLock;                              //0x1c
    SLIST_HEADER* volatile AtlThunkSListPtr;                         //0x20
    PVOID IFEOKey;                                                          //0x24
} PEB32, * PPEB32;

typedef struct _STRING64
{
    USHORT Length;                                                          //0x0
    USHORT MaximumLength;                                                   //0x2
    ULONGLONG Buffer;                                                       //0x8
}STRING64, * LPSTRING64;

typedef struct _PEB_LDR_DATA64
{
    ULONG Length;                                                           //0x0
    UCHAR Initialized;                                                      //0x4
    PVOID SsHandle;                                                         //0x8
    LIST_ENTRY InLoadOrderModuleList;                               //0x10
    LIST_ENTRY InMemoryOrderModuleList;                             //0x20
    LIST_ENTRY InInitializationOrderModuleList;                     //0x30
    PVOID EntryInProgress;                                                  //0x40
    UCHAR ShutdownInProgress;                                               //0x48
    PVOID ShutdownThreadId;                                                 //0x50
}PEB_LDR_DATA64, *PPEB_LDR_DATA64;

typedef struct _PEB64
{
    UCHAR InheritedAddressSpace;                                            //0x0
    UCHAR ReadImageFileExecOptions;                                         //0x1
    UCHAR BeingDebugged;                                                    //0x2
    union
    {
        UCHAR BitField;                                                     //0x3
        struct
        {
            UCHAR ImageUsesLargePages : 1;                                    //0x3
            UCHAR IsProtectedProcess : 1;                                     //0x3
            UCHAR IsImageDynamicallyRelocated : 1;                            //0x3
            UCHAR SkipPatchingUser32Forwarders : 1;                           //0x3
            UCHAR IsPackagedProcess : 1;                                      //0x3
            UCHAR IsAppContainer : 1;                                         //0x3
            UCHAR IsProtectedProcessLight : 1;                                //0x3
            UCHAR IsLongPathAwareProcess : 1;                                 //0x3
        };
    };
    UCHAR Padding0[4];                                                      //0x4
    ULONGLONG Mutant;                                                       //0x8
    ULONGLONG ImageBaseAddress;                                             //0x10
    PEB_LDR_DATA64* Ldr;                                                          //0x18
    ULONGLONG ProcessParameters;                                            //0x20
    ULONGLONG SubSystemData;                                                //0x28
    ULONGLONG ProcessHeap;                                                  //0x30
    ULONGLONG FastPebLock;                                                  //0x38
    ULONGLONG AtlThunkSListPtr;                                             //0x40
    ULONGLONG 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;                                                           //0x0
    UCHAR Initialized;                                                      //0x4
    PVOID SsHandle;                                                         //0x8
    LIST_ENTRY InLoadOrderModuleList;                               //0x10
    LIST_ENTRY InMemoryOrderModuleList;                             //0x20
    LIST_ENTRY InInitializationOrderModuleList;                     //0x30
    PVOID EntryInProgress;                                                  //0x40
    UCHAR ShutdownInProgress;                                               //0x48
    PVOID 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 
#include 
//#include 

// Kernels | x64 | Windows 10 | 2016 | 2210 22H2(May 2023 Update)

//0x18 bytes (sizeof)
typedef struct _RTL_BALANCED_NODE
{
    union
    {
        _RTL_BALANCED_NODE* Children[2];                             //0x0
        struct
        {
            _RTL_BALANCED_NODE* Left;                                //0x0
            _RTL_BALANCED_NODE* Right;                               //0x8
        };
    };
    union
    {
        struct
        {
            UCHAR Red : 1;                                                    //0x10
            UCHAR 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;                                           //0x0
    ULONG 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;                                                     //0x0
    PLDR_SERVICE_TAG_RECORD ServiceTagList;                                 //0x10
    ULONG LoadCount;                                                        //0x18
    ULONG LoadWhileUnloadingCount;                                          //0x1c
    ULONG LowestLink;                                                       //0x20
    LDRP_CSLIST Dependencies;                                               //0x28
    LDRP_CSLIST IncomingDependencies;                                       //0x30
    LDR_DDAG_STATE State;                                                   //0x38
    SINGLE_LIST_ENTRY CondenseLink;                                         //0x40
    ULONG 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;                                            //0x0
    LIST_ENTRY InMemoryOrderLinks;                                          //0x10
    LIST_ENTRY InInitializationOrderLinks;                                  //0x20
    VOID* DllBase;                                                          //0x30
    VOID* EntryPoint;                                                       //0x38
    ULONG SizeOfImage;                                                      //0x40
    UNICODE_STRING FullDllName;                                             //0x48
    UNICODE_STRING BaseDllName;                                             //0x58
    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;
    };
    USHORT ObsoleteLoadCount;                                               //0x6c
    USHORT TlsIndex;                                                        //0x6e
    LIST_ENTRY HashLinks;                                                   //0x70
    ULONG TimeDateStamp;                                                    //0x80
    struct ACTIVATION_CONTEXT* EntryPointActivationContext;                 //0x88
    VOID* Lock;                                                             //0x90
    LDR_DDAG_NODE* DdagNode;                                                //0x98
    LIST_ENTRY NodeModuleLink;                                              //0xa0
    struct LDRP_LOAD_CONTEXT* LoadContext;                                  //0xb0
    VOID* ParentDllBase;                                                    //0xb8
    VOID* SwitchBackContext;                                                //0xc0
    RTL_BALANCED_NODE BaseAddressIndexNode;                                 //0xc8
    RTL_BALANCED_NODE MappingInfoIndexNode;                                 //0xe0
    ULONGLONG OriginalBase;                                                 //0xf8
    LARGE_INTEGER LoadTime;                                                 //0x100
    ULONG BaseNameHashValue;                                                //0x108
    LDR_DLL_LOAD_REASON LoadReason;                                         //0x10c
    ULONG ImplicitPathOptions;                                              //0x110
    ULONG ReferenceCount;                                                   //0x114
    ULONG DependentLoadFlags;                                               //0x118
    UCHAR SigningLevel;                                                     //0x11c
}LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;


//0x58 bytes (sizeof)
typedef struct _PEB_LDR_DATA32
{
    ULONG Length; // +0x00
    BOOLEAN Initialized; // +0x04
    PVOID SsHandle; // +0x08
    LIST_ENTRY InLoadOrderModuleList; // +0x0c
    LIST_ENTRY InMemoryOrderModuleList; // +0x14
    LIST_ENTRY InInitializationOrderModuleList;// +0x1c
} PEB_LDR_DATA32, * PPEB_LDR_DATA32; // +0x24


typedef struct _PEB32
{
    UCHAR InheritedAddressSpace;                                            //0x0
    UCHAR ReadImageFileExecOptions;                                         //0x1
    UCHAR BeingDebugged;                                                    //0x2
    union
    {
        UCHAR BitField;                                                     //0x3
        struct
        {
            UCHAR ImageUsesLargePages : 1;                                    //0x3
            UCHAR IsProtectedProcess : 1;                                     //0x3
            UCHAR IsImageDynamicallyRelocated : 1;                            //0x3
            UCHAR SkipPatchingUser32Forwarders : 1;                           //0x3
            UCHAR IsPackagedProcess : 1;                                      //0x3
            UCHAR IsAppContainer : 1;                                         //0x3
            UCHAR IsProtectedProcessLight : 1;                                //0x3
            UCHAR IsLongPathAwareProcess : 1;                                 //0x3
        };
    };
    PVOID Mutant;                                                           //0x4
    PVOID ImageBaseAddress;                                                 //0x8
    PEB_LDR_DATA32* Ldr;                                                    //0xc
    struct RTL_USER_PROCESS_PARAMETERS* ProcessParameters;                  //0x10
    PVOID SubSystemData;                                                    //0x14
    PVOID ProcessHeap;                                                      //0x18
    RTL_CRITICAL_SECTION* FastPebLock;                                      //0x1c
    SLIST_HEADER* volatile AtlThunkSListPtr;                                //0x20
    PVOID IFEOKey;                                                          //0x24
} PEB32, * PPEB32;

typedef struct _STRING64
{
    USHORT Length;                                                          //0x0
    USHORT MaximumLength;                                                   //0x2
    ULONGLONG Buffer;                                                       //0x8
}STRING64, * LPSTRING64;

typedef struct _PEB_LDR_DATA64
{
    ULONG Length;                                                           //0x0
    UCHAR Initialized;                                                      //0x4
    PVOID SsHandle;                                                         //0x8
    LIST_ENTRY InLoadOrderModuleList;                                       //0x10
    LIST_ENTRY InMemoryOrderModuleList;                                     //0x20
    LIST_ENTRY InInitializationOrderModuleList;                             //0x30
    PVOID EntryInProgress;                                                  //0x40
    UCHAR ShutdownInProgress;                                               //0x48
    PVOID ShutdownThreadId;                                                 //0x50
}PEB_LDR_DATA64, * PPEB_LDR_DATA64;

typedef struct _PEB64
{
    UCHAR InheritedAddressSpace;                                            //0x0
    UCHAR ReadImageFileExecOptions;                                         //0x1
    UCHAR BeingDebugged;                                                    //0x2
    union
    {
        UCHAR BitField;                                                     //0x3
        struct
        {
            UCHAR ImageUsesLargePages : 1;                                    //0x3
            UCHAR IsProtectedProcess : 1;                                     //0x3
            UCHAR IsImageDynamicallyRelocated : 1;                            //0x3
            UCHAR SkipPatchingUser32Forwarders : 1;                           //0x3
            UCHAR IsPackagedProcess : 1;                                      //0x3
            UCHAR IsAppContainer : 1;                                         //0x3
            UCHAR IsProtectedProcessLight : 1;                                //0x3
            UCHAR IsLongPathAwareProcess : 1;                                 //0x3
        };
    };
    UCHAR Padding0[4];                                                      //0x4
    ULONGLONG Mutant;                                                       //0x8
    ULONGLONG ImageBaseAddress;                                             //0x10
    PEB_LDR_DATA64* Ldr;                                                    //0x18
    ULONGLONG ProcessParameters;                                            //0x20
    ULONGLONG SubSystemData;                                                //0x28
    ULONGLONG ProcessHeap;                                                  //0x30
    ULONGLONG FastPebLock;                                                  //0x38
    ULONGLONG AtlThunkSListPtr;                                             //0x40
    ULONGLONG 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 _WIN64
    ULONGLONG ModuleSum = NULL;
    PPEB peb = (PPEB)__readgsqword(0x60);
#else
    ULONG 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

你可能感兴趣的:(单片机,stm32,嵌入式硬件)