• 滴水逆向-RVA和FOA直接互相转换


    参考图:

    具体相关代码

     核心相关代码

       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 //ImageBuffer ---> NewImageBuffer
     524 //将拉伸后加载到内存的ImageBuffer存入到NewImageBuffer,修改数据完成之后,准备存盘操作
     525 DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pNewImageBuffer)
     526 {
     527     PIMAGE_DOS_HEADER pDosHeader = NULL;
     528     PIMAGE_NT_HEADERS pNTHeader = NULL;
     529     PIMAGE_FILE_HEADER pPEHeader = NULL;
     530     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     531     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     532     PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
     533     LPVOID pTempNewImageBuffer = NULL;
     534     DWORD ImageBuffer_Size = 0;
     535     DWORD numberOfSection = 0;
     536 
     537     //判断读取pImageBuffer是否成功 
     538     if (!pFileBuffer)
     539     {
     540         printf("缓冲区指针无效
    ");
     541     }
     542 
     543     //判断是否是有效的MZ头
     544     if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
     545     {
     546         printf("不是有效的MZ头
    ");
     547         return 0;
     548     }
     549 
     550     //判断是否是有效的PE头
     551     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
     552     if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     553     {
     554         printf("不是有效的PE头
    ");
     555         return 0;
     556     }
     557 
     558     //定位NT头
     559     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
     560 
     561     //定位标准的PE文件头
     562     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
     563 
     564     //定位可选PE头
     565     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     566 
     567     //定位第一个节表地址
     568     numberOfSection = pPEHeader->NumberOfSections;
     569     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
     570 
     571     //定位最后一个节表地址
     572     pLastSectionHeader = &pSectionHeader[numberOfSection-1];
     573 //    printf("numberOfSection --> %#X 
    ",numberOfSection);
     574 //    printf("*pSectionHeader --> %#X 
    ",pSectionHeader->Misc.VirtualSize);
     575 //    printf("*pLastSectionHeader --> %#X 
    ",&pLastSectionHeader);
     576 
     577     //开始操作需要修改的部分
     578     
     579     //最后一个节中内存中对齐前的大小;
     580     PDWORD pVirtualSize = &pLastSectionHeader->Misc.VirtualSize;
     581     //最后一个节在文件中对齐后的大小;
     582     PDWORD pSizeOfRawData = &pLastSectionHeader->SizeOfRawData;
     583     //文件中SizeOfImage的大小;
     584     PDWORD pSizeOfImage = &pOptionHeader->SizeOfImage;
     585 
     586     //扩展修改之前的数据
     587 //    printf("&pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",pVirtualSize);
     588 //    printf("*pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",*pVirtualSize);
     589 //
     590 //    printf("&pLastSectionHeader->SizeOfRawData --> %#X 
    ",pSizeOfRawData);
     591 //    printf("*pLastSectionHeader->SizeOfRawData --> %#X 
    ",*pSizeOfRawData);
     592 //    
     593 //    printf("&pOptionHeader->SizeOfImage --> %#X 
    ",pSizeOfImage);
     594 //    printf("*pOptionHeader->SizeOfImage --> %#X 
    ",*pSizeOfImage);
     595 
     596     //扩展修改pVirtualSize
     597     *pVirtualSize = AlignLength(*pVirtualSize,pOptionHeader->SectionAlignment)+0x1000;
     598 //    printf("&pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",pVirtualSize);
     599 //    printf("*pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",*pVirtualSize);
     600 //    printf("&pLastSectionHeader->SizeOfRawData --> %#X 
    ",pSizeOfRawData);
     601 //    printf("*pLastSectionHeader->SizeOfRawData --> %#X 
    ",*pSizeOfRawData);
     602 // 
     603     //扩展修改pSizeOfRawData
     604     *pSizeOfRawData = AlignLength(*pSizeOfRawData,pOptionHeader->SectionAlignment)+0x1000;
     605 //    printf("&pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",pVirtualSize);
     606 //    printf("*pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",*pVirtualSize);
     607 //    printf("&pLastSectionHeader->SizeOfRawData --> %#X 
    ",pSizeOfRawData);
     608 //    printf("*pLastSectionHeader->SizeOfRawData --> %#X 
    ",*pSizeOfRawData);
     609 //    printf("&pOptionHeader->SizeOfImage --> %#X 
    ",pSizeOfImage);
     610 //    printf("*pOptionHeader->SizeOfImage --> %#X 
    ",*pSizeOfImage);
     611 
     612     //修改SizeOfImage
     613     *pSizeOfImage += 0x1000;
     614 //    printf("&pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",pVirtualSize);
     615 //    printf("*pLastSectionHeader->Misc.VirtualSize --> %#X 
    ",*pVirtualSize);
     616 //    printf("&pLastSectionHeader->SizeOfRawData --> %#X 
    ",pSizeOfRawData);
     617 //    printf("*pLastSectionHeader->SizeOfRawData --> %#X 
    ",*pSizeOfRawData);
     618 //    printf("&pOptionHeader->SizeOfImage --> %#X 
    ",pSizeOfImage);
     619 //    printf("*pOptionHeader->SizeOfImage --> %#X 
    ",*pSizeOfImage);
     620 
     621     //得到修改之后的大小准备申请内存空间
     622 
     623     ImageBuffer_Size = pOptionHeader->SizeOfImage;
     624     pTempNewImageBuffer = malloc(ImageBuffer_Size);
     625 
     626     if (!pTempNewImageBuffer)
     627     {
     628         printf("分配内存空间失败
    ");
     629         return 0;
     630     }
     631 
     632     //初始化内存空间
     633     memset(pTempNewImageBuffer,0,ImageBuffer_Size);
     634 
     635     //复制SizeOfHeaders
     636     memcpy(pTempNewImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
     637 
     638     //创建临时节的结构体指针,遍历数据
     639     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     640 
     641     for (DWORD i = 0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++)
     642     {
     643         memcpy((PVOID)((DWORD)pTempNewImageBuffer+pTempSectionHeader->VirtualAddress),
     644             (void*)((DWORD)pFileBuffer+pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData);
     645     }
     646 
     647     *pNewImageBuffer = pTempNewImageBuffer;
     648     pTempNewImageBuffer = NULL;
     649     return *pSizeOfImage;
     650 }
     651 
     652 //将ImageBuffer更改为一个节表和节然后压缩为NewBuffer,供存盘准备
     653 DWORD FileBufferToModifyOneImageBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer)
     654 {
     655     PIMAGE_DOS_HEADER pDosHeader = NULL;
     656     PIMAGE_NT_HEADERS pNTHeader = NULL;
     657     PIMAGE_FILE_HEADER pPEHeader = NULL;
     658     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     659     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     660     PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
     661     LPVOID pTempNewBuffer = NULL;
     662     DWORD finalSections_Size = 0;
     663     DWORD numberOfSection = 0;
     664     DWORD lastSectionsMax_Size = 0;
     665     DWORD sizeOfFile = 0;
     666 
     667     //判断读取pImageBuffer是否成功 
     668     if (pImageBuffer == NULL)
     669     {
     670         printf("缓冲区指针无效
    ");
     671     }
     672     //判断是否是有效的MZ标志
     673     if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
     674     {
     675         printf("不是有效的MZ头
    ");
     676         return 0;
     677     }
     678     //判断是否是有效的PE标志
     679 
     680     pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
     681     if (*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     682     {
     683         printf("不是有效的PE标志
    ");
     684         return 0;
     685     }
     686 
     687 
     688     //定位NT头
     689     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer+pDosHeader->e_lfanew);
     690 
     691     //定位标准的PE文件头
     692     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
     693 
     694     //定位可选PE头
     695     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     696 
     697     //定位第一个节表地址
     698     numberOfSection = pPEHeader->NumberOfSections;
     699     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
     700 
     701     //定位最后一个节表地址
     702     pLastSectionHeader = &pSectionHeader[numberOfSection-1];
     703 
     704 
     705     //最后一个节中内存对齐前的大小;
     706     PDWORD pVirtualSize = &pLastSectionHeader->Misc.VirtualSize;
     707     //最后一个节在文件中对齐后的大小;
     708     PDWORD pSizeOfRawData = &pLastSectionHeader->SizeOfRawData;
     709 
     710     //计算最后一个节中最大值是SizeOfRawData还是VirtualSize
     711     lastSectionsMax_Size = *pSizeOfRawData > *pVirtualSize ? *pSizeOfRawData : *pVirtualSize;
     712 
     713     //计算最终合并后节对应SizeOfRawData或VirtualSize的大小
     714     finalSections_Size = pLastSectionHeader->VirtualAddress + lastSectionsMax_Size - pOptionHeader->SizeOfHeaders;
     715 
     716     //修改第一个节的SizeOfRawData和VirtualSize的值,将其更改为上面计算出来的最终值
     717     pSectionHeader->Misc.VirtualSize = finalSections_Size;
     718     pSectionHeader->SizeOfRawData = finalSections_Size;
     719 
     720     //修改pPEHeader->NumberOfSections的属性为0x01
     721     numberOfSection = 0x01;
     722 
     723     sizeOfFile = pOptionHeader->SizeOfHeaders + finalSections_Size;
     724     //使用winhex打开notepad.exe 是0x00000400,这是第一个节之前的所有大小
     725     // for(DWORD i = 0;i<numberOfSection;i++)
     726     // {
     727     //     sizeOfFile += pSectionHeader[i].SizeOfRawData;  // pSectionHeader[i]另一种加法
     728     // }
     729 
     730     //根据SizeOfImage申请新的空间
     731     pTempNewBuffer = malloc(sizeOfFile);
     732 
     733     if (!pTempNewBuffer)
     734     {
     735         printf("申请内存空间失败
    ");
     736         return 0;
     737     }
     738     //初始化新的缓冲区
     739     memset(pTempNewBuffer,0,sizeOfFile);
     740     //根据SizeOfHeaders 先copy头
     741     memcpy(pTempNewBuffer,pDosHeader,sizeOfFile);
     742     //根据节表循环复制节
     743     //PIMAGE_SECTION_HEADER pTempSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader);
     744     // PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     745     // for (int j=0;j<pPEHeader->NumberOfSections;j++,pTempSectionHeader++)
     746     // {
     747     //        memcpy((PDWORD)((DWORD)pTempNewBuffer+pTempSectionHeader->PointerToRawData),
     748     //     (PDWORD)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress),
     749     //     pTempSectionHeader->SizeOfRawData);
     750     // }
     751 
     752     //返回数据
     753     *pNewBuffer = pTempNewBuffer;
     754     pTempNewBuffer = NULL;
     755     return sizeOfFile;
     756   }
     757 
     758 //ImageBuffer ---> NewBuffer
     759 //将拉伸后加载到内存的ImageBuffer存入到NewBuffer里面,然后准备存盘;
     760 DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer)
     761 {
     762     //下面大部分操作都是跟上面一样的,这里就不再赘述了
     763     PIMAGE_DOS_HEADER pDosHeader = NULL;
     764     PIMAGE_NT_HEADERS pNTHeader = NULL;
     765     PIMAGE_FILE_HEADER pPEHeader = NULL;
     766     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     767     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     768     LPVOID pTempNewBuffer = NULL;
     769     DWORD sizeOfFile = 0;
     770     DWORD numberOfSection = 0;
     771 
     772     if (pImageBuffer == NULL)
     773     {
     774         printf("缓冲区指针无效
    ");
     775     }
     776     //判断是否是有效的MZ标志
     777     if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
     778     {
     779         printf("不是有效的MZ头
    ");
     780         return 0;
     781     }
     782     pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
     783     //判断是否是有效的PE标志
     784     if (*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     785     {
     786         printf("不是有效的PE标志
    ");
     787         return 0;
     788     }
     789     //NT头地址
     790     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
     791     //标准PE文件头
     792     pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
     793     //可选PE头
     794     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     795     //第一个节表地址
     796     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
     797 
     798     //计算文件需要的空间--最后一个节的文件偏移+节对齐后的长度
     799     /*
     800     numberOfSection = pPEHeader->NumberOfSections;
     801     pSectionHeader = pSectionHeader[numberOfSection-1];
     802     sizeOfFile = (pSectionHeader->PointerToRawData + pSectionHeader->Misc.VirtualSize + pOptionHeader->FileAlignment);
     803     printf("sizeOfFile %X 
    ",sizeOfFile);
     804 
     805     for (DWORD i=0;i<=numberOfSection;i++)
     806     {
     807         sizeOfFile += sizeOfFile[i];
     808     }
     809     */
     810 
     811     sizeOfFile = pOptionHeader->SizeOfHeaders;
     812     //使用winhex打开notepad.exe 是0x00000400,这是第一个节之前的所有大小
     813     for(DWORD i = 0;i<pPEHeader->NumberOfSections;i++)
     814     {
     815         sizeOfFile += pSectionHeader[i].SizeOfRawData;  // pSectionHeader[i]另一种加法
     816     }
     817 
     818     /*
     819     上面的for循环大概意思就是基于几个节的数量依次循环叠加sizeOfFile的值;因为SizeOfRawData是文件中对齐后的大小;
     820     所以循环计算如下:
     821     sizeOfFile = 0x00000400 + 0x00007800 = 0x00007C00
     822     sizeOfFile = 0x00007C00 + 0x00000800 = 0x00008400
     823     sizeOfFile = 0x00008400 + 0x00008000 = 0x00010400
     824 
     825     */
     826 
     827     //根据SizeOfImage申请新的空间
     828     pTempNewBuffer = malloc(sizeOfFile);
     829 
     830     if (!pTempNewBuffer)
     831     {
     832         printf("申请内存空间失败
    ");
     833         return 0;
     834     }
     835     //初始化新的缓冲区
     836     memset(pTempNewBuffer,0,sizeOfFile);
     837     //根据SizeOfHeaders 先copy头
     838     memcpy(pTempNewBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
     839     //根据节表循环复制节
     840     //PIMAGE_SECTION_HEADER pTempSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader);
     841     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     842     for (int j=0;j<pPEHeader->NumberOfSections;j++,pTempSectionHeader++)
     843     {
     844         /*memcpy((LPVOID)((DWORD)pTempNewBuffer + pTempSectionHeader->PointerToRawData),
     845         (LPVOID)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress),
     846         pTempSectionHeader->SizeOfRawData);*/
     847         //PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
     848         memcpy((PDWORD)((DWORD)pTempNewBuffer+pTempSectionHeader->PointerToRawData),
     849         (PDWORD)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress),
     850         pTempSectionHeader->SizeOfRawData);
     851         //printf("%X  --> PoniterToRadata
    ",pTempSectionHeader->PointerToRawData);
     852         //printf("%X  --> VirtualAddress
    ",pTempSectionHeader->VirtualAddress);
     853         //printf("%X  --> VirtualSize
    ",pTempSectionHeader->Misc.VirtualSize);
     854     }
     855 
     856     //返回数据
     857     *pNewBuffer = pTempNewBuffer;
     858     pTempNewBuffer = NULL;
     859     return sizeOfFile;
     860   }
     861 
     862 //将上面得到的MemBuffer存盘到本地;
     863 BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile)
     864 {
     865     FILE* fp = NULL;
     866     fp = fopen(lpszFile, "wb+");
     867     if (!fp)  //  这里我刚开始写漏了一个等于号,变成复制NULL了,导致错误
     868 //  if(fp == NULL)  可以这么写,没问题
     869     {
     870         fclose(fp);
     871         return FALSE;
     872     }
     873     fwrite(pMemBuffer,size,1,fp);
     874     fclose(fp);
     875     fp = NULL;
     876     return TRUE;
     877 }
     878 
     879 //RVA格式转换FOA  --- RvaToFileOffset
     880 DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva)
     881 {
     882     PIMAGE_DOS_HEADER pDosHeader = NULL;
     883     PIMAGE_NT_HEADERS pNTHeader = NULL;
     884     PIMAGE_FILE_HEADER pPEHeader = NULL;
     885     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     886     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     887     DWORD numberOfSection = 0;
     888     DWORD dwFOAValue = 0;
     889 
     890     //判断指针是否有效
     891     if (!pFileBuffer)
     892     {
     893         printf("pFileBuffer 指针无效
    ");
     894         return 0;
     895     }
     896     //判断是否是有效的MZ标志
     897     if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
     898     {
     899         printf("pFileBuffer不是有效的MZ标志
    ");
     900         return 0;
     901     }
     902     //判断是否是一个有效的PE标志
     903     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
     904     if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     905     {
     906         printf("pFileBuffer不是一个有效的PE标志
    ");
     907         return 0;
     908     }
     909 
     910     printf("当前的Rva地址: %#X 
    ",dwRva);
     911     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
     912     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
     913     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     914     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
     915 
     916     //定义个临时节表指针进行下面的计算操作
     917     numberOfSection = pPEHeader->NumberOfSections;
     918     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     919 
     920 
     921     //判断dwRva所处的节
     922     if (dwRva <= pOptionHeader->SizeOfHeaders)
     923     {
     924         return (DWORD)dwRva;
     925     }
     926     //上面是判断如果rva地址所处的节在第一个节之前那么直接返回rva的地址;
     927     //否则下面就是开始遍历查找节;
     928     else
     929     {
     930         for (DWORD n = 0; n < numberOfSection; n++, pTempSectionHeader++)
     931         {//下面是判断在哪个节的范围,然后根据rva所在的地址减去所在节的VirtualAddress得到的偏移值加上文件中对应节的偏移值PointerToRawData
     932             if ((dwRva >= pTempSectionHeader->VirtualAddress) && (dwRva < pTempSectionHeader->VirtualAddress + pTempSectionHeader->Misc.VirtualSize))
     933             {
     934                 dwFOAValue = dwRva - pTempSectionHeader->VirtualAddress + pTempSectionHeader->PointerToRawData;
     935             }
     936             else
     937             {
     938                 printf("RvaToFoa 转换失败!
    ");
     939                 return 0;
     940             }
     941         }
     942     }
     943     return dwFOAValue;
     944 }
     945 
     946 //FOA格式转换RVA  --- ImageOffset
     947 DWORD FoaToImageOffset(IN LPVOID pFileBuffer,IN DWORD dwFoa)
     948 {
     949     PIMAGE_DOS_HEADER pDosHeader = NULL;
     950     PIMAGE_NT_HEADERS pNTHeader = NULL;
     951     PIMAGE_FILE_HEADER pPEHeader = NULL;
     952     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
     953     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
     954     DWORD numberOfSection = 0;
     955     DWORD dwRVAValue = 0;
     956 
     957     //判断指针是否有效
     958     if (!pFileBuffer)
     959     {
     960         printf("pFileBuffer 指针无效
    ");
     961         return 0;
     962     }
     963     //判断是否是有效的MZ标志
     964     if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
     965     {
     966         printf("pFileBuffer不是有效的MZ标志
    ");
     967         return 0;
     968     }
     969     //判断是否是一个有效的PE标志
     970     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
     971     if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
     972     {
     973         printf("pFileBuffer不是一个有效的PE标志
    ");
     974         return 0;
     975     }
     976     
     977     printf("当前的Foa地址: %#X 
    ",dwFoa);
     978     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
     979     pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04);
     980     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
     981     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
     982     
     983     //定义个临时节表指针进行下面的计算操作
     984     numberOfSection = pPEHeader->NumberOfSections;
     985     PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
     986 
     987     if (dwFoa <= pOptionHeader->SizeOfHeaders)
     988     {
     989         return (DWORD)dwFoa;
     990     }
     991     else
     992     {
     993         for (DWORD n = 0; n < numberOfSection; n++, pTempSectionHeader++)
     994         {
     995             if ((dwFoa >= pTempSectionHeader->PointerToRawData) && (dwFoa < pTempSectionHeader->SizeOfRawData))
     996             {
     997                 dwRVAValue = dwFoa - pTempSectionHeader->PointerToRawData + pTempSectionHeader->VirtualAddress;
     998             }
     999             else
    1000             {
    1001                 printf("FoaToRva 转换失败!
    ");
    1002                 return 0;
    1003             }
    1004         }
    1005     }
    1006     return dwRVAValue;
    1007 }
    1008 
    1009 //在原有的exe文件中开始操作添加ShellCode代码;
    1010 
    1011 VOID AddCodeInCodeSec()
    1012 {
    1013     LPVOID pFileBuffer = NULL;
    1014     LPVOID pImageBuffer = NULL;
    1015     LPVOID pNewBuffer = NULL;
    1016     PIMAGE_DOS_HEADER pDosHeader = NULL;
    1017     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    1018     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    1019     PBYTE codeBegin = NULL;
    1020     BOOL isOK = FALSE;
    1021     DWORD size = 0;
    1022 
    1023     //File-->FileBuffer
    1024     ReadPEFile(FilePath_In,&pFileBuffer);
    1025     if (!pFileBuffer)
    1026     {
    1027         printf("文件-->缓冲区失败
    ");
    1028         return ;
    1029     }
    1030 
    1031     //FileBuffer-->ImageBuffer
    1032     CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
    1033     if (!pImageBuffer)
    1034     {
    1035         printf("FileBuffer-->ImageBuffer失败
    ");
    1036         free(pFileBuffer);
    1037         return ;
    1038     }
    1039 
    1040     //判断代码段空闲区域是否能够足够存储ShellCode代码
    1041     pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    1042     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    1043     pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_NT_OPTIONAL32_HEADER);
    1044     if (((pSectionHeader->SizeOfRawData) - (pSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH)
    1045     {
    1046         printf("代码区域空闲空间不够
    ");
    1047         free(pFileBuffer);
    1048         free(pImageBuffer);
    1049     }
    1050 
    1051     //将代码复制到空闲区域
    1052     codeBegin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);
    1053     printf("pSectionHeader->VirtualAddress: %#010X
    ", pSectionHeader->VirtualAddress);
    1054     printf("pSectionHeader->Misc.VirtualSize: %#010X
    ", pSectionHeader->Misc.VirtualSize);
    1055     printf("codeBegin: %#010X
    ", codeBegin);
    1056 
    1057     memcpy(codeBegin,ShellCode,SHELLCODELENGTH);
    1058 
    1059     //修正E8-->call后面的代码区域
    1060     DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + 0xD) - (DWORD)pImageBuffer)));
    1061     printf("callAddr ---> %#010X 
    ",callAddr);
    1062     *(PDWORD)(codeBegin + 0x09) = callAddr;
    1063     printf("*(PWORD)(codeBegin + 0x09) ---> %#010X 
    ",*(PDWORD)(codeBegin + 0x09));
    1064     /*
    1065     关于修正E8的理解,公式:X = 要跳转的地址 - (E8当前的地址 + 5);
    1066     要跳转的地址,这里是毋庸置疑的,就是我们要加入代码MessageBox的地址;
    1067     然后要减去E8当前的地址+5的位置,这里不是太好理解;
    1068     我们的目的是要将E8后面的4个字节计算出来,然后写入到E8后面,也就是公式中X;
    1069     上面公式E8当前地址+5 ,而在此情况要定位到这个位置就要从代码的Dos开始通过指针相加;
    1070     进行位置偏移到E8当前地址+5的位置;
    1071     所以定位codeBegin的位置是:pImageBuffer指针最开始的位置(Dos头位置)通过内存中偏移的宽度移动到第一个节表的位置;
    1072     也就是上面的pSectionHeader->VirtualAddress 操作形式;
    1073     然后再偏移第一个节表在内存中对齐前实际的宽度(尺寸)pSectionHeader->Misc.VirtualSize;
    1074     上述一番操作之后就到了第一个节表没有对齐前的位置,这个位置就是我们可以添加ShellCode代码的起始位置;
    1075     到了添加ShellCode代码的起始位置之后,就要想办法添加E8位置后面的4个字节,此时根据ShellCode代码的宽度;
    1076     进行计算,确认0x6A 00 0x6A 00 0x6A 00 0x6A 00 E8 00 00 00 00 刚好向后面数13个位置,按照十六进制看;
    1077     就是0xD,所以在codeBegin偏移0xD个位置即可到达E9的位置,这也就是我们说的(E8当前的地址 + 5);
    1078     到了上面的位置之后,由于我们最终是需要在程序运行之后在内存中添加ShellCode代码;所以这里一定要计算出;
    1079     其准确的偏移地址,这样不管怎么拉伸到哪个位置,都能准确找到位置;
    1080     注意:这里需要注意一点理解,上面说的pImageBuffer这个是我们加载程序到我们申请的内存中,绝不是程序在;
    1081     运行中的那个内存,这里一定要理解清楚,她们是不一样的,理解了这个就能理解上面代码为什么要减去Dos头的;
    1082     首地址,(DWORD)(codeBegin + 0xD) - (DWORD)pImageBuffer)
    1083     */
    1084 
    1085     //修正E9-->jmp后面的代码区域
    1086     DWORD jmpAddr = ((pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint) - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + SHELLCODELENGTH) - (DWORD)pImageBuffer)));
    1087     printf("jmpAddr ---> %#010X 
    ",jmpAddr);
    1088     *(PDWORD)(codeBegin + 0x0E) = jmpAddr;
    1089     printf("*(PWORD)(codeBegin + 0x0E) ---> %#010X 
    ",*(PDWORD)(codeBegin + 0x0E));
    1090     /*
    1091     公式:X = 要跳转的地址 - (E9当前的地址 + 5)
    1092     这里同样是要计算出E9后面4个字节的地址,我们的目的是在这里添加OEP的地址,让其执行完成MessageBox之后跳转;
    1093     OEP的地址,那么这里就要先计算出OEP地址,就是pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint;
    1094     再减去(E9当前的地址 + 5) 0x6A 00 0x6A 00 0x6A 00 0x6A 00 E8 00 00 00 00 E9 00 00 00 00;
    1095     (DWORD)codeBegin + SHELLCODELENGTH 就是加上ShellCode总长度,偏移完成之后减去ImageBuffer首地址再加上ImageBase;
    1096     */
    1097 
    1098     //修正OEP
    1099     printf("pOptionHeader->AddressOfEntryPoint ---> %#010X 
    ",pOptionHeader->AddressOfEntryPoint);
    1100     printf("(DWORD)codeBegin ---> %#010X 
    ",((DWORD)codeBegin - (DWORD)pImageBuffer));
    1101     pOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pImageBuffer;
    1102     printf("pOptionHeader->AddressOfEntryPoint ---> %#010X 
    ",pOptionHeader->AddressOfEntryPoint);
    1103     //修正OEP好理解,就是定位到OEP地址,然后直接通过codeBegin地址减去pImageBuffer的首地址即可;
    1104 
    1105     //ImageBuffer-->NewBuffer
    1106     size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewBuffer);
    1107     if (size == 0 || !pNewBuffer)
    1108     {
    1109         printf("ImageBuffer-->NewBuffer失败
    ");
    1110         free(pFileBuffer);
    1111         free(pImageBuffer);
    1112         return ;
    1113     }
    1114 
    1115     //NewBuffer-->文件
    1116     isOK = MemeryTOFile(pNewBuffer,size,FilePath_Out);
    1117     if (isOK)
    1118     {
    1119         printf("修改代码添加SHELLCODE 存盘成功
    ");
    1120         return ;
    1121     }
    1122 
    1123     //释放内存
    1124     free(pFileBuffer);
    1125     free(pImageBuffer);
    1126     free(pNewBuffer);
    1127 }
    1128 
    1129 //调用函数新增节表和节操作,成功之后并存盘到本地;
    1130 VOID NewSectionsInCodeSec()
    1131 {
    1132     LPVOID pFileBuffer = NULL;
    1133     LPVOID pNewImageBuffer = NULL;
    1134     BOOL isOK = FALSE;
    1135     DWORD size1 = 0;
    1136     DWORD size2 = 0;
    1137     
    1138     //File-->FileBuffer
    1139     size1 = ReadPEFile(FilePath_In,&pFileBuffer);
    1140     if (size1 == 0 || !pFileBuffer)
    1141     {
    1142         printf("文件-->缓冲区失败
    ");
    1143         return ;
    1144     }
    1145     printf("fileSize - Final: %#X 
    ",size1);
    1146     
    1147     //FileBuffer-->NewImageBuffer
    1148     size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&pNewImageBuffer);
    1149     if (size2 == 0 || !pFileBuffer)
    1150     {
    1151         printf("FileBuffer-->NewImageBuffer失败
    ");
    1152         free(pFileBuffer);
    1153         return ;
    1154     }
    1155     printf("sizeOfFile - Final: %#X 
    ",size2);
    1156     //NewImageBuffer-->文件
    1157     isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out);
    1158     if (isOK)
    1159     {
    1160         printf("新增节表和节存盘成功
    ");
    1161        return ;
    1162     }
    1163     
    1164     //释放内存
    1165     free(pFileBuffer);
    1166     free(pNewImageBuffer);
    1167 }
    1168 
    1169 //调用函数扩大一个节
    1170 VOID ExtendLastSectionsInCodeSec()
    1171 {
    1172     //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewImageBuffer
    1173 
    1174     LPVOID pFileBuffer = NULL;
    1175     LPVOID pImageBuffer = NULL;
    1176     LPVOID pNewImageBuffer = NULL;
    1177     BOOL isOK = FALSE;
    1178     DWORD FileBufferSize = 0;
    1179     DWORD ImageBufferSize = 0;
    1180     DWORD size = 0;
    1181     
    1182     //File-->FileBuffer
    1183     FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer);
    1184     if (FileBufferSize == 0 || !pFileBuffer)
    1185     {
    1186         printf("文件-->缓冲区失败
    ");
    1187         return ;
    1188     }
    1189     printf("FileBufferSize - Final: %#X 
    ",FileBufferSize);
    1190     
    1191     //FileBuffer-->ImageBuffer
    1192     ImageBufferSize = FileBufferToModifyImageBuffer(pFileBuffer,&pImageBuffer);
    1193     if (ImageBufferSize == 0 || !pFileBuffer)
    1194     {
    1195         printf("FileBuffer-->ImageBuffer失败
    ");
    1196         free(pFileBuffer);
    1197         return ;
    1198     }
    1199     printf("ImageBufferSize - Final: %#X 
    ",ImageBufferSize);
    1200 
    1201     size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewImageBuffer);
    1202     if (size == 0 || !pImageBuffer)
    1203     {
    1204         printf("pImageBuffer-->pNewImageBuffer失败
    ");
    1205         free(pFileBuffer);
    1206         return ;
    1207     }
    1208     //pNewImageBuffer-->文件
    1209     isOK = MemeryTOFile(pNewImageBuffer,size,FilePath_Out);
    1210     if (isOK)
    1211     {
    1212         printf("扩大一个节成功,并存盘
    ");
    1213         return ;
    1214     }
    1215     
    1216     //释放内存
    1217     free(pFileBuffer);
    1218     free(pImageBuffer);
    1219     free(pNewImageBuffer);
    1220 }
    1221 
    1222 
    1223 //调用函数扩大一个节
    1224 VOID ModifySectionsOneInCodeSec()
    1225 {
    1226     //ReadPEFile CopyFileBufferToImageBuffer FileBufferToModifyOneImageBuffer MemeryTOFile
    1227     
    1228     LPVOID pFileBuffer = NULL;
    1229     LPVOID pImageBuffer = NULL;
    1230     LPVOID pNewImageBuffer = NULL;
    1231     BOOL isOK = FALSE;
    1232     DWORD FileBufferSize = 0;
    1233     DWORD ImageBufferSize = 0;
    1234     DWORD size = 0;
    1235     
    1236     //File-->FileBuffer
    1237     FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer);
    1238     if (FileBufferSize == 0 || !pFileBuffer)
    1239     {
    1240         printf("文件-->缓冲区失败
    ");
    1241         return ;
    1242     }
    1243     printf("FileBufferSize - Final: %#X 
    ",FileBufferSize);
    1244     
    1245     //FileBuffer-->ImageBuffer
    1246     ImageBufferSize = CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
    1247     if (ImageBufferSize == 0 || !pFileBuffer)
    1248     {
    1249         printf("FileBuffer-->ImageBuffer失败
    ");
    1250         free(pFileBuffer);
    1251         return ;
    1252     }
    1253     printf("ImageBufferSize - Final: %#X 
    ",ImageBufferSize);
    1254     
    1255     size = FileBufferToModifyOneImageBuffer(pImageBuffer,&pNewImageBuffer);
    1256     if (size == 0 || !pImageBuffer)
    1257     {
    1258         printf("pImageBuffer-->pNewImageBuffer失败
    ");
    1259         free(pFileBuffer);
    1260         return ;
    1261     }
    1262     //pNewImageBuffer-->文件
    1263     isOK = MemeryTOFile(pNewImageBuffer,size,FilePath_Out);
    1264     if (isOK)
    1265     {
    1266         printf("合并节完成,存盘成功
    ");
    1267         return ;
    1268     }
    1269     
    1270     //释放内存
    1271     free(pFileBuffer);
    1272     free(pImageBuffer);
    1273     free(pNewImageBuffer);
    1274 }
    1275 
    1276 VOID RvaAndFoaConversion()
    1277 {
    1278     LPVOID pFileBuffer = NULL;
    1279     DWORD FileBufferSize = 0;
    1280     DWORD FoaFinalVaule = 0;
    1281     DWORD RvaFinalVaule = 0;
    1282     size_t pRVA = 1180;
    1283     size_t pFOA = 2279;
    1284 
    1285     //File-->FileBuffer
    1286     FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer);
    1287     if (FileBufferSize == 0 || !pFileBuffer)
    1288     {
    1289         printf("文件-->缓冲区失败
    ");
    1290         return ;
    1291     }
    1292     printf("FileBufferSize: %#X 
    ",FileBufferSize);
    1293 
    1294     FoaFinalVaule = RvaToFileOffset(pFileBuffer,pRVA);
    1295     if (FoaFinalVaule == 0 || !pFileBuffer)
    1296     {
    1297         printf("pFileBuffer-->读取失败
    ");
    1298         free(pFileBuffer);
    1299         return ;
    1300     }
    1301     printf("转换成功 --> FoaFinalVaule 传进来的pRVA值: : %#X %#X
    ",FoaFinalVaule,pRVA);
    1302 
    1303     RvaFinalVaule = FoaToImageOffset(pFileBuffer,pFOA);
    1304     if (RvaFinalVaule == 0 || !pFileBuffer)
    1305     {
    1306         printf("pFileBuffer-->读取失败
    ");
    1307         free(pFileBuffer);
    1308         return ;
    1309     }
    1310     printf("转换成功 --> RvaFinalVaule 传进来的pFOA值 : %#X %#X
    ",RvaFinalVaule,pFOA);
    1311     
    1312 
    1313     free(pFileBuffer);
    1314 }

    头文件代码

    // gbpeall.h: interface for the gbpeall class.
    //
    //////////////////////////////////////////////////////////////////////
    
    #if !defined(AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_)
    #define AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    #include <string.h>
    #include <windows.h>
    #include <stdlib.h>
    
    //#define FILEPATH_IN         "C:\WINDOWS\system32\kernel32.dll"
    //    #define FilePath_In         "C:\cntflx\notepad.exe"
    #define FilePath_In         "C:\cntflx\ipmsg.exe"
    //#define FilePath_Out        "C:\cntflx\notepadnewpes.exe"
    //#define FilePath_Out        "C:\cntflx\ipmsgnewpeaddcodes.exe"
    //#define FilePath_Out        "C:\cntflx\ipmsgnewaddsections.exe"
    //#define FilePath_Out        "C:\cntflx\ipmsgextendsections.exe"
    #define FilePath_Out        "C:\cntflx\ipmsgemerge.exe"
    #define MESSAGEBOXADDR      0x77D5050B
    #define SHELLCODELENGTH     0x12 //16进制的,转换为十进制就是18
    
    extern BYTE ShellCode[];
    
    //读文件 --->FileBuffer
    DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer);
    
    //写到ImageBuffer,FileBuffer ---> ImageBuffer
    DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer);
    
    //写到NewImageBuffer, FileBuffer ---> NewImageBuffer
    DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer);
    
    //写到NewImageBuffer, 这里供扩大节使用;
    DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pNewImageBuffer);
    
    //写入到NewBuffer,目的是将拉伸后的ImageBuffer再缩回来,为存盘准备
    DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer);
    
    //写入到NewImageBuffer,这里供合并节使用?
    DWORD FileBufferToModifyOneImageBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer);
    
    //写到pNewBuffer里面,从pNewImageBuffer写入 ---> pNewBuffer
    //DWORD ModifyImageBufferToNewBuffer(IN LPVOID pNewImageBuffer,OUT LPVOID* pNewBuffer);
    
    //Rva转Foa
    DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva);
    
    //Foa转RVA
    DWORD FoaToImageOffset(IN LPVOID pFileBuffer,IN DWORD dwFoa);
    
    //对齐大小
    DWORD AlignLength(DWORD Actuall_size,DWORD Align_size);
    
    //将MemBuffer写入到硬盘,这里就是将各种修改好的内存文件,存入到本地硬盘中;
    BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile);
    
    //DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva);
    
    //调用函数,添加ShellCode代码
    VOID AddCodeInCodeSec();  //这个调用函数用到下面的4个函数
    //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewBuffer MemeryTOFile
    
    //调用函数,新增节表和节操作;
    VOID NewSectionsInCodeSec();  //这个调用函数用到下面的3个函数
    //ReadPEFile CopyFileBufferToNewImageBuffer MemeryTOFile
    
    //调用函数,扩大最后一个节
    VOID ExtendLastSectionsInCodeSec(); //这个调用函数用到下面的4个函数
    //ReadPEFile FileBufferToModifyImageBuffer CopyImageBufferToNewImageBuffer MemeryTOFile
    
    //调用函数,合并节
    VOID ModifySectionsOneInCodeSec(); //这个调用函数用到下面的4个函数
    //ReadPEFile CopyFileBufferToImageBuffer FileBufferToModifyOneImageBuffer MemeryTOFile
    
    //调用函数,Rva和Foa之间的相互转换;
    VOID RvaAndFoaConversion(); //这个调用函数用到下面的3个函数
    //ReadPEFile RvaToFileOffset FoaToImageOffset
    
    #endif // !defined(AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_)

    main函数入口代码

    // allpelx.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "gbpeall.h"
    
    int main(int argc, char* argv[])
    {
        //Fun();
        //AddCodeInCodeSec();
        //NewSectionsInCodeSec();
        //ExtendLastSectionsInCodeSec();
        //ModifySectionsOneInCodeSec();
        RvaAndFoaConversion();
        printf("Hello World! Cntf
    ");
        system("pause");
        return 0;
    }

    执行结果

    迷茫的人生,需要不断努力,才能看清远方模糊的志向!
  • 相关阅读:
    Mybatis 原始dao CRUD方法
    JQuery的焦点事件focus() 与按键事件keydown() 及js判断当前页面是否为顶级页面 子页面刷新将顶级页面刷新 window.top.location
    使用actionerror做失败登录验证
    Java项目中的下载 与 上传
    shiro框架 4种授权方式 说明
    javascript 中数组的创建 添加 与将数组转换成字符串 页面三种提交请求的方式
    序列化表单为json对象,datagrid带额外参提交一次查询 后台用Spring data JPA 实现带条件的分页查询 多表关联查询
    Spring data JPA 理解(默认查询 自定义查询 分页查询)及no session 三种处理方法
    orcal 数据库 maven架构 ssh框架 的全注解环境模版 maven中央仓库批量删除lastupdated文件后依然是lastupdated解决方法 mirror aliyun中央仓库
    EasyUI加zTree使用解析 easyui修改操作的表单回显方法 验证框提交表单前验证 datagrid的load方法
  • 原文地址:https://www.cnblogs.com/autopwn/p/15292809.html
Copyright © 2020-2023  润新知