• 进程加载_模块隐藏


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

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

    需要注意的细节:

    1.通过INT表来对IAT表进行修复

    2.修复重定位时候的注意差值的运算

    3.通过内联汇编的时候JMP 的地址是 ENTRY + IMAGEBASE

    // 06_04_Inject_process.cpp : Defines the entry point for the console application.
    //
    
    #include "PeTools.h"
    
    int main(int argc, char* argv[])
    {
    
    	
    	LPVOID pFileBuffer = NULL;
    	LPVOID pImageBuffer = NULL;
    	DWORD dwBufferLength = 0;
    	LPVOID pAllocAddr = NULL;
    	HANDLE hProcess = NULL;
    	DWORD dwSizeOfImage;
    	
    	MyReadFile(&pFileBuffer, &dwBufferLength, "C:\Users\dell\Desktop\ipmsg.exe");
    	CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
    
    	// get ImageBase
    	DWORD dwImageBase;
    	dwImageBase = GetImageBase(pFileBuffer);
    
    	// get SizeOfImage
    	dwSizeOfImage = GetSizeOfImage(pFileBuffer);
    	
    	// to alloc memory
    	pAllocAddr = VirtualAlloc((LPVOID)dwImageBase, dwSizeOfImage, MEM_COMMIT, PAGE_READWRITE);
    	if (pAllocAddr == NULL) {
    		printf("VirtualAlloc Failed , the error is %d", GetLastError());
    	}
    
    	// memcpy
    	memcpy(pAllocAddr, pImageBuffer, dwSizeOfImage);
    
    	// 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;
    
    	TCHAR ImportTableDllName[20] = { 0 };
    	TCHAR FunctionName[20] = { 0 };
    
    	PDWORD OriginalFirstThunk_INT = NULL;
    	PDWORD FirstThunk_IAT = NULL;
    	PIMAGE_THUNK_DATA pImageThunkData = NULL;
    	
    	DWORD Original = 0;
    
    	pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase;
    	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)dwImageBase + 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));
    
    	//获取导入表的位置,每个导入表的相关信息占20个字节
    	pIMPORT_DESCRIPTOR = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)dwImageBase + (DWORD)pOptionHeader->DataDirectory[1].VirtualAddress);
    	
    	//这里可以进行while操作,这里while的判断依据为pIMPORT_DESCRIPTOR个数
    	while (pIMPORT_DESCRIPTOR->FirstThunk && pIMPORT_DESCRIPTOR->OriginalFirstThunk) {
    		HMODULE hModule;
    		memset(ImportTableDllName, 20, 0);
    		memset(FunctionName, 20, 0);
    		strcpy(ImportTableDllName, (PCHAR)((DWORD)pFileBuffer + (DWORD)pIMPORT_DESCRIPTOR->Name));
    
    		hModule = LoadLibrary(ImportTableDllName);
    
    		//FirstThunk转换FOA
    		FirstThunk_IAT = (PDWORD)((DWORD)pFileBuffer + (DWORD)pIMPORT_DESCRIPTOR->FirstThunk);
    
    		DWORD dwFuncAddr = 0;
    		while (*FirstThunk_IAT) {
    			if ((*FirstThunk_IAT) & 0X80000000) {
    				//高位为1 则 除去最高位的值就是函数的导出序号
    				Original = *FirstThunk_IAT & 0xFFF;	//去除最高标志位。
    				dwFuncAddr = (DWORD)GetProcAddress(hModule, (char*)Original);
    			}
    			else
    			{
    				//高位不为1 则指向IMAGE_IMPORT_BY_NAME
    				pImage_IMPORT_BY_NAME = (PIMAGE_IMPORT_BY_NAME)((DWORD)pFileBuffer + *FirstThunk_IAT);
    				strcpy(FunctionName, (PCHAR)pImage_IMPORT_BY_NAME->Name);
    				dwFuncAddr = (DWORD)GetProcAddress(hModule, FunctionName);
    			}
    
    			pImageThunkData = (PIMAGE_THUNK_DATA)FirstThunk_IAT;
    			pImageThunkData->u1.Function = dwFuncAddr;
    
    			FirstThunk_IAT++;
    		}
    
    		// 进行遍历操作
    		pIMPORT_DESCRIPTOR++;
    	}
    
    
    	DWORD dwOep = GetOep(pFileBuffer) + dwImageBase;
    
    	__asm {
    		jmp dwOep
    	}
    	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;
    	
    }
    
  • 相关阅读:
    HDU 4346 The Beautiful Road ( 反向考虑 思路题 )
    HTTP 之缓存
    HTTP head meta
    Git远程操作
    git fetch和push的区别
    git 提交 src refspec master does not match any
    git提交远程报错[rejected] master -> master (fetch first)
    (转载)git常用命令
    Git配置和常用命令
    git常用命令(三)
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/13368169.html
Copyright © 2020-2023  润新知