进程加载_模块隐藏

前言:原本已经打算不继续写博客了,但是今天看到了网上有人说的一句话,还是要不停的催促自己来写博客!

通过自身加载模块来实现进程加载:

需要注意的细节:

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;
	
}
posted @ 2020-07-23 19:17  zpchcbd  阅读(1052)  评论(0编辑  收藏  举报