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指向新节

  1. #include <windows.h>
  2. #include <iostream>
  3. #include <exception>
  4. #include <string>
  5.  
  6. using namespace std;
  7.  
  8. #define ERROR_MESSAGE(Msg) std::cout<<Msg<<std::endl;
  9. BOOL AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName);
  10. BOOL AddNewSection(const string& strTargetFile, ULONG ulNewSectionSize);
  11. BOOL AddNewImportDescriptor(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName);
  12. DWORD RVAToFOA(PIMAGE_NT_HEADERS pNtHeaders, DWORD dwRVA);
  13. ULONG32 PEAlign(ULONG32 dwNumber, ULONG32 dwAlign);
  14.  
  15. int main()
  16. {
  17. AddImportTable("Target.exe", "Dll.dll", "InjectFunction");
  18.  
  19. system("pause");
  20. return true;
  21. }
  22.  
  23. BOOL AddImportTable(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
  24. {
  25. BOOL bOk = false;
  26. try
  27. {
  28. bOk = AddNewSection(strTargetFile, );
  29. if (!bOk)
  30. {
  31. ERROR_MESSAGE("AddImportTable:AddNewSection failed.");
  32. return false;
  33. }
  34.  
  35. bOk = AddNewImportDescriptor(strTargetFile, strInjectDllName, strFunctionName);
  36. if (!bOk)
  37. {
  38. ERROR_MESSAGE("AddImportTable:AddNewImportDescriptor failed.");
  39. return false;
  40. }
  41. }
  42. catch (exception* e)
  43. {
  44. ERROR_MESSAGE((string("AddImportTable:") + e->what()).c_str());
  45. return false;
  46. }
  47.  
  48. return true;
  49. }
  50.  
  51. BOOL AddNewSection(const string& strTargetFile, ULONG ulNewSectionSize)
  52. {
  53. BOOL bOk = true;
  54. HANDLE TargetFileHandle = nullptr;
  55. HANDLE MappingHandle = nullptr;
  56. PVOID FileData = nullptr;
  57.  
  58. try
  59. {
  60. // 打开文件
  61. TargetFileHandle = CreateFileA(strTargetFile.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  62. if (TargetFileHandle == INVALID_HANDLE_VALUE)
  63. {
  64. ERROR_MESSAGE(string("AddNewSection:CreateFileA error with error code:" + GetLastError()).c_str());
  65. bOk = false;
  66. goto EXIT;
  67. }
  68.  
  69. ULONG ulFileSize = GetFileSize(TargetFileHandle, NULL);
  70.  
  71. // 映射文件
  72. MappingHandle = CreateFileMappingA(TargetFileHandle, NULL, PAGE_READWRITE, , ulFileSize, NULL);
  73. if (MappingHandle == NULL)
  74. {
  75. ERROR_MESSAGE(string("AddNewSection:CreateFileMapping error with error code:" + GetLastError()).c_str());
  76. bOk = false;
  77. goto EXIT;
  78. }
  79.  
  80. // 得到缓存头
  81. FileData = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, , , ulFileSize);
  82. if (FileData == NULL)
  83. {
  84. ERROR_MESSAGE(string("AddNewSection:MapViewOfFile error with error code:" + GetLastError()).c_str());
  85. bOk = false;
  86. goto EXIT;
  87. }
  88.  
  89. // 判断是否是PE文件
  90. if (((PIMAGE_DOS_HEADER)FileData)->e_magic != IMAGE_DOS_SIGNATURE)
  91. {
  92. ERROR_MESSAGE("AddNewSection:Target File is not a vaild file");
  93. bOk = false;
  94. goto EXIT;
  95. }
  96.  
  97. PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)FileData + ((PIMAGE_DOS_HEADER)FileData)->e_lfanew);
  98. if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
  99. {
  100. ERROR_MESSAGE("AddNewSection:Target File is not a vaild file");
  101. bOk = false;
  102. goto EXIT;
  103. }
  104.  
  105. // 判断是否可以增加一个新节
  106. if ((pNtHeaders->FileHeader.NumberOfSections + ) * sizeof(IMAGE_SECTION_HEADER) > pNtHeaders->OptionalHeader.SizeOfHeaders/*三个部分的总大小*/)
  107. {
  108. ERROR_MESSAGE("AddNewSection:There is not enough space to add a new section.");
  109. bOk = false;
  110. goto EXIT;
  111. }
  112.  
  113. // 得到新节的起始地址, 最后的起始地址
  114. PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + ) + pNtHeaders->FileHeader.NumberOfSections;
  115. PIMAGE_SECTION_HEADER pLastSectionHeader = pNewSectionHeader - ;
  116.  
  117. // 对齐RVA和偏移
  118. DWORD FileSize = PEAlign(ulNewSectionSize, pNtHeaders->OptionalHeader.FileAlignment);
  119. DWORD FileOffset = PEAlign(pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData, pNtHeaders->OptionalHeader.FileAlignment);
  120. DWORD VirtualSize = PEAlign(ulNewSectionSize, pNtHeaders->OptionalHeader.SectionAlignment);
  121. DWORD VirtualOffset = PEAlign(pLastSectionHeader->VirtualAddress + pLastSectionHeader->Misc.VirtualSize, pNtHeaders->OptionalHeader.SectionAlignment);
  122.  
  123. // 填充新节表
  124. memcpy(pNewSectionHeader->Name, "Inject", strlen("Inject"));
  125. pNewSectionHeader->VirtualAddress = VirtualOffset;
  126. pNewSectionHeader->Misc.VirtualSize = VirtualSize;
  127. pNewSectionHeader->PointerToRawData = FileOffset;
  128. pNewSectionHeader->SizeOfRawData = FileSize;
  129. pNewSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
  130.  
  131. // 修改IMAGE_NT_HEADERS
  132. pNtHeaders->FileHeader.NumberOfSections++;
  133. pNtHeaders->OptionalHeader.SizeOfImage += VirtualSize;
  134. pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = ; // 关闭绑定导入
  135. pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = ;
  136.  
  137. // 添加新节到文件尾部
  138. SetFilePointer(TargetFileHandle, , , FILE_END);
  139. PCHAR pNewSectionContent = new CHAR[FileSize];
  140. RtlZeroMemory(pNewSectionContent, FileSize);
  141. DWORD dwWrittenLength = ;
  142. bOk = WriteFile(TargetFileHandle, pNewSectionContent, FileSize, &dwWrittenLength, nullptr);
  143. if (bOk == false)
  144. {
  145. ERROR_MESSAGE(string("AddNewSection:WriteFile error with error code:" + GetLastError()).c_str());
  146. bOk = false;
  147. goto EXIT;
  148. }
  149. }
  150. catch (exception* e)
  151. {
  152. ERROR_MESSAGE((string("AddNewSection:") + e->what()).c_str());
  153. bOk = false;
  154. }
  155. EXIT:
  156. if (TargetFileHandle != NULL)
  157. {
  158. CloseHandle(TargetFileHandle);
  159. TargetFileHandle = nullptr;
  160. }
  161. if (FileData != NULL)
  162. {
  163. UnmapViewOfFile(FileData);
  164. FileData = nullptr;
  165. }
  166. if (MappingHandle != NULL)
  167. {
  168. CloseHandle(MappingHandle);
  169. MappingHandle = nullptr;
  170. }
  171.  
  172. return bOk;
  173. }
  174.  
  175. ULONG32 PEAlign(ULONG32 dwNumber, ULONG32 dwAlign)
  176. {
  177. return(((dwNumber + dwAlign - ) / dwAlign) * dwAlign); // 想 dwAlign 对齐,加上 dwAlign - 1,这样就可以保证对齐后的值 >= dwNumber
  178. }
  179.  
  180. BOOL AddNewImportDescriptor(const string& strTargetFile, const string& strInjectDllName, const string& strFunctionName)
  181. {
  182. bool bOk = true;
  183. HANDLE TargetFileHandle = nullptr;
  184. HANDLE MappingHandle = nullptr;
  185. PVOID FileData = nullptr;
  186. PIMAGE_IMPORT_DESCRIPTOR pImportTable = nullptr;
  187.  
  188. try
  189. {
  190. // 打开文件
  191. TargetFileHandle = CreateFileA(strTargetFile.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  192. if (TargetFileHandle == INVALID_HANDLE_VALUE)
  193. {
  194. ERROR_MESSAGE(string("AddNewImportDescriptor:CreateFileA error with error code:" + GetLastError()).c_str());
  195. bOk = false;
  196. goto EXIT;
  197. }
  198.  
  199. ULONG ulFileSize = GetFileSize(TargetFileHandle, NULL);
  200.  
  201. // 映射文件
  202. MappingHandle = CreateFileMappingA(TargetFileHandle, NULL, PAGE_READWRITE, , ulFileSize, NULL);
  203. if (MappingHandle == NULL)
  204. {
  205. cout << "AddNewImportDescriptor:CreateFileMapping error with error code:" << std::to_string(GetLastError()).c_str();
  206. bOk = false;
  207. goto EXIT;
  208. }
  209.  
  210. // 得到缓存头
  211. FileData = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, , , ulFileSize);
  212. if (FileData == NULL)
  213. {
  214. ERROR_MESSAGE(string("AddNewImportDescriptor:MapViewOfFile error with error code:" + GetLastError()).c_str());
  215. bOk = false;
  216. goto EXIT;
  217. }
  218.  
  219. // 判断是否是PE文件
  220. if (((PIMAGE_DOS_HEADER)FileData)->e_magic != IMAGE_DOS_SIGNATURE)
  221. {
  222. ERROR_MESSAGE("AddNewImportDescriptor:Target File is not a vaild file");
  223. bOk = false;
  224. goto EXIT;
  225. }
  226.  
  227. PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)FileData + ((PIMAGE_DOS_HEADER)FileData)->e_lfanew);
  228. if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
  229. {
  230. ERROR_MESSAGE("AddNewImportDescriptor:Target File is not a vaild file");
  231. bOk = false;
  232. goto EXIT;
  233. }
  234.  
  235. // 得到原导入表
  236. pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)FileData + RVAToFOA(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
  237. // 判断是否使用了绑定导入表
  238. bool bBoundImport = false;
  239. if (pImportTable->Characteristics == && pImportTable->FirstThunk != )
  240. {
  241. // 桥一为0 桥二不是0 说明使用了绑定导入表
  242. bBoundImport = true;
  243. pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = ; // 关闭绑定导入
  244. pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = ;
  245. }
  246.  
  247. // 找到自己添加的新节
  248. PIMAGE_SECTION_HEADER pNewSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + ) + pNtHeaders->FileHeader.NumberOfSections - ;
  249. PBYTE pNewSectionData = pNewSectionHeader->PointerToRawData + (PBYTE)FileData;
  250. PBYTE pNewImportDescriptor = pNewSectionData;
  251. // 往新节中拷贝原导入表内容
  252. int i = ;
  253. while (pImportTable->FirstThunk != || pImportTable->Characteristics != )
  254. {
  255. memcpy(pNewSectionData + i * sizeof(IMAGE_IMPORT_DESCRIPTOR), pImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR));
  256. pImportTable++;
  257. pNewImportDescriptor += sizeof(IMAGE_IMPORT_DESCRIPTOR);
  258. i++;
  259. }
  260. // 复制最后一个描述符
  261. memcpy(pNewImportDescriptor, pNewImportDescriptor - sizeof(IMAGE_IMPORT_DESCRIPTOR), sizeof(IMAGE_IMPORT_DESCRIPTOR));
  262.  
  263. // 计算修正值
  264. DWORD dwDelt = pNewSectionHeader->VirtualAddress - pNewSectionHeader->PointerToRawData;
  265.  
  266. // pNewImportDescriptor 当前指向要构造的新描述符 再空出一个空描述符作为导入表的结束符 所以是 2 *
  267. PIMAGE_THUNK_DATA pNewThunkData = PIMAGE_THUNK_DATA(pNewImportDescriptor + * sizeof(IMAGE_IMPORT_DESCRIPTOR));
  268. PBYTE pszDllName = (PBYTE)(pNewThunkData + );
  269. memcpy(pszDllName, strInjectDllName.c_str(), strInjectDllName.length());
  270. // 确定 DllName 的位置
  271. pszDllName[strInjectDllName.length() + ] = ;
  272. // 确定 IMAGE_IMPORT_BY_NAM 的位置
  273. PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)(pszDllName + strInjectDllName.length() + );
  274. // 初始化 IMAGE_THUNK_DATA
  275. pNewThunkData->u1.Ordinal = (DWORD_PTR)pImportByName - (DWORD_PTR)FileData + /*加上修正值 - 这里应该填充在内存中的地址*/dwDelt;
  276. // 初始化 IMAGE_IMPORT_BY_NAME
  277. pImportByName->Hint = ;
  278. memcpy(pImportByName->Name, strFunctionName.c_str(), strFunctionName.length());
  279. pImportByName->Name[strFunctionName.length() + ] = ;
  280. // 初始化 PIMAGE_IMPORT_DESCRIPTOR
  281. if (bBoundImport)
  282. {
  283. ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = ;
  284. }
  285. else
  286. {
  287. ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->OriginalFirstThunk = dwDelt + (DWORD_PTR)pNewThunkData - (DWORD_PTR)FileData;
  288. }
  289. ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->FirstThunk = dwDelt + (DWORD_PTR)pNewThunkData - (DWORD_PTR)FileData;
  290. ((PIMAGE_IMPORT_DESCRIPTOR)pNewImportDescriptor)->Name = dwDelt + (DWORD_PTR)pszDllName - (DWORD_PTR)FileData;
  291. // 修改导入表入口
  292. pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = pNewSectionHeader->VirtualAddress;
  293. pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (i + ) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
  294. }
  295. catch (exception* e)
  296. {
  297. ERROR_MESSAGE((string("AddNewImportDescriptor:") + e->what()).c_str());
  298. bOk = false;
  299. }
  300.  
  301. EXIT:
  302. {
  303. if (TargetFileHandle != NULL)
  304. {
  305. CloseHandle(TargetFileHandle);
  306. TargetFileHandle = nullptr;
  307. }
  308.  
  309. if (FileData != NULL)
  310. {
  311. UnmapViewOfFile(FileData);
  312. FileData = nullptr;
  313. }
  314.  
  315. if (MappingHandle != NULL)
  316. {
  317. CloseHandle(MappingHandle);
  318. MappingHandle = nullptr;
  319. }
  320. }
  321.  
  322. return bOk;
  323. }
  324.  
  325. PIMAGE_SECTION_HEADER GetOwnerSection(PIMAGE_NT_HEADERS pNTHeaders, DWORD dwRVA)
  326. {
  327. int i;
  328. PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(pNTHeaders + );
  329. for (i = ; i < pNTHeaders->FileHeader.NumberOfSections; i++)
  330. {
  331. if ((dwRVA >= (pSectionHeader + i)->VirtualAddress) && (dwRVA <= ((pSectionHeader + i)->VirtualAddress + (pSectionHeader + i)->SizeOfRawData)))
  332. {
  333. return ((PIMAGE_SECTION_HEADER)(pSectionHeader + i));
  334. }
  335. }
  336. return PIMAGE_SECTION_HEADER(NULL);
  337. }
  338.  
  339. DWORD RVAToFOA(PIMAGE_NT_HEADERS pNTHeaders, DWORD dwRVA)
  340. {
  341. DWORD _offset;
  342. PIMAGE_SECTION_HEADER section;
  343. // 找到偏移所在节
  344. section = GetOwnerSection(pNTHeaders, dwRVA);
  345. if (section == NULL)
  346. {
  347. return();
  348. }
  349. // 修正偏移
  350. _offset = dwRVA + section->PointerToRawData - section->VirtualAddress;
  351. return(_offset);
  352. }

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. 比较两种数组随机排序方法的效率 JavaScript版

    //比较2中数组随机排序方法的效率 JavaScript版 //randon1思路 //当len=5时候,从0-5中随机3一个放入i=0, // 从0-3随机一个2放入i=2 // 从0-2随机一个1 ...

  2. C/S架构与B/S架构的区别

    什么是C/S结构和B/S结构? C/S结构 C/S结构是指Client/Server (客户机/服务器) 结构,是大家熟知的软件系统体系结构,通过将任务合理分配到Client端和Server端,降低了 ...

  3. python3 模块安装列表

    pip install scrapy pip install twisted pip install BeautifulSoup4 pip install lxml pip install Pillo ...

  4. Flask中的的SQLAlchemy

    好久没有更新Blog了 今天来聊一聊 Python 的 ORM 框架 SQLAlchemy 有的孩子已经听说过这个框架的大名了,也听说了 SQLAlchemy 没有 Django 的 Models 好 ...

  5. 在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. ...

  6. Android多语言与国际化

    internationalization (国际化)简称 i18n,因为在i和n之间还有18个字符,localization(本地化 ),简称L10n.一般用 语言_地区的形式表示一种语言,如 zh_ ...

  7. pat1015. Reversible Primes (20)

    1015. Reversible Primes (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A r ...

  8. rpm重装python和yum

    前些天升级的python, yum就不能用了, 提示 "No module named yum", 然后搜索了一下, 说要重装python和yum, 也没多想, 就按照那些教程去做 ...

  9. git提交代码报错 trailing whitespace的解决方法

    1. git提交代码报错 trailing whitespace 禁止执行pre-commit脚本 进入到项目目录中 chmod a-x .git/hooks/pre-commit 2.git提交代码 ...

  10. 【Xshell】设置XShell最大的显示行数

    选择会话,依次点击“文件"->"属性”,打开“会话属性”窗体   在“会话属性”窗体中,选择“终端”,下图中红框标注的地方是“缓冲区大小”,修改其中的值,其范围在0~2,14 ...