zoukankan      html  css  js  c++  java
  • 滴水逆向-合并节操作

    课堂上很好理解的一副,贴进来;

     

    合并节算法解释

    1.读取文件,拉伸到内存;
    2.第一种算法;
    (1)取最后一个节中(SizeOfRawData和VirtualSize)的值,谁大就取谁,下面是简单的算法表达式;
    最后一个节Max = SizeOfRawData>VirtualSize?SizeOfRawData:VirtualSize;
    (2)通过最后一个节的VirtualAddress + 上面得到的最后一个节Max - 拉伸后的SizeOfHeaders内存对齐后的大小
    (3)将上面算出来的值分别将其置为一样 --> SizeOfRawData = VirtualSize;
      第二种算法;
    (1)直接获取拉伸后的SizeOfImage大小减去拉伸后的第一个节VirtualAddress大小即可得到一个值;SizeOfImage-VirtualAddress
    (2)将上面算出来的值分别将其置为一样 --> SizeOfRawData = VirtualSize;
    
    3.将第一个节的属性改为包含所有节的属性,这一步操作其实就是上面的算法操作;
    4.修改节的数量为1;
    5.上面操作完成就是动态申请内存,完成初始化置0,然后内存复制数据,存盘的操作即可;

    核心代码部分

       1 // gbpeall.cpp: implementation of the gbpeall class.
       2 //
       3 //////////////////////////////////////////////////////////////////////
       4 
       5 #include "stdafx.h"
       6 #include "gbpeall.h"
       7 
       8 
       9 //////////////////////////////////////////////////////////////////////
      10 // Construction/Destruction
      11 //////////////////////////////////////////////////////////////////////
      12 
      13 
      14 //定义一个全局变量
      15 BYTE ShellCode[] =
      16 {
      17     0x6A,00,0x6A,00,0x6A,00,0x6A,00, //MessageBox push 0的硬编码
      18     0xE8,00,00,00,00,  // call汇编指令E8和后面待填充的硬编码
      19     0xE9,00,00,00,00   // jmp汇编指令E9和后面待填充的硬编码
      20 };
      21 
      22 //ExeFile->FileBuffer  返回值为计算所得文件大小
      23 //读取一个exe文件,然后输出为FileBuffer
      24 DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer)
      25 {
      26     //下面有个IN和OUT,大致意思就是参数的类型传入进来之后不进行宏扩展;
      27     //啥也不干,即使理解成干,也是扩展成空白,这个是C++语法中允许的;
      28     //LPSTR  ---->  typedef CHAR *LPSTR, *PSTR; 意思就是char* 指针;在WINNT.H头文件里面
      29     FILE* pFile = NULL;
      30     //定义一个FILE结构体指针,在标准的Stdio.h文件头里面
      31     //可参考:https://blog.csdn.net/qq_15821725/article/details/78929344
      32     DWORD fileSize = 0;
      33     // typedef unsigned long       DWORD;  DWORD是无符号4个字节的整型
      34     LPVOID pTempFileBuffer = NULL;
      35     //LPVOID ---->  typedef void far *LPVOID;在WINDEF.H头文件里面;别名的void指针类型
      36 
      37     //打开文件
      38     pFile = fopen(lpszFile,"rb"); //lpszFile是当作参数传递进来
      39     if (!pFile)
      40     {
      41         printf("打开文件失败!
    ");
      42         return 0;
      43     }
      44     /*
      45     关于在指针类型中进行判断的操作,下面代码出现的情况和此一样,这里解释下:
      46     1.因为指针判断都要跟NULL比较,相当于0,假值,其余都是真值
      47     2.if(!pFile)和if(pFile == NULL), ----> 为空,就执行语句;这里是两个等于号不是一个等于号
      48     3.if(pFile)就是if(pFile != NULL), 不为空,就执行语句;
      49     */
      50 
      51     //读取文件内容后,获取文件的大小
      52     fseek(pFile,0,SEEK_END);
      53     fileSize = ftell(pFile);
      54     fseek(pFile,0,SEEK_SET);
      55 
      56     /*
      57     fseek 通过使用二进制的方式打开文件,移动文件读写指针的位置,在stdio.h头文件里
      58 
      59     int fseek(FILE * stream, long offset, int fromwhere);
      60 
      61     上面是fseek的函数原型
      62     第一个参数stream 为文件指针
      63     第二个参数offset 为偏移量,整数表示正向偏移,负数表示负向偏移
      64     第三个参数fromwhere 为指针的起始位置,设定从文件的哪里开始偏移,可能取值为:SEEK_CUR,SEEK_END,SEEK_SET
      65     SEEK_SET 0 文件开头
      66     SEEK_CUR 1 当前读写的位置
      67     SEEK_END 2 文件尾部
      68 
      69     下面是相关用法和例子:
      70   fseek(fp,100L,0);把fp指针移动到离文件开头100字节处;
      71   fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处;
      72     fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。
      73     fseek(fp,0,SEEK_SET);将读写位置移动到文件开头;
      74     fseek(fp,0,SEEK_END);将读写位置移动到文件尾时;
      75     fseek(fp,100L,SEEK_SET);将读写位置移动到离文件开头100字节处;
      76     fseek(fp,100L,SEEK_CUR);将读写位置移动到离文件当前位置100字节处;
      77     fseek(fp,-100L,SEEK_END);将读写指针退回到离文件结尾100字节处;
      78     fseek(fp,1234L,SEEK_CUR);把读写位置从当前位置向后移动1234字节;
      79     fseek(fp,0L,2);把读写位置移动到文件尾;
      80     其中 --->  L后缀表示长整数
      81 
      82     ftell()用于返回文件当前指针指向的位置,与fseek配合可以算出文件元素数据总数。
      83     参考:http://c.biancheng.net/cpp/html/2519.html
      84 
      85     ftell()函数用来获取文件读写指针的当前位置,其原型为:long ftell(FILE * stream); 同样在stdio.h头文件里
      86     参数:stream 为已打开的文件指针。
      87     */
      88 
      89     //动态申请内存空间
      90     pTempFileBuffer = malloc(fileSize);
      91 
      92     /*
      93     参考:http://c.biancheng.net/cpp/html/137.html
      94     原型:void* malloc (size_t size);
      95     size_t ---> typedef unsigned int size_t; 无符号整型别名是size_t
      96     void*  ---> 函数的返回值类型是 void* ;void并不是说没有返回值或者返回空指针,而是返回的指针类型未知;
      97     所以在使用 malloc() 时通常需要进行强制类型转换,将 void 指针转换成我们希望的类型;
      98     例如:char *ptr = (char *)malloc(10);  //分配10个字节的内存空间,用来存放字符
      99     参数说明 ---> size 为需要分配的内存空间的大小,以字节(Byte)计。
     100     函数说明 ---> malloc()在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化;
     101     它们的值是未知的,所以分配完成内存之后需要初始化;
     102     返回值:分配成功返回指向该内存的地址,失败则返回 NULL。
     103     */
     104 
     105     if (!pTempFileBuffer)
     106     {
     107         printf("内存分配失败!
    ");
     108         fclose(pFile);
     109         return 0;
     110     }
     111 
     112     //根据申请到的内存空间,读取数据
     113 
     114     size_t n = fread(pTempFileBuffer,fileSize,1,pFile);
     115     if (!n)
     116     {
     117         printf("读取数据失败!
    ");
     118         free(pTempFileBuffer);   // 释放内存空间
     119         fclose(pFile);           // 关闭文件流
     120         return 0;
     121     }
     122 
     123     //数据读取成功,关闭文件
     124     *pFileBuffer = pTempFileBuffer;  // 将读取成功的数据所在的内存空间的首地址放入指针类型pFileBuffer
     125     pTempFileBuffer = NULL;  // 初始化清空临时申请的内存空间
     126     fclose(pFile);           // 关闭文件
     127     return fileSize;         // 返回获取文件的大小
     128 }
     129 
     130 //CopyFileBuffer --> ImageBuffer
     131 //将读取的FileBuffer拉伸加载到ImageBuffer,用作测试验证文件拉伸;
     132 DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer)
     133 {
     134     //LPVOID ---->  typedef void far *LPVOID;在WINDEF.H头文件里面;别名的void指针类型
     135     PIMAGE_DOS_HEADER pDosHeader = NULL;
     136     PIMAGE_NT_HEADERS pNTHeader = NULL;
     137     PIMAGE_FILE_HEADER pPEHeader = NULL;
     138     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     139     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     140     LPVOID pTempImageBuffer = NULL;
     141     /*
     142     上面都是PE里面的相关结构体类型,使用其类型进行自定义变量,并初始化值为NULL
     143     PIMAGE_DOS_HEADER ---> 指向结构体,别名为这两个 IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER
     144     PIMAGE_NT_HEADERS ---> 指向结构体,typedef PIMAGE_NT_HEADERS32    PIMAGE_NT_HEADERS;
     145     PIMAGE_FILE_HEADER ---> 指向结构体,别名为这两个 IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
     146     PIMAGE_OPTIONAL_HEADER32 ---> 指向结构体,别名为这两个 IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
     147     PIMAGE_SECTION_HEADER ---> 指向结构体,别名为这两个 IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
     148     */
     149 
     150     if (pFileBuffer == NULL)
     151     {
     152         printf("FileBuffer 获取失败!
    ");
     153         return 0;
     154     }
     155 
     156     //判断是否是有效的MZ标志
     157     if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
     158     {
     159         printf("无效的MZ标识
    ");
     160         return 0;
     161     }
     162     /*
     163     IMAGE_DOS_SIGNATURE 这个在头文件WINNT.H里面,对应是个无参数宏;
     164     #define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
     165     在宏扩展的时候就会替换为0x5A4D ,然后根据架构的不同进行排序存储,分大端和小端模式;
     166     使用上面方式进行比对是否是有效的MZ头是非常有效;
     167     而且IMAGE_DOS_SIGNATURE存储的值是两个字节,刚好就是PWORD ---> typedef WORD near *PWORD;
     168     所以在进行比较的时候需要强制类型转换为相同的类型进行比较
     169     */
     170 
     171     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
     172     //这里的定义,就相当于已经确定了,其头肯定是MZ了,然后强制转换类型为PIMAGE_DOS_HEADER,就是Dos头
     173 
     174     //判断是否是有效的PE标志
     175     if (*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     176     {
     177         printf("无效的PE标记
    ");
     178         return 0;
     179     }
     180     /*
     181     IMAGE_NT_SIGNATURE  ---> #define IMAGE_NT_SIGNATURE   0x00004550  // PE00
     182     上述同样是个宏扩展,在头文件WINNT.H里面;
     183     在进行比对的时候因为在Dos头里面有个值是 e_lfanew 对应的时候DWORD类型,所以在进行指针相加的时候
     184     需要先进行强制类型转换,然后相加,即移动指针位置;然后最终需要比对的结果是0x4550站两个字节
     185     所以又要强制转换类型为PWORD;
     186     */
     187     //定位NT头
     188     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
     189     //上面偏移完成之后pFileBuffer的指针偏移到了NT头---> pNTHeader
     190     //****************************************************************************************
     191     //定位PE文件头
     192     pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+4);
     193     //根据PE头的结构体内容,PE文件头位置在NT头首地址偏移4个字节即可得到pPEHeader
     194     //****************************************************************************************
     195     //定位可选PE头
     196     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     197     /*
     198     要得到可选PE的首地址位置,就根据上面得到的PE文件头位置里面的IMAGE_SIZEOF_FILE_HEADER来定位;
     199     IMAGE_SIZEOF_FILE_HEADER也是个宏扩展,里面字节描述了PE文件头的大小是20个字节;
     200     #define IMAGE_SIZEOF_FILE_HEADER  20,所以只要在PE文件头的首地址偏移20个字节即可移动到可选PE头;
     201     指针相加的时候,此处的类型依然是DWORD
     202     */
     203     //****************************************************************************************
     204     //第一个节表指针
     205     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
     206     /*
     207     这里要移动到第一个节表指针的首地址,就需要根据上面标准PE文件头中的SizeOfOptionalHeader获取具体可选PE
     208     头的大小,然后根据这个大小进行偏移即可;
     209     */
     210     //****************************************************************************************
     211 
     212     /*
     213     到了节表的首地址位置之后,因为需要将FileBuffer复制到ImageBuffer,这个过程中,节表之前的Dos头,NT头
     214     PE文件头,可选PE头,她们的大小都是不变的,所以定位出来之后,到后面的操作中直接复制即可,而节表不一样
     215     她在FileBuffer状态和ImageBuffer状态是不相同的,她们节表之间复制转换到ImageBuffer是需要拉长节表,所以
     216     在操作的时候是需要确定FileBuffer到ImageBuffer之后ImageBuffer的大小是多少,而这个大小,已经在可选PE头
     217     里面的某一个值中已经给出来了 ---> SizeOfImage ;
     218     注意:FileBuffer和ImageBuffer都是在内存中的展示,只不过FileBuffer是使用winhex等类似的形式打开查看其
     219     二进制的形式,而ImageBuffer则是双击打开应用程序,将其加载至内存中显示的二进制的形式;
     220     */
     221     //****************************************************************************************
     222 
     223     //根据SizeOfImage申请新的内存空间
     224     pTempImageBuffer = malloc(pOptionHeader->SizeOfImage);
     225 
     226     if (!pTempImageBuffer)
     227     {
     228         printf("再次在堆中申请一块内存空间失败
    ");
     229         return 0;
     230     }
     231 
     232     //因为下面要开始对内存空间进行复制操作,所以需要初始化操作,将其置为0,避免垃圾数据,或者其他异常
     233     //初始化新的缓冲区
     234     memset(pTempImageBuffer,0,pOptionHeader->SizeOfImage);
     235     /*
     236     参考:http://c.biancheng.net/cpp/html/157.html
     237 
     238     在头文件string.h里面
     239 
     240     void* memset( void* ptr,int value,size_t num );
     241     memset()函数用来将指定内存的前n个字节设置为特定的值;
     242 
     243     参数说明:
     244     ptr     为要操作的内存的指针;
     245     value   为要设置的值;既可以向value传递int类型的值,也可以传递char类型的值,int和char可以根据ASCII码相互转换;
     246     num     为ptr的前num个字节,size_t就是unsigned int。
     247     函数说明:memset()会将ptr所指的内存区域的前num个字节的值都设置为value,然后返回指向ptr的指针;
     248     */
     249     //****************************************************************************************
     250 
     251     //根据SizeOfHeaders大小的确定,先复制Dos头
     252     memcpy(pTempImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
     253     /*
     254     参考:http://c.biancheng.net/cpp/html/155.html
     255 
     256     在头文件string.h里面
     257 
     258     void* memcpy (void* dest,const void* src,size_t num);
     259     memcpy()函数功能用来复制内存的;她会复制src所指向内容的首地址,作为起始位置,然后偏移num个字节到dest所指的内存地址
     260     的位置;此函数有个特征就是,她并不关心被复制的数据类型,只是逐字节地进行复制,这给函数的使用带来了很大的灵活性,
     261     可以面向任何数据类型进行复制;
     262 
     263     需要注意的是:
     264     dest 指针要分配足够的空间,也就是要大于等于num字节的空间,如果没有分配足够的空间会出现错误;
     265     dest和src所指的内存空间不能重叠(如果发生了重叠,使用 memmove() 会更加安全)。
     266 
     267     所以上面的代码的含义如下:
     268     (1)pDosHeader ---> 是指向pFileBuffer的首地址,也就是内存复制的时候从这里开始;
     269     (2)pTempImageBuffer  ---> 这里是表示上面要复制的目的,要把内容复制到这块内存来;
     270     (3)pOptionHeader->SizeOfHeaders  ---> 这里表示复制多大的内容到pTempImageBuffer里面去;
     271     (4)从上面看来我们就知道复制到目标pOptionHeader->SizeOfHeaders所在的内存空间一定要比pTempImageBuffer大;
     272     */
     273     //****************************************************************************************
     274 
     275     //上面把已经确定的头都复制好了,那么下面就可以开始复制节的里面的内容,因为节不仅仅是一个,所以需要用到for循环进行操作
     276     //根据节表循环copy节的内容
     277     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     278     //定义一个临时节表的指针
     279     for (int i=0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++)
     280     {
     281         memcpy((void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress),
     282             (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData);
     283     }
     284     /*
     285     上面的大概操作就是根据标准PE文件头里面的值 NumberOfSections确定有几个节,然后不断的计算并增加指针偏移位置,不停的复制
     286 
     287     PointerToRawData   ---> 节在文件中的偏移地址;
     288     VirtualAddress     ---> 节在内存中的偏移地址;
     289     SizeOfRawData      ---> 节在文件中对齐后的尺寸;
     290 
     291     (void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress)   ---> Dest(目的地)
     292     上面我们已经知道了函数memcpy是怎么复制操作的,所以这里我们依依解释下:
     293     首先我们知道,上面展示的是目的地,而且我们的目的是要从FileBuffer节内容复制到ImageBuffer节的内容,
     294     那么要使用到的是文件被双击打开之后在内存中的偏移地址,这个地址就是VirtualAddress;这里举个例子:
     295     正常打开notepad.exe,然后使用winhex加载这个notepad.exe的内存数据,同时使用PE解析工具得到两个值的信息如下:
     296     可选PE头 ---> ImageBase   ---> 0x01000000
     297     第一个节表显示的VirtualAddress  ---> 00001000
     298     上面两个值相加就得到了文件被打开在内存中第一个节的真实数据的起始位置 ---> 0x01001000
     299     查看winhex对应的地址,确认是对的;
     300 
     301     (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData)      ---> Src(源复制的起始内存地址)
     302     同样是上面的例子:
     303     PointerToRawData是节在文件中的偏移地址,而我们知道,在文件中和在内存中是不一样的,因为在内存中有ImageBase的说法,
     304     但在文件中没有,所以她的起始位置就是文件存储在硬盘的时候使用winhex打开的开头位置,为这里同样使用winhex以二进制的形式
     305     打开notepad.exe(非双击打开),发现文件的起始位置是0x00000000,同时使用PE解析工具确认出了PointerToRawData的值
     306     PointerToRawData  ---> 0x00000400 ; 起始位置为0x00000000 ,她们相加就得到第一个节表的起始位置为0x00000400
     307     查看winhex对应的地址,确认是对的;
     308     所以这里总结下来的Src,就是内存复制的时候,从这个偏移地址开始拿数据开始复制;
     309 
     310     pTempSectionHeader->SizeOfRawData
     311     这里就是告诉我们上面复制要复制多大的内容到 (void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress)
     312     SizeOfRawData ---> 节在文件中对齐后的尺寸;
     313     例子还是以上面的为例:
     314     通过PE解析工具确认SizeOfRawData的大小为:0x00007800
     315 
     316     总结:
     317     memcpy((void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress),
     318     (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData),
     319     pTempSectionHeader->SizeOfRawData);
     320 
     321     上面代码就是在文件中的形式找到要复制的位置0x00000400的起始位置开始复制,要复制0x00007800个字节大小,也就是从
     322     0x00000400这个地址开始向后偏移7800个字节,将这些数据复制到文件双击被打开时候的内存地址0x01001000为起点向后覆盖复制
     323     完成即可,为这里测试算了下;0x00000400+0x00007800=0x00007C00 ; 0x00007C00这个地址刚好是第二个节的PointerToRawData
     324     这样就可以很好的理解for循环对第二个节的复制;
     325     */
     326 
     327     //****************************************************************************************
     328     //返回数据
     329     *pImageBuffer = pTempImageBuffer;
     330     //将复制好后节的首地址保存到指针pImageBuffer中
     331     pTempImageBuffer = NULL;
     332     //初始化清空临时使用的pTempImageBuffer
     333 
     334     return pOptionHeader->SizeOfImage;
     335 }
     336 
     337 //FileBuffer ---> NewImageBuffer(新增节操作)?
     338 //通过复制FileBuffer并增加1000H到新的NewImageBuffer,用作新增节;
     339 DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer)
     340 {
     341     PIMAGE_DOS_HEADER pDosHeader = NULL;
     342     PIMAGE_NT_HEADERS pNTHeader = NULL;
     343     PIMAGE_FILE_HEADER pPEHeder = NULL;
     344     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     345     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     346     PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
     347     LPVOID pTempNewImageBuffer = 0;
     348     DWORD sizeOfFile = 0;
     349     DWORD numberOfSection = 0;
     350     DWORD okAddSections = 0;
     351     
     352 
     353     //判断读取pFileBuffer读取是否成功
     354     if (!pFileBuffer)
     355     {
     356         printf("缓冲区指针无效
    ");
     357         return 0;
     358     }
     359 
     360     //判断是否为MZ标志
     361 
     362     if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE --> MZ
     363     {
     364         printf("不是一个有效的MZ标志
    ");
     365         return 0;
     366     }
     367 
     368     //判断是否为PE标志
     369     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
     370     if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // IMAGE_NT_SIGNATURE --> PE
     371     {
     372         printf("不是有效的PE标志
    ");
     373         return 0;
     374     }
     375 
     376 //*********************申请开辟内存空间*****************************************************************
     377 
     378     sizeOfFile = fileSize+0x1000;
     379     pTempNewImageBuffer = malloc(sizeOfFile);
     380 
     381     //判断内存空间开辟是否成功
     382     if (!pTempNewImageBuffer)
     383     {
     384         printf("pTempNewImageBuffer开辟内存空间失败
    ");
     385         return 0;
     386     }
     387 
     388     //初始化内存内容
     389     memset(pTempNewImageBuffer,0,sizeOfFile);
     390 
     391     //初始化完成之后,先把为修改的内存空间全部拷贝到新的内存空间
     392     memcpy(pTempNewImageBuffer,pFileBuffer,fileSize);
     393 
     394     //定位Dos头地址
     395     pDosHeader = (PIMAGE_DOS_HEADER)(pTempNewImageBuffer);
     396 
     397     //定位NT头的地址
     398     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pTempNewImageBuffer+pDosHeader->e_lfanew);
     399 
     400     //定位标志PE头地址
     401     pPEHeder = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+0x04);//PE SIGNATURE 站4个字节
     402 
     403     //定位可选PE头地址
     404     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeder)+IMAGE_SIZEOF_FILE_HEADER);//IMAGE_SIZEOF_FILE_HEADER -> 20个字节
     405 
     406     //定位第一个节表地址
     407     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeder->SizeOfOptionalHeader);
     408 
     409     //定位最后一个节表的地址
     410     pLastSectionHeader = &pSectionHeader[pPEHeder->NumberOfSections-1];
     411 
     412     //判断是否有足够的空间添加一个节表
     413     //判断条件:
     414     /*
     415         SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小
     416         SizeOfHeader在可选PE头里面
     417     */
     418 
     419     okAddSections = (DWORD)(pOptionHeader->SizeOfHeaders - (pDosHeader->e_lfanew + 0x04 + 
     420         sizeof(PIMAGE_FILE_HEADER) + pPEHeder->SizeOfOptionalHeader + sizeof(PIMAGE_SECTION_HEADER) 
     421         * pPEHeder->NumberOfSections));
     422 
     423     if (okAddSections < 2*sizeof(PIMAGE_SECTION_HEADER))
     424     {
     425         printf("这个exe文件头不剩余空间不够
    ");
     426         free(pTempNewImageBuffer);
     427         return 0;
     428     }
     429 
     430     //上面没问题,就开始修改内容了
     431 //*************************修改内容*******************************************************************
     432 
     433     //初始化新节表信息
     434     PWORD pNumberOfSection = &pPEHeder->NumberOfSections;
     435     PDWORD pSizeOfImage = &pOptionHeader->SizeOfImage;
     436 
     437     numberOfSection = pPEHeder->NumberOfSections;
     438     PVOID pSecName = &pSectionHeader[numberOfSection].Name;
     439     PDWORD pSecMisc = &pSectionHeader[numberOfSection].Misc.VirtualSize;
     440     PDWORD pSecVirtualAddress = &pSectionHeader[numberOfSection].VirtualAddress;
     441     PDWORD pSecSizeOfRawData = &pSectionHeader[numberOfSection].SizeOfRawData;
     442     PDWORD pSecPointToRawData = &pSectionHeader[numberOfSection].PointerToRawData;
     443     PDWORD pSecCharacteristics = &pSectionHeader[numberOfSection].Characteristics;
     444    
     445     //修改PE文件头里面的节数量信息
     446 
     447     printf("*pNumberOfSection:%#X 
    ",pPEHeder->NumberOfSections);
     448     *pNumberOfSection = pPEHeder->NumberOfSections + 1;
     449     printf("*pNumberOfSection:%#X 
    ",pPEHeder->NumberOfSections);
     450     
     451     //修改PE可选头里面SizeOfImage信息
     452     printf("*pSizeOfImage:%#X 
    ",pOptionHeader->SizeOfImage);
     453     *pSizeOfImage = pOptionHeader->SizeOfImage + 0x1000;
     454     printf("*pSizeOfImage:%#X 
    ",pOptionHeader->SizeOfImage);
     455 
     456     //向节表中添加数据
     457 
     458     memcpy(pSecName,".newSec",8);
     459     *pSecMisc = 0x1000;
     460     //这里VirtualAddress的地址需要根据最后一个节表中对齐前内存中的实际大小?
     461     //和文件中对齐后的大小,分别使用VirtualAddress加上她们的值,哪个大,就是
     462     //哪个;
     463     //VirtualAddress+max(VirtualSize,SizeOfRawData)
     464     //就是上面的公式
     465 
     466     //判断出要添加的值
     467     DWORD add_size = pLastSectionHeader->Misc.VirtualSize > pLastSectionHeader->SizeOfRawData?
     468         pLastSectionHeader->Misc.VirtualSize:pLastSectionHeader->SizeOfRawData;
     469     //上面是个三目运算符
     470 
     471     printf("pLastSectionHeader: %#X 
    ",pLastSectionHeader);    
     472     printf("add_size: %#X 
    ",add_size);
     473     printf("numberOfSection: %#X 
    ",pPEHeder->NumberOfSections);
     474     printf("pLastSectionHeader->Misc.VirtualSize: %#X 
    ",pLastSectionHeader->Misc.VirtualSize);
     475     printf("pLastSectionHeader->SizeOfRawData: %#X 
    ",pLastSectionHeader->SizeOfRawData);
     476     printf("add_size: %#X 
    ",add_size);
     477 
     478     *pSecVirtualAddress = pLastSectionHeader->VirtualAddress + add_size;
     479 
     480     //SectionAlignment对齐
     481 
     482     if (*pSecVirtualAddress % pOptionHeader->SectionAlignment)
     483     {
     484         *pSecVirtualAddress = *pSecVirtualAddress / pOptionHeader->SectionAlignment * 
     485             pOptionHeader->SectionAlignment + pOptionHeader->SectionAlignment;
     486     }
     487 
     488     *pSecSizeOfRawData = 0x1000;
     489     *pSecPointToRawData = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
     490 
     491     //FileAlignment对齐
     492 
     493     if (*pSecPointToRawData % pOptionHeader->FileAlignment)
     494     {
     495         *pSecPointToRawData = *pSecPointToRawData / pOptionHeader->FileAlignment * 
     496             pOptionHeader->FileAlignment + pOptionHeader->FileAlignment;
     497     }
     498 
     499     *pSecCharacteristics = 0xFFFFFFFF;
     500 
     501     *pNewImageBuffer = pTempNewImageBuffer;
     502     pTempNewImageBuffer = NULL;
     503     
     504     return sizeOfFile;
     505 }
     506 
     507 //求对齐后的大小
     508 //Actuall_size  ---> 内存中对齐前实际的大小 ---> VirtualSize
     509 //Align_size  ---> 文件中对齐后的大小 ---> SizeOfRawData
     510 DWORD AlignLength(DWORD Actuall_size,DWORD Align_size)
     511 {
     512     if (Actuall_size % Align_size == 0)
     513     {
     514         return Actuall_size;
     515     }
     516     else
     517     {
     518         DWORD n = Actuall_size / Align_size;
     519         return Align_size*(n+1);
     520     }
     521 }
     522 
     523 //另一种对齐计算方式
     524 DWORD Alignment(DWORD alignment_value, DWORD addend, DWORD address)
     525 {
     526     int n = 0;
     527     if (addend / alignment_value)
     528     {
     529         if (addend % alignment_value)
     530         {
     531             n = addend / alignment_value + 1;
     532         }
     533         else
     534         {
     535             n = addend / alignment_value;
     536         }
     537     }
     538     else
     539     {
     540         if (addend)
     541         {
     542             n = 1;
     543         }
     544         else
     545         {
     546             n = 0;
     547         }
     548     }
     549     address += n * alignment_value;
     550     return address;
     551 }
     552 
     553 //ImageBuffer ---> NewImageBuffer
     554 //将拉伸后加载到内存的ImageBuffer存入到NewImageBuffer,修改数据完成之后,准备存盘操作
     555 DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pNewImageBuffer)
     556 {
     557     PIMAGE_DOS_HEADER pDosHeader = NULL;
     558     PIMAGE_NT_HEADERS pNTHeader = NULL;
     559     PIMAGE_FILE_HEADER pPEHeader = NULL;
     560     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     561     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     562     PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
     563     LPVOID pTempNewImageBuffer = NULL;
     564     DWORD ImageBuffer_Size = 0;
     565     DWORD numberOfSection = 0;
     566 
     567     //判断读取pImageBuffer是否成功 
     568     if (!pFileBuffer)
     569     {
     570         printf("缓冲区指针无效
    ");
     571     }
     572 
     573     //判断是否是有效的MZ头
     574     if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
     575     {
     576         printf("不是有效的MZ头
    ");
     577         return 0;
     578     }
     579 
     580     //判断是否是有效的PE头
     581     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
     582     if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     583     {
     584         printf("不是有效的PE头
    ");
     585         return 0;
     586     }
     587 
     588     //定位NT头
     589     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
     590 
     591     //定位标准的PE文件头
     592     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
     593 
     594     //定位可选PE头
     595     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     596 
     597     //定位第一个节表地址
     598     numberOfSection = pPEHeader->NumberOfSections;
     599     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
     600 
     601     //定位最后一个节表地址
     602     pLastSectionHeader = &pSectionHeader[numberOfSection-1];
     603 //    printf("numberOfSection --> %#X 
    ",numberOfSection);
     604 //    printf("*pSectionHeader --> %#X 
    ",pSectionHeader->Misc.VirtualSize);
     605 //    printf("*pLastSectionHeader --> %#X 
    ",&pLastSectionHeader);
     606 
     607     //开始操作需要修改的部分
     608     
     609     //最后一个节中内存中对齐前的大小;
     610     PDWORD pVirtualSize = &pLastSectionHeader->Misc.VirtualSize;
     611     //最后一个节在文件中对齐后的大小;
     612     PDWORD pSizeOfRawData = &pLastSectionHeader->SizeOfRawData;
     613     //文件中SizeOfImage的大小;
     614     PDWORD pSizeOfImage = &pOptionHeader->SizeOfImage;
     615 
     616     //扩展修改之前的数据
     617 //    printf("&pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",pVirtualSize);
     618 //    printf("*pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",*pVirtualSize);
     619 //
     620 //    printf("&pLastSectionHeader->SizeOfRawData --> %#X 
    ",pSizeOfRawData);
     621 //    printf("*pLastSectionHeader->SizeOfRawData --> %#X 
    ",*pSizeOfRawData);
     622 //    
     623 //    printf("&pOptionHeader->SizeOfImage --> %#X 
    ",pSizeOfImage);
     624 //    printf("*pOptionHeader->SizeOfImage --> %#X 
    ",*pSizeOfImage);
     625 
     626     //扩展修改pVirtualSize
     627     *pVirtualSize = AlignLength(*pVirtualSize,pOptionHeader->SectionAlignment)+0x1000;
     628 //    printf("&pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",pVirtualSize);
     629 //    printf("*pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",*pVirtualSize);
     630 //    printf("&pLastSectionHeader->SizeOfRawData --> %#X 
    ",pSizeOfRawData);
     631 //    printf("*pLastSectionHeader->SizeOfRawData --> %#X 
    ",*pSizeOfRawData);
     632 // 
     633     //扩展修改pSizeOfRawData
     634     *pSizeOfRawData = AlignLength(*pSizeOfRawData,pOptionHeader->SectionAlignment)+0x1000;
     635 //    printf("&pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",pVirtualSize);
     636 //    printf("*pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",*pVirtualSize);
     637 //    printf("&pLastSectionHeader->SizeOfRawData --> %#X 
    ",pSizeOfRawData);
     638 //    printf("*pLastSectionHeader->SizeOfRawData --> %#X 
    ",*pSizeOfRawData);
     639 //    printf("&pOptionHeader->SizeOfImage --> %#X 
    ",pSizeOfImage);
     640 //    printf("*pOptionHeader->SizeOfImage --> %#X 
    ",*pSizeOfImage);
     641 
     642     //修改SizeOfImage
     643     *pSizeOfImage += 0x1000;
     644 //    printf("&pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",pVirtualSize);
     645 //    printf("*pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",*pVirtualSize);
     646 //    printf("&pLastSectionHeader->SizeOfRawData --> %#X 
    ",pSizeOfRawData);
     647 //    printf("*pLastSectionHeader->SizeOfRawData --> %#X 
    ",*pSizeOfRawData);
     648 //    printf("&pOptionHeader->SizeOfImage --> %#X 
    ",pSizeOfImage);
     649 //    printf("*pOptionHeader->SizeOfImage --> %#X 
    ",*pSizeOfImage);
     650 
     651     //得到修改之后的大小准备申请内存空间
     652 
     653     ImageBuffer_Size = pOptionHeader->SizeOfImage;
     654     pTempNewImageBuffer = malloc(ImageBuffer_Size);
     655 
     656     if (!pTempNewImageBuffer)
     657     {
     658         printf("分配内存空间失败
    ");
     659         return 0;
     660     }
     661 
     662     //初始化内存空间
     663     memset(pTempNewImageBuffer,0,ImageBuffer_Size);
     664 
     665     //复制SizeOfHeaders
     666     memcpy(pTempNewImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
     667 
     668     //创建临时节的结构体指针,遍历数据
     669     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     670 
     671     for (DWORD i = 0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++)
     672     {
     673         memcpy((PVOID)((DWORD)pTempNewImageBuffer+pTempSectionHeader->VirtualAddress),
     674             (void*)((DWORD)pFileBuffer+pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData);
     675     }
     676 
     677     *pNewImageBuffer = pTempNewImageBuffer;
     678     pTempNewImageBuffer = NULL;
     679     return *pSizeOfImage;
     680 }
     681 
     682 //将ImageBuffer更改为一个节表和节然后压缩为NewBuffer,供存盘准备
     683 DWORD ImageBufferMergeSections(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer)
     684 {
     685     PIMAGE_DOS_HEADER pDosHeader = NULL;
     686     PIMAGE_NT_HEADERS pNTHeader = NULL;
     687     PIMAGE_FILE_HEADER pPEHeader = NULL;
     688     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     689     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     690     PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
     691     LPVOID pTempMergeSection = NULL;
     692     DWORD finalSections_Size = 0;
     693     DWORD numberOfSection = 0;
     694     DWORD lastSectionsMax_Size = 0;
     695     DWORD sizeOfFile = 0;
     696     DWORD NewSecCharacteristics = 0;
     697     DWORD NewSectionsBuffer = 0;
     698 
     699     //判断读取pImageBuffer是否成功 
     700     if (pImageBuffer == NULL)
     701     {
     702         printf("缓冲区指针无效
    ");
     703     }
     704     //判断是否是有效的MZ标志
     705     if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
     706     {
     707         printf("不是有效的MZ头
    ");
     708         free(pImageBuffer);
     709         return 0;
     710     }
     711     //判断是否是有效的PE标志
     712 
     713     pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
     714     if (*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     715     {
     716         printf("不是有效的PE标志
    ");
     717         free(pImageBuffer);
     718         return 0;
     719     }
     720 
     721 
     722     //定位NT头
     723     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer+pDosHeader->e_lfanew);
     724 
     725     //定位标准的PE文件头
     726     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
     727 
     728     //定位可选PE头
     729     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     730 
     731     //定位第一个节表地址
     732     numberOfSection = pPEHeader->NumberOfSections;
     733     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
     734 
     735     //定位最后一个节表地址
     736     pLastSectionHeader = &pSectionHeader[numberOfSection - 1];
     737 
     738     //定义一个临时节表指针
     739     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     740 
     741     //先计算出SizeOfHeaders
     742     pOptionHeader->SizeOfHeaders = Alignment(pOptionHeader->SectionAlignment,pOptionHeader->SizeOfHeaders,0);
     743 
     744 
     745     //最后一个节中内存对齐前的大小;
     746     DWORD pVirtualSize = pLastSectionHeader->Misc.VirtualSize;
     747     //最后一个节在文件中对齐后的大小;
     748     DWORD pSizeOfRawData = pLastSectionHeader->SizeOfRawData;
     749 
     750     //计算最后一个节中最大值是SizeOfRawData还是VirtualSize
     751     lastSectionsMax_Size = (pSizeOfRawData > pVirtualSize ? pSizeOfRawData : pVirtualSize);
     752 
     753     //测试一把
     754     if (!debug)
     755     {
     756         printf("pLastSectionHeader->SizeOfRawData: %#X 
    ", pSizeOfRawData);
     757         printf("pLastSectionHeader->Misc.VirtualSize: %#X 
    ", pVirtualSize);
     758         printf("lastSectionsMax_Size: %#X 
    ", lastSectionsMax_Size);
     759     }
     760 
     761     //计算最终合并后节对应SizeOfRawData或VirtualSize的大小
     762     finalSections_Size = (pLastSectionHeader->VirtualAddress + lastSectionsMax_Size - pOptionHeader->SizeOfHeaders);
     763 
     764     //遍历到最后一个节表,具体操作就是将每个节都置为0
     765     for (DWORD i = 0; i < numberOfSection; i++, pTempSectionHeader++)
     766     {
     767         NewSecCharacteristics |= pTempSectionHeader->Characteristics; 
     768         //上述 |= 按位或然后赋值,因为NewSecCharacteristics为0,所以新的节对应的值也都置为0了
     769         if (i > 0)
     770         {
     771             memset(&pSectionHeader[i],0,IMAGE_SIZEOF_SECTION_HEADER);//将每个节都置为0
     772         }
     773     }
     774 
     775     //IMAGE_SIZEOF_SECTION_HEADER --> 40
     776 
     777     //修改第一个节的SizeOfRawData和VirtualSize的值,将其更改为上面计算出来的最终值
     778     pSectionHeader->Misc.VirtualSize = finalSections_Size;
     779     pSectionHeader->SizeOfRawData = finalSections_Size;
     780 
     781     //修改新节的Characteristics的值
     782     pSectionHeader->Characteristics = NewSecCharacteristics;
     783 
     784     //修改pPEHeader->NumberOfSections的属性为0x01
     785     pPEHeader->NumberOfSections = 0x01;
     786 
     787     //继续测试一把
     788     if (!debug)
     789     {
     790         printf("pSectionHeader->Characteristics: %#X 
    ", pSectionHeader->Characteristics);
     791         printf("pSectionHeader->SizeOfRawData: %#X 
    ", pSectionHeader->SizeOfRawData);
     792         printf("pSectionHeader->Misc.VirtualSize: %#X 
    ", pSectionHeader->Misc.VirtualSize);
     793     }
     794 
     795     //根据SizeOfImage申请新的空间,到此处说明上面已经更改完成了各个相关的属性值,可以申请内存空间为存盘做准备了;
     796     pTempMergeSection = malloc(pOptionHeader->SizeOfImage);
     797 
     798     //sizeOfFile = pOptionHeader->SizeOfHeaders + finalSections_Size;
     799     //使用winhex打开notepad.exe 是0x00000400,这是第一个节之前的所有大小
     800     // for(DWORD i = 0;i<numberOfSection;i++)
     801     // {
     802     //     sizeOfFile += pSectionHeader[i].SizeOfRawData;  // pSectionHeader[i]另一种加法
     803     // }
     804 
     805     //pTempNewBuffer = malloc(sizeOfFile);
     806 
     807     if (!pTempMergeSection)
     808     {
     809         printf("申请内存空间失败
    ");
     810         return 0;
     811     }
     812 
     813     //初始化新的缓冲区
     814     memset(pTempMergeSection,0,pOptionHeader->SizeOfImage);
     815     //根据SizeOfHeaders 先copy头
     816     memcpy(pTempMergeSection,pDosHeader,pOptionHeader->SizeOfHeaders);
     817     //开始复制节的信息,因为这里是合并节,只有一个节,所以不需要使用for循环进行遍历复制,直接复制即可;
     818     memcpy((PDWORD)((DWORD)pTempMergeSection+pSectionHeader->PointerToRawData),
     819         (PDWORD)((DWORD)pImageBuffer+pSectionHeader->VirtualAddress),
     820         pSectionHeader->SizeOfRawData);
     821 
     822     //返回数据
     823     *pNewBuffer = pTempMergeSection;
     824     pTempMergeSection = NULL;
     825     return pOptionHeader->SizeOfImage;
     826   }
     827 
     828 //ImageBuffer ---> NewBuffer
     829 //将拉伸后加载到内存的ImageBuffer存入到NewBuffer里面,然后准备存盘;
     830 DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer)
     831 {
     832     //下面大部分操作都是跟上面一样的,这里就不再赘述了
     833     PIMAGE_DOS_HEADER pDosHeader = NULL;
     834     PIMAGE_NT_HEADERS pNTHeader = NULL;
     835     PIMAGE_FILE_HEADER pPEHeader = NULL;
     836     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     837     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     838     LPVOID pTempNewBuffer = NULL;
     839     DWORD sizeOfFile = 0;
     840     DWORD numberOfSection = 0;
     841 
     842     if (pImageBuffer == NULL)
     843     {
     844         printf("缓冲区指针无效
    ");
     845     }
     846     //判断是否是有效的MZ标志
     847     if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
     848     {
     849         printf("不是有效的MZ头
    ");
     850         return 0;
     851     }
     852     pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
     853     //判断是否是有效的PE标志
     854     if (*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     855     {
     856         printf("不是有效的PE标志
    ");
     857         return 0;
     858     }
     859     //NT头地址
     860     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
     861     //标准PE文件头
     862     pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
     863     //可选PE头
     864     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     865     //第一个节表地址
     866     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
     867 
     868     //计算文件需要的空间--最后一个节的文件偏移+节对齐后的长度
     869     /*
     870     numberOfSection = pPEHeader->NumberOfSections;
     871     pSectionHeader = pSectionHeader[numberOfSection-1];
     872     sizeOfFile = (pSectionHeader->PointerToRawData + pSectionHeader->Misc.VirtualSize + pOptionHeader->FileAlignment);
     873     printf("sizeOfFile %X 
    ",sizeOfFile);
     874 
     875     for (DWORD i=0;i<=numberOfSection;i++)
     876     {
     877         sizeOfFile += sizeOfFile[i];
     878     }
     879     */
     880 
     881     sizeOfFile = pOptionHeader->SizeOfHeaders;
     882     //使用winhex打开notepad.exe 是0x00000400,这是第一个节之前的所有大小
     883     for(DWORD i = 0;i<pPEHeader->NumberOfSections;i++)
     884     {
     885         sizeOfFile += pSectionHeader[i].SizeOfRawData;  // pSectionHeader[i]另一种加法
     886     }
     887 
     888     /*
     889     上面的for循环大概意思就是基于几个节的数量依次循环叠加sizeOfFile的值;因为SizeOfRawData是文件中对齐后的大小;
     890     所以循环计算如下:
     891     sizeOfFile = 0x00000400 + 0x00007800 = 0x00007C00
     892     sizeOfFile = 0x00007C00 + 0x00000800 = 0x00008400
     893     sizeOfFile = 0x00008400 + 0x00008000 = 0x00010400
     894 
     895     */
     896 
     897     //根据SizeOfImage申请新的空间
     898     pTempNewBuffer = malloc(sizeOfFile);
     899 
     900     if (!pTempNewBuffer)
     901     {
     902         printf("申请内存空间失败
    ");
     903         return 0;
     904     }
     905     //初始化新的缓冲区
     906     memset(pTempNewBuffer,0,sizeOfFile);
     907     //根据SizeOfHeaders 先copy头
     908     memcpy(pTempNewBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
     909     //根据节表循环复制节
     910     //PIMAGE_SECTION_HEADER pTempSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader);
     911     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     912     for (int j=0;j<pPEHeader->NumberOfSections;j++,pTempSectionHeader++)
     913     {
     914         /*memcpy((LPVOID)((DWORD)pTempNewBuffer + pTempSectionHeader->PointerToRawData),
     915         (LPVOID)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress),
     916         pTempSectionHeader->SizeOfRawData);*/
     917         //PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
     918         memcpy((PDWORD)((DWORD)pTempNewBuffer+pTempSectionHeader->PointerToRawData),
     919         (PDWORD)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress),
     920         pTempSectionHeader->SizeOfRawData);
     921         //printf("%X  --> PoniterToRadata
    ",pTempSectionHeader->PointerToRawData);
     922         //printf("%X  --> VirtualAddress
    ",pTempSectionHeader->VirtualAddress);
     923         //printf("%X  --> VirtualSize
    ",pTempSectionHeader->Misc.VirtualSize);
     924     }
     925 
     926     //返回数据
     927     *pNewBuffer = pTempNewBuffer;
     928     pTempNewBuffer = NULL;
     929     return sizeOfFile;
     930   }
     931 
     932 //将上面得到的MemBuffer存盘到本地;
     933 BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile)
     934 {
     935     FILE* fp = NULL;
     936     fp = fopen(lpszFile, "wb+");
     937     if (!fp)  //  这里我刚开始写漏了一个等于号,变成复制NULL了,导致错误
     938 //  if(fp == NULL)  可以这么写,没问题
     939     {
     940         fclose(fp);
     941         return FALSE;
     942     }
     943     fwrite(pMemBuffer,size,1,fp);
     944     fclose(fp);
     945     fp = NULL;
     946     return TRUE;
     947 }
     948 
     949 //RVA格式转换FOA  --- RvaToFileOffset
     950 DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva)
     951 {
     952     PIMAGE_DOS_HEADER pDosHeader = NULL;
     953     PIMAGE_NT_HEADERS pNTHeader = NULL;
     954     PIMAGE_FILE_HEADER pPEHeader = NULL;
     955     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     956     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     957     DWORD numberOfSection = 0;
     958     DWORD dwFOAValue = 0;
     959 
     960     //判断指针是否有效
     961     if (!pFileBuffer)
     962     {
     963         printf("pFileBuffer 指针无效
    ");
     964         return 0;
     965     }
     966     //判断是否是有效的MZ标志
     967     if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
     968     {
     969         printf("pFileBuffer不是有效的MZ标志
    ");
     970         return 0;
     971     }
     972     //判断是否是一个有效的PE标志
     973     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
     974     if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     975     {
     976         printf("pFileBuffer不是一个有效的PE标志
    ");
     977         return 0;
     978     }
     979 
     980     printf("当前的Rva地址: %#X 
    ",dwRva);
     981     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
     982     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
     983     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     984     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
     985 
     986     //定义个临时节表指针进行下面的计算操作
     987     numberOfSection = pPEHeader->NumberOfSections;
     988     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     989 
     990 
     991     //判断dwRva所处的节
     992     if (dwRva <= pOptionHeader->SizeOfHeaders)
     993     {
     994         return (DWORD)dwRva;
     995     }
     996     //上面是判断如果rva地址所处的节在第一个节之前那么直接返回rva的地址;
     997     //否则下面就是开始遍历查找节;
     998     else
     999     {
    1000         for (DWORD n = 0; n < numberOfSection; n++, pTempSectionHeader++)
    1001         {//下面是判断在哪个节的范围,然后根据rva所在的地址减去所在节的VirtualAddress得到的偏移值加上文件中对应节的偏移值PointerToRawData
    1002             if ((dwRva >= pTempSectionHeader->VirtualAddress) && (dwRva < pTempSectionHeader->VirtualAddress + pTempSectionHeader->Misc.VirtualSize))
    1003             {
    1004                 dwFOAValue = dwRva - pTempSectionHeader->VirtualAddress + pTempSectionHeader->PointerToRawData;
    1005             }
    1006             else
    1007             {
    1008                 printf("RvaToFoa 转换失败!
    ");
    1009                 return 0;
    1010             }
    1011         }
    1012     }
    1013     return dwFOAValue;
    1014 }
    1015 
    1016 //FOA格式转换RVA  --- ImageOffset
    1017 DWORD FoaToImageOffset(IN LPVOID pFileBuffer,IN DWORD dwFoa)
    1018 {
    1019     PIMAGE_DOS_HEADER pDosHeader = NULL;
    1020     PIMAGE_NT_HEADERS pNTHeader = NULL;
    1021     PIMAGE_FILE_HEADER pPEHeader = NULL;
    1022     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    1023     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    1024     DWORD numberOfSection = 0;
    1025     DWORD dwRVAValue = 0;
    1026 
    1027     //判断指针是否有效
    1028     if (!pFileBuffer)
    1029     {
    1030         printf("pFileBuffer 指针无效
    ");
    1031         return 0;
    1032     }
    1033     //判断是否是有效的MZ标志
    1034     if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
    1035     {
    1036         printf("pFileBuffer不是有效的MZ标志
    ");
    1037         return 0;
    1038     }
    1039     //判断是否是一个有效的PE标志
    1040     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    1041     if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
    1042     {
    1043         printf("pFileBuffer不是一个有效的PE标志
    ");
    1044         return 0;
    1045     }
    1046     
    1047     printf("当前的Foa地址: %#X 
    ",dwFoa);
    1048     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
    1049     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
    1050     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
    1051     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
    1052     
    1053     //定义个临时节表指针进行下面的计算操作
    1054     numberOfSection = pPEHeader->NumberOfSections;
    1055     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
    1056 
    1057     if (dwFoa <= pOptionHeader->SizeOfHeaders)
    1058     {
    1059         return (DWORD)dwFoa;
    1060     }
    1061     else
    1062     {
    1063         for (DWORD n = 0; n < numberOfSection; n++, pTempSectionHeader++)
    1064         {
    1065             if ((dwFoa >= pTempSectionHeader->PointerToRawData) && (dwFoa < pTempSectionHeader->SizeOfRawData))
    1066             {
    1067                 dwRVAValue = dwFoa - pTempSectionHeader->PointerToRawData + pTempSectionHeader->VirtualAddress;
    1068             }
    1069             else
    1070             {
    1071                 printf("FoaToRva 转换失败!
    ");
    1072                 return 0;
    1073             }
    1074         }
    1075     }
    1076     return dwRVAValue;
    1077 }
    1078 
    1079 //在原有的exe文件中开始操作添加ShellCode代码;
    1080 
    1081 VOID AddCodeInCodeSec()
    1082 {
    1083     LPVOID pFileBuffer = NULL;
    1084     LPVOID pImageBuffer = NULL;
    1085     LPVOID pNewBuffer = NULL;
    1086     PIMAGE_DOS_HEADER pDosHeader = NULL;
    1087     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    1088     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    1089     PBYTE codeBegin = NULL;
    1090     BOOL isOK = FALSE;
    1091     DWORD size = 0;
    1092 
    1093     //File-->FileBuffer
    1094     ReadPEFile(FilePath_In,&pFileBuffer);
    1095     if (!pFileBuffer)
    1096     {
    1097         printf("文件-->缓冲区失败
    ");
    1098         return ;
    1099     }
    1100 
    1101     //FileBuffer-->ImageBuffer
    1102     CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
    1103     if (!pImageBuffer)
    1104     {
    1105         printf("FileBuffer-->ImageBuffer失败
    ");
    1106         free(pFileBuffer);
    1107         return ;
    1108     }
    1109 
    1110     //判断代码段空闲区域是否能够足够存储ShellCode代码
    1111     pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    1112     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    1113     pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_NT_OPTIONAL32_HEADER);
    1114     if (((pSectionHeader->SizeOfRawData) - (pSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH)
    1115     {
    1116         printf("代码区域空闲空间不够
    ");
    1117         free(pFileBuffer);
    1118         free(pImageBuffer);
    1119     }
    1120 
    1121     //将代码复制到空闲区域
    1122     codeBegin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);
    1123     printf("pSectionHeader->VirtualAddress: %#010X
    ", pSectionHeader->VirtualAddress);
    1124     printf("pSectionHeader->Misc.VirtualSize: %#010X
    ", pSectionHeader->Misc.VirtualSize);
    1125     printf("codeBegin: %#010X
    ", codeBegin);
    1126 
    1127     memcpy(codeBegin,ShellCode,SHELLCODELENGTH);
    1128 
    1129     //修正E8-->call后面的代码区域
    1130     DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + 0xD) - (DWORD)pImageBuffer)));
    1131     printf("callAddr ---> %#010X 
    ",callAddr);
    1132     *(PDWORD)(codeBegin + 0x09) = callAddr;
    1133     printf("*(PWORD)(codeBegin + 0x09) ---> %#010X 
    ",*(PDWORD)(codeBegin + 0x09));
    1134     /*
    1135     关于修正E8的理解,公式:X = 要跳转的地址 - (E8当前的地址 + 5);
    1136     要跳转的地址,这里是毋庸置疑的,就是我们要加入代码MessageBox的地址;
    1137     然后要减去E8当前的地址+5的位置,这里不是太好理解;
    1138     我们的目的是要将E8后面的4个字节计算出来,然后写入到E8后面,也就是公式中X;
    1139     上面公式E8当前地址+5 ,而在此情况要定位到这个位置就要从代码的Dos开始通过指针相加;
    1140     进行位置偏移到E8当前地址+5的位置;
    1141     所以定位codeBegin的位置是:pImageBuffer指针最开始的位置(Dos头位置)通过内存中偏移的宽度移动到第一个节表的位置;
    1142     也就是上面的pSectionHeader->VirtualAddress 操作形式;
    1143     然后再偏移第一个节表在内存中对齐前实际的宽度(尺寸)pSectionHeader->Misc.VirtualSize;
    1144     上述一番操作之后就到了第一个节表没有对齐前的位置,这个位置就是我们可以添加ShellCode代码的起始位置;
    1145     到了添加ShellCode代码的起始位置之后,就要想办法添加E8位置后面的4个字节,此时根据ShellCode代码的宽度;
    1146     进行计算,确认0x6A 00 0x6A 00 0x6A 00 0x6A 00 E8 00 00 00 00 刚好向后面数13个位置,按照十六进制看;
    1147     就是0xD,所以在codeBegin偏移0xD个位置即可到达E9的位置,这也就是我们说的(E8当前的地址 + 5);
    1148     到了上面的位置之后,由于我们最终是需要在程序运行之后在内存中添加ShellCode代码;所以这里一定要计算出;
    1149     其准确的偏移地址,这样不管怎么拉伸到哪个位置,都能准确找到位置;
    1150     注意:这里需要注意一点理解,上面说的pImageBuffer这个是我们加载程序到我们申请的内存中,绝不是程序在;
    1151     运行中的那个内存,这里一定要理解清楚,她们是不一样的,理解了这个就能理解上面代码为什么要减去Dos头的;
    1152     首地址,(DWORD)(codeBegin + 0xD) - (DWORD)pImageBuffer)
    1153     */
    1154 
    1155     //修正E9-->jmp后面的代码区域
    1156     DWORD jmpAddr = ((pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint) - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + SHELLCODELENGTH) - (DWORD)pImageBuffer)));
    1157     printf("jmpAddr ---> %#010X 
    ",jmpAddr);
    1158     *(PDWORD)(codeBegin + 0x0E) = jmpAddr;
    1159     printf("*(PWORD)(codeBegin + 0x0E) ---> %#010X 
    ",*(PDWORD)(codeBegin + 0x0E));
    1160     /*
    1161     公式:X = 要跳转的地址 - (E9当前的地址 + 5)
    1162     这里同样是要计算出E9后面4个字节的地址,我们的目的是在这里添加OEP的地址,让其执行完成MessageBox之后跳转;
    1163     OEP的地址,那么这里就要先计算出OEP地址,就是pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint;
    1164     再减去(E9当前的地址 + 5) 0x6A 00 0x6A 00 0x6A 00 0x6A 00 E8 00 00 00 00 E9 00 00 00 00;
    1165     (DWORD)codeBegin + SHELLCODELENGTH 就是加上ShellCode总长度,偏移完成之后减去ImageBuffer首地址再加上ImageBase;
    1166     */
    1167 
    1168     //修正OEP
    1169     printf("pOptionHeader->AddressOfEntryPoint ---> %#010X 
    ",pOptionHeader->AddressOfEntryPoint);
    1170     printf("(DWORD)codeBegin ---> %#010X 
    ",((DWORD)codeBegin - (DWORD)pImageBuffer));
    1171     pOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pImageBuffer;
    1172     printf("pOptionHeader->AddressOfEntryPoint ---> %#010X 
    ",pOptionHeader->AddressOfEntryPoint);
    1173     //修正OEP好理解,就是定位到OEP地址,然后直接通过codeBegin地址减去pImageBuffer的首地址即可;
    1174 
    1175     //ImageBuffer-->NewBuffer
    1176     size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewBuffer);
    1177     if (size == 0 || !pNewBuffer)
    1178     {
    1179         printf("ImageBuffer-->NewBuffer失败
    ");
    1180         free(pFileBuffer);
    1181         free(pImageBuffer);
    1182         return ;
    1183     }
    1184 
    1185     //NewBuffer-->文件
    1186     isOK = MemeryTOFile(pNewBuffer,size,FilePath_Out);
    1187     if (isOK)
    1188     {
    1189         printf("修改代码添加SHELLCODE 存盘成功
    ");
    1190         return ;
    1191     }
    1192 
    1193     //释放内存
    1194     free(pFileBuffer);
    1195     free(pImageBuffer);
    1196     free(pNewBuffer);
    1197 }
    1198 
    1199 //调用函数新增节表和节操作,成功之后并存盘到本地;
    1200 VOID NewSectionsInCodeSec()
    1201 {
    1202     LPVOID pFileBuffer = NULL;
    1203     LPVOID pNewImageBuffer = NULL;
    1204     BOOL isOK = FALSE;
    1205     DWORD size1 = 0;
    1206     DWORD size2 = 0;
    1207     
    1208     //File-->FileBuffer
    1209     size1 = ReadPEFile(FilePath_In,&pFileBuffer);
    1210     if (size1 == 0 || !pFileBuffer)
    1211     {
    1212         printf("文件-->缓冲区失败
    ");
    1213         return ;
    1214     }
    1215     printf("fileSize - Final: %#X 
    ",size1);
    1216     
    1217     //FileBuffer-->NewImageBuffer
    1218     size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&pNewImageBuffer);
    1219     if (size2 == 0 || !pFileBuffer)
    1220     {
    1221         printf("FileBuffer-->NewImageBuffer失败
    ");
    1222         free(pFileBuffer);
    1223         return ;
    1224     }
    1225     printf("sizeOfFile - Final: %#X 
    ",size2);
    1226     //NewImageBuffer-->文件
    1227     isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out);
    1228     if (isOK)
    1229     {
    1230         printf("新增节表和节存盘成功
    ");
    1231        return ;
    1232     }
    1233     
    1234     //释放内存
    1235     free(pFileBuffer);
    1236     free(pNewImageBuffer);
    1237 }
    1238 
    1239 //调用函数扩大一个节
    1240 VOID ExtendLastSectionsInCodeSec()
    1241 {
    1242     //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewImageBuffer
    1243 
    1244     LPVOID pFileBuffer = NULL;
    1245     LPVOID pImageBuffer = NULL;
    1246     LPVOID pNewImageBuffer = NULL;
    1247     BOOL isOK = FALSE;
    1248     DWORD FileBufferSize = 0;
    1249     DWORD ImageBufferSize = 0;
    1250     DWORD size = 0;
    1251     
    1252     //File-->FileBuffer
    1253     FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer);
    1254     if (FileBufferSize == 0 || !pFileBuffer)
    1255     {
    1256         printf("文件-->缓冲区失败
    ");
    1257         return ;
    1258     }
    1259     printf("FileBufferSize - Final: %#X 
    ",FileBufferSize);
    1260     
    1261     //FileBuffer-->ImageBuffer
    1262     ImageBufferSize = FileBufferToModifyImageBuffer(pFileBuffer,&pImageBuffer);
    1263     if (ImageBufferSize == 0 || !pFileBuffer)
    1264     {
    1265         printf("FileBuffer-->ImageBuffer失败
    ");
    1266         free(pFileBuffer);
    1267         return ;
    1268     }
    1269     printf("ImageBufferSize - Final: %#X 
    ",ImageBufferSize);
    1270 
    1271     size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewImageBuffer);
    1272     if (size == 0 || !pImageBuffer)
    1273     {
    1274         printf("pImageBuffer-->pNewImageBuffer失败
    ");
    1275         free(pFileBuffer);
    1276         return ;
    1277     }
    1278     //pNewImageBuffer-->文件
    1279     isOK = MemeryTOFile(pNewImageBuffer,size,FilePath_Out);
    1280     if (isOK)
    1281     {
    1282         printf("扩大一个节成功,并存盘
    ");
    1283         return ;
    1284     }
    1285     
    1286     //释放内存
    1287     free(pFileBuffer);
    1288     free(pImageBuffer);
    1289     free(pNewImageBuffer);
    1290 }
    1291 
    1292 
    1293 //调用函数扩大一个节
    1294 VOID ModifySectionsOneInCodeSec()
    1295 {
    1296     //ReadPEFile CopyFileBufferToImageBuffer FileBufferToModifyOneImageBuffer MemeryTOFile
    1297     
    1298     LPVOID pFileBuffer = NULL;
    1299     LPVOID pImageBuffer = NULL;
    1300     LPVOID pNewImageBuffer = NULL;
    1301     BOOL isOK = FALSE;
    1302     DWORD FileBufferSize = 0;
    1303     DWORD ImageBufferSize = 0;
    1304     DWORD size = 0;
    1305     
    1306     //File-->FileBuffer
    1307     FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer);
    1308     if (FileBufferSize == 0 || !pFileBuffer)
    1309     {
    1310         printf("文件-->缓冲区失败
    ");
    1311         return ;
    1312     }
    1313     printf("FileBufferSize ---> %#X 
    ",FileBufferSize);
    1314     
    1315     //FileBuffer-->ImageBuffer
    1316     ImageBufferSize = CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
    1317     if (ImageBufferSize == 0 || !pFileBuffer)
    1318     {
    1319         printf("FileBuffer-->ImageBuffer失败
    ");
    1320         free(pFileBuffer);
    1321         return ;
    1322     }
    1323     printf("ImageBufferSize ---> %#X 
    ",ImageBufferSize);
    1324     
    1325     size = ImageBufferMergeSections(pImageBuffer,&pNewImageBuffer);
    1326     if (size == 0 || !pImageBuffer)
    1327     {
    1328         printf("pImageBuffer-->pNewImageBuffer失败
    ");
    1329         free(pFileBuffer);
    1330         return ;
    1331     }
    1332     //pNewImageBuffer-->文件
    1333     isOK = MemeryTOFile(pNewImageBuffer,size,FilePath_Out);
    1334     if (isOK)
    1335     {
    1336         printf("合并节完成,存盘成功
    ");
    1337         return ;
    1338     }
    1339     
    1340     //释放内存
    1341     free(pFileBuffer);
    1342     free(pImageBuffer);
    1343     free(pNewImageBuffer);
    1344 }
    1345 
    1346 VOID RvaAndFoaConversion()
    1347 {
    1348     LPVOID pFileBuffer = NULL;
    1349     DWORD FileBufferSize = 0;
    1350     DWORD FoaFinalVaule = 0;
    1351     DWORD RvaFinalVaule = 0;
    1352     size_t pRVA = 1180;
    1353     size_t pFOA = 2279;
    1354 
    1355     //File-->FileBuffer
    1356     FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer);
    1357     if (FileBufferSize == 0 || !pFileBuffer)
    1358     {
    1359         printf("文件-->缓冲区失败
    ");
    1360         return ;
    1361     }
    1362     printf("FileBufferSize: %#X 
    ",FileBufferSize);
    1363 
    1364     FoaFinalVaule = RvaToFileOffset(pFileBuffer,pRVA);
    1365     if (FoaFinalVaule == 0 || !pFileBuffer)
    1366     {
    1367         printf("pFileBuffer-->读取失败
    ");
    1368         free(pFileBuffer);
    1369         return ;
    1370     }
    1371     printf("转换成功 --> FoaFinalVaule 传进来的pRVA值: : %#X %#X
    ",FoaFinalVaule,pRVA);
    1372 
    1373     RvaFinalVaule = FoaToImageOffset(pFileBuffer,pFOA);
    1374     if (RvaFinalVaule == 0 || !pFileBuffer)
    1375     {
    1376         printf("pFileBuffer-->读取失败
    ");
    1377         free(pFileBuffer);
    1378         return ;
    1379     }
    1380     printf("转换成功 --> RvaFinalVaule 传进来的pFOA值 : %#X %#X
    ",RvaFinalVaule,pFOA);
    1381     
    1382 
    1383     free(pFileBuffer);
    1384 }

    头文件代码

     1 // gbpeall.h: interface for the gbpeall class.
     2 //
     3 //////////////////////////////////////////////////////////////////////
     4 
     5 #if !defined(AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_)
     6 #define AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_
     7 
     8 #if _MSC_VER > 1000
     9 #pragma once
    10 #endif // _MSC_VER > 1000
    11 
    12 #include <string.h>
    13 #include <windows.h>
    14 #include <stdlib.h>
    15 
    16 #define debug 1
    17 //#define FILEPATH_IN         "C:\WINDOWS\system32\kernel32.dll"
    18 //    #define FilePath_In         "C:\cntflx\notepad.exe"
    19 #define FilePath_In         "C:\cntflx\ipmsg.exe"
    20 //#define FilePath_Out        "C:\cntflx\notepadnewpes.exe"
    21 //#define FilePath_Out        "C:\cntflx\ipmsgnewpeaddcodes.exe"
    22 //#define FilePath_Out        "C:\cntflx\ipmsgnewaddsections.exe"
    23 //#define FilePath_Out        "C:\cntflx\ipmsgextendsections.exe"
    24 #define FilePath_Out        "C:\cntflx\ipmsg_cntf_merge.exe"
    25 #define MESSAGEBOXADDR      0x77D5050B
    26 #define SHELLCODELENGTH     0x12 //16进制的,转换为十进制就是18
    27 
    28 extern BYTE ShellCode[];
    29 
    30 //读文件 --->FileBuffer
    31 DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer);
    32 
    33 //写到ImageBuffer,FileBuffer ---> ImageBuffer
    34 DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer);
    35 
    36 //写到NewImageBuffer, FileBuffer ---> NewImageBuffer
    37 DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer);
    38 
    39 //写到NewImageBuffer, 这里供扩大节使用;
    40 DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pNewImageBuffer);
    41 
    42 //写入到NewBuffer,目的是将拉伸后的ImageBuffer再缩回来,为存盘准备
    43 DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer);
    44 
    45 //写入到NewImageBuffer,这里供合并节使用
    46 DWORD ImageBufferMergeSections(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer);
    47 
    48 //写到pNewBuffer里面,从pNewImageBuffer写入 ---> pNewBuffer
    49 //DWORD ModifyImageBufferToNewBuffer(IN LPVOID pNewImageBuffer,OUT LPVOID* pNewBuffer);
    50 
    51 //Rva转Foa
    52 DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva);
    53 
    54 //Foa转RVA
    55 DWORD FoaToImageOffset(IN LPVOID pFileBuffer,IN DWORD dwFoa);
    56 
    57 //对齐大小
    58 DWORD AlignLength(DWORD Actuall_size,DWORD Align_size);
    59 
    60 //另一种对齐计算方式
    61 DWORD Alignment(DWORD alignment_value, DWORD addend, DWORD address);
    62 
    63 //将MemBuffer写入到硬盘,这里就是将各种修改好的内存文件,存入到本地硬盘中;
    64 BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile);
    65 
    66 //DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva);
    67 
    68 //调用函数,添加ShellCode代码
    69 VOID AddCodeInCodeSec();  //这个调用函数用到下面的4个函数
    70 //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewBuffer MemeryTOFile
    71 
    72 //调用函数,新增节表和节操作;
    73 VOID NewSectionsInCodeSec();  //这个调用函数用到下面的3个函数
    74 //ReadPEFile CopyFileBufferToNewImageBuffer MemeryTOFile
    75 
    76 //调用函数,扩大最后一个节
    77 VOID ExtendLastSectionsInCodeSec(); //这个调用函数用到下面的4个函数
    78 //ReadPEFile FileBufferToModifyImageBuffer CopyImageBufferToNewImageBuffer MemeryTOFile
    79 
    80 //调用函数,合并节
    81 VOID ModifySectionsOneInCodeSec(); //这个调用函数用到下面的4个函数
    82 //ReadPEFile CopyFileBufferToImageBuffer FileBufferToModifyOneImageBuffer MemeryTOFile
    83 
    84 //调用函数,Rva和Foa之间的相互转换;
    85 VOID RvaAndFoaConversion(); //这个调用函数用到下面的3个函数
    86 //ReadPEFile RvaToFileOffset FoaToImageOffset
    87 
    88 #endif // !defined(AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_)

    main函数入口处,这里根据调用的函数,直接找到对应合并节的代码即可

     1 // allpelx.cpp : Defines the entry point for the console application.
     2 //
     3 
     4 #include "stdafx.h"
     5 #include "gbpeall.h"
     6 
     7 int main(int argc, char* argv[])
     8 {
     9     //Fun();
    10     //AddCodeInCodeSec();
    11     //NewSectionsInCodeSec();
    12     //ExtendLastSectionsInCodeSec();
    13     ModifySectionsOneInCodeSec();
    14     //RvaAndFoaConversion();
    15     printf("Hello World! Cntf
    ");
    16     system("pause");
    17     return 0;
    18 }

    执行结果

    正常执行,并且可正常打开;

    PE解析结果验证

    迷茫的人生,需要不断努力,才能看清远方模糊的志向!
  • 相关阅读:
    @从零开始实现一个插件化框架(一)
    @从零开始实现一个插件化框架(二)
    @从零开始实现一个插件化框架(三)
    @CoordinatorLayout使用详解: 打造折叠悬浮效果
    Oracle 11g数据库详细安装过程
    web service 的跨语言特性
    struts2--值栈
    事务处理中如何获取同一个connection 对象
    jsp中文乱码问题
    设置工作集
  • 原文地址:https://www.cnblogs.com/autopwn/p/15293906.html
Copyright © 2011-2022 走看看