核态获取PsLoadedModuleList地址的稳定方法

本文介绍了在Windows环境下,如何在内核态稳定地获取PsLoadedModuleList地址的方法,此链表包含了系统加载的所有内核模块信息,对于AntiRootkit等应用场景至关重要。文中提供了具体的实现代码,并针对不同版本的Windows系统进行了测试。
    PsLoadedModuleList是Windows加载的所有内核模块构成的链表的表头,利用它可以枚举所有这些模块的信息,这些信息可用在AntiRootkit等方面。
    由于Windows 2003 Server SP1开始不再支持用户态访问Physical Memory,所以我这介绍一种在内核态获取PsLoadedModuleList地址的稳定方法。次方法已在Windows XP SP2和Windows 2003 SP1下测试通过。
    代码如下:
   

typedef struct _LDR_DATA_TABLE_ENTRY {
    LIST_ENTRY InLoadOrderLinks;
    LIST_ENTRY InMemoryOrderLinks;
    LIST_ENTRY InInitializationOrderLinks;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT TlsIndex;
    union {
        LIST_ENTRY HashLinks;
        struct {
            PVOID SectionPointer;
            ULONG CheckSum;
        };
    };
    union {
        struct {
            ULONG TimeDateStamp;
        };
        struct {
            PVOID LoadedImports;
        };
    };
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

extern PLIST_ENTRY g_PsLoadedModuleList   ;
PLIST_ENTRY FindPsLoadedModuleList (IN PDRIVER_OBJECT DriverObject)
{
    PLDR_DATA_TABLE_ENTRY pModuleCurrent = NULL;
    PLDR_DATA_TABLE_ENTRY PsLoadedModuleList = NULL;

    if (DriverObject == NULL)
        return 0;

    pModuleCurrent = *((PLDR_DATA_TABLE_ENTRY*)(DriverObject->DriverSection));
    if (pModuleCurrent == NULL)
        return 0;

    PsLoadedModuleList = pModuleCurrent;

    while ((PLDR_DATA_TABLE_ENTRY)pModuleCurrent->InLoadOrderLinks.Flink != PsLoadedModuleList)
    {
        if (((pModuleCurrent->SizeOfImage == 0x00000000)
              && (pModuleCurrent->FullDllName.Length == 0))
              || (pModuleCurrent->FullDllName.Buffer == NULL))
        {
            return (PLIST_ENTRY) pModuleCurrent;
        }

         pModuleCurrent = (PLDR_DATA_TABLE_ENTRY)pModuleCurrent->InLoadOrderLinks.Flink;
    }

    return NULL;
}

    我在测试中发现了这样一个有趣的现象,在Windows 2003 Server SP1下PsLoadedModuleList满足((pModuleCurrent->SizeOfImage == 0x00000000) && (pModuleCurrent->FullDllName.Length == 0))而在WindowXP SP2PsLoadedModuleList满足(pModuleCurrent->FullDllName.Buffer == NULL)。

  转载请注明出处!

隐藏驱动程序或以无痕模式加载驱动程序是Windows开发和安全研究中的一个高级主题,通常涉及对操作系统底层机制的深入理解。以下是一些常见的技术手段,但需要注意的是,这些方法可能违反操作系统使用协议或被安全软件视为恶意行为,因此仅限于合法授权的研究或测试环境中使用。 ### 3. 驱动隐藏与无痕加载的心技术 #### 从PsLoadedModuleList中移除驱动 Windows系统维护了一个名为`PsLoadedModuleList`的双向链表,用于记录所有已加载的驱动模块。通过修改该链表结构,可以将特定驱动从列表中摘除,从而在一些依赖此链表获取驱动信息的工具中“消失”。 - 每个驱动对象的`DriverSection`字段指向一个`_LDR_DATA_TABLE_ENTRY`结构。 - 该结构中包含多个链表指针(如`InLoadOrderLinks`、`InMemoryOrderLinks`等),其中`InLoadOrderLinks`决定了驱动在`PsLoadedModuleList`中的位置。 - 修改此链表指针使其前向与后向节点相互连接,即可将当前驱动节点从链表中移除[^1]。 ```c // 示例伪代码:从 PsLoadedModuleList 中移除驱动 PLIST_ENTRY pListEntry = (PLIST_ENTRY)pLdrDataTableEntry->InLoadOrderLinks.Flink; pListEntry->Blink->Flink = pListEntry->Flink; pListEntry->Flink->Blink = pListEntry->Blink; ``` #### 不注册DriverObject 标准驱动程序加载时会调用`DriverEntry`函数,并通过`ZwSetSystemInformation`或其他方式注册自身。如果希望实现“无痕”加载,则可以在驱动入口点直接跳过注册过程,甚至不创建完整的`DRIVER_OBJECT`结构。 - 可通过自定义加载器将驱动映像直接映射到内空间。 - 手动解析PE结构并完成重定位、导入表修复等工作。 - 调用驱动入口点时传递伪造的`PDRIVER_OBJECT`参数,或者根本不调用`DriverEntry`。 #### 使用内级Hook技术 另一种实现无痕加载的方式是利用内级别的钩子(Hook)技术,拦截系统调用或中断处理流程,从而在不注册驱动的情况下执行任意代码。 - Hook `KiSystemServiceTable` 中的服务例程,例如替换`NtLoadDriver`。 - 利用IRP(I/O Request Packet)机制劫持其他驱动的请求流。 - 使用Inline Hook或SSDT Hook等技术改变执行路径。 #### 内存映像直接注入 类似于用户的DLL注入,内也可以将驱动代码直接注入到另一个合法驱动的内存空间中执行。 - 查找目标驱动的内存映像基址。 - 分配非分页池内存并将驱动代码复制进去。 - 修改目标驱动的某些回调函数指针(如IRP MajorFunction)指向注入代码。 --- ### 注意事项 - 上述方法均属于高级内编程范畴,需具备扎实的Windows驱动开发知识。 - 实施过程中可能导致系统不稳定、蓝屏甚至无法启动。 - 现代Windows版本(如Win10/Win11)引入了签名验证、PatchGuard等保护机制,增加了隐藏驱动的难度。 - 合法用途应严格限定于安全研究、逆向工程教学等场景。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值