在32位PE文件中的任意一个节中添加代码

时间:2021-07-22 03:32:31


// SectionOp.cpp : 定义控制台应用程序的入口点。
//

/************************************************
*程序说明:在32位PE文件中的任意一个节中添加代码
*          第一个参数为PE文件 第二个参数为第N个节
*
* 时间: 20170718
* Win10 VS2010 测试通过  ver 0.01
**************************************************/

#include "stdafx.h"
unsigned char DEMOCODE[] = {0X6A,0X00,0X6A,0X00,0X6A,0X00,0X6A,0X00,0XE8,0X00,0X00,0X00,0X00,0XE9,0X00,0X00,0X00,0X00};

int _tmain(int argc, _TCHAR* argv[])
{
     unsigned char* FileBuff;
     errno_t err;
     _TCHAR NewFile[1024] = L"New_";

    if(argc >1)
     {
         FileBuff = FileBuffer(argv[1]);
     }
     else
     {
         printf("No PE File\n");
         return 1;
     }
     int NumOfSection = 1;
     if (argc >2 )
     {
         size_t i;
         size_t num = wcslen(argv[2]);
         char* pMBBuffer = (char*)malloc(num*2);
         wcstombs_s(&i,pMBBuffer,num*2,argv[2],num);
         NumOfSection = atoi(pMBBuffer);

        if(NumOfSection < 1)
             NumOfSection = 1;
     }
    
     if(AddCodeAtSection(FileBuff,NumOfSection,DEMOCODE,sizeof(DEMOCODE)) != 0)
     {
         free(FileBuff);
         return -1;
     }
    
     err = wcscat_s(NewFile,argv[1]);
     if(err != 0)
     {
         return -1;
     }

    SaveFile(FileBuff,NewFile);
     free(FileBuff);
     return 0;
}


==================================================================

////功能文件

#include "stdafx.h"

#define FUN_AD 0x7497D330 //修改成本机的MessageBoxW的地址

/*********************************************
在任意节添加代码                           
输入:FileBuffer NoOfSection  Code CodeSize                           
输出:添加了Code的FileBuffer,运行程序时,先运行Code再转到原来的程序入口                           
实现步聚:    (假定FileBuffer 为Pe格式)                       
1、NoOfSection 数量不要超过 节数量                            
2、相应节的文件对齐空间要足够代码Code存放                           
3、找到程序的OEP                           
3、计算IMAGEBUFF和FILEBUFF之间节的位置转化关系                           
4、算出JMP <原OEP> CALL〈MessageBoxW〉把位置填入Code中                            
5、找到节的空白起始区域,存放Code   
6、将OEP的值改成Code的RV
**************************************************/
//unsigned char CODE[] = {0X6A,0X00,0X6A,0X00,0X6A,0X00,0X6A,0X00,0XE8,0X00,0X00,0X00,0X00,0XE9,0X00,0X00,0X00,0X00};
int AddCodeAtSection(unsigned char* FileBuffer,int NoOfSection,unsigned char* Code,int CodeSize)
{
     PIMAGE_DOS_HEADER pDosHeader;
     PIMAGE_NT_HEADERS32 pNt32Header;
     PIMAGE_SECTION_HEADER pSectionHeader;

//1、NoOfSection 数量不要超过 节数量    
     pDosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
     pNt32Header = (PIMAGE_NT_HEADERS32)(FileBuffer+pDosHeader->e_lfanew);
     if(int(pNt32Header->FileHeader.NumberOfSections) < NoOfSection)
     {
         printf("NoOfSection Bigger NumberOfSections\n");
         return -1;
     }

//2、相应节的文件对齐空间要足够代码Code存放   
     //unsigned int CodeSize = sizeof(Code);
     //printf("CodeSize %d\n",CodeSize);
     pSectionHeader =(PIMAGE_SECTION_HEADER)(pNt32Header+1);
     pSectionHeader = pSectionHeader +(NoOfSection-1);
     if(CodeSize > int(pSectionHeader->SizeOfRawData-pSectionHeader->Misc.VirtualSize))
     {
         printf("No space to write Code\n");
         return -2;
     }

//3、找到程序的OEP           
     int OEP = pNt32Header->OptionalHeader.AddressOfEntryPoint;

//3、计算IMAGEBUFF和FILEBUFF之间节的位置转化关系       
    
     long InsImageRV = pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize;
     long InsPostionRV = pSectionHeader->PointerToRawData + pSectionHeader->Misc.VirtualSize;
     long ImageBase = pNt32Header->OptionalHeader.ImageBase;

//4、算出JMP <原OEP> CALL〈MessageBoxW〉把位置填入Code中 X = 真实要跳的地址-下一条指令地址    
// YY = ImageBase+OEP - Imagebase+NEXT_Y
// XX = MessageBoxW@AD - ImageBase+NEXT_X
     int* YY = (int*)(Code+JMP_Y);
     int* XX = (int*)(Code+CALL_X);
     *YY = (ImageBase+OEP)-(ImageBase+InsImageRV+NEXT_Y);
     *XX = FUN_AD - (ImageBase+InsImageRV+NEXT_X);

//5、找到节的空白起始区域,存放Code
     unsigned char* InsCode = FileBuffer+InsPostionRV;
     unsigned int x  = 0;
     for (;x<CodeSize;x++)
     {
         InsCode[x] = Code[x];   
     }

//6、将OEP的值改成Code的RV
     pNt32Header->OptionalHeader.AddressOfEntryPoint = pSectionHeader->Misc.VirtualSize + pSectionHeader->VirtualAddress;

    return 0;
}

///////////////////////////////////////////////////////////

//将PE文件读到FileBuffer

unsigned char* FileBuffer(const _TCHAR* FileName)
{
     unsigned char* Heap = NULL;
     FILE* Stream;
     errno_t err;
     //打开文件
     err = _wfopen_s(&Stream,FileName,L"rb");
     if(err != 0)
     {
         perror("Open File Error:");
         return NULL;
     }
     //计算文件大小
     fseek(Stream,0L,SEEK_END);
     long FileSize = ftell(Stream);
     fseek(Stream,0L,SEEK_SET);
     //分配堆空间
     Heap = (unsigned char*)malloc(sizeof(char)*FileSize);
     //将文件拷到堆
     fread(Heap,sizeof(char),FileSize,Stream);
     fclose(Stream);

    return Heap;
}

//////////////////////////////////////////
//将FileBuffer 保存成文件
int SaveFile(unsigned char* FileBuffer,const _TCHAR* FileName)
{
     FILE* Stream;
     errno_t err;

    err = _wfopen_s(&Stream,FileName,L"wb");
     if(err != 0)
     {
         perror("File Create Error:");
         return -1;
     }

    //计算FileBuff大小
     PIMAGE_DOS_HEADER pDosHeader;
     PIMAGE_NT_HEADERS32 pNt32Header;
     PIMAGE_SECTION_HEADER pSecHeader;
     pDosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
     pNt32Header = (PIMAGE_NT_HEADERS32)(FileBuffer + pDosHeader->e_lfanew);
     pSecHeader = (PIMAGE_SECTION_HEADER)(pNt32Header+1);
    
     long FileSize = pNt32Header->OptionalHeader.SizeOfHeaders;
     int NumOfSec = pNt32Header->FileHeader.NumberOfSections;
     int x;
     for(x=0;x<NumOfSec;x++)
     {
         FileSize += pSecHeader->SizeOfRawData;
         pSecHeader++;
     }

    // 写入文件
     fwrite(FileBuffer,sizeof(char),FileSize,Stream);
     fclose(Stream);
     return 0;
}



========================================================

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>
#include <Windows.h>
#include <WinNT.h>
#include <assert.h>



// TODO: 在此处引用程序需要的其他头文件


int AddCodeAtSection(unsigned char* FileBuffer,int NoOfSection,unsigned char* Code,int CodeSize);
unsigned char* FileBuffer(const _TCHAR* FileName);
int SaveFile(unsigned char* FileBuffer,const _TCHAR* FileName);


#ifndef _DEMO_CODE
#define _DEMO_CODE


#define CALL_X 9         //填写X的超始地址
#define JMP_Y  14        //填写Y的超始地址
#define NEXT_X 13        //X的下一条指令的地址
#define NEXT_Y 18        //Y的下一条指令的地址

#endif