利用 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);
}
}
}
如果相同,则加载的是进程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);
}
}
}