[资料] http://www.cppblog.com/sleepwom/archive/2009/10/24/99375.html
在 HOOK SSDT Hide Process (五) R3 已经知道 ZwQuerySystemInformation 函数用来 enum 进程
那么现在看下 R0 的HOOK 函数实现先
从致是调用回 ntdll.dll 中的 ZwQuerySystemInformation 函数,取得返回值后,再把相关的数据过滤掉
编译后运行有问题,于是乎对程序作了一下修改,主要改了 MyZwQuerySystemInformation 函数
在判断到进程的名字是 taskmgr.exe 就把它改为 haha
运行后, 事与愿违, 并没有显示 haha, 而是显示为空
用 DebugView 显示调试信息
Q:为何在 taskmgr.exe 中会显示为空?疑问中
采用 HOOK SSDT Hide Process (五) 中的程序跟踪发现,taskmgr.exe 的 imagename.buffer 的地址居然是 0xb049480
这个地址显然不是应用层的地址,后果然后是不让访问了
于是改成用 memcpy
DbgPrint("before 0x%X %d %wZ\n", &(curr->ProcessName), curr->ProcessName.Length, &(curr->ProcessName));
//RtlInitUnicodeString(&(curr->ProcessName), L"fdsf");
memcpy(curr->ProcessName.Buffer, L"_root_", 12);
DbgPrint("after 0x%X %d %wZ\n", &(curr->ProcessName), curr->ProcessName.Length, &(curr->ProcessName));
结果,运行成功
taskmgr.exe 的 imagename 被成功修改为 _root_r.exe
产生新的问题:
Q: RtlInitUnicodeString 对 UNICODE_STRING 赋值是会同时分配缓冲区的空间?这一点查了MSDN,没看到有相关的说明
需要找时间去验证下
A: RtlInitUnicodeString() 这个函数它并不是直接去修改内存,而是重新分配一段缓冲区,而这段缓冲区在离开函数后就无效了
而用户传进来的 SystemInformation 指针,是一段连续的内存空间
Q: 用户区传进来的 SystemInformation 指针,是一段连续的内存空间,也就是说, 如果修改了 IMAGENAME 的内容,导致
原来 UNICODE_STRING.buffer 不足的话,那么需要把后面的 SystemInformation 都往后移?(这一点也需要找时间验证下)
比较保险的做法是,先执行系统的 ZwQuerySytemInformation 后,先把所有的 SystemInformation 都读出来,然后再分别写到
用户传进来的 SystemInformation 缓冲区。
A: 这个尝试过,不过蓝屏,需要找时间再仔细研究下
在 HOOK SSDT Hide Process (五) R3 已经知道 ZwQuerySystemInformation 函数用来 enum 进程
那么现在看下 R0 的HOOK 函数实现先
从致是调用回 ntdll.dll 中的 ZwQuerySystemInformation 函数,取得返回值后,再把相关的数据过滤掉
编译后运行有问题,于是乎对程序作了一下修改,主要改了 MyZwQuerySystemInformation 函数
在判断到进程的名字是 taskmgr.exe 就把它改为 haha
#include
"
ssdthook.h
"
#pragma pack( 1 )
typedef struct _SSDT_TABLE
{
PVOID ServiceTableBase;
PULONG ServiceCounterTableBase;
ULONG NumberOfService;
ULONG ParamTableBase;
}SSDT_TABLE, * PSSDT_TABLE;
#pragma pack()
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;
};
// ======================================================
typedef NTSTATUS (__stdcall * ZWQUERYSYSTEMINFORMATION)(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
NTSTATUS MyZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
// 定义全局变量
extern " C " extern PSSDT_TABLE KeServiceDescriptorTable;
ULONG OldAddress;
ZWQUERYSYSTEMINFORMATION OldZwQuerySystemInformation;
PVOID Base;
void UnHook();
VOID Unload (IN PDRIVER_OBJECT pDriverObject)
{
KdPrint(( " Enter DriverUnload\n " ));
UnHook(); // mark
}
NTSTATUS MyZwQuerySystemInformation(IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength) // 定义自己的Hook函数
{
NTSTATUS rc;
UNICODE_STRING process_name;
RtlInitUnicodeString( & process_name, L " taskmgr.exe " );
rc = (OldZwQuerySystemInformation) (
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength);
if (NT_SUCCESS(rc))
{
if ( 5 == SystemInformationClass)
{
struct _SYSTEM_PROCESSES * curr = ( struct _SYSTEM_PROCESSES * )SystemInformation;
while (curr)
{
if (RtlEqualUnicodeString( & process_name, & curr -> ProcessName, 1 ))
{
DbgPrint( " before %wZ\n " , & process_name);
RtlInitUnicodeString( & (curr -> ProcessName), L " haha " );
DbgPrint( " after %wZ\n " , & (curr -> ProcessName));
} // if (RtlEqualUnicodeString(&process_name, &curr->ProcessName, 1))
if (curr -> NextEntryDelta)
curr = (_SYSTEM_PROCESSES * )((ULONG)curr + curr -> NextEntryDelta);
else
curr = NULL;
} // while(curr)
} // if(5 == SystemInformationClass)
} // if(NT_SUCCESS(rc))
// KdPrint(("HookZwQuerySystemInformation is Succeessfully. \n"));
return rc;
}
VOID Hook()
{
DbgPrint( " Entry Hook()\n " );
OldAddress = (ULONG)KeServiceDescriptorTable -> ServiceTableBase + 4 * 0xAd ; // 用windbg反汇编查到zwquerysysteminformationde的ID号是0xADh
DbgPrint( " KeServiceDescriptorTable->ServiceTableBase is :0x%0x\n " ,KeServiceDescriptorTable -> ServiceTableBase);
// 保存原来函数的地址
OldZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION) * (ULONG * )OldAddress;
DbgPrint( " OldZwQuerySystemInformation is :0x%0x\n " , OldZwQuerySystemInformation);
DbgPrint( " MyZwQuerySystemInformation is :0x%0x\n " , MyZwQuerySystemInformation);
// 取消内存写保护
_asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
* (ULONG * )OldAddress = (ULONG) MyZwQuerySystemInformation; // mark MyZwQuerySystemInformation;
// 还原内存写保护
_asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
void UnHook()
{
ULONG Address;
Address = (ULONG) KeServiceDescriptorTable -> ServiceTableBase + 0xAD * 4 ;
__asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
* (ULONG * )Address = (ULONG) OldZwQuerySystemInformation;
__asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
DbgPrint( " Unhook leave!\n " );
}
// ========================驱动入口函数
extern " C " NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
{
DbgPrint( " Entry Hook Function!\n " );
pDriverObject -> DriverUnload = Unload;
Hook();
DbgPrint( " Leave DriverEntry!\n " );
return STATUS_SUCCESS;
}
#pragma pack( 1 )
typedef struct _SSDT_TABLE
{
PVOID ServiceTableBase;
PULONG ServiceCounterTableBase;
ULONG NumberOfService;
ULONG ParamTableBase;
}SSDT_TABLE, * PSSDT_TABLE;
#pragma pack()
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;
};
// ======================================================
typedef NTSTATUS (__stdcall * ZWQUERYSYSTEMINFORMATION)(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
NTSTATUS MyZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
// 定义全局变量
extern " C " extern PSSDT_TABLE KeServiceDescriptorTable;
ULONG OldAddress;
ZWQUERYSYSTEMINFORMATION OldZwQuerySystemInformation;
PVOID Base;
void UnHook();
VOID Unload (IN PDRIVER_OBJECT pDriverObject)
{
KdPrint(( " Enter DriverUnload\n " ));
UnHook(); // mark
}
NTSTATUS MyZwQuerySystemInformation(IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength) // 定义自己的Hook函数
{
NTSTATUS rc;
UNICODE_STRING process_name;
RtlInitUnicodeString( & process_name, L " taskmgr.exe " );
rc = (OldZwQuerySystemInformation) (
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength);
if (NT_SUCCESS(rc))
{
if ( 5 == SystemInformationClass)
{
struct _SYSTEM_PROCESSES * curr = ( struct _SYSTEM_PROCESSES * )SystemInformation;
while (curr)
{
if (RtlEqualUnicodeString( & process_name, & curr -> ProcessName, 1 ))
{
DbgPrint( " before %wZ\n " , & process_name);
RtlInitUnicodeString( & (curr -> ProcessName), L " haha " );
DbgPrint( " after %wZ\n " , & (curr -> ProcessName));
} // if (RtlEqualUnicodeString(&process_name, &curr->ProcessName, 1))
if (curr -> NextEntryDelta)
curr = (_SYSTEM_PROCESSES * )((ULONG)curr + curr -> NextEntryDelta);
else
curr = NULL;
} // while(curr)
} // if(5 == SystemInformationClass)
} // if(NT_SUCCESS(rc))
// KdPrint(("HookZwQuerySystemInformation is Succeessfully. \n"));
return rc;
}
VOID Hook()
{
DbgPrint( " Entry Hook()\n " );
OldAddress = (ULONG)KeServiceDescriptorTable -> ServiceTableBase + 4 * 0xAd ; // 用windbg反汇编查到zwquerysysteminformationde的ID号是0xADh
DbgPrint( " KeServiceDescriptorTable->ServiceTableBase is :0x%0x\n " ,KeServiceDescriptorTable -> ServiceTableBase);
// 保存原来函数的地址
OldZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION) * (ULONG * )OldAddress;
DbgPrint( " OldZwQuerySystemInformation is :0x%0x\n " , OldZwQuerySystemInformation);
DbgPrint( " MyZwQuerySystemInformation is :0x%0x\n " , MyZwQuerySystemInformation);
// 取消内存写保护
_asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
* (ULONG * )OldAddress = (ULONG) MyZwQuerySystemInformation; // mark MyZwQuerySystemInformation;
// 还原内存写保护
_asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
void UnHook()
{
ULONG Address;
Address = (ULONG) KeServiceDescriptorTable -> ServiceTableBase + 0xAD * 4 ;
__asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
* (ULONG * )Address = (ULONG) OldZwQuerySystemInformation;
__asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
DbgPrint( " Unhook leave!\n " );
}
// ========================驱动入口函数
extern " C " NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
{
DbgPrint( " Entry Hook Function!\n " );
pDriverObject -> DriverUnload = Unload;
Hook();
DbgPrint( " Leave DriverEntry!\n " );
return STATUS_SUCCESS;
}
运行后, 事与愿违, 并没有显示 haha, 而是显示为空
用 DebugView 显示调试信息
Entry Hook Function
!
Entry Hook()
KeServiceDescriptorTable -> ServiceTableBase is : 0x804e2d20
OldZwQuerySystemInformation is : 0x8057cc27
MyZwQuerySystemInformation is : 0xf8ed4080
Leave DriverEntry !
before taskmgr.exe
after haha
Entry Hook()
KeServiceDescriptorTable -> ServiceTableBase is : 0x804e2d20
OldZwQuerySystemInformation is : 0x8057cc27
MyZwQuerySystemInformation is : 0xf8ed4080
Leave DriverEntry !
before taskmgr.exe
after haha
Q:为何在 taskmgr.exe 中会显示为空?疑问中
采用 HOOK SSDT Hide Process (五) 中的程序跟踪发现,taskmgr.exe 的 imagename.buffer 的地址居然是 0xb049480
这个地址显然不是应用层的地址,后果然后是不让访问了
于是改成用 memcpy
DbgPrint("before 0x%X %d %wZ\n", &(curr->ProcessName), curr->ProcessName.Length, &(curr->ProcessName));
//RtlInitUnicodeString(&(curr->ProcessName), L"fdsf");
memcpy(curr->ProcessName.Buffer, L"_root_", 12);
DbgPrint("after 0x%X %d %wZ\n", &(curr->ProcessName), curr->ProcessName.Length, &(curr->ProcessName));
结果,运行成功
taskmgr.exe 的 imagename 被成功修改为 _root_r.exe
产生新的问题:
Q: RtlInitUnicodeString 对 UNICODE_STRING 赋值是会同时分配缓冲区的空间?这一点查了MSDN,没看到有相关的说明
需要找时间去验证下
A: RtlInitUnicodeString() 这个函数它并不是直接去修改内存,而是重新分配一段缓冲区,而这段缓冲区在离开函数后就无效了
而用户传进来的 SystemInformation 指针,是一段连续的内存空间
Q: 用户区传进来的 SystemInformation 指针,是一段连续的内存空间,也就是说, 如果修改了 IMAGENAME 的内容,导致
原来 UNICODE_STRING.buffer 不足的话,那么需要把后面的 SystemInformation 都往后移?(这一点也需要找时间验证下)
比较保险的做法是,先执行系统的 ZwQuerySytemInformation 后,先把所有的 SystemInformation 都读出来,然后再分别写到
用户传进来的 SystemInformation 缓冲区。
A: 这个尝试过,不过蓝屏,需要找时间再仔细研究下