PE原理就不阐述了, 这个注入是PE感染的一种,通过添加一个新节注入,会改变PE文件的大小,将原有的导入表复制到新节中,并添加自己的导入表描述符,最后将数据目录项中指向的导入表的入口指向新节。

步骤:

1.添加一个新节;映射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指向新节

 #include <windows.h>
#include <iostream>
#include <exception>
#include <string> using namespace std; #define ERROR_MESSAGE(Msg) std::cout<<Msg<<std::endl;
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); int main()
{
AddImportTable("Target.exe", "Dll.dll", "InjectFunction"); system("pause");
return true;
} BOOL AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
{
BOOL bOk = false;
try
{
bOk = AddNewSection(strTargetFile, );
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, , 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, , , 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 + ) * 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 + ) + pNtHeaders->FileHeader.NumberOfSections;
PIMAGE_SECTION_HEADER pLastSectionHeader = pNewSectionHeader - ; // 对齐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, "Inject", strlen("Inject"));
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 = ; // 关闭绑定导入
pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = ; // 添加新节到文件尾部
SetFilePointer(TargetFileHandle, , , FILE_END);
PCHAR pNewSectionContent = new CHAR[FileSize];
RtlZeroMemory(pNewSectionContent, FileSize);
DWORD dwWrittenLength = ;
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 - ) / 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, , 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, , , 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 == && pImportTable->FirstThunk != )
{
// 桥一为0 桥二不是0 说明使用了绑定导入表
bBoundImport = true;
pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = ; // 关闭绑定导入
pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = ;
} // 找到自己添加的新节
PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + ) + pNtHeaders->FileHeader.NumberOfSections - ;
PBYTE pNewSectionData = pNewSectionHeader->PointerToRawData + (PBYTE)FileData;
PBYTE pNewImportDescriptor = pNewSectionData;
// 往新节中拷贝原导入表内容
int i = ;
while (pImportTable->FirstThunk != || pImportTable->Characteristics != )
{
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 + * sizeof(IMAGE_IMPORT_DESCRIPTOR));
PBYTE pszDllName = (PBYTE)(pNewThunkData + );
memcpy(pszDllName, strInjectDllName.c_str(), strInjectDllName.length());
// 确定 DllName 的位置
pszDllName[strInjectDllName.length() + ] = ;
// 确定 IMAGE_IMPORT_BY_NAM 的位置
PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)(pszDllName + strInjectDllName.length() + );
// 初始化 IMAGE_THUNK_DATA
pNewThunkData->u1.Ordinal = (DWORD_PTR)pImportByName - (DWORD_PTR)FileData + /*加上修正值 - 这里应该填充在内存中的地址*/dwDelt;
// 初始化 IMAGE_IMPORT_BY_NAME
pImportByName->Hint = ;
memcpy(pImportByName->Name, strFunctionName.c_str(), strFunctionName.length());
pImportByName->Name[strFunctionName.length() + ] = ;
// 初始化 PIMAGE_IMPORT_DESCRIPTOR
if (bBoundImport)
{
((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = ;
}
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 + ) * 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 + );
for (i = ; 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();
}
// 修正偏移
_offset = dwRVA + section->PointerToRawData - section->VirtualAddress;
return(_offset);
}

Dll注入:修改PE文件 IAT注入的更多相关文章

  1. 修改PE文件的入口函数OEP

    修改入口函数地址.这个是最省事的办法,在原PE文件中新增加一个节,计算新节的RVA,然后修改入口代码,使其指向新增加的节.当然,如果.text节空隙足够大的话,不用添加新节也可以. BOOL Chan ...

  2. 动态修改PE文件图标(使用UpdateResource API函数)

    PE文件的图标存储在资源文件中,而操作资源要用到的API函数就是UpdateResource首先我们需要先了解一下ICO格式,参考资料:http://www.moon-soft.com/program ...

  3. DLL注入之修改PE静态注入

    DLL注入之修改PE静态注入 0x00 前言 我们要注入的的力量功能是下载baidu首页数据.代码如下: #include "stdio.h" #include"stdi ...

  4. 利用模块加载回调函数修改PE导入表实现注入

    最近整理PE文件相关代码的时候,想到如果能在PE刚刚读进内存的时候再去修改内存PE镜像,那不是比直接对PE文件进行操作隐秘多了么? PE文件在运行时会根据导入表来进行dll库的"动态链接&q ...

  5. Python读取PE文件(exe/dll)中的时间戳

    代码原文地址: https://www.snip2code.com/Snippet/144008/Read-the-PE-Timestamp-from-a-Windows-Exe https://gi ...

  6. 深入学习PE文件(转)

    PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一. 基本结构. 上图便是PE文件的基本结构.(注意:DO ...

  7. 深入剖析PE文件

    不赖猴的笔记,转载请注明出处. 深入剖析PE文件 PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一.   ...

  8. 【黑客免杀攻防】读书笔记6 - PE文件知识在免杀中的应用

    0x1 PE文件与免杀思路 基于PE文件结构知识的免杀技术主要用于对抗启发式扫描. 通过修改PE文件中的一些关键点来达到欺骗反病毒软件的目的. 修改区段名 1.1 移动PE文件头位置免杀 工具:PeC ...

  9. PE文件学习系列二 DOS头分析

    合肥程序员群:49313181.    合肥实名程序员群 :128131462 (不愿透露姓名和信息者勿加入)Q  Q:408365330     E-Mail:egojit@qq.com PE文件结 ...

随机推荐

  1. C++ GUI Qt4编程(10)-3.4spreadsheet

    1. C++ GUI Qt4编程第三章,增加spreadsheet. 2. spreadsheet.h /**/ #ifndef SPREADSHEET_H #define SPREADSHEET_H ...

  2. 集成 Jenkins 和 TestNG 实现自助式自动化测试平台

    背景介绍 在软件业十分成熟的今天,敏捷(Agile)开发在业界日益流行,而面临的挑战也日益增多,不断变化的用户需求.缩短的开发周期.频繁的部署上线.复杂的产品架构和团队组织,如何继续保证软件的质量是一 ...

  3. oracle 基础知识(七)----动态性能视图

    一,动态性能视图介绍 动态性能视图属于数据字典,系统管理员用户 SYS 可以访问它们.在数据库打开和使用时不断进行更新,而且它们的内容主要与性能有关.虽然这些视图很像普通的数据库表,但它们不允许用户直 ...

  4. oracle 基础知识(四) 构成

    一, oracle服务 一个oracle 服务由一个oracle 实例和一个oracle数据库组成. oracle = instance + database 总体概念: 二, oracle 实例 0 ...

  5. Java中多线程并发体系知识点汇总

    一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种 ...

  6. C++11并发编程:async,future,packaged_task,promise

    一:async std::async:用于创建异步任务,可以代替创建线程,函数原型:async(std::launch::async | std::launch::deferred, f, args. ...

  7. 【c#文档】在 C# 中,(int) ,Int32.Parse() 和 Convert.toInt32() 三种方法的区别

    [c#文档]https://msdn.microsoft.com/zh-cn/library/system.convert.toint32.aspx 转载自:http://www.cnblogs.co ...

  8. Bootstrap 斜体、文本对齐、缩略图、地址、列表等

    目录1.标题2.页面主体3.强调    a.小号文本    b.着重    c.斜体    d.对齐class    e.强调class4.缩略语5.地址6.列表    a.无序列表    b.有序列 ...

  9. 《X86汇编语言:从实模式到保护模式》读书笔记之引言

    有幸结识了<X86汇编语言:从实模式到保护模式>一书.我觉得这本书非常好,语言活泼,通俗易懂,源码丰富,受益匪浅.读罢一遍,意犹未尽.于是打算再读一遍,并把自己的读书所学总结成笔记,一来给 ...

  10. java多线程lock的使用

    看代码: package com.ming.thread.reentrantlock; import java.util.concurrent.locks.Lock; import java.util ...