zoukankan      html  css  js  c++  java
  • 逆向笔记——在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
    ");
             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
    ");
             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;
    	
    }
    
  • 相关阅读:
    HDU 4757 Tree 可持久化字典树 trie
    BZOJ 4198: [Noi2015]荷马史诗 哈夫曼树 k叉哈夫曼树
    BZOJ 3253 Fence Repair 哈夫曼树 水题
    BZOJ 3572: [Hnoi2014]世界树 虚树 树形dp
    2-SAT的一些题目
    二分图相关定理 最小点覆盖 最小路径覆盖 最大独立集 最小覆盖集
    POJ 1469 COURSES 二分图最大匹配 二分图
    快速排序
    排序算法:希尔排序
    霍夫曼编码实现
  • 原文地址:https://www.cnblogs.com/Erma/p/12593860.html
Copyright © 2011-2022 走看看