阅读:3659回复:4
驱动中给进程注入DLL,模拟GlobaHook,不完整,某些情况下报错
利用 PsSetLoadImageNotifyRoutine 设置回调,等有镜像被加载的时候,根据进程PID获取基址,然后和镜像基址对比,
如果相同,则加载的是进程EXE的镜像,这个时候通过修改镜像头中的导入表 来注入DLL。 修改导入表部分的代码,是修改的MS的detours库来的。 经过测试大部分进程注入都没问题,碰到一些比较特殊的进程运行的时候会报错,请教高手。。。 一下是核心代码: //获取进程基址 PVOID GetProcessBaseAddress(IN HANDLE PID) { NTSTATUS status; HANDLE hProcess = NULL; CLIENT_ID clientid; OBJECT_ATTRIBUTES ObjectAttributes; PPROCESS_BASIC_INFORMATION pProcessBaseInfo; ULONG returnedLength; PMY_PEB Peb; PVOID ImageBase = NULL; if(KeGetCurrentIrql() >= DISPATCH_LEVEL) { return ImageBase; } InitializeObjectAttributes(&ObjectAttributes, 0, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, 0, 0); clientid.UniqueProcess = PID; clientid.UniqueThread = 0; //通过PID获得进程句柄 status = ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &ObjectAttributes, &clientid); if(!NT_SUCCESS(status)) { DbgPrint("[GetProcessBaseAddress] ZwOpenProcess 调用失败\n"); return ImageBase; } pProcessBaseInfo = (PPROCESS_BASIC_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESS_BASIC_INFORMATION), 'sam1'); if (pProcessBaseInfo == NULL) { DbgPrint("[GetProcessBaseAddress]ExAllocatePoolWithTag 分配内存失败\n"); ZwClose(hProcess); return ImageBase; } RtlZeroMemory(pProcessBaseInfo, sizeof(PROCESS_BASIC_INFORMATION)); //获得文件镜像名 status = ZwQueryInformationProcess(hProcess, ProcessBasicInformation, pProcessBaseInfo, sizeof(PROCESS_BASIC_INFORMATION), &returnedLength); if(NT_SUCCESS(status)) { Peb = (PMY_PEB)pProcessBaseInfo->PebBaseAddress; ImageBase = Peb->Reserved3[1]; } else { DbgPrint("[GetProcessBaseAddress]2.ZwQueryInformationProcess 调用失败\n"); } ZwClose(hProcess); ExFreePool(pProcessBaseInfo); return ImageBase; } //----------------------------------------------------------------------------------------------------- //--------------------------------------- ULONG PadToDword(ULONG dw) { return (dw + 3) & ~3u; } ULONG PadToDwordPtr(ULONG dw) { return (dw + 7) & ~7u; } BOOLEAN StringCchCopyA(CHAR *pszDest, size_t cchDest, const CHAR *pszSrc) { BOOLEAN hr = TRUE; if (cchDest == 0) { hr = FALSE; } else { while (cchDest && (*pszSrc != '\0')) { *pszDest++ = *pszSrc++; cchDest--; } if (cchDest == 0) { // we are going to truncate pszDest pszDest--; hr = FALSE; } *pszDest= '\0'; } return hr; } //修改导入表注入DLL BOOLEAN XXXXXDLL(IN HANDLE ProcessId, IN PVOID pImageBase, PCHAR lpDlls[], ULONG nDlls) { NTSTATUS ntStatus; PEPROCESS EProcess; KAPC_STATE ApcState; HANDLE hProcessHandle; CHAR curProcessName[16] = {0}; PIMAGE_DOS_HEADER pDos; //DOS头 PIMAGE_NT_HEADERS pHeader; //NT头 PIMAGE_IMPORT_DESCRIPTOR pImportDesc; //原始导入表 PDETOUR_CLR_HEADER pClr; ULONG nBound = 0; ULONG dwFileSize = 0; ULONG dwSec = 0; PVOID pbNewIid = NULL; PVOID pbNew = NULL; ULONG cbNew = 0; ULONG obRem = 0; ULONG obTab = 0; ULONG obDll = 0; ULONG obStr = 0; ULONG cbTmp = 0; ULONG obBase = 0; ULONG i=0, n=0; ULONG OldProtect = 0; PVOID lpTemp1 = NULL; ULONG dwTemp1 = 0; if(ProcessId == 0 || pImageBase == NULL) { return FALSE; } pDos =(PIMAGE_DOS_HEADER) pImageBase; pHeader = (PIMAGE_NT_HEADERS)((ULONG)pImageBase + (ULONG)pDos->e_lfanew); pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG)pImageBase + pHeader->IMPORT_DIRECTORY.VirtualAddress); if(pHeader->IMPORT_DIRECTORY.VirtualAddress == 0) { return FALSE; } if(PsLookupProcessByProcessId( (PVOID)ProcessId, (PEPROCESS *)&EProcess) != STATUS_SUCCESS) { DbgPrint("[XXXXXDLL] PsLookupProcessByProcessId failed\n"); return FALSE; } __try { KeStackAttachProcess(EProcess, &ApcState); ntStatus = ObOpenObjectByPointer(EProcess, OBJ_KERNEL_HANDLE, NULL, 0x008, NULL, KernelMode, &hProcessHandle); if(!NT_SUCCESS(ntStatus)) { DbgPrint("[XXXXXDLL] ObOpenObjectByPointer failed error [%08X]\n", ntStatus); __leave; } lpTemp1 = (PVOID)(&pHeader->BOUND_DIRECTORY.VirtualAddress); dwTemp1 = 4; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect); pHeader->BOUND_DIRECTORY.VirtualAddress = 0; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL); lpTemp1 = (PVOID)(&pHeader->BOUND_DIRECTORY.Size); dwTemp1 = 4; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect); pHeader->BOUND_DIRECTORY.Size = 0; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL); dwSec = (ULONG)pDos->e_lfanew + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + pHeader->FileHeader.SizeOfOptionalHeader; for (i=0; i<pHeader->FileHeader.NumberOfSections; i++) { PIMAGE_SECTION_HEADER pSectionHeader; pSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG)pImageBase + dwSec + (sizeof(IMAGE_SECTION_HEADER) * i)); // 如果该文件不具有IAT_DIRECTORY,我们创建一个. if (pHeader->IAT_DIRECTORY.VirtualAddress == 0 && pHeader->IMPORT_DIRECTORY.VirtualAddress >= pSectionHeader->VirtualAddress && pHeader->IMPORT_DIRECTORY.VirtualAddress < pSectionHeader->VirtualAddress +pSectionHeader->SizeOfRawData ) { lpTemp1 = (PVOID)(&pHeader->IAT_DIRECTORY.VirtualAddress); dwTemp1 = 4; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect); pHeader->IAT_DIRECTORY.VirtualAddress = pSectionHeader->VirtualAddress; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL); lpTemp1 = (PVOID)(&pHeader->IAT_DIRECTORY.Size); dwTemp1 = 4; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect); pHeader->IAT_DIRECTORY.Size = pSectionHeader->SizeOfRawData; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL); } // Find the end of the file... if (dwFileSize < pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData) { dwFileSize = pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData; } } obRem = sizeof(IMAGE_IMPORT_DESCRIPTOR) * nDlls; obTab = PadToDwordPtr(obRem + pHeader->IMPORT_DIRECTORY.Size); obDll = obTab + sizeof(DWORD_PTR) * 4 * nDlls; obStr = obDll; cbNew = obStr; for(n=0; n<nDlls; n++) { cbNew += PadToDword((DWORD)strlen(lpDlls[n]) + 1); } // 分配本地内存,先在本地内存中构造好输入表 pbNew = ExAllocatePoolWithTag(NonPagedPool, cbNew, 'sam1'); if (pbNew == NULL) { DbgPrint("[XXXXXDLL] ExAllocatePoolWithTag cbNew faile\n"); __leave; } RtlZeroMemory(pbNew, cbNew); // 在进程中分配和本地内存同样大小的虚拟内存 cbTmp = cbNew; ntStatus = ZwAllocateVirtualMemory(hProcessHandle, &pbNewIid, 0, &cbTmp, MEM_COMMIT|MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); if(!NT_SUCCESS(ntStatus)) { DbgPrint("[XXXXXDLL] ZwAllocateVirtualMemory pbNewIid failed error [%08X]\n", ntStatus); __leave; } RtlZeroMemory(pbNewIid, cbNew); // pbNewIid 是我们在远程线程分配的新的输入表的首地址,和pbModule想减后就得到它的RVA了 obBase = (ULONG)((ULONG)pbNewIid - (ULONG)pImageBase); // 将旧的输入表读入到本地内存,注意有一个偏移obRem RtlCopyMemory((PUCHAR)((ULONG)pbNew + obRem), pImportDesc, pHeader->IMPORT_DIRECTORY.Size); { PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew; ULONG_PTR *pt = NULL; ULONG nOffset = 0; for(n=0; n<nDlls; n++) { if(!StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, lpDlls[n])) { DbgPrint("StringCchCopyA 拷贝DLL路径失败\n"); __leave; } nOffset = obTab + (sizeof(ULONG_PTR) * (4 * n)); piid[n].OriginalFirstThunk = obBase + nOffset; pt = ((ULONG_PTR*)((ULONG)pbNew + nOffset)); pt[0] = IMAGE_ORDINAL_FLAG + 1; pt[1] = 0; nOffset = obTab + (sizeof(ULONG_PTR) * ((4 * n) + 2)); piid[n].FirstThunk = obBase + nOffset; pt = ((ULONG_PTR*)((ULONG)pbNew + nOffset)); pt[0] = IMAGE_ORDINAL_FLAG + 1; pt[1] = 0; piid[n].TimeDateStamp = 0; piid[n].ForwarderChain = 0; piid[n].Name = obBase + obStr; obStr += PadToDword((ULONG)strlen(lpDlls[n]) + 1); } } //Update the CLR header. if (pHeader->CLR_DIRECTORY.VirtualAddress != 0 && pHeader->CLR_DIRECTORY.Size != 0) { ULONG flg = 0; pClr = (PDETOUR_CLR_HEADER)((ULONG)pImageBase + pHeader->CLR_DIRECTORY.VirtualAddress); flg = pClr->Flags & 0xfffffffe; lpTemp1 = (PVOID)(&pClr->Flags); dwTemp1 = 4; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect); pClr->Flags = flg; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL); } if(pHeader->IMPORT_DIRECTORY.VirtualAddress > 0) { //拷贝本地内存中的新的输入表数据到虚拟内存中 ntStatus = ZwWriteVirtualMemory(hProcessHandle, pbNewIid, pbNew, obStr, NULL); if(!NT_SUCCESS(ntStatus)) { DbgPrint("[XXXXXDLL] ZwWriteVirtualMemory pbNewIid failed error [%08X]\n", ntStatus); __leave; } KdPrint(("原导入表: [%08X] - [%d]\n", pHeader->IMPORT_DIRECTORY.VirtualAddress, pHeader->IMPORT_DIRECTORY.Size)); //设置输入表的地址和大小,为刚才分配的虚拟内存 lpTemp1 = (PVOID)(&pHeader->IMPORT_DIRECTORY.VirtualAddress); dwTemp1 = 4; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect); pHeader->IMPORT_DIRECTORY.VirtualAddress = obBase; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL); lpTemp1 = (PVOID)(&pHeader->IMPORT_DIRECTORY.Size); dwTemp1 = 4; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, PAGE_EXECUTE_READWRITE, &OldProtect); pHeader->IMPORT_DIRECTORY.Size = cbNew; ZwProtectVirtualMemory(hProcessHandle, &lpTemp1, &dwTemp1, OldProtect, NULL); KdPrint(("新导入表: [%08X] - [%d]\n", pHeader->IMPORT_DIRECTORY.VirtualAddress, pHeader->IMPORT_DIRECTORY.Size)); } } __finally { if(pbNew) { ExFreePool(pbNew); } if(hProcessHandle) { ZwClose(hProcessHandle); hProcessHandle = NULL; } KeUnstackDetachProcess(&ApcState); } ObDereferenceObject(EProcess); return TRUE; } //-------------------------------------------------------------------------------------- //LoadImage回调,在此注入DLL VOID LoadImageRoutine( IN PUNICODE_STRING FullImageName, IN HANDLE ProcessId, // where image is mapped IN PIMAGE_INFO ImageInfo ) { PVOID pProcessBase = NULL; if(ImageInfo->SystemModeImage) { } else { pProcessBase = GetProcessBaseAddress(ProcessId); if(pProcessBase == ImageInfo->ImageBase) { //注入DLL CHAR *rlpDlls[2]; ULONG nDlls = 0; rlpDlls[nDlls++] = "HookReg.dll"; XXXXXDLL(ProcessId, ImageInfo->ImageBase, rlpDlls, nDlls); } } } |
|
|
沙发#
发布于:2013-03-06 16:39
这类东东,它的价值在于稳定性。
不过鼓励楼上的创新精神 :) |
|
|
板凳#
发布于:2013-03-06 16:41
特殊进程,有可能是 pe 结构不规范,追一下就明白了
|
|
|
地板#
发布于:2013-03-06 20:36
不错,
给出一个思路。 要通用64位, 搞定pe+. |
|
地下室#
发布于:2013-04-08 16:08
这方法不错
|
|