Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
驱动对象(驱动隐藏技术)
1._DRIVER_OBJECT结构体
2. xx.sys中的INIT节区
3. DriverObject.DriverSection节区
4. 遍历全部驱动
5. 驱动隐藏
6. 更进一步的驱动隐藏技巧
7. 总结
1._DRIVER_OBJECT结构体
2. xx.sys中的INIT节区
DriverObject.DriverInit 其就启动该节区中的代码,但是该节区启动之后就会自动删除。
在调试时应该注意,使用IDA查看在节区的函数但是无法动态调试。
3. DriverObject.DriverSection节区
该节区指向 _LDR_DATA_ENTRY_TABLE结构体,保存着该驱动的有关信息。
同时其存在三个双向链表,可以用其来遍历全部驱动。
//0x50 bytes (sizeof)
typedef struct _LDR_DATA_TABLE_ENTRY
{
struct _LIST_ENTRY InLoadOrderLinks; //0x0
struct _LIST_ENTRY InMemoryOrderLinks; //0x8
struct _LIST_ENTRY InInitializationOrderLinks; //0x10
VOID* DllBase; //0x18
VOID* EntryPoint; //0x1c
ULONG SizeOfImage; //0x20
struct _UNICODE_STRING FullDllName; //0x24
struct _UNICODE_STRING BaseDllName; //0x2c
ULONG Flags; //0x34
USHORT LoadCount; //0x38
USHORT TlsIndex; //0x3a
union
{
struct _LIST_ENTRY HashLinks; //0x3c
struct
{
VOID* SectionPointer; //0x3c
ULONG CheckSum; //0x40
};
};
union
{
ULONG TimeDateStamp; //0x44
VOID* LoadedImports; //0x44
};
VOID* EntryPointActivationContext; //0x48
VOID* PatchInformation; //0x4c
}LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;
4. 遍历全部驱动
#include <ntddk.h> #include <intrin.h> #include <ntstrsafe.h> //0x50 bytes (sizeof) typedef struct _LDR_DATA_TABLE_ENTRY { struct _LIST_ENTRY InLoadOrderLinks; //0x0 struct _LIST_ENTRY InMemoryOrderLinks; //0x8 struct _LIST_ENTRY InInitializationOrderLinks; //0x10 VOID* DllBase; //0x18 VOID* EntryPoint; //0x1c ULONG SizeOfImage; //0x20 struct _UNICODE_STRING FullDllName; //0x24 struct _UNICODE_STRING BaseDllName; //0x2c ULONG Flags; //0x34 USHORT LoadCount; //0x38 USHORT TlsIndex; //0x3a union { struct _LIST_ENTRY HashLinks; //0x3c struct { VOID* SectionPointer; //0x3c ULONG CheckSum; //0x40 }; }; union { ULONG TimeDateStamp; //0x44 VOID* LoadedImports; //0x44 }; VOID* EntryPointActivationContext; //0x48 VOID* PatchInformation; //0x4c }LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY; VOID DriverUnload(_In_ struct _DRIVER_OBJECT* DriverObject) { DbgPrint("%s ", "驱动卸载成功"); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath) { DbgPrint("地址:%x", pDriver); pDriver->DriverUnload = DriverUnload; PLDR_DATA_TABLE_ENTRY pList = (PLDR_DATA_TABLE_ENTRY)pDriver->DriverSection; PLDR_DATA_TABLE_ENTRY pNext = pList->InLoadOrderLinks.Flink; DbgPrint("%wZ ", &pList->BaseDllName); // 输出本地驱动名字 // 双向链表,如果到结尾则返回头部 while (pList != pNext) { DbgPrint("%wZ ", &pNext->BaseDllName); pNext = pNext->InLoadOrderLinks.Flink; // 输出下一个驱动名字 } return STATUS_SUCCESS; }
5. 驱动隐藏
我们采用最基本的断链来测试一下:
PLDR_DATA_TABLE_ENTRY pList = (PLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;
RemoveEntryList((PLIST_ENTRY)pList);
如果我们采用上面那种遍历方法自然遍历不到,但是如果使用PcHunter等工具来查看,则明显无法删除干净。
6. 更进一步的驱动隐藏技巧(代码2-4)
我们下面使用MiProcessLoaderEntry内核函数来实现驱动隐藏效果。
1)在IDA中定位其特征码
2)特征码搜索在内核函数中
3)调用内核函数将该链表从节区中移除
调用内核函数移除之后,我门将该节区的Section指向下一个,之后再用PcHunter扫描其结果如下。
4)对于节区属性更进一步清空
上面那步之后,我们还可以发现其有关属性,我们下面对其属性进一步清空。
5)在驱动卸载时恢复
我们在发现卸载驱动时,恢复Section节区,然后调用函数在挂在链表中,让系统自动卸载。
7. 总结
首先,我们发现其并没有完全成功绕过PcHunter,我们之后会利用内存加载,句柄表等知识进一步完善驱动隐藏技术。
对于驱动隐藏,要知道我们分析某些程序时是反PcHunter,其会不断扫描链表发现有PcHunter等工具,然后结束自身进程(另外还有OD等),我们可以利用该策略隐藏自己的PcHunter。