• 滴水逆向-新增一个节(编写代码)


    下面是综合性相关代码中,关于新增一个节的代码

      1 DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer)
      2 {
      3     //下面有个IN和OUT,大致意思就是参数的类型传入进来之后不进行宏扩展;
      4     //啥也不干,即使理解成干,也是扩展成空白,这个是C++语法中允许的;
      5     //LPSTR  ---->  typedef CHAR *LPSTR, *PSTR; 意思就是char* 指针;在WINNT.H头文件里面
      6     FILE* pFile = NULL;
      7     //定义一个FILE结构体指针,在标准的Stdio.h文件头里面
      8     //可参考:https://blog.csdn.net/qq_15821725/article/details/78929344
      9     DWORD fileSize = 0;
     10     // typedef unsigned long       DWORD;  DWORD是无符号4个字节的整型
     11     LPVOID pTempFileBuffer = NULL;
     12     //LPVOID ---->  typedef void far *LPVOID;在WINDEF.H头文件里面;别名的void指针类型
     13 
     14     //打开文件
     15     pFile = fopen(lpszFile,"rb"); //lpszFile是当作参数传递进来
     16     if (!pFile)
     17     {
     18         printf("打开文件失败!
    ");
     19         return 0;
     20     }
     21     /*
     22     关于在指针类型中进行判断的操作,下面代码出现的情况和此一样,这里解释下:
     23     1.因为指针判断都要跟NULL比较,相当于0,假值,其余都是真值
     24     2.if(!pFile)和if(pFile == NULL), ----> 为空,就执行语句;这里是两个等于号不是一个等于号
     25     3.if(pFile)就是if(pFile != NULL), 不为空,就执行语句;
     26     */
     27 
     28     //读取文件内容后,获取文件的大小
     29     fseek(pFile,0,SEEK_END);
     30     fileSize = ftell(pFile);
     31     fseek(pFile,0,SEEK_SET);
     32 
     33     /*
     34     fseek 通过使用二进制的方式打开文件,移动文件读写指针的位置,在stdio.h头文件里
     35 
     36     int fseek(FILE * stream, long offset, int fromwhere);
     37 
     38     上面是fseek的函数原型
     39     第一个参数stream 为文件指针
     40     第二个参数offset 为偏移量,整数表示正向偏移,负数表示负向偏移
     41     第三个参数fromwhere 为指针的起始位置,设定从文件的哪里开始偏移,可能取值为:SEEK_CUR,SEEK_END,SEEK_SET
     42     SEEK_SET 0 文件开头
     43     SEEK_CUR 1 当前读写的位置
     44     SEEK_END 2 文件尾部
     45 
     46     下面是相关用法和例子:
     47   fseek(fp,100L,0);把fp指针移动到离文件开头100字节处;
     48   fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处;
     49     fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。
     50     fseek(fp,0,SEEK_SET);将读写位置移动到文件开头;
     51     fseek(fp,0,SEEK_END);将读写位置移动到文件尾时;
     52     fseek(fp,100L,SEEK_SET);将读写位置移动到离文件开头100字节处;
     53     fseek(fp,100L,SEEK_CUR);将读写位置移动到离文件当前位置100字节处;
     54     fseek(fp,-100L,SEEK_END);将读写指针退回到离文件结尾100字节处;
     55     fseek(fp,1234L,SEEK_CUR);把读写位置从当前位置向后移动1234字节;
     56     fseek(fp,0L,2);把读写位置移动到文件尾;
     57     其中 --->  L后缀表示长整数
     58 
     59     ftell()用于返回文件当前指针指向的位置,与fseek配合可以算出文件元素数据总数。
     60     参考:http://c.biancheng.net/cpp/html/2519.html
     61 
     62     ftell()函数用来获取文件读写指针的当前位置,其原型为:long ftell(FILE * stream); 同样在stdio.h头文件里
     63     参数:stream 为已打开的文件指针。
     64     */
     65 
     66     //动态申请内存空间
     67     pTempFileBuffer = malloc(fileSize);
     68 
     69     /*
     70     参考:http://c.biancheng.net/cpp/html/137.html
     71     原型:void* malloc (size_t size);
     72     size_t ---> typedef unsigned int size_t; 无符号整型别名是size_t
     73     void*  ---> 函数的返回值类型是 void* ;void并不是说没有返回值或者返回空指针,而是返回的指针类型未知;
     74     所以在使用 malloc() 时通常需要进行强制类型转换,将 void 指针转换成我们希望的类型;
     75     例如:char *ptr = (char *)malloc(10);  //分配10个字节的内存空间,用来存放字符
     76     参数说明 ---> size 为需要分配的内存空间的大小,以字节(Byte)计。
     77     函数说明 ---> malloc()在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化;
     78     它们的值是未知的,所以分配完成内存之后需要初始化;
     79     返回值:分配成功返回指向该内存的地址,失败则返回 NULL。
     80     */
     81 
     82     if (!pTempFileBuffer)
     83     {
     84         printf("内存分配失败!
    ");
     85         fclose(pFile);
     86         return 0;
     87     }
     88 
     89     //根据申请到的内存空间,读取数据
     90 
     91     size_t n = fread(pTempFileBuffer,fileSize,1,pFile);
     92     if (!n)
     93     {
     94         printf("读取数据失败!
    ");
     95         free(pTempFileBuffer);   // 释放内存空间
     96         fclose(pFile);           // 关闭文件流
     97         return 0;
     98     }
     99 
    100     //数据读取成功,关闭文件
    101     *pFileBuffer = pTempFileBuffer;  // 将读取成功的数据所在的内存空间的首地址放入指针类型pFileBuffer
    102     pTempFileBuffer = NULL;  // 初始化清空临时申请的内存空间
    103     fclose(pFile);           // 关闭文件
    104     return fileSize;         // 返回获取文件的大小
    105 }
    106 
    107 
    108 //通过复制FileBuffer并增加1000H到新的ImageBuffer里面
    109 DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer)
    110 {
    111     PIMAGE_DOS_HEADER pDosHeader = NULL;
    112     PIMAGE_NT_HEADERS pNTHeader = NULL;
    113     PIMAGE_FILE_HEADER pPEHeder = NULL;
    114     PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    115     PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    116     PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
    117     LPVOID pTempNewImageBuffer = 0;
    118     DWORD sizeOfFile = 0;
    119     DWORD numberOfSection = 0;
    120     DWORD okAddSections = 0;
    121     
    122 
    123     //判断读取pFileBuffer读取是否成功
    124     if (!pFileBuffer)
    125     {
    126         printf("缓冲区指针无效
    ");
    127         return 0;
    128     }
    129 
    130     //判断是否为MZ标志
    131 
    132     if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE --> MZ
    133     {
    134         printf("不是一个有效的MZ标志
    ");
    135         return 0;
    136     }
    137 
    138     //判断是否为PE标志
    139     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    140     if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // IMAGE_NT_SIGNATURE --> PE
    141     {
    142         printf("不是有效的PE标志
    ");
    143         return 0;
    144     }
    145 
    146 //*********************申请开辟内存空间*****************************************************************
    147 
    148     sizeOfFile = fileSize+0x1000;
    149     pTempNewImageBuffer = malloc(sizeOfFile);
    150 
    151     //判断内存空间开辟是否成功
    152     if (!pTempNewImageBuffer)
    153     {
    154         printf("pTempNewImageBuffer开辟内存空间失败
    ");
    155         return 0;
    156     }
    157 
    158     //初始化内存内容
    159     memset(pTempNewImageBuffer,0,sizeOfFile);
    160 
    161     //初始化完成之后,先把为修改的内存空间全部拷贝到新的内存空间
    162     memcpy(pTempNewImageBuffer,pFileBuffer,fileSize);
    163 
    164     //定位Dos头地址
    165     pDosHeader = (PIMAGE_DOS_HEADER)(pTempNewImageBuffer);
    166 
    167     //定位NT头的地址
    168     pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pTempNewImageBuffer+pDosHeader->e_lfanew);
    169 
    170     //定位标志PE头地址
    171     pPEHeder = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+0x04);//PE SIGNATURE 站4个字节
    172 
    173     //定位可选PE头地址
    174     pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeder)+IMAGE_SIZEOF_FILE_HEADER);//IMAGE_SIZEOF_FILE_HEADER -> 20个字节
    175 
    176     //定位第一个节表地址
    177     pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeder->SizeOfOptionalHeader);
    178 
    179     //定位最后一个节表的地址
    180     pLastSectionHeader = &pSectionHeader[pPEHeder->NumberOfSections-1];
    181 
    182     //判断是否有足够的空间添加一个节表
    183     //判断条件:
    184     /*
    185         SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小
    186         SizeOfHeader在可选PE头里面
    187     */
    188 
    189     okAddSections = (DWORD)(pOptionHeader->SizeOfHeaders - (pDosHeader->e_lfanew + 0x04 + 
    190         sizeof(PIMAGE_FILE_HEADER) + pPEHeder->SizeOfOptionalHeader + sizeof(PIMAGE_SECTION_HEADER) 
    191         * pPEHeder->NumberOfSections));
    192 
    193     if (okAddSections < 2*sizeof(PIMAGE_SECTION_HEADER))
    194     {
    195         printf("这个exe文件头不剩余空间不够
    ");
    196         free(pTempNewImageBuffer);
    197         return 0;
    198     }
    199 
    200     //上面没问题,就开始修改内容了
    201 //*************************修改内容*******************************************************************
    202 
    203     //初始化新节表信息
    204     PWORD pNumberOfSection = &pPEHeder->NumberOfSections;
    205     PDWORD pSizeOfImage = &pOptionHeader->SizeOfImage;
    206 
    207     numberOfSection = pPEHeder->NumberOfSections;
    208     PVOID pSecName = &pSectionHeader[numberOfSection].Name;
    209     PDWORD pSecMisc = &pSectionHeader[numberOfSection].Misc.VirtualSize;
    210     PDWORD pSecVirtualAddress = &pSectionHeader[numberOfSection].VirtualAddress;
    211     PDWORD pSecSizeOfRawData = &pSectionHeader[numberOfSection].SizeOfRawData;
    212     PDWORD pSecPointToRawData = &pSectionHeader[numberOfSection].PointerToRawData;
    213     PDWORD pSecCharacteristics = &pSectionHeader[numberOfSection].Characteristics;
    214    
    215     //修改PE文件头里面的节数量信息
    216 
    217     printf("*pNumberOfSection:%#X 
    ",pPEHeder->NumberOfSections);
    218     *pNumberOfSection = pPEHeder->NumberOfSections + 1;
    219     printf("*pNumberOfSection:%#X 
    ",pPEHeder->NumberOfSections);
    220     
    221     //修改PE可选头里面SizeOfImage信息
    222     printf("*pSizeOfImage:%#X 
    ",pOptionHeader->SizeOfImage);
    223     *pSizeOfImage = pOptionHeader->SizeOfImage + 0x1000;
    224     printf("*pSizeOfImage:%#X 
    ",pOptionHeader->SizeOfImage);
    225 
    226     //向节表中添加数据
    227 
    228     memcpy(pSecName,".newSec",8);
    229     *pSecMisc = 0x1000;
    230     //这里VirtualAddress的地址需要根据最后一个节表中对齐前内存中的实际大小?
    231     //和文件中对齐后的大小,分别使用VirtualAddress加上她们的值,哪个大,就是
    232     //哪个;
    233     //VirtualAddress+max(VirtualSize,SizeOfRawData)
    234     //就是上面的公式
    235 
    236     //判断出要添加的值
    237     DWORD add_size = pLastSectionHeader->Misc.VirtualSize > pLastSectionHeader->SizeOfRawData?
    238         pLastSectionHeader->Misc.VirtualSize:pLastSectionHeader->SizeOfRawData;
    239     //上面是个三目运算符
    240 
    241     printf("pLastSectionHeader: %#X 
    ",pLastSectionHeader);    
    242     printf("add_size: %#X 
    ",add_size);
    243     printf("numberOfSection: %#X 
    ",pPEHeder->NumberOfSections);
    244     printf("pLastSectionHeader->Misc.VirtualSize: %#X 
    ",pLastSectionHeader->Misc.VirtualSize);
    245     printf("pLastSectionHeader->SizeOfRawData: %#X 
    ",pLastSectionHeader->SizeOfRawData);
    246     printf("add_size: %#X 
    ",add_size);
    247 
    248     *pSecVirtualAddress = pLastSectionHeader->VirtualAddress + add_size;
    249 
    250     //SectionAlignment对齐
    251 
    252     if (*pSecVirtualAddress % pOptionHeader->SectionAlignment)
    253     {
    254         *pSecVirtualAddress = *pSecVirtualAddress / pOptionHeader->SectionAlignment * 
    255             pOptionHeader->SectionAlignment + pOptionHeader->SectionAlignment;
    256     }
    257 
    258     *pSecSizeOfRawData = 0x1000;
    259     *pSecPointToRawData = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
    260 
    261     //FileAlignment对齐
    262 
    263     if (*pSecPointToRawData % pOptionHeader->FileAlignment)
    264     {
    265         *pSecPointToRawData = *pSecPointToRawData / pOptionHeader->FileAlignment * 
    266             pOptionHeader->FileAlignment + pOptionHeader->FileAlignment;
    267     }
    268 
    269     *pSecCharacteristics = 0xFFFFFFFF;
    270 
    271     *pNewImageBuffer = pTempNewImageBuffer;
    272     pTempNewImageBuffer = NULL;
    273     
    274     return sizeOfFile;
    275 }
    276 
    277 BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile)
    278 {
    279     FILE* fp = NULL;
    280     fp = fopen(lpszFile, "wb+");
    281     if (!fp)  //  这里我刚开始写漏了一个等于号,变成复制NULL了,导致错误
    282 //  if(fp == NULL)  可以这么写,没问题
    283     {
    284         fclose(fp);
    285         return FALSE;
    286     }
    287     fwrite(pMemBuffer,size,1,fp);
    288     fclose(fp);
    289     fp = NULL;
    290     return TRUE;
    291 }

    调用上面代码的函数部分代码

     1 VOID NewSectionsInCodeSec()
     2 {
     3     LPVOID pFileBuffer = NULL;
     4     LPVOID pNewImageBuffer = NULL;
     5     BOOL isOK = FALSE;
     6     DWORD size1 = 0;
     7     DWORD size2 = 0;
     8     
     9     //File-->FileBuffer
    10     size1 = ReadPEFile(FilePath_In,&pFileBuffer);
    11     if (size1 == 0 || !pFileBuffer)
    12     {
    13         printf("文件-->缓冲区失败
    ");
    14         return ;
    15     }
    16     printf("fileSize - Final: %#X 
    ",size1);
    17     
    18     //FileBuffer-->NewImageBuffer
    19     size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&pNewImageBuffer);
    20     if (size2 == 0 || !pFileBuffer)
    21     {
    22         printf("FileBuffer-->NewImageBuffer失败
    ");
    23         free(pFileBuffer);
    24         return ;
    25     }
    26     printf("sizeOfFile - Final: %#X 
    ",size2);
    27     //NewImageBuffer-->文件
    28     isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out);
    29     if (isOK)
    30     {
    31         printf("新增节表和节存盘成功
    ");
    32        return ;
    33     }
    34     
    35     //释放内存
    36     free(pFileBuffer);
    37     free(pNewImageBuffer);
    38 }

    用户程序入口main执行代码部分

    #include "stdafx.h"
    #include "gbpeall.h"
    
    int main(int argc, char* argv[])
    {
        NewSectionsInCodeSec();
        printf("Hello World! Cntf
    ");
        return 0;
    }

    执行结果:

    查看效果:

    本次操作未添加ShellCode测试;

    迷茫的人生,需要不断努力,才能看清远方模糊的志向!
  • 相关阅读:
    【Others】2048逻辑整理
    【MySQL】MySQL学习笔记(一)
    【PHP】对TP中session的理解
    【Python基础】python 作用域
    【phantomJs + selenium】动态cookie,数据采集记录
    [ZJOI2015][LOJ2137]诸神眷顾的幻想乡(广义SAM)
    [CF235C]Cyclical Quest(SAM)
    [BZOJ1426]收集邮票(概率期望dp)
    [HDU5421]Victor and String(PAM)
    [CF932G]Palindrome Partition(PAM回文划分dp)
  • 原文地址:https://www.cnblogs.com/autopwn/p/15263287.html
Copyright © 2020-2023  润新知