最近有在作一个东西,须要在ring0下拦截进程启动并注入DLL(dll用于hook ring3下的API),不少种实现方法,此处采用sudami大神提供的思路,另外一位大侠提供的参考代码。虽然这个东西没什么技术含量,但对于我这种刚入门内核的人仍是搞了好久才作出来,蓝屏不少,要注意不少细节.多线程
思路:进程建立完时是一个空水壶,里面没有沸腾的热水(threads),因而系统调用NtCreateThread建立其主线程(给空水壶注水 – 凉水),在这个暂停的线程里面折腾了一阵后完事了也厌倦了,因而系统跳了出来,回到进程空间中,调用Kernel32.dll去通知CSRSS.EXE,对它说:“这里有一个新进程出生了,你在你的表里标记一下”。而后就开始加载DLL啦,把系统KnownDLLs中的本身须要的DLL都Map一份到这个大水壶中。接着KiThreadStartup加热水壶中的凉水,因而水就开始沸腾了,此时主线程开始工做。。。
拦截NtCreateThread,取得当前线程上下文,保存它要返回的地址(会回到空水壶中去),劫持为咱们本身分配的地址,在其中填充ShellCode来加载目的DLL。至于选择Buffer,思路不少。这里可简单的Attach到当前进程,在充足的虚拟2GB进程地址空间中分配属于你本身的一块小内存,够放ShellCode足矣。示意图以下:spa
代码:写的很丑线程
NTSTATUS MyNtCreateThread ( OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle, OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, IN PHANDLE InitialTeb, IN BOOLEAN CreateSuspended ) { pfnNtCreateThread oldNtCreateThread = (pfnNtCreateThread)SystemServiceAddr[ServiceCreateThreadID]; if(IsHandleExist(ProcessHandle)){ CHAR ProcessName[16]; NTSTATUS ObjectStatus; PRKPROCESS pProcess; POBJECT_TYPE PsProcessType; NTSTATUS ResultStatus; DbgPrint( "CreateThread(%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x)\n", ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, ClientId, ThreadContext, InitialTeb, CreateSuspended); PsProcessType = NULL; ///得到EPROCESS对象 ObjectStatus = ObReferenceObjectByHandle( ProcessHandle, PROCESS_ALL_ACCESS, PsProcessType, UserMode, (PVOID *)&pProcess, NULL); if (ObjectStatus ==STATUS_SUCCESS) { //ProcessName = (CHAR*)pProcess+0x174; RtlStringCbCopyA(ProcessName,16,(CHAR*)pProcess+0x174); _strlwr(ProcessName);//进程名转换为小写 if(strstr(ProcessName,Iexplore)) { NTSTATUS AllocStatus; UCHAR * BaseAddr; SIZE_T RegionSize; ULONG Win32StartAddr; ULONG LoadLibraryAddr; RegionSize = 100; BaseAddr = NULL; PsProcessType = NULL; KAPC_STATE apcstate; LoadLibraryAddr = g_addrinfo.LoadLibraryAddr; if(ThreadContext) { Win32StartAddr = ThreadContext->Eax; if (!Win32StartAddr) { DbgPrint("Win32StartAddr not set\n"); } else { //切换上下文 KeDetachProcess(); KeAttachProcess(pProcess); //allocating memory with PAGE_EXECUTE_READWRITE access rights // KeUnstackDetachProcess(&apcstate); // KeStackAttachProcess(pProcess,&apcstate); AllocStatus = ZwAllocateVirtualMemory( NtCurrentProcess(), (PVOID*)&BaseAddr, 0, &RegionSize, MEM_COMMIT , PAGE_EXECUTE_READWRITE); if (AllocStatus!=STATUS_SUCCESS) { DbgPrint("Fail to Allocate memory! AllocStatus = 0x%x\n",AllocStatus); } else { ULONG Offset = 0; ULONG OffsetStrAddr = 0; DbgPrint("Memory allocation OK! BaseAddr = 0x%x\n",BaseAddr); BaseAddr[Offset] = 0x68; //push 0xXXXXXXXX ++Offset; OffsetStrAddr = Offset; Offset += 4; BaseAddr[Offset] = 0xbb; //mov ebx,LoadLibraryAddr ++Offset; *(ULONG *)(BaseAddr+Offset) = LoadLibraryAddr; Offset += 4; BaseAddr[Offset] = 0xff; //call ebx ++Offset; BaseAddr[Offset] = 0xd3; ++Offset; BaseAddr[Offset] = 0xb8; //mov eax,Win32StartAddr ++Offset; *(ULONG *)(BaseAddr+Offset) = Win32StartAddr; Offset += 4; BaseAddr[Offset] = 0x50; //push eax ++Offset; BaseAddr[Offset] = 0xc3; //ret ++Offset; *(ULONG *)(BaseAddr+OffsetStrAddr) = (ULONG)(BaseAddr + Offset); // parameter for LoadLibrary //tSetKey.dll //memcpy(BaseAddr+Offset,"tSetKey.dll",strlen("tSetKey.dll")+1); memcpy(BaseAddr+Offset,g_addrinfo.DllPath,sizeof(g_addrinfo.DllPath)); DbgPrint("<EAX:0x%08x>\n",Win32StartAddr); Win32StartAddr = (ULONG)BaseAddr; }//end ZwAllocateVirtualMemory //切换上下文 KeDetachProcess(); ///设置Win32StartAddr ThreadContext->Eax = Win32StartAddr; } }//end ThreadConext ObDereferenceObject(pProcess); }//end strstr RemoveHandle(ProcessHandle); }//end obj else { DbgPrint(("Fail to RefernceObject. Stopping Injecting Technique.\n")); } }//end Ishandleexist; return oldNtCreateThread(ThreadHandle,DesiredAccess,ObjectAttributes,ProcessHandle,ClientId,ThreadContext,InitialTeb,CreateSuspended); }
对于一个进程的多线程环境 ,这里用一个链表来维护进程句柄,同时hook zwcreateprocessex,在里面添加句柄,在createthread里删除.code