进程加载_模块隐藏
前言:原本已经打算不继续写博客了,但是今天看到了网上有人说的一句话,还是要不停的催促自己来写博客!
通过自身加载模块来实现进程加载:
需要注意的细节:
1.通过INT表来对IAT表进行修复
2.修复重定位时候的注意差值的运算
3.通过内联汇编的时候JMP 的地址是 ENTRY + IMAGEBASE
// 06_04_Inject_process.cpp : Defines the entry point for the console application.
//
#include "AAAA.h"
// 06_04_Inject_process.cpp : Defines the entry point for the console application.
//
int main(int argc, char* argv[])
{
LPVOID pFileBuffer = NULL;
DWORD dwBufferLength = 0;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_IMPORT_DESCRIPTOR pIMPORT_DESCRIPTOR = NULL;
PIMAGE_IMPORT_BY_NAME pImage_IMPORT_BY_NAME = NULL;
MyReadFile(&pFileBuffer, &dwBufferLength, "C:\\Users\\Administrator\\Desktop\\HelloWorld.exe");
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNTHeader = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//检测是否是'MZ'标志
if (*(PWORD)pFileBuffer != IMAGE_DOS_SIGNATURE)
{
printf("Not 'MZ' signature!\n");
free(pFileBuffer);
return -1;
}
//检测是否是'PE'标志
pNTHeader = (PIMAGE_NT_HEADERS32)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
{
printf("Not 'PE' signature\n");
free(pFileBuffer);
return -1;
}
//检测是否存在重定位表
DWORD dwFlagRelocation = 0;
if (pOptionHeader->DataDirectory[5].VirtualAddress == 0)
{
dwFlagRelocation = 1;
printf("EXE Have Not Base Relocation Table!\n");
}
LPVOID pImageBuffer = NULL;
CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer); // free pFileBuffer
// get ImageBase
DWORD dwImageBase;
dwImageBase = GetImageBase(pImageBuffer);
// get SizeOfImage
DWORD dwSizeOfImage = 0;
dwSizeOfImage = GetSizeOfImage(pImageBuffer);
// to alloc memory
LPVOID pAllocAddr = NULL;
pAllocAddr = VirtualAlloc((PVOID)dwImageBase, (SIZE_T)dwSizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pAllocAddr == NULL) {
printf("PE's ImageBase VirtualAlloc Fail, The Error is %d.\n", GetLastError());
if(dwFlagRelocation){
printf("No Base Relocation Table, And Pe's ImageBase VirtualAlloc Fail.\n");
free(pImageBuffer);
return -1;
}
pAllocAddr = VirtualAlloc(NULL, (SIZE_T)dwSizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
printf("Start Second VirtualAlloc....\n");
if(pAllocAddr == NULL){
printf("Second VirtualAlloc Fail, The Error is %d.\n", GetLastError());
free(pImageBuffer);
return -1;
}
printf("Second VirtualAlloc: %x\n", pAllocAddr);
}
printf("Fina VirtualAlloc: %x\n", pAllocAddr);
// memcpy
memcpy(pAllocAddr, pImageBuffer, dwSizeOfImage);
//CopyMemory(pAllocAddr, pImageBuffer, dwSizeOfImage);
// load pe
PDWORD pIAT = NULL;
DWORD Original = 0;
pDosHeader = (PIMAGE_DOS_HEADER)pAllocAddr;
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pAllocAddr + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + sizeof(IMAGE_OPTIONAL_HEADER32));
// 修复重定位表
FixRelocation(pAllocAddr, (DWORD)pAllocAddr - dwImageBase);
//获取导入表的位置,每个导入表的相关信息占20个字节
pIMPORT_DESCRIPTOR = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pAllocAddr + (DWORD)pOptionHeader->DataDirectory[1].VirtualAddress);
HMODULE hModule;
//这里可以进行while操作,这里while的判断依据为pIMPORT_DESCRIPTOR个数
while (pIMPORT_DESCRIPTOR->FirstThunk && pIMPORT_DESCRIPTOR->OriginalFirstThunk) {
hModule = LoadLibrary((PCHAR)((DWORD)pAllocAddr + (DWORD)pIMPORT_DESCRIPTOR->Name));
pIAT = (PDWORD)((DWORD)pAllocAddr + (DWORD)pIMPORT_DESCRIPTOR->FirstThunk);
while (*pIAT) {
if (*pIAT & 0x80000000) {
//高位为1 则 除去最高位的值就是函数的导出序号
Original = *pIAT & 0x7FFFFFFF; //去除最高标志位。
*pIAT = (DWORD)GetProcAddress(hModule, (PCHAR)Original);
}
else
{
//高位不为1 则指向IMAGE_IMPORT_BY_NAME;
pImage_IMPORT_BY_NAME = (PIMAGE_IMPORT_BY_NAME)((DWORD)pAllocAddr + *pIAT);
*pIAT = (DWORD)GetProcAddress(hModule, (PCHAR)pImage_IMPORT_BY_NAME->Name);
}
pIAT++;
}
pIMPORT_DESCRIPTOR++;
}
LPVOID dwOep = (LPVOID)(GetOep(pAllocAddr) + (DWORD)pAllocAddr);
printf("oep: %x\n", GetOep(pAllocAddr));
printf("pAllocAddr: %x\n", pAllocAddr);
printf("oep+pAllocAddr: %x\n", (DWORD)dwOep);
printf("=================PE Loader=================\n");
((void(*)())((DWORD)pDosHeader + pOptionHeader->AddressOfEntryPoint))();
system("pause");
return 0;
}
第二种:内存写入(将自身进程注入指定进程内存中)实现模块进程
需要注意的细节:
1.通过INT表来对IAT表进行修复
2.修复重定位时候的注意差值的运算
3、CreateRemoteThread的时候如果直接使用已存在的线程函数的时候,计算方式是ThreadProc的地址 - 原Imagebase的地址 + 指定进程申请的内存空间的首地址
#include "PeTools.h"
DWORD WINAPI ThreadProc(LPVOID lpParam) {
// load pe
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_IMPORT_DESCRIPTOR pIMPORT_DESCRIPTOR = NULL;
PIMAGE_IMPORT_BY_NAME pImage_IMPORT_BY_NAME = NULL;
PDWORD OriginalFirstThunk = NULL;
PDWORD FirstThunk = NULL;
PIMAGE_THUNK_DATA pImageThunkData = NULL;
DWORD Original = 0;
pDosHeader = (PIMAGE_DOS_HEADER)lpParam;
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)lpParam + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//每个导入表的相关信息占20个字节
pIMPORT_DESCRIPTOR = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)lpParam + pOptionHeader->DataDirectory[1].VirtualAddress);
//这里可以进行while操作,这里while的判断依据为pIMPORT_DESCRIPTOR个数
DWORD dwFuncAddr = 0;
HMODULE hModule;
while (pIMPORT_DESCRIPTOR->FirstThunk && pIMPORT_DESCRIPTOR->OriginalFirstThunk) {
hModule = LoadLibrary((PCHAR)((DWORD)lpParam + (DWORD)pIMPORT_DESCRIPTOR->Name));
// FirstThunk 指向 IMAGE_THUNK_DATA 结构数组
OriginalFirstThunk = (PDWORD)((DWORD)lpParam + (DWORD)pIMPORT_DESCRIPTOR->OriginalFirstThunk);
FirstThunk = (PDWORD)((DWORD)lpParam + (DWORD)pIMPORT_DESCRIPTOR->FirstThunk);
while (*OriginalFirstThunk) {
if (*OriginalFirstThunk & 0x80000000) {
//高位为1 则 除去最高位的值就是函数的导出序号
Original = *OriginalFirstThunk & 0xFFF; //去除最高标志位。
dwFuncAddr = (DWORD)GetProcAddress(hModule, (PCHAR)Original);
}
else
{
//高位不为1 则指向IMAGE_IMPORT_BY_NAME;
pImage_IMPORT_BY_NAME = (PIMAGE_IMPORT_BY_NAME)((DWORD)lpParam + *OriginalFirstThunk);
dwFuncAddr = (DWORD)GetProcAddress(hModule, (PCHAR)pImage_IMPORT_BY_NAME->Name);
}
*FirstThunk = dwFuncAddr;
OriginalFirstThunk++;
}
pIMPORT_DESCRIPTOR++;
}
MessageBox(0, 0, 0, 0);
return 0;
}
int main() {
// 获取自身句柄
HMODULE hModule = GetModuleHandle(NULL);
// 得到自己的ImageBase / SizeOfImage
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_IMPORT_DESCRIPTOR pIMPORT_DESCRIPTOR;
PIMAGE_IMPORT_BY_NAME pImage_IMPORT_BY_NAME;
PDWORD OriginalFirstThunk_INT = NULL;
PDWORD FirstThunk_IAT = NULL;
DWORD Original = 0;
pDosHeader = (PIMAGE_DOS_HEADER)hModule;
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + sizeof(IMAGE_OPTIONAL_HEADER));
DWORD dwImageBase = pOptionHeader->ImageBase;
DWORD dwSizeOfImage = pOptionHeader->SizeOfImage;
// 创建一个新的缓冲区,将自己复制进去
LPVOID pNewBufferAddress = malloc(dwSizeOfImage);
memset(pNewBufferAddress, dwSizeOfImage, 0);
memcpy(pNewBufferAddress, (LPVOID)hModule, dwSizeOfImage); //需要注意的是当前的PE已经是拉伸过后的了 所以直接用的就是RVA是正确的
// 打开要注入的A进程
HANDLE hProcess;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 14816);
if (hProcess == NULL) {
printf("OpenProcess Failed, the error is %d", GetLastError());
return -1;
}
// 在A进程中申请内存,大小就是SizeOfImage
LPVOID AllocAddress = VirtualAllocEx(hProcess, NULL, dwSizeOfImage, MEM_COMMIT, PAGE_READWRITE);
if (AllocAddress == NULL) {
printf("VirtualAllocEx Failed, the error is %d", GetLastError());
CloseHandle(hProcess);
return -1;
}
// 修复重定位表
FixRelocation(pNewBufferAddress, (DWORD)AllocAddress - dwImageBase);
// 通过 WriteProcessMemory 写入远程进程的内存空间中
DWORD bytes;
BOOL ret;
ret = WriteProcessMemory(hProcess, AllocAddress, pNewBufferAddress, dwSizeOfImage, &bytes);
if (!ret) {
printf("WriteProcessMemory Failed, the error is %d", GetLastError());
CloseHandle(hProcess);
return -1;
}
// 在指定进程中申请要执行线程函数的内存
/*LPVOID lpRemoteThreadAddr = VirtualAllocEx(hProcess, NULL, 0x400, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 写入大小为0x400,内容的是 要在对方进程中进行执行的线程函数的地址
ret = WriteProcessMemory(hProcess, lpRemoteThreadAddr, (LPVOID)ThreadProc, 0x400, &bytes);
if (!ret){
printf("WriteProcessMemory Failed, the error is %d", GetLastError());
CloseHandle(hProcess);
return -1;
}*/
// 得到模块中要运行的函数的地址,并且进行IAT表的修复
// ((DWORD)ThreadProc + (DWORD)AllocAddress - (DWORD)hModule)
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)((DWORD)ThreadProc + (DWORD)AllocAddress - (DWORD)hModule), (LPVOID)AllocAddress, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
return 0;
}