逆向笔记——在PE任意一个节中添加代码

备注:添加代码这个原理与加壳、恶意代码的原理类似

基本步骤

1、NoOfSection 数量不要超过 节数量
2、相应节的文件对齐空间要足够代码Code存放
3、找到程序的OEP
3、计算IMAGEBUFF和FILEBUFF之间节的位置转化关系
4、算出JMP <原OEP> CALL〈MessageBoxW〉把位置填入Code中
5、找到节的空白起始区域,存放Code
6、将OEP的值改成Code的RV

手工

1、用PETool查看一下文件信息
用PETool查看一下文件信息

2、定位第一个节的插入位置:VirtualSize+VirtualAddress = 00019722 + 1000 = 1A722
可以插在1A722 后的任意空白区域

3、计算 CALL JMP指令后面的4位机器码
X = 真实要跳的地址 - 下一条指令地址
CALL 要跳转到MessageBoxA的地址
MessageBoxA的地址

JMP 要跳转到 OEP的地址

最后要填进去的代码: 6A 00 6A 00 6A 00 6A 00 E8 AD 60 93 77 E9 95 DC FF FF

改一下OEP为填进去的代码的首地址,0001a730

改完之后运行一下

再用PETool看一下入口点

写代码

工作区的文件结构

Function.h


#include <stdio.h>
#include <windows.h>

#define FUN_AD 0x77D507EA  //不同的机器不一样
#define CALL_X 9         //DEMOCODE中E8的地址
#define JMP_Y  14        //DEMOCODE中E9的地址
#define NEXT_X 13        //DEMOCODE中X的下一条指令的地址
#define NEXT_Y 18        //DEMOCODE中Y的下一条指令的地址

/*
unsigned char DEMOCODE[] = {
	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,unsigned int CodeSize);
unsigned char* FileBuffer(const char* FileName);
int SaveFile(unsigned char* FileBuffer,const char* FileName);

Add.cpp



#include "Function.h"
/*********************************************
在任意节添加代码                           
输入: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
**************************************************/

int AddCodeAtSection(unsigned char* FileBuffer,int NoOfSection,unsigned char* Code,unsigned 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存放   
     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〈MessageBoxA〉把位置填入Code中 X = 真实要跳的地址 - 下一条指令地址    
     int* JMP = (int*)(Code+JMP_Y);
     int* CALL = (int*)(Code+CALL_X);
     *JMP = (ImageBase+OEP)-(ImageBase+InsImageRV+NEXT_Y);
     *CALL = FUN_AD - (ImageBase+InsImageRV+NEXT_X);

//5、找到节的空白起始区域,存放Code
     unsigned char* InsCode = FileBuffer+InsPostionRV;  //在文件buffer中的插入地址
     unsigned int i  = 0;
     for (i=0;i<CodeSize;i++)
     {
         InsCode[i] = Code[i];   
     }

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

     return 0;
}

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

//将PE文件读到FileBuffer

unsigned char* FileBuffer(const char* FileName)
{
     unsigned char* Heap = NULL;
     FILE* Stream;

     //打开文件
     Stream = fopen(FileName,"rb");
     //计算文件大小
     fseek(Stream,0,SEEK_END);
     long FileSize = ftell(Stream);
     fseek(Stream,0,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 char* FileName)
{
     FILE* Stream;

     //打开文件
     Stream = fopen(FileName,"wb");

    //计算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;
}

main.cpp


/************************************************
*程序说明:在32位PE文件中的任意一个节中添加代码
*          第一个参数为PE文件 第二个参数为第N个节
*
* 时间: 2020 3.29
* Winxp VC++6.0 
**************************************************/

#include "Function.h"

unsigned char DEMOCODE[] = {0X6A,0X00,0X6A,0X00,0X6A,0X00,0X6A,0X00,0XE8,0X00,0X00,0X00,0X00,0XE9,0X00,0X00,0X00,0X00};

int main()
{
	// PE文件   N个节
	unsigned char* FileBuff;
	FileBuff = FileBuffer("NOTEPAD.EXE");
	int NumOfSection = 1;

    if(AddCodeAtSection(FileBuff,NumOfSection,DEMOCODE,sizeof(DEMOCODE)) != 0)
    {
        free(FileBuff);
        return -1;
    }
    SaveFile(FileBuff,"CopyNOTEPAD.EXE");
    free(FileBuff);
    return 0;
	
}
posted @ 2020-03-29 18:24  程序媛墨禾  阅读(438)  评论(0编辑  收藏  举报