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

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

  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("打开文件失败!\r\n");
 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("内存分配失败!\r\n");
 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("读取数据失败!\r\n");
 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("缓冲区指针无效\r\n");
127         return 0;
128     }
129 
130     //判断是否为MZ标志
131 
132     if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE --> MZ
133     {
134         printf("不是一个有效的MZ标志\r\n");
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标志\r\n");
143         return 0;
144     }
145 
146 //*********************申请开辟内存空间*****************************************************************
147 
148     sizeOfFile = fileSize+0x1000;
149     pTempNewImageBuffer = malloc(sizeOfFile);
150 
151     //判断内存空间开辟是否成功
152     if (!pTempNewImageBuffer)
153     {
154         printf("pTempNewImageBuffer开辟内存空间失败\r\n");
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文件头不剩余空间不够\r\n");
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 \r\n",pPEHeder->NumberOfSections);
218     *pNumberOfSection = pPEHeder->NumberOfSections + 1;
219     printf("*pNumberOfSection:%#X \r\n",pPEHeder->NumberOfSections);
220     
221     //修改PE可选头里面SizeOfImage信息
222     printf("*pSizeOfImage:%#X \r\n",pOptionHeader->SizeOfImage);
223     *pSizeOfImage = pOptionHeader->SizeOfImage + 0x1000;
224     printf("*pSizeOfImage:%#X \r\n",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 \r\n",pLastSectionHeader);    
242     printf("add_size: %#X \r\n",add_size);
243     printf("numberOfSection: %#X \r\n",pPEHeder->NumberOfSections);
244     printf("pLastSectionHeader->Misc.VirtualSize: %#X \r\n",pLastSectionHeader->Misc.VirtualSize);
245     printf("pLastSectionHeader->SizeOfRawData: %#X \r\n",pLastSectionHeader->SizeOfRawData);
246     printf("add_size: %#X \r\n",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("文件-->缓冲区失败\r\n");
14         return ;
15     }
16     printf("fileSize - Final: %#X \r\n",size1);
17     
18     //FileBuffer-->NewImageBuffer
19     size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&pNewImageBuffer);
20     if (size2 == 0 || !pFileBuffer)
21     {
22         printf("FileBuffer-->NewImageBuffer失败\r\n");
23         free(pFileBuffer);
24         return ;
25     }
26     printf("sizeOfFile - Final: %#X \r\n",size2);
27     //NewImageBuffer-->文件
28     isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out);
29     if (isOK)
30     {
31         printf("新增节表和节存盘成功\r\n");
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\r\n");
    return 0;
}

执行结果:

 

查看效果:

 

 

本次操作未添加ShellCode测试;

 

posted @ 2021-09-13 17:13  皇帽讲绿帽带法技巧  阅读(395)  评论(0编辑  收藏  举报