深入分析PE结构(三)

分享者才是学习中最大的受益者!

0x0新增节

前言

手动新增一个节表和节,保证修改后的程序能正确执行.

PE结构

image-20220204152216145

整体过程

SizeOfHeaders:DOS + DOS stub(垃圾数据) + NT头(PE标记 + 标准PE头 + 可选PE头) + 已存在节表 —>>对齐之后的大小

SizeOfHeaders是不能随便变的,代价太大了

1、新增一个节

2、在新增一个节表(40个字节)

判断条件:

我们要保证在我们新增的这个节表后边,还有40个0的空间,所以我们要计算的是节表剩下的空间够不够80个字节,还有没有两个节表

导出我们的计算公式:

SizeOfHeader - (DOS + DOS stub(垃圾数据) + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小(80个字节)

3、需要修改的数据

  1. 1) 添加一个新的节(可以copy一份)
  2. 2) 在新增节后面 填充一个节大小的000
  3. 3) 修改标准PE头中节的数量(NumberOfSections参数)
  4. 4) 修改内存中整个PE文件的映射的尺寸(可选PE头中sizeOfImage参数)
  5. 5) 再原有数据的最后,新增一个节的数据(内存对齐的整数倍)
  6. 6)修正新增节表的属性

手动分析-1

先把我们要操作的exe复制一份出来,一会可以用作参考

判断空间

节表从这里开始

image-20220131174500396

判断有几个节

  1. 0008

有8个节,所以有8个节表

image-20220131174653422

一个节表40个字节

第一个节表

image-20220131180040301

第二个节表

image-20220131180114356

这下面都是空白区,足够80个字节(2个节表)了

image-20220131180218835

添加新节表

把第一个.text节表 粘贴过来 放到最后面

image-20220131180513970

修改NumberOfSections参数

修改标准PE头中节的数量(NumberOfSections参数)

image-20220131180747473

修改内存中整个PE文件的映射的尺寸(可选PE头中sizeOfImage参数)

注:在可选PE头中的后56个字节

image-20220131180858866

标准PE头

image-20220131181100362

修改sizeOfImage参数

我们找到sizeOfImage了

  1. 0002E000

image-20220131181440911

进行修改,给1000个字节

  1. 0002F000

image-20220131183635101

填充新节

开始插入,进行添加节

16进制1000个字节对应十进制4096

image-20220203200747703

image-20220203200818355

这里注意:别碰原来的数据

image-20220203201046757

修改新增的节表

注意是小端存储!

image-20220203201537193

拿出之前复制的exe,进行参考

image-20220203201857395

第一个参数是:Name,8个字节

image-20220203202000763

第二个参数是:VirtualSize,它是内存中大小(对齐前的长度).

这里有个小技巧,我们可以把它和文件中大小(对齐后的长度)写成一样的大小

我们要加的值是1000

  1. 00 10 00 00

image-20220203203124094

第三个参数是:VirtualAddress,它是内存中偏移(该块的RVA)

我们要看最后一个节表

image-20220203204758797

这里要看他两谁大

  1. 内存中大小(对齐前的长度)
  2. 文件中大小(对齐后的长度)

要用内存中偏移(该块的RVA)+上面两者大的那个

  1. 0002D000 + 1000 = 0002E000

然后 按照1000进行对齐,在根据小端存储

最后的结果就是

  1. 00 E0 02 00

第四个参数是:SizeOfRawData,它是文件中大小(对齐后的长度)

我们要加的值是1000

  1. 00 10 00 00

第五个参数是:PointerToRawData,它是文件中偏移.

继续看最后一个节表

image-20220203210121424

要用文件中偏移+文件中大小(对齐后的长度)

  1. 00013A00 + 00000000 = 00013A00

然后使用小端存储

  1. 00 3A 01 00

image-20220203212603538

最后是节表的属性

因为这个节,是我从.texe复制过来的,所以我就不用改了

保存 尝试执行

重新看一下

9个节 没有问题

image-20220203211002867

image-20220203212943505

手动分析-2

考虑另一种极端情况

打开notepad.exe

我们可以看到节表后又跟了一堆数据,他们是有用的数据,我们不能去动

image-20220204151701261

这块数据不能干掉,也不能动,但是我们没地方进行新增节

同时节表是连续存储的,不可以断掉的

重新看PE结构

image-20220204152259001

我们的思路就是

把PE结构中间的垃圾数据给干掉,然后把下面的PE标记往上提

只需要修改一个参数:DOS头中的e_lfanew1参数

image-20220204153239390

进行覆盖数据

image-20220204153857044

覆盖成功

image-20220204154008276

原先这块数据就没有用了 全部补0即可

image-20220204154037750

image-20220204154136028

最后修改DOS头中的e_lfanew1参数 把它指向40即可

image-20220204154326479

双击 依然可以正常运行

image-20220204154433908

核心代码

  1. DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer)
  2. {
  3. FILE* pFile = NULL;
  4. DWORD fileSize = 0;
  5. LPVOID pTempFileBuffer = NULL;
  6. //打开文件
  7. pFile = fopen(lpszFile,"rb"); //lpszFile是当作参数传递进来
  8. if (!pFile)
  9. {
  10. printf("打开文件失败!\r\n");
  11. return 0;
  12. }
  13. //读取文件内容后,获取文件的大小
  14. fseek(pFile,0,SEEK_END);
  15. fileSize = ftell(pFile);
  16. fseek(pFile,0,SEEK_SET);
  17. //动态申请内存空间
  18. pTempFileBuffer = malloc(fileSize);
  19. if (!pTempFileBuffer)
  20. {
  21. printf("内存分配失败!\r\n");
  22. fclose(pFile);
  23. return 0;
  24. }
  25. //根据申请到的内存空间,读取数据
  26. size_t n = fread(pTempFileBuffer,fileSize,1,pFile);
  27. if (!n)
  28. {
  29. printf("读取数据失败!\r\n");
  30. free(pTempFileBuffer); // 释放内存空间
  31. fclose(pFile); // 关闭文件流
  32. return 0;
  33. }
  34. //数据读取成功,关闭文件
  35. *pFileBuffer = pTempFileBuffer; // 将读取成功的数据所在的内存空间的首地址放入指针类型pFileBuffer
  36. pTempFileBuffer = NULL; // 初始化清空临时申请的内存空间
  37. fclose(pFile); // 关闭文件
  38. return fileSize; // 返回获取文件的大小
  39. }
  40. //通过复制FileBuffer并增加1000H到新的ImageBuffer里面
  41. DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer)
  42. {
  43. PIMAGE_DOS_HEADER pDosHeader = NULL;
  44. PIMAGE_NT_HEADERS pNTHeader = NULL;
  45. PIMAGE_FILE_HEADER pPEHeder = NULL;
  46. PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
  47. PIMAGE_SECTION_HEADER pSectionHeader = NULL;
  48. PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
  49. LPVOID pTempNewImageBuffer = 0;
  50. DWORD sizeOfFile = 0;
  51. DWORD numberOfSection = 0;
  52. DWORD okAddSections = 0;
  53. //判断读取pFileBuffer读取是否成功
  54. if (!pFileBuffer)
  55. {
  56. printf("缓冲区指针无效\r\n");
  57. return 0;
  58. }
  59. //判断是否为MZ标志
  60. if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE --> MZ
  61. {
  62. printf("不是一个有效的MZ标志\r\n");
  63. return 0;
  64. }
  65. //判断是否为PE标志
  66. pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
  67. if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // IMAGE_NT_SIGNATURE --> PE
  68. {
  69. printf("不是有效的PE标志\r\n");
  70. return 0;
  71. }
  72. //申请开辟内存空间
  73. sizeOfFile = fileSize+0x1000;
  74. pTempNewImageBuffer = malloc(sizeOfFile);
  75. //判断内存空间开辟是否成功
  76. if (!pTempNewImageBuffer)
  77. {
  78. printf("pTempNewImageBuffer开辟内存空间失败\r\n");
  79. return 0;
  80. }
  81. //初始化内存内容
  82. memset(pTempNewImageBuffer,0,sizeOfFile);
  83. //初始化完成之后,先把为修改的内存空间全部拷贝到新的内存空间
  84. memcpy(pTempNewImageBuffer,pFileBuffer,fileSize);
  85. //定位Dos头地址
  86. pDosHeader = (PIMAGE_DOS_HEADER)(pTempNewImageBuffer);
  87. //定位NT头的地址
  88. pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pTempNewImageBuffer+pDosHeader->e_lfanew);
  89. //定位标志PE头地址
  90. pPEHeder = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+0x04);//PE SIGNATURE 站4个字节
  91. //定位可选PE头地址
  92. pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeder)+IMAGE_SIZEOF_FILE_HEADER);//IMAGE_SIZEOF_FILE_HEADER -> 20个字节
  93. //定位第一个节表地址
  94. pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeder->SizeOfOptionalHeader);
  95. //定位最后一个节表的地址
  96. pLastSectionHeader = &pSectionHeader[pPEHeder->NumberOfSections-1];
  97. //判断是否有足够的空间添加一个节表
  98. //判断条件:
  99. /*
  100. SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小
  101. SizeOfHeader在可选PE头里面
  102. */
  103. okAddSections = (DWORD)(pOptionHeader->SizeOfHeaders - (pDosHeader->e_lfanew + 0x04 + \
  104. sizeof(PIMAGE_FILE_HEADER) + pPEHeder->SizeOfOptionalHeader + sizeof(PIMAGE_SECTION_HEADER) \
  105. * pPEHeder->NumberOfSections));
  106. if (okAddSections < 2*sizeof(PIMAGE_SECTION_HEADER))
  107. {
  108. printf("这个exe文件头不剩余空间不够\r\n");
  109. free(pTempNewImageBuffer);
  110. return 0;
  111. }
  112. //修改
  113. //初始化新节表信息
  114. PWORD pNumberOfSection = &amp;pPEHeder->NumberOfSections;
  115. PDWORD pSizeOfImage = &amp;pOptionHeader->SizeOfImage;
  116. numberOfSection = pPEHeder->NumberOfSections;
  117. PVOID pSecName = &amp;pSectionHeader[numberOfSection].Name;
  118. PDWORD pSecMisc = &amp;pSectionHeader[numberOfSection].Misc.VirtualSize;
  119. PDWORD pSecVirtualAddress = &amp;pSectionHeader[numberOfSection].VirtualAddress;
  120. PDWORD pSecSizeOfRawData = &amp;pSectionHeader[numberOfSection].SizeOfRawData;
  121. PDWORD pSecPointToRawData = &amp;pSectionHeader[numberOfSection].PointerToRawData;
  122. PDWORD pSecCharacteristics = &amp;pSectionHeader[numberOfSection].Characteristics;
  123. //修改PE文件头里面的节数量信息
  124. printf("*pNumberOfSection:%#X \r\n",pPEHeder->NumberOfSections);
  125. *pNumberOfSection = pPEHeder->NumberOfSections + 1;
  126. printf("*pNumberOfSection:%#X \r\n",pPEHeder->NumberOfSections);
  127. //修改PE可选头里面SizeOfImage信息
  128. printf("*pSizeOfImage:%#X \r\n",pOptionHeader->SizeOfImage);
  129. *pSizeOfImage = pOptionHeader->SizeOfImage + 0x1000;
  130. printf("*pSizeOfImage:%#X \r\n",pOptionHeader->SizeOfImage);
  131. //向节表中添加数据
  132. memcpy(pSecName,".newSec",8);
  133. *pSecMisc = 0x1000;
  134. //使用上面的公式
  135. //判断出要添加的值
  136. DWORD add_size = pLastSectionHeader->Misc.VirtualSize > pLastSectionHeader->SizeOfRawData?\
  137. pLastSectionHeader->Misc.VirtualSize:pLastSectionHeader->SizeOfRawData;
  138. //上面是个三目运算符
  139. printf("pLastSectionHeader: %#X \r\n",pLastSectionHeader);
  140. printf("add_size: %#X \r\n",add_size);
  141. printf("numberOfSection: %#X \r\n",pPEHeder->NumberOfSections);
  142. printf("pLastSectionHeader->Misc.VirtualSize: %#X \r\n",pLastSectionHeader->Misc.VirtualSize);
  143. printf("pLastSectionHeader->SizeOfRawData: %#X \r\n",pLastSectionHeader->SizeOfRawData);
  144. printf("add_size: %#X \r\n",add_size);
  145. *pSecVirtualAddress = pLastSectionHeader->VirtualAddress + add_size;
  146. //SectionAlignment对齐
  147. if (*pSecVirtualAddress % pOptionHeader->SectionAlignment)
  148. {
  149. *pSecVirtualAddress = *pSecVirtualAddress / pOptionHeader->SectionAlignment * \
  150. pOptionHeader->SectionAlignment + pOptionHeader->SectionAlignment;
  151. }
  152. *pSecSizeOfRawData = 0x1000;
  153. *pSecPointToRawData = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
  154. //FileAlignment对齐
  155. if (*pSecPointToRawData % pOptionHeader->FileAlignment)
  156. {
  157. *pSecPointToRawData = *pSecPointToRawData / pOptionHeader->FileAlignment * \
  158. pOptionHeader->FileAlignment + pOptionHeader->FileAlignment;
  159. }
  160. *pSecCharacteristics = 0xFFFFFFFF;
  161. *pNewImageBuffer = pTempNewImageBuffer;
  162. pTempNewImageBuffer = NULL;
  163. return sizeOfFile;
  164. }
  165. BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile)
  166. {
  167. FILE* fp = NULL;
  168. fp = fopen(lpszFile, "wb+");
  169. if (!fp) // 这里我刚开始写漏了一个等于号,变成复制NULL了,导致错误
  170. // if(fp == NULL) 可以这么写,没问题
  171. {
  172. fclose(fp);
  173. return FALSE;
  174. }
  175. fwrite(pMemBuffer,size,1,fp);
  176. fclose(fp);
  177. fp = NULL;
  178. return TRUE;
  179. }
  1. VOID NewSectionsInCodeSec()
  2. {
  3. LPVOID pFileBuffer = NULL;
  4. LPVOID pNewImageBuffer = NULL;
  5. BOOL isOK = FALSE;
  6. DWORD size1 = 0;
  7. DWORD size2 = 0;
  8. //File-->FileBuffer
  9. size1 = ReadPEFile(FilePath_In,&amp;pFileBuffer);
  10. if (size1 == 0 || !pFileBuffer)
  11. {
  12. printf("文件-->缓冲区失败\r\n");
  13. return ;
  14. }
  15. printf("fileSize - Final: %#X \r\n",size1);
  16. //FileBuffer-->NewImageBuffer
  17. size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&amp;pNewImageBuffer);
  18. if (size2 == 0 || !pFileBuffer)
  19. {
  20. printf("FileBuffer-->NewImageBuffer失败\r\n");
  21. free(pFileBuffer);
  22. return ;
  23. }
  24. printf("sizeOfFile - Final: %#X \r\n",size2);
  25. //NewImageBuffer-->文件
  26. isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out);
  27. if (isOK)
  28. {
  29. printf("新增节表和节存盘成功\r\n");
  30. return ;
  31. }
  32. //释放内存
  33. free(pFileBuffer);
  34. free(pNewImageBuffer);
  35. }
  1. // test2.cpp:程序执行代码
  2. #include "stdafx.h"
  3. #include "test.h"
  4. int main(int argc, char* argv[])
  5. {
  6. NewSectionsInCodeSec();
  7. printf("Hello World! Cntf\r\n");
  8. return 0;
  9. }

手动分析-3

继续考虑一种更极端的情况

DOS头到PE标记中的垃圾数据是由编译器生成的,那么如果我们提升了PE标记,空间任然不够我们去新增一个节表

这个时候,我们就要去扩大最后一个节

0x2扩大节

前言

之前我们都是在空白区域,去新增我们的节

但是,当空白区域无法满足我们的要求,我们就要去扩大节

整体流程

  1. 1、拉伸到内存
  2. 2、分配一块新的空间:SizeOfImage + Ex(要扩大的节)
  3. 3、将最后一个节的SizeOfRawData(文件中对齐后的大小)和VirtualSize(内存中对齐前的大小)改成一样大,改成N
  4. NSizeOfRawData(文件中对齐后的大小)和VirtualSize(内存中对齐前的大小)两者之间,大的那个值
  5. N = 大的那个值 + Ex
  6. SizeOfRawData = VirtualSize = N
  7. 4、修改SizeOfImage大小
  8. SizeOfImage = SizeOfImage + Ex

image-20220204160435499

核心代码

  1. // test.h: 头文件
  2. #if !defined(AFX_test_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_)
  3. #define AFX_test_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_
  4. #if _MSC_VER > 1000
  5. #pragma once
  6. #endif // _MSC_VER > 1000
  7. #include <string.h>
  8. #include <windows.h>
  9. #include <stdlib.h>
  10. #define FilePath_In "C:\\notepad.exe"
  11. #define FilePath_Out "C:\\notepadnewpes.exe"
  12. #define MESSAGEBOXADDR 0x77D5050B
  13. #define SHELLCODELENGTH 0x12 //16进制的,转换为十进制就是18
  14. extern BYTE ShellCode[];
  15. //读文件 --->FileBuffer
  16. DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer);
  17. //写到ImageBuffer,FileBuffer ---> ImageBuffer
  18. DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer);
  19. //写到NewImageBuffer, FileBuffer ---> NewImageBuffer
  20. DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer);
  21. //写到NewImageBuffer, 这里是从ImageBuffer写入 ---> NewImageBuffer
  22. DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pNewImageBuffer);
  23. DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer);
  24. //写到pNewBuffer里面,从pNewImageBuffer写入 ---> pNewBuffer
  25. //DWORD ModifyImageBufferToNewBuffer(IN LPVOID pNewImageBuffer,OUT LPVOID* pNewBuffer);
  26. //对齐大小
  27. DWORD AlignLength(DWORD Actuall_size,DWORD Align_size);
  28. //将MemBuffer写入到硬盘,这里就是将各种修改好的内存文件,存入到本地硬盘中;
  29. BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile);
  30. //DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva);
  31. //调用函数,添加ShellCode代码
  32. VOID AddCodeInCodeSec(); //这个调用函数用到下面的4个函数
  33. //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewBuffer MemeryTOFile
  34. //调用函数,新增节表和节操作;
  35. VOID NewSectionsInCodeSec(); //这个调用函数用到下面的3个函数
  36. //ReadPEFile CopyFileBufferToNewImageBuffer MemeryTOFile
  37. //调用函数,扩大最后一个节
  38. VOID ExtendLastSectionsInCodeSec(); //这个调用函数用到下面的4个函数
  39. //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewImageBuffer MemeryTOFile
  40. #endif // !defined(AFX_test_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_)
  1. // test.cpp
  2. #include "stdafx.h"
  3. #include "test.h"
  4. //定义一个全局变量
  5. BYTE ShellCode[] =
  6. {
  7. 0x6A,00,0x6A,00,0x6A,00,0x6A,00, //MessageBox push 0的硬编码
  8. 0xE8,00,00,00,00, // call汇编指令E8和后面待填充的硬编码
  9. 0xE9,00,00,00,00 // jmp汇编指令E9和后面待填充的硬编码
  10. };
  11. //ExeFile->FileBuffer 返回值为计算所得文件大小
  12. //读取一个exe文件,然后输出为FileBuffer
  13. DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer)
  14. {
  15. //下面有个IN和OUT,大致意思就是参数的类型传入进来之后不进行宏扩展;
  16. //啥也不干,即使理解成干,也是扩展成空白,这个是C++语法中允许的;
  17. //LPSTR ----> typedef CHAR *LPSTR, *PSTR; 意思就是char* 指针;在WINNT.H头文件里面
  18. FILE* pFile = NULL;
  19. //定义一个FILE结构体指针,在标准的Stdio.h文件头里面
  20. //可参考:https://blog.csdn.net/qq_15821725/article/details/78929344
  21. DWORD fileSize = 0;
  22. // typedef unsigned long DWORD; DWORD是无符号4个字节的整型
  23. LPVOID pTempFileBuffer = NULL;
  24. //LPVOID ----> typedef void far *LPVOID;在WINDEF.H头文件里面;别名的void指针类型
  25. //打开文件
  26. pFile = fopen(lpszFile,"rb"); //lpszFile是当作参数传递进来
  27. if (!pFile)
  28. {
  29. printf("打开文件失败!\r\n");
  30. return 0;
  31. }
  32. //读取文件内容后,获取文件的大小
  33. fseek(pFile,0,SEEK_END);
  34. fileSize = ftell(pFile);
  35. fseek(pFile,0,SEEK_SET);
  36. //动态申请内存空间
  37. pTempFileBuffer = malloc(fileSize);
  38. if (!pTempFileBuffer)
  39. {
  40. printf("内存分配失败!\r\n");
  41. fclose(pFile);
  42. return 0;
  43. }
  44. //根据申请到的内存空间,读取数据
  45. size_t n = fread(pTempFileBuffer,fileSize,1,pFile);
  46. if (!n)
  47. {
  48. printf("读取数据失败!\r\n");
  49. free(pTempFileBuffer); // 释放内存空间
  50. fclose(pFile); // 关闭文件流
  51. return 0;
  52. }
  53. //数据读取成功,关闭文件
  54. *pFileBuffer = pTempFileBuffer; // 将读取成功的数据所在的内存空间的首地址放入指针类型pFileBuffer
  55. pTempFileBuffer = NULL; // 初始化清空临时申请的内存空间
  56. fclose(pFile); // 关闭文件
  57. return fileSize; // 返回获取文件的大小
  58. }
  59. //CopyFileBuffer --> ImageBuffer
  60. //将读取的FileBuffer拉伸加载到ImageBuffer,用作测试验证文件拉伸;
  61. DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer)
  62. {
  63. PIMAGE_DOS_HEADER pDosHeader = NULL;
  64. PIMAGE_NT_HEADERS pNTHeader = NULL;
  65. PIMAGE_FILE_HEADER pPEHeader = NULL;
  66. PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
  67. PIMAGE_SECTION_HEADER pSectionHeader = NULL;
  68. LPVOID pTempImageBuffer = NULL;
  69. if (pFileBuffer == NULL)
  70. {
  71. printf("FileBuffer 获取失败!\r\n");
  72. return 0;
  73. }
  74. //判断是否是有效的MZ标志
  75. if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
  76. {
  77. printf("无效的MZ标识\r\n");
  78. return 0;
  79. }
  80. pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
  81. //判断是否是有效的PE标志
  82. if (*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
  83. {
  84. printf("无效的PE标记\r\n");
  85. return 0;
  86. }
  87. //定位NT头
  88. pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
  89. //上面偏移完成之后pFileBuffer的指针偏移到了NT头---> pNTHeader
  90. //****************************************************************************************
  91. //定位PE文件头
  92. pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+4);
  93. //根据PE头的结构体内容,PE文件头位置在NT头首地址偏移4个字节即可得到pPEHeader
  94. //****************************************************************************************
  95. //定位可选PE头
  96. pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
  97. /*
  98. 要得到可选PE的首地址位置,就根据上面得到的PE文件头位置里面的IMAGE_SIZEOF_FILE_HEADER来定位;
  99. IMAGE_SIZEOF_FILE_HEADER也是个宏扩展,里面字节描述了PE文件头的大小是20个字节;
  100. #define IMAGE_SIZEOF_FILE_HEADER 20,所以只要在PE文件头的首地址偏移20个字节即可移动到可选PE头;
  101. 指针相加的时候,此处的类型依然是DWORD
  102. */
  103. //****************************************************************************************
  104. //第一个节表指针
  105. pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
  106. /*
  107. 这里要移动到第一个节表指针的首地址,就需要根据上面标准PE文件头中的SizeOfOptionalHeader获取具体可选PE
  108. 头的大小,然后根据这个大小进行偏移即可;
  109. */
  110. //根据SizeOfImage申请新的内存空间
  111. pTempImageBuffer = malloc(pOptionHeader->SizeOfImage);
  112. if (!pTempImageBuffer)
  113. {
  114. printf("再次在堆中申请一块内存空间失败\r\n");
  115. return 0;
  116. }
  117. //因为下面要开始对内存空间进行复制操作,所以需要初始化操作,将其置为0,避免垃圾数据,或者其他异常
  118. //初始化新的缓冲区
  119. memset(pTempImageBuffer,0,pOptionHeader->SizeOfImage);
  120. //根据SizeOfHeaders大小的确定,先复制Dos头
  121. memcpy(pTempImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
  122. //上面把已经确定的头都复制好了,那么下面就可以开始复制节的里面的内容,因为节不仅仅是一个,所以需要用到for循环进行操作
  123. //根据节表循环copy节的内容
  124. PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
  125. //定义一个临时节表的指针
  126. for (int i=0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++)
  127. {
  128. memcpy((void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress),
  129. (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData);
  130. }
  131. //返回数据
  132. *pImageBuffer = pTempImageBuffer;
  133. //将复制好后节的首地址保存到指针pImageBuffer中
  134. pTempImageBuffer = NULL;
  135. //初始化清空临时使用的pTempImageBuffer
  136. return pOptionHeader->SizeOfImage;
  137. }
  138. //FileBuffer ---> NewImageBuffer(新增节操作)?
  139. //通过复制FileBuffer并增加1000H到新的NewImageBuffer,用作新增节;
  140. DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer)
  141. {
  142. PIMAGE_DOS_HEADER pDosHeader = NULL;
  143. PIMAGE_NT_HEADERS pNTHeader = NULL;
  144. PIMAGE_FILE_HEADER pPEHeder = NULL;
  145. PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
  146. PIMAGE_SECTION_HEADER pSectionHeader = NULL;
  147. PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
  148. LPVOID pTempNewImageBuffer = 0;
  149. DWORD sizeOfFile = 0;
  150. DWORD numberOfSection = 0;
  151. DWORD okAddSections = 0;
  152. //判断读取pFileBuffer读取是否成功
  153. if (!pFileBuffer)
  154. {
  155. printf("缓冲区指针无效\r\n");
  156. return 0;
  157. }
  158. //判断是否为MZ标志
  159. if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE --> MZ
  160. {
  161. printf("不是一个有效的MZ标志\r\n");
  162. return 0;
  163. }
  164. //判断是否为PE标志
  165. pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
  166. if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // IMAGE_NT_SIGNATURE --> PE
  167. {
  168. printf("不是有效的PE标志\r\n");
  169. return 0;
  170. }
  171. //申请开辟内存空间
  172. sizeOfFile = fileSize+0x1000;
  173. pTempNewImageBuffer = malloc(sizeOfFile);
  174. //判断内存空间开辟是否成功
  175. if (!pTempNewImageBuffer)
  176. {
  177. printf("pTempNewImageBuffer开辟内存空间失败\r\n");
  178. return 0;
  179. }
  180. //初始化内存内容
  181. memset(pTempNewImageBuffer,0,sizeOfFile);
  182. //初始化完成之后,先把为修改的内存空间全部拷贝到新的内存空间
  183. memcpy(pTempNewImageBuffer,pFileBuffer,fileSize);
  184. //定位Dos头地址
  185. pDosHeader = (PIMAGE_DOS_HEADER)(pTempNewImageBuffer);
  186. //定位NT头的地址
  187. pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pTempNewImageBuffer+pDosHeader->e_lfanew);
  188. //定位标志PE头地址
  189. pPEHeder = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+0x04);//PE SIGNATURE 站4个字节
  190. //定位可选PE头地址
  191. pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeder)+IMAGE_SIZEOF_FILE_HEADER);//IMAGE_SIZEOF_FILE_HEADER -> 20个字节
  192. //定位第一个节表地址
  193. pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeder->SizeOfOptionalHeader);
  194. //定位最后一个节表的地址
  195. pLastSectionHeader = &amp;pSectionHeader[pPEHeder->NumberOfSections-1];
  196. //判断是否有足够的空间添加一个节表
  197. //判断条件:
  198. /*
  199. SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小
  200. SizeOfHeader在可选PE头里面
  201. */
  202. okAddSections = (DWORD)(pOptionHeader->SizeOfHeaders - (pDosHeader->e_lfanew + 0x04 + \
  203. sizeof(PIMAGE_FILE_HEADER) + pPEHeder->SizeOfOptionalHeader + sizeof(PIMAGE_SECTION_HEADER) \
  204. * pPEHeder->NumberOfSections));
  205. if (okAddSections < 2*sizeof(PIMAGE_SECTION_HEADER))
  206. {
  207. printf("这个exe文件头不剩余空间不够\r\n");
  208. free(pTempNewImageBuffer);
  209. return 0;
  210. }
  211. //修改
  212. //初始化新节表信息
  213. PWORD pNumberOfSection = &amp;pPEHeder->NumberOfSections;
  214. PDWORD pSizeOfImage = &amp;pOptionHeader->SizeOfImage;
  215. numberOfSection = pPEHeder->NumberOfSections;
  216. PVOID pSecName = &amp;pSectionHeader[numberOfSection].Name;
  217. PDWORD pSecMisc = &amp;pSectionHeader[numberOfSection].Misc.VirtualSize;
  218. PDWORD pSecVirtualAddress = &amp;pSectionHeader[numberOfSection].VirtualAddress;
  219. PDWORD pSecSizeOfRawData = &amp;pSectionHeader[numberOfSection].SizeOfRawData;
  220. PDWORD pSecPointToRawData = &amp;pSectionHeader[numberOfSection].PointerToRawData;
  221. PDWORD pSecCharacteristics = &amp;pSectionHeader[numberOfSection].Characteristics;
  222. //修改PE文件头里面的节数量信息
  223. printf("*pNumberOfSection:%#X \r\n",pPEHeder->NumberOfSections);
  224. *pNumberOfSection = pPEHeder->NumberOfSections + 1;
  225. printf("*pNumberOfSection:%#X \r\n",pPEHeder->NumberOfSections);
  226. //修改PE可选头里面SizeOfImage信息
  227. printf("*pSizeOfImage:%#X \r\n",pOptionHeader->SizeOfImage);
  228. *pSizeOfImage = pOptionHeader->SizeOfImage + 0x1000;
  229. printf("*pSizeOfImage:%#X \r\n",pOptionHeader->SizeOfImage);
  230. //向节表中添加数据
  231. memcpy(pSecName,".newSec",8);
  232. *pSecMisc = 0x1000;
  233. //判断出要添加的值
  234. DWORD add_size = pLastSectionHeader->Misc.VirtualSize > pLastSectionHeader->SizeOfRawData?\
  235. pLastSectionHeader->Misc.VirtualSize:pLastSectionHeader->SizeOfRawData;
  236. //上面是个三目运算符
  237. printf("pLastSectionHeader: %#X \r\n",pLastSectionHeader);
  238. printf("add_size: %#X \r\n",add_size);
  239. printf("numberOfSection: %#X \r\n",pPEHeder->NumberOfSections);
  240. printf("pLastSectionHeader->Misc.VirtualSize: %#X \r\n",pLastSectionHeader->Misc.VirtualSize);
  241. printf("pLastSectionHeader->SizeOfRawData: %#X \r\n",pLastSectionHeader->SizeOfRawData);
  242. printf("add_size: %#X \r\n",add_size);
  243. *pSecVirtualAddress = pLastSectionHeader->VirtualAddress + add_size;
  244. //SectionAlignment对齐
  245. if (*pSecVirtualAddress % pOptionHeader->SectionAlignment)
  246. {
  247. *pSecVirtualAddress = *pSecVirtualAddress / pOptionHeader->SectionAlignment * \
  248. pOptionHeader->SectionAlignment + pOptionHeader->SectionAlignment;
  249. }
  250. *pSecSizeOfRawData = 0x1000;
  251. *pSecPointToRawData = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
  252. //FileAlignment对齐
  253. if (*pSecPointToRawData % pOptionHeader->FileAlignment)
  254. {
  255. *pSecPointToRawData = *pSecPointToRawData / pOptionHeader->FileAlignment * \
  256. pOptionHeader->FileAlignment + pOptionHeader->FileAlignment;
  257. }
  258. *pSecCharacteristics = 0xFFFFFFFF;
  259. *pNewImageBuffer = pTempNewImageBuffer;
  260. pTempNewImageBuffer = NULL;
  261. return sizeOfFile;
  262. }
  263. //求对齐后的大小
  264. //Actuall_size ---> 实际大小
  265. //Align_size ---> 对齐大小
  266. DWORD AlignLength(DWORD Actuall_size,DWORD Align_size)
  267. {
  268. if (Actuall_size % Align_size == 0)
  269. {
  270. return Actuall_size;
  271. }
  272. else
  273. {
  274. DWORD n = Actuall_size / Align_size;
  275. return Align_size*(n+1);
  276. }
  277. }
  278. //ImageBuffer ---> NewImageBuffer
  279. //将拉伸后加载到内存的ImageBuffer存入到NewImageBuffer,修改数据完成之后,准备存盘操作
  280. DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pNewImageBuffer)
  281. {
  282. PIMAGE_DOS_HEADER pDosHeader = NULL;
  283. PIMAGE_NT_HEADERS pNTHeader = NULL;
  284. PIMAGE_FILE_HEADER pPEHeader = NULL;
  285. PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
  286. PIMAGE_SECTION_HEADER pSectionHeader = NULL;
  287. PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
  288. LPVOID pTempNewImageBuffer = NULL;
  289. DWORD ImageBuffer_Size = 0;
  290. DWORD numberOfSection = 0;
  291. //判断读取pImageBuffer是否成功
  292. if (!pFileBuffer)
  293. {
  294. printf("缓冲区指针无效\r\n");
  295. }
  296. //判断是否是有效的MZ头
  297. if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
  298. {
  299. printf("不是有效的MZ头\r\n");
  300. return 0;
  301. }
  302. //判断是否是有效的PE头
  303. pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
  304. if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
  305. {
  306. printf("不是有效的PE头\r\n");
  307. return 0;
  308. }
  309. //定位NT头
  310. pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
  311. //定位标准的PE文件头
  312. pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
  313. //定位可选PE头
  314. pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
  315. //定位第一个节表地址
  316. numberOfSection = pPEHeader->NumberOfSections;
  317. pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
  318. //定位最后一个节表地址
  319. pLastSectionHeader = &amp;pSectionHeader[numberOfSection-1];
  320. printf("numberOfSection --> %#X \r\n",numberOfSection);
  321. printf("*pSectionHeader --> %#X \r\n",pSectionHeader->Misc.VirtualSize);
  322. printf("*pLastSectionHeader --> %#X \r\n",&amp;pLastSectionHeader);
  323. //开始操作需要修改的部分
  324. //最后一个节中内存中对齐前的大小;
  325. PDWORD pVirtualSize = &amp;pLastSectionHeader->Misc.VirtualSize;
  326. //最后一个节在文件中对齐后的大小;
  327. PDWORD pSizeOfRawData = &amp;pLastSectionHeader->SizeOfRawData;
  328. //文件中SizeOfImage的大小;
  329. PDWORD pSizeOfImage = &amp;pOptionHeader->SizeOfImage;
  330. //扩展修改之前的数据
  331. printf("&amp;pLastSectionHeader->Misc.VirtualSize --> %#X \r\n",pVirtualSize);
  332. printf("*pLastSectionHeader->Misc.VirtualSize --> %#X \r\n",*pVirtualSize);
  333. //
  334. printf("&amp;pLastSectionHeader->SizeOfRawData --> %#X \r\n",pSizeOfRawData);
  335. printf("*pLastSectionHeader->SizeOfRawData --> %#X \r\n",*pSizeOfRawData);
  336. //
  337. printf("&amp;pOptionHeader->SizeOfImage --> %#X \r\n",pSizeOfImage);
  338. printf("*pOptionHeader->SizeOfImage --> %#X \r\n",*pSizeOfImage);
  339. //扩展修改pVirtualSize
  340. *pVirtualSize = AlignLength(*pVirtualSize,pOptionHeader->SectionAlignment)+0x1000;
  341. printf("&amp;pLastSectionHeader->Misc.VirtualSize --> %#X \r\n",pVirtualSize);
  342. printf("*pLastSectionHeader->Misc.VirtualSize --> %#X \r\n",*pVirtualSize);
  343. printf("&amp;pLastSectionHeader->SizeOfRawData --> %#X \r\n",pSizeOfRawData);
  344. printf("*pLastSectionHeader->SizeOfRawData --> %#X \r\n",*pSizeOfRawData);
  345. //扩展修改pSizeOfRawData
  346. *pSizeOfRawData = AlignLength(*pSizeOfRawData,pOptionHeader->SectionAlignment)+0x1000;
  347. printf("&amp;pLastSectionHeader->Misc.VirtualSize --> %#X \r\n",pVirtualSize);
  348. printf("*pLastSectionHeader->Misc.VirtualSize --> %#X \r\n",*pVirtualSize);
  349. printf("&amp;pLastSectionHeader->SizeOfRawData --> %#X \r\n",pSizeOfRawData);
  350. printf("*pLastSectionHeader->SizeOfRawData --> %#X \r\n",*pSizeOfRawData);
  351. printf("&amp;pOptionHeader->SizeOfImage --> %#X \r\n",pSizeOfImage);
  352. printf("*pOptionHeader->SizeOfImage --> %#X \r\n",*pSizeOfImage);
  353. //修改SizeOfImage
  354. *pSizeOfImage += 0x1000;
  355. printf("&amp;pLastSectionHeader->Misc.VirtualSize --> %#X \r\n",pVirtualSize);
  356. printf("*pLastSectionHeader->Misc.VirtualSize --> %#X \r\n",*pVirtualSize);
  357. printf("&amp;pLastSectionHeader->SizeOfRawData --> %#X \r\n",pSizeOfRawData);
  358. printf("*pLastSectionHeader->SizeOfRawData --> %#X \r\n",*pSizeOfRawData);
  359. printf("&amp;pOptionHeader->SizeOfImage --> %#X \r\n",pSizeOfImage);
  360. printf("*pOptionHeader->SizeOfImage --> %#X \r\n",*pSizeOfImage);
  361. //得到修改之后的大小准备申请内存空间
  362. ImageBuffer_Size = pOptionHeader->SizeOfImage;
  363. pTempNewImageBuffer = malloc(ImageBuffer_Size);
  364. if (!pTempNewImageBuffer)
  365. {
  366. printf("分配内存空间失败\r\n");
  367. return 0;
  368. }
  369. //初始化内存空间
  370. memset(pTempNewImageBuffer,0,ImageBuffer_Size);
  371. //复制SizeOfHeaders
  372. memcpy(pTempNewImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
  373. //创建临时节的结构体指针,遍历数据
  374. PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
  375. for (DWORD i = 0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++)
  376. {
  377. memcpy((PVOID)((DWORD)pTempNewImageBuffer+pTempSectionHeader->VirtualAddress),\
  378. (void*)((DWORD)pFileBuffer+pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData);
  379. }
  380. *pNewImageBuffer = pTempNewImageBuffer;
  381. pTempNewImageBuffer = NULL;
  382. return *pSizeOfImage;
  383. }
  384. //ImageBuffer ---> NewBuffer
  385. //将拉伸后加载到内存的ImageBuffer存入到NewBuffer里面,然后准备存盘;
  386. DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer)
  387. {
  388. //下面大部分操作都是跟上面一样的,这里就不再赘述了
  389. PIMAGE_DOS_HEADER pDosHeader = NULL;
  390. PIMAGE_NT_HEADERS pNTHeader = NULL;
  391. PIMAGE_FILE_HEADER pPEHeader = NULL;
  392. PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
  393. PIMAGE_SECTION_HEADER pSectionHeader = NULL;
  394. LPVOID pTempNewBuffer = NULL;
  395. DWORD sizeOfFile = 0;
  396. DWORD numberOfSection = 0;
  397. if (pImageBuffer == NULL)
  398. {
  399. printf("缓冲区指针无效\r\n");
  400. }
  401. //判断是否是有效的MZ标志
  402. if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
  403. {
  404. printf("不是有效的MZ头\r\n");
  405. return 0;
  406. }
  407. pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
  408. //判断是否是有效的PE标志
  409. if (*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
  410. {
  411. printf("不是有效的PE标志\r\n");
  412. return 0;
  413. }
  414. //NT头地址
  415. pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
  416. //标准PE文件头
  417. pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
  418. //可选PE头
  419. pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
  420. //第一个节表地址
  421. pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
  422. //计算文件需要的空间--最后一个节的文件偏移+节对齐后的长度
  423. /*
  424. numberOfSection = pPEHeader->NumberOfSections;
  425. pSectionHeader = pSectionHeader[numberOfSection-1];
  426. sizeOfFile = (pSectionHeader->PointerToRawData + pSectionHeader->Misc.VirtualSize + pOptionHeader->FileAlignment);
  427. printf("sizeOfFile %X \r\n",sizeOfFile);
  428. for (DWORD i=0;i<=numberOfSection;i++)
  429. {
  430. sizeOfFile += sizeOfFile[i];
  431. }
  432. */
  433. sizeOfFile = pOptionHeader->SizeOfHeaders;
  434. //使用winhex打开notepad.exe 是0x00000400,这是第一个节之前的所有大小
  435. for(DWORD i = 0;i<pPEHeader->NumberOfSections;i++)
  436. {
  437. sizeOfFile += pSectionHeader[i].SizeOfRawData; // pSectionHeader[i]另一种加法
  438. }
  439. /*
  440. 上面的for循环大概意思就是基于几个节的数量依次循环叠加sizeOfFile的值;因为SizeOfRawData是文件中对齐后的大小;
  441. 所以循环计算如下:
  442. sizeOfFile = 0x00000400 + 0x00007800 = 0x00007C00
  443. sizeOfFile = 0x00007C00 + 0x00000800 = 0x00008400
  444. sizeOfFile = 0x00008400 + 0x00008000 = 0x00010400
  445. */
  446. //根据SizeOfImage申请新的空间
  447. pTempNewBuffer = malloc(sizeOfFile);
  448. if (!pTempNewBuffer)
  449. {
  450. printf("申请内存空间失败\r\n");
  451. return 0;
  452. }
  453. //初始化新的缓冲区
  454. memset(pTempNewBuffer,0,sizeOfFile);
  455. //根据SizeOfHeaders 先copy头
  456. memcpy(pTempNewBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
  457. //根据节表循环复制节
  458. //PIMAGE_SECTION_HEADER pTempSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader);
  459. PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
  460. for (int j=0;j<pPEHeader->NumberOfSections;j++,pTempSectionHeader++)
  461. {
  462. /*memcpy((LPVOID)((DWORD)pTempNewBuffer + pTempSectionHeader->PointerToRawData),
  463. (LPVOID)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress),
  464. pTempSectionHeader->SizeOfRawData);*/
  465. //PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
  466. memcpy((PDWORD)((DWORD)pTempNewBuffer+pTempSectionHeader->PointerToRawData),
  467. (PDWORD)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress),
  468. pTempSectionHeader->SizeOfRawData);
  469. //printf("%X --> PoniterToRadata\r\n",pTempSectionHeader->PointerToRawData);
  470. //printf("%X --> VirtualAddress\r\n",pTempSectionHeader->VirtualAddress);
  471. //printf("%X --> VirtualSize\r\n",pTempSectionHeader->Misc.VirtualSize);
  472. }
  473. //返回数据
  474. *pNewBuffer = pTempNewBuffer;
  475. pTempNewBuffer = NULL;
  476. return sizeOfFile;
  477. }
  478. //将上面得到的MemBuffer存盘到本地;
  479. BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile)
  480. {
  481. FILE* fp = NULL;
  482. fp = fopen(lpszFile, "wb+");
  483. if (!fp) // 这里我刚开始写漏了一个等于号,变成复制NULL了,导致错误
  484. // if(fp == NULL) 可以这么写,没问题
  485. {
  486. fclose(fp);
  487. return FALSE;
  488. }
  489. fwrite(pMemBuffer,size,1,fp);
  490. fclose(fp);
  491. fp = NULL;
  492. return TRUE;
  493. }
  494. /*
  495. DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva)
  496. {
  497. DWORD dwFOAValue = 0;
  498. PIMAGE_DOS_HEADER pDosHeader = NULL;
  499. PIMAGE_NT_HEADERS pNTHeader = NULL;
  500. PIMAGE_FILE_HEADER pPEHeader = NULL;
  501. PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
  502. PIMAGE_SECTION_HEADER pSectionHeader = NULL;
  503. pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
  504. //判断指针是否有效
  505. if (!pFileBuffer)
  506. {
  507. printf("FileBuffer 指针无效\r\n");
  508. return dwFOAValue;
  509. }
  510. //判断是否是有效的MZ标志
  511. if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
  512. {
  513. printf("不是有效的MZ标志\r\n");
  514. return dwFOAValue;
  515. }
  516. //为需要用到的指针赋值
  517. pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
  518. pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
  519. pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
  520. pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
  521. //判断dwRva所处的节
  522. //计算与节开始位置的差
  523. //该节文件中的偏移+差 == 该值在文件中的偏移
  524. return 0;
  525. }
  526. */
  527. //在原有的exe文件中开始操作添加ShellCode代码;
  528. VOID AddCodeInCodeSec()
  529. {
  530. LPVOID pFileBuffer = NULL;
  531. LPVOID pImageBuffer = NULL;
  532. LPVOID pNewBuffer = NULL;
  533. PIMAGE_DOS_HEADER pDosHeader = NULL;
  534. PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
  535. PIMAGE_SECTION_HEADER pSectionHeader = NULL;
  536. PBYTE codeBegin = NULL;
  537. BOOL isOK = FALSE;
  538. DWORD size = 0;
  539. //File-->FileBuffer
  540. ReadPEFile(FilePath_In,&amp;pFileBuffer);
  541. if (!pFileBuffer)
  542. {
  543. printf("文件-->缓冲区失败\r\n");
  544. return ;
  545. }
  546. //FileBuffer-->ImageBuffer
  547. CopyFileBufferToImageBuffer(pFileBuffer,&amp;pImageBuffer);
  548. if (!pImageBuffer)
  549. {
  550. printf("FileBuffer-->ImageBuffer失败\r\n");
  551. free(pFileBuffer);
  552. return ;
  553. }
  554. //判断代码段空闲区域是否能够足够存储ShellCode代码
  555. pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
  556. pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
  557. pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_NT_OPTIONAL32_HEADER);
  558. if (((pSectionHeader->SizeOfRawData) - (pSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH)
  559. {
  560. printf("代码区域空闲空间不够\r\n");
  561. free(pFileBuffer);
  562. free(pImageBuffer);
  563. }
  564. //将代码复制到空闲区域
  565. codeBegin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);
  566. printf("pSectionHeader->VirtualAddress: %#010X\r\n", pSectionHeader->VirtualAddress);
  567. printf("pSectionHeader->Misc.VirtualSize: %#010X\r\n", pSectionHeader->Misc.VirtualSize);
  568. printf("codeBegin: %#010X\r\n", codeBegin);
  569. memcpy(codeBegin,ShellCode,SHELLCODELENGTH);
  570. //修正E8-->call后面的代码区域
  571. DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + 0xD) - (DWORD)pImageBuffer)));
  572. printf("callAddr ---> %#010X \r\n",callAddr);
  573. *(PDWORD)(codeBegin + 0x09) = callAddr;
  574. printf("*(PWORD)(codeBegin + 0x09) ---> %#010X \r\n",*(PDWORD)(codeBegin + 0x09));
  575. //修正E9-->jmp后面的代码区域
  576. DWORD jmpAddr = ((pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint) - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + SHELLCODELENGTH) - (DWORD)pImageBuffer)));
  577. printf("jmpAddr ---> %#010X \r\n",jmpAddr);
  578. *(PDWORD)(codeBegin + 0x0E) = jmpAddr;
  579. printf("*(PWORD)(codeBegin + 0x0E) ---> %#010X \r\n",*(PDWORD)(codeBegin + 0x0E));
  580. //修正OEP
  581. printf("pOptionHeader->AddressOfEntryPoint ---> %#010X \r\n",pOptionHeader->AddressOfEntryPoint);
  582. printf("(DWORD)codeBegin ---> %#010X \r\n",((DWORD)codeBegin - (DWORD)pImageBuffer));
  583. pOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pImageBuffer;
  584. printf("pOptionHeader->AddressOfEntryPoint ---> %#010X \r\n",pOptionHeader->AddressOfEntryPoint);
  585. //修正OEP好理解,就是定位到OEP地址,然后直接通过codeBegin地址减去pImageBuffer的首地址即可;
  586. //ImageBuffer-->NewBuffer
  587. size = CopyImageBufferToNewBuffer(pImageBuffer,&amp;pNewBuffer);
  588. if (size == 0 || !pNewBuffer)
  589. {
  590. printf("ImageBuffer-->NewBuffer失败\r\n");
  591. free(pFileBuffer);
  592. free(pImageBuffer);
  593. return ;
  594. }
  595. //NewBuffer-->文件
  596. isOK = MemeryTOFile(pNewBuffer,size,FilePath_Out);
  597. if (isOK)
  598. {
  599. printf("修改代码添加SHELLCODE 存盘成功\r\n");
  600. return ;
  601. }
  602. //释放内存
  603. free(pFileBuffer);
  604. free(pImageBuffer);
  605. free(pNewBuffer);
  606. }
  607. //调用函数新增节表和节操作,成功之后并存盘到本地;
  608. VOID NewSectionsInCodeSec()
  609. {
  610. LPVOID pFileBuffer = NULL;
  611. LPVOID pNewImageBuffer = NULL;
  612. BOOL isOK = FALSE;
  613. DWORD size1 = 0;
  614. DWORD size2 = 0;
  615. //File-->FileBuffer
  616. size1 = ReadPEFile(FilePath_In,&amp;pFileBuffer);
  617. if (size1 == 0 || !pFileBuffer)
  618. {
  619. printf("文件-->缓冲区失败\r\n");
  620. return ;
  621. }
  622. printf("fileSize - Final: %#X \r\n",size1);
  623. //FileBuffer-->NewImageBuffer
  624. size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&amp;pNewImageBuffer);
  625. if (size2 == 0 || !pFileBuffer)
  626. {
  627. printf("FileBuffer-->NewImageBuffer失败\r\n");
  628. free(pFileBuffer);
  629. return ;
  630. }
  631. printf("sizeOfFile - Final: %#X \r\n",size2);
  632. //NewImageBuffer-->文件
  633. isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out);
  634. if (isOK)
  635. {
  636. printf("新增节表和节存盘成功\r\n");
  637. return ;
  638. }
  639. //释放内存
  640. free(pFileBuffer);
  641. free(pNewImageBuffer);
  642. }
  643. VOID ExtendLastSectionsInCodeSec()
  644. {
  645. //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewImageBuffer
  646. LPVOID pFileBuffer = NULL;
  647. LPVOID pImageBuffer = NULL;
  648. LPVOID pNewImageBuffer = NULL;
  649. BOOL isOK = FALSE;
  650. DWORD FileBufferSize = 0;
  651. DWORD ImageBufferSize = 0;
  652. DWORD size = 0;
  653. //File-->FileBuffer
  654. FileBufferSize = ReadPEFile(FilePath_In,&amp;pFileBuffer);
  655. if (FileBufferSize == 0 || !pFileBuffer)
  656. {
  657. printf("文件-->缓冲区失败\r\n");
  658. return ;
  659. }
  660. printf("FileBufferSize - Final: %#X \r\n",FileBufferSize);
  661. //FileBuffer-->ImageBuffer
  662. ImageBufferSize = FileBufferToModifyImageBuffer(pFileBuffer,&amp;pImageBuffer);
  663. if (ImageBufferSize == 0 || !pFileBuffer)
  664. {
  665. printf("FileBuffer-->ImageBuffer失败\r\n");
  666. free(pFileBuffer);
  667. return ;
  668. }
  669. printf("ImageBufferSize - Final: %#X \r\n",ImageBufferSize);
  670. size = CopyImageBufferToNewBuffer(pImageBuffer,&amp;pNewImageBuffer);
  671. if (size == 0 || !pImageBuffer)
  672. {
  673. printf("pImageBuffer-->pNewImageBuffer失败\r\n");
  674. free(pFileBuffer);
  675. return ;
  676. }
  677. //pNewImageBuffer-->文件
  678. isOK = MemeryTOFile(pNewImageBuffer,size,FilePath_Out);
  679. if (isOK)
  680. {
  681. printf("扩大一个节成功,并存盘\r\n");
  682. return ;
  683. }
  684. //释放内存
  685. free(pFileBuffer);
  686. free(pImageBuffer);
  687. free(pNewImageBuffer);
  688. }
  1. // test2.cpp:程序入口
  2. //
  3. #include "stdafx.h"
  4. #include "test.h"
  5. int main(int argc, char* argv[])
  6. {
  7. //Fun();
  8. //AddCodeInCodeSec();
  9. //NewSectionsInCodeSec();
  10. ExtendLastSectionsInCodeSec();
  11. printf("Hello World! Cntf\r\n");
  12. return 0;
  13. }
  • 发表于 2022-02-18 09:37:41
  • 阅读 ( 6600 )
  • 分类:渗透测试

0 条评论

略略略
略略略

36 篇文章

站长统计