Dll注入:修改PE文件 IAT注入
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注入的更多相关文章
- 修改PE文件的入口函数OEP
修改入口函数地址.这个是最省事的办法,在原PE文件中新增加一个节,计算新节的RVA,然后修改入口代码,使其指向新增加的节.当然,如果.text节空隙足够大的话,不用添加新节也可以. BOOL Chan ...
- 动态修改PE文件图标(使用UpdateResource API函数)
PE文件的图标存储在资源文件中,而操作资源要用到的API函数就是UpdateResource首先我们需要先了解一下ICO格式,参考资料:http://www.moon-soft.com/program ...
- DLL注入之修改PE静态注入
DLL注入之修改PE静态注入 0x00 前言 我们要注入的的力量功能是下载baidu首页数据.代码如下: #include "stdio.h" #include"stdi ...
- 利用模块加载回调函数修改PE导入表实现注入
最近整理PE文件相关代码的时候,想到如果能在PE刚刚读进内存的时候再去修改内存PE镜像,那不是比直接对PE文件进行操作隐秘多了么? PE文件在运行时会根据导入表来进行dll库的"动态链接&q ...
- Python读取PE文件(exe/dll)中的时间戳
代码原文地址: https://www.snip2code.com/Snippet/144008/Read-the-PE-Timestamp-from-a-Windows-Exe https://gi ...
- 深入学习PE文件(转)
PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一. 基本结构. 上图便是PE文件的基本结构.(注意:DO ...
- 深入剖析PE文件
不赖猴的笔记,转载请注明出处. 深入剖析PE文件 PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一. ...
- 【黑客免杀攻防】读书笔记6 - PE文件知识在免杀中的应用
0x1 PE文件与免杀思路 基于PE文件结构知识的免杀技术主要用于对抗启发式扫描. 通过修改PE文件中的一些关键点来达到欺骗反病毒软件的目的. 修改区段名 1.1 移动PE文件头位置免杀 工具:PeC ...
- PE文件学习系列二 DOS头分析
合肥程序员群:49313181. 合肥实名程序员群 :128131462 (不愿透露姓名和信息者勿加入)Q Q:408365330 E-Mail:egojit@qq.com PE文件结 ...
随机推荐
- 比较两种数组随机排序方法的效率 JavaScript版
//比较2中数组随机排序方法的效率 JavaScript版 //randon1思路 //当len=5时候,从0-5中随机3一个放入i=0, // 从0-3随机一个2放入i=2 // 从0-2随机一个1 ...
- C/S架构与B/S架构的区别
什么是C/S结构和B/S结构? C/S结构 C/S结构是指Client/Server (客户机/服务器) 结构,是大家熟知的软件系统体系结构,通过将任务合理分配到Client端和Server端,降低了 ...
- python3 模块安装列表
pip install scrapy pip install twisted pip install BeautifulSoup4 pip install lxml pip install Pillo ...
- Flask中的的SQLAlchemy
好久没有更新Blog了 今天来聊一聊 Python 的 ORM 框架 SQLAlchemy 有的孩子已经听说过这个框架的大名了,也听说了 SQLAlchemy 没有 Django 的 Models 好 ...
- 在CentOS 7上搭建私有Docker仓库
Hub IP:10.0.2.6 操作系统:CentOS 7 64位 Docker版本:1.12.5Client IP:10.0.2.4 操作系统:CentOS 7 64位 Docker版本:1.12. ...
- Android多语言与国际化
internationalization (国际化)简称 i18n,因为在i和n之间还有18个字符,localization(本地化 ),简称L10n.一般用 语言_地区的形式表示一种语言,如 zh_ ...
- pat1015. Reversible Primes (20)
1015. Reversible Primes (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A r ...
- rpm重装python和yum
前些天升级的python, yum就不能用了, 提示 "No module named yum", 然后搜索了一下, 说要重装python和yum, 也没多想, 就按照那些教程去做 ...
- git提交代码报错 trailing whitespace的解决方法
1. git提交代码报错 trailing whitespace 禁止执行pre-commit脚本 进入到项目目录中 chmod a-x .git/hooks/pre-commit 2.git提交代码 ...
- 【Xshell】设置XShell最大的显示行数
选择会话,依次点击“文件"->"属性”,打开“会话属性”窗体 在“会话属性”窗体中,选择“终端”,下图中红框标注的地方是“缓冲区大小”,修改其中的值,其范围在0~2,14 ...