最近有在做一个东西,需要在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足矣。
代码:写的很丑
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里删除.