Huanghousec 发表于 2022-6-2 15:11

PE结构代码

2015年注册的吾爱,这8年一直在做渗透,因为特殊的工作性质,没有在吾爱发过技术贴,对论坛也没有什么贡献,感谢H大提供的平台,我在这里找到了很多技术资料。
感觉渗透做累了~没有一点提高这8年,最近打算转逆向,望各位师兄们能够多多指导我这个菜鸡

最近在打基础,学习了一段时间PE,在这里分享一下我的笔记:



PE结构图
```
1、DOS头(64byte)
WORD   e_magic; *          //5A4D   //重要,DOS头的开始MZ(MZ是一个人名,DOS的开发)
WORD   e_cblp;             //0090
WORD   e_cp;               //0003
WORD   e_crlc;             //0000
WORD   e_cparhdr;          //0004
WORD   e_minalloc;         //0000
WORD   e_maxalloc;         //FFFF
WORD   e_ss;               //0000
WORD   e_sp;               //00B8
WORD   e_csum;             //0000
WORD   e_ip;            //0000
WORD   e_cs;            //0000
WORD   e_lfarlc;          //0040
WORD   e_ovno;            //0000
WORD   e_res;         //00 00 00 00 00 00 00 00
WORD   e_oemid;         //0000
WORD   e_oeminfo;         //0000
WORD   e_res2;      //20 0
DWORD   e_lfanew;*       //00 00 00 D8    //重要,指向PE头开始的偏移位置

2、PE头->>(_IMAGE_FILE_HEADER FileHeader)(_IMAGE_OPTIONAL_HEADER OptionalHeader):
DWORD   Signature; //00 00 45 50


3、_IMAGE_FILE_HEADER FileHeader:   //共20个byte
WORD    Machine;               //014C            *      //程序运行的CPU型号,1、0x0能在任何处理器运行 2、0x14c 可以在386及后续处理器运行
WORD    NumberOfSections;      //0003            *      //文件中存在的节(除了PE头(可选头和标准头就是NT)以外的节)的总数,如果要新增一个节那么就需要修改这个值
DWORD   TimeDateStamp;          //6264 D913          *
DWORD   PointerToSymbolTable;   //0000 0000
DWORD   NumberOfSymbols;      //0000 0000
WORD    SizeOfOptionalHeader;    //00E0            *      //option_header pe头的大小,如果是32位的话默认是E0h,64位默认的是F0h,大小可以自定义
WORD    Characteristics;         //010F            *      //每个位有不同的含义,可执行文件值为10F,即0 1 2 3 8位置1

4、_IMAGE_OPTIONAL_HEADER OptionalHeader:
WORD    Magic;               //010B                *         //说明文件类型,如果是32位则是10B,如果是64位则是20B
BYTE    MajorLinkerVersion;   //06
BYTE    MinorLinkerVersion;   //00
DWORD   SizeOfCode;             //0000 4000                  //所有代码节的和,必须是FileAlignment的整数倍 编译器填的 没用(不影响PE文件运行)
DWORD   SizeOfInitializedData;   //0000 3000          *
DWORD   SizeOfUninitializedData;//0000 0000         *
DWORD   AddressOfEntryPoint;      //0000 1041       *       //重要,程序的入口点(OEP)   比如OD加载程序的时候,停的入口点即是Imagebase+AddressOfEntryPoint 的地址
DWORD   BaseOfCode;                //0000 1000         *          //代码段的基址,没有用
DWORD   BaseOfData;                //0000 0050         *      //数据开始的基址,没有用
DWORD   ImageBase;               //0040 0000          *      //重要,内存镜像地址
DWORD   SectionAlignment;          //0000 0010          *         //内存对齐
DWORD   FileAlignment;             //0000 0010          *         //文件对齐
WORD    MajorOperatingSystemVersion;       //0040
WORD    MinorOperatingSystemVersion;       //0000
WORD    MajorImageVersion;                  //0000
WORD    MinorImageVersion;                //0000
WORD    MajorSubsystemVersion;            //0004
WORD    MinorSubsystemVersion;            //0000
DWORD   Win32VersionValue;                //0000 0000
DWORD   SizeOfImage;                      //0001 A000       *      //内存中映像(拉伸后(peloader))的大小,可以比实际的值大,但必须是内存对齐的整数倍
DWORD   SizeOfHeaders;                     //0000 1000       *   //所有头+节表对齐后的大小,否则加载会出错
DWORD   CheckSum;                        //0000 0000       *      //效验和(把一个PE文件按照2个字节循环加,加完的值存到checksum里面),判断文件是否被修改
WORD    Subsystem;                        //0003
WORD    DllCharacteristics;                //0000
DWORD   SizeOfStackReserve;                  //0010 0000   *
DWORD   SizeOfStackCommit;                   //0010 0000   *
DWORD   SizeOfHeapReserve;                   //0010 0000   *
DWORD   SizeOfHeapCommit;                  //0010 0000   *
DWORD   LoaderFlags;                         //0000 0000
DWORD   NumberOfRvaAndSizes;                  //0000 0010   //目录项数据,编译器用的
```
2、节表
```
BYTE Name;      // 8个字节的节区名称
union {
DWORD PhysicalAddress;DWORD VirtualSize;}Misc; //节区真实共有多少个字节,VirtualSize 节真正长度即节结束的偏移
DWORD VirtualAddress;            // 从imagebase开始,离imagebase有多远。节的偏移地址,真实节地址为Imagebase+VirtualAddress
DWORD SizeOfRawData;            // 节在文件中对齐后的尺寸(当前节在文件中对齐的大小是132h,如果文件对齐是200,那么就是200h。如果是1000h,那么对齐后的尺寸就是1000h。1000的整数倍)
DWORD PointerToRawData;      // 在文件中的偏移量(在文件中的起始位置)
DWORD PointerToRelocations;   
DWORD PointerToLinenumbers;   
WORD NumberOfRelocations;   
WORD NumberOfLinenumbers;   
DWORD Characteristics;       // 节属性如可读,可写,可执行等
```

以上是PE结构参考,下面是用c实现的代码,按照海哥讲的基础分为几个功能模块:读取PE结构,在代码空白区添加节,导入表读取,filebuffer to imagebuffer以及imagebuffer to newbuffer(部分实现参考网上的师哥,其中导出表部分还未完善。64.h是封装的函数体部分。

```
#include"stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include"64.h"




//#define file_path "c:\\windows\\system32\\notepad.exe"


//open the file and get the files size

/*void Function()
{
      printf("Hello\n");
}
*/

int main()

{
//      LPVOID PFilebuffer = NULL;
//      LPVOID* ptr = &PFilebuffer;
      LPSTR PNewImagebuffer =NULL;
    char filepath[] = "c:\\dynamic.dll";
      char memoryfiletopath[] = "c:\\ipmsg_memory.exe";
      char Imagefiletopath[] = "c:\\ipmsg_Imagebuffer.exe";
      char opmode[] = "ab+";
      FILE* fp = openfile(filepath,opmode);
      int size = calcutesize(fp);
      char* file_address = allocate_buffer(size);
      char* buffer = filebuffer(file_address,size,fp);
      WriteMemorytoFile(memoryfiletopath,"wb+",buffer,size);
//      ReadPefileDos(buffer);    //reade pe
//ilebuffertoImagebuffer(buffer,PPImagebuffer);
//magebuffertoFilebuffer(PPImagebuffer,buffer);
//      ImagebuffertoNewbuffer(buffer,PNewImagebuffer);


      int SizeOfFileBuffer = size;
      LPSTR ImageBuffer = FileBuffertoImageBuffer(buffer);
      LPSTR PNewBuffer = ImageBuffertoNewBuffer(ImageBuffer,size);
      LPSTR PImageBuffer = ShellCode(SizeOfFileBuffer,ImageBuffer);
      writeMemorytoFile2(Imagefiletopath,PNewBuffer,size);
//      AddNewSection(buffer);
      GetFuncFileAddressOfDll(ImageBuffer);
//      GetFunctionAddrByName(ImageBuffer);
      //ReadPefileDos(buffer);
//      DWORD pRVA =NULL;
//      convertRVAtoFOA(pRVA,ImageBuffer);
//      Function();
//      MessageBox(0,"0",0,0);
    return 0;

}






//64.h

#define MESSAGEBOXADDR 0x77D507EA   //这个值需要将任一exe文件拖入OD打开,搜索 MessageBoxA 记录它的地址到这里(不同机子的地址不一样)

/*unsigned char ShellCodeData[] =
{
      0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,//这行是push 四个0 作为 MessageBox 的参数
      0xE8,0x00,0x00,0x00,0x00,
      0xE9,0x00,0x00,0x00,0x00
};
*/
unsigned char ShellCodeData[] =
{
      0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,//这行是push 四个0 作为 MessageBox 的参数
      0xE8,0x00,0x00,0x00,0x00,
      0xE9,0x00,0x00,0x00,0x00
};

FILE* openfile(char* file_path,char*opmode);
int calcutesize(FILE* fp);
char* allocate_buffer(int size_t);
char* filebuffer(char* ptr,int size,FILE* fp);
int WriteMemorytoFile(char* file_path,char*opmode,char* buffer,int size);
LPSTR FileBuffertoImageBuffer(LPSTR pfilebuffer);
LPSTR ImageBuffertoNewBuffer(LPSTR pfileBuffer,int NewBufferSize);
DWORD convertRVAtoFOA(PVOID pImageBuffer,DWORD pRVA);
DWORD GetFuncFileAddressOfDll(char* dllbuffer);

FILE* openfile(char* file_path,char*opmode)
{
//      char file_path[]="c:\\windows\\system32\\notepad.exe";
      
      FILE* fp=fopen(file_path,opmode);
      if(!fp)
      {
                printf("open file failed!\n");
                exit(1);
      }
      else
      {
                printf("open file OK!,start load files to memory...\n");
      }
      return fp;
}

int calcutesize(FILE* fp)
{
      fseek(fp,0,SEEK_END);
      int size = ftell(fp);
      printf("start calculate the file size is : %d\n",size);
      fseek(fp,0,SEEK_SET);
      return size;
}
      
char* allocate_buffer(int size_t)
{
//load files to memory,read memory address
      char* ptr=(char*)malloc(size_t);
      if(!ptr)
      {
                printf("malloc the memory failed!");
                exit(1);
      }
      else
      {
                printf("malloc the memory ok!\n");               
      }
return ptr;
}

char* filebuffer(char* ptr,int size,FILE* fp)
{
      if(!(fread(ptr,size,1,fp)))
      {
                printf("fread files to filebuffer failed!\n");
                exit(1);
      }
      else
      {
                printf("fread files to filebuffer ok!\n");
      }
printf("the filebuffer address is : %x\n",ptr);
      returnptr;
}

int WriteMemorytoFile(char* file_path,char*opmode,char* buffer,int size)
{
      FILE* fp = fopen(file_path, opmode);
      
      if (!(fwrite(buffer, 1, size, fp))) {
                printf("memory write to file failed!\n");
                return 0;
      }else
      {
                printf("write to file ok!\n");
      }
      return 1;

}

LPSTR FileBuffertoImageBuffer(LPSTR pfilebuffer)
{
//      char* ImageBuffer = pfilebuffer;
//      LPSTR imagebuffer = NULL;
      PIMAGE_DOS_HEADER pdos= NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER PPeHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 POptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      pdos = (PIMAGE_DOS_HEADER)pfilebuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pdos+pdos->e_lfanew);
      PPeHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      POptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)PPeHeader+IMAGE_SIZEOF_FILE_HEADER);//nt IS 20 BYTE
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)POptionHeader+PPeHeader->SizeOfOptionalHeader);
      DWORD numbofsections = PPeHeader->NumberOfSections;      
      DWORD headerSize = POptionHeader->SizeOfHeaders;      
//      memcpy(PNewImagebuffer, pfileBuffer, headerSize);
      DWORD ImageSize = POptionHeader->SizeOfImage;
//      DWORD headerSize = POptionHeader->SizeOfHeaders;
      char* ImageBuffer = pfilebuffer;
//      memcpy(ImageBuffer,pfileBuffer,ImageSize);
      ImageBuffer = (char*)malloc(POptionHeader->SizeOfImage);
      memset(ImageBuffer,0,POptionHeader->SizeOfImage);
      memcpy(ImageBuffer,pdos,POptionHeader->SizeOfHeaders);
      for(DWORD i=0;i<numbofsections;i++,pSectionHeader++)
      {      
      memcpy(LPVOID((DWORD)ImageBuffer+pSectionHeader->VirtualAddress),LPVOID((DWORD)pdos+pSectionHeader->PointerToRawData),pSectionHeader->SizeOfRawData);
      }
      printf("ImageBuffer address is : %x\n",ImageBuffer);
//      return (LPSTR)POptionHeader->SizeOfImage;
      return ImageBuffer;
}


LPSTR ImageBuffertoNewBuffer(LPSTR pfileBuffer,int NewBufferSize)
{
      LPSTR pNewBuffer = NULL;
      PIMAGE_DOS_HEADER pdos= NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER PPeHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 POptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      pdos = (PIMAGE_DOS_HEADER)pfileBuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pdos+pdos->e_lfanew);
      PPeHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      POptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)PPeHeader+IMAGE_SIZEOF_FILE_HEADER);//nt IS 20 BYTE
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)POptionHeader+PPeHeader->SizeOfOptionalHeader);
      DWORD numbofsections = PPeHeader->NumberOfSections;               
//      pNewBuffer= (char*)malloc(NewBufferSize);
      pNewBuffer= pfileBuffer;
//      DWORD headerSize = POptionHeader->SizeOfHeaders;
      //**********************************************************
      //void *memcpy(void *str1, const void *str2, size_t n)
      //str1 -- 目标数组
    //str2 -- 要复制的数据源
    //n -- 要被复制的字节数
      //**********************************************************
//      memcpy(pNewBuffer, pdos, headerSize);
      memcpy(pNewBuffer,pdos,POptionHeader->SizeOfHeaders);
      for(DWORD i=0;i<numbofsections;i++,pSectionHeader++)
      {      
//                printf(".......the %d Sections Name.........\n",i+1);
                memcpy((pNewBuffer + (DWORD)(pSectionHeader->PointerToRawData)), (pNewBuffer + (DWORD)(pSectionHeader->VirtualAddress)),pSectionHeader->SizeOfRawData);
//                pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader + sizeof(_IMAGE_SECTION_HEADER));
      }
      printf("pNewBuffer address is : %x\n",pNewBuffer);
      return pNewBuffer;
}
DWORD convertRVAtoFOA(PVOID pImageBuffer,DWORD pRVA)
{
      PIMAGE_DOS_HEADER pdos= NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER PPeHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 POptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      pdos = (PIMAGE_DOS_HEADER)pImageBuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pdos+pdos->e_lfanew);
      PPeHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      POptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)PPeHeader+IMAGE_SIZEOF_FILE_HEADER);//nt IS 20 BYTE
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)POptionHeader+PPeHeader->SizeOfOptionalHeader);
      DWORD numbofsections = PPeHeader->NumberOfSections;               
      


      int image_panyi = pRVA;// pRVA是在内存中的偏移偏移
//      printf("VirtulAddress : %x\n",(DWORD)pSectionHeader->VirtualAddress);
//      printf("image_panyi:%#x\n",image_panyi);

      // 循环查找在那个imagebuffer节中
      PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
      for(DWORD i = 0;i<PPeHeader->NumberOfSections;i++,pTempSectionHeader++)
      {      //判断 :Misc.VirtualSize+ VirtualAddress 内存偏移+节数据没对齐的大小>image_panyi>内存偏移 VirtualAddress (即是在文件的哪个节中)
                if(((DWORD)image_panyi>=(DWORD)pTempSectionHeader->VirtualAddress) && ((DWORD)image_panyi<pTempSectionHeader->VirtualAddress+pTempSectionHeader->Misc.VirtualSize))
                {
                        
                        return image_panyi-pTempSectionHeader->VirtualAddress+pTempSectionHeader->PointerToRawData;
                }
      }
return 0;
}

DWORD GetFunctionAddrByName(char* dllbuffer)
{
      
      PIMAGE_DOS_HEADER pdos= NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER PPeHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 POptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;

      

      DWORD nameFOA = NULL;
      DWORD AddressOfNamesFOA = NULL;
      DWORD AddressOfNameOrdinalsFOA = NULL;
      DWORD AddressOfFunctionsFOA = NULL;
      DWORD AddressOfFunctions = NULL;

      WORD Ordinal = NULL;
      char* name = NULL;

      pdos = (PIMAGE_DOS_HEADER)dllbuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pdos+pdos->e_lfanew);
      PPeHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      POptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)PPeHeader+IMAGE_SIZEOF_FILE_HEADER);//nt IS 20 BYTE
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)POptionHeader+PPeHeader->SizeOfOptionalHeader);
      DWORD numbofsections = PPeHeader->NumberOfSections;               
      pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)dllbuffer + convertRVAtoFOA(dllbuffer, POptionHeader->DataDirectory.VirtualAddress));

      AddressOfFunctionsFOA = convertRVAtoFOA(dllbuffer, pExportDirectory->AddressOfFunctions);
      AddressOfNamesFOA = convertRVAtoFOA(dllbuffer,pExportDirectory->AddressOfNames);

      for(DWORD k = 0; k < (DWORD)pExportDirectory->NumberOfFunctions; k++)
      {
      //因Address表元素为4字节,绝对地址加上k*4直接取第k个元素
      AddressOfFunctions = *(PDWORD)((DWORD)dllbuffer + AddressOfFunctionsFOA + k*4);
      printf("%x\n",AddressOfFunctions);

      
      }
      for (DWORD i = 0; i < (DWORD)pExportDirectory->NumberOfNames; i++)
      {      
                printf("*******函数名称表*******\n");
                //AddressOfNamesFOA只是Names表的FOA地址,需加上pFileBuffer构成的绝对地址才能取出其中的值。
                //取出的值即Names地址表第i个name的Rva地址,转成FOA得到name的FOA地址
                nameFOA = convertRVAtoFOA(dllbuffer,*(PDWORD)(AddressOfNamesFOA+(DWORD)dllbuffer));
                name = (char*)(nameFOA + (DWORD)dllbuffer);
                printf("%s\n",name);
                AddressOfNamesFOA = AddressOfNamesFOA + 4;


      }

return 0;
}

DWORD GetFuncFileAddressOfDll(char* dllbuffer)
{
      
      PIMAGE_DOS_HEADER pdos= NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER PPeHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 POptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;

      

      DWORD nameFOA = NULL;
      DWORD AddressOfNamesFOA = NULL;
      DWORD AddressOfNameOrdinalsFOA = NULL;
      DWORD AddressOfFunctionsFOA = NULL;
      DWORD AddressOfFunctions = NULL;
      WORD Ordinal = NULL;
      char * name = NULL;

      pdos = (PIMAGE_DOS_HEADER)dllbuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pdos+pdos->e_lfanew);
      PPeHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      POptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)PPeHeader+IMAGE_SIZEOF_FILE_HEADER);//nt IS 20 BYTE
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)POptionHeader+PPeHeader->SizeOfOptionalHeader);
      DWORD numbofsections = PPeHeader->NumberOfSections;               
      pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)dllbuffer + convertRVAtoFOA(dllbuffer, POptionHeader->DataDirectory.VirtualAddress));

      
//      printf("DIRECTORY_ENTRY_EXPORT VirtualAddress:%x\n", POptionHeader->DataDirectory.VirtualAddress);
//      printf("FOA:%x\n", convertRVAtoFOA(dllbuffer, POptionHeader->DataDirectory.VirtualAddress));
//      printf("导出表文件名字符串Name:%x\n", pExportDirectory->Name);
//      printf("导出函数起始序号Base:%d\n", pExportDirectory->Base);
//      printf("导出函数的个数:%d\n", pExportDirectory->NumberOfFunctions);
//      printf("以函数名字导出的函数个数NumberOfNames:%d\n", pExportDirectory->NumberOfNames);
      

      printf("*******函数地址表*******\n");
      AddressOfFunctionsFOA = convertRVAtoFOA(dllbuffer, pExportDirectory->AddressOfFunctions);
//      printf("导出函数RVA:%x\n", AddressOfFunctionsFOA);
      for (DWORD i = 0; i < (DWORD)pExportDirectory->NumberOfFunctions; i++)
      {      
                AddressOfFunctions = *(PDWORD)((DWORD)dllbuffer + AddressOfFunctionsFOA + i * 4);//因Address表元素为4字节,绝对地址加上i*4直接取第i个元素
                printf("下标:%d,函数地址:%x\n", i, AddressOfFunctions);
      }


      printf("*******函数名称表*******\n");
      //导出表中的AddressOfNames为Rva,将其转换为FOA得到AddressOfNamesFOA
      AddressOfNamesFOA = convertRVAtoFOA(dllbuffer, pExportDirectory->AddressOfNames);
      for (DWORD k = 0; k < pExportDirectory->NumberOfNames; k++)
      {      //AddressOfNamesFOA只是Names表的FOA地址,需加上pFileBuffer构成的绝对地址才能取出其中的值。
                //取出的值即Names地址表第i个name的Rva地址,转成FOA得到name的FOA地址

                nameFOA = convertRVAtoFOA(dllbuffer, *(PDWORD)((DWORD)dllbuffer + AddressOfNamesFOA));
                name = (char *)(nameFOA + (DWORD)dllbuffer);//name的FOA加上pFileBuffer构成绝对地址,该地址才真正指向字符串
                printf("下标:%d,函数名称:%s\n", k, name);
                AddressOfNamesFOA = AddressOfNamesFOA + 4;//往前走4字节,指向Names地址表下一个元素,即下一个name地址
      }


      printf("*******函数序号表*******\n");
      AddressOfNameOrdinalsFOA = convertRVAtoFOA(dllbuffer, pExportDirectory->AddressOfNameOrdinals);      //同Names表找法
      for (DWORD f = 0; f < pExportDirectory->NumberOfNames; f++)
      {
                Ordinal = *(WORD*)((DWORD)dllbuffer + AddressOfNameOrdinalsFOA + f * 2);      //因为序号表元素为2字节,绝对地址加上f*2直接取第f个元素
                printf("下标:%d,函数序号:%d\n", f, Ordinal);

      }
//      result = (DWORD)GetFunctionAddrByName(dllbuffer, "plus");      //得到的是函数Rva地址
//      printf("result:%x\n", result);
      

//      result = (DWORD)GetFunctionAddrByOrdinals(dllbuffer, 2);
//      printf("result:%x\n", result);

return 0;
      
}

/*
DWORD AddNewSection(LPSTR PFilebuffer)
{
      PIMAGE_DOS_HEADER pdos= NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER PPeHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 POptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      PIMAGE_SECTION_HEADER LastpSectionHeader = NULL;

      pdos = (PIMAGE_DOS_HEADER)PFilebuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)PFilebuffer+pdos->e_lfanew);
      PPeHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      POptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)PPeHeader+IMAGE_SIZEOF_FILE_HEADER);//nt IS 20 BYTE
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)POptionHeader+PPeHeader->SizeOfOptionalHeader);
      DWORD numbofsections = PPeHeader->NumberOfSections;

      //判断条件:

      //      if ((DWORD)pNewSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * 2 <= (DWORD)pFileBuffer + pOptionalHeader->SizeOfHeaders)
      for(DWORD i=0;i<numbofsections;i++,pSectionHeader++){
      //      printf("%d\n",i);
      }

      LastpSectionHeader = pSectionHeader + 1;
      if ((DWORD)LastpSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * 2 <= (DWORD)PFilebuffer + POptionHeader->SizeOfHeaders)
      {
      printf("SizeofHeaders >= 2个节表的大小,you can add new sectioncode\n");      
      }
      else
      {
      printf("SizeofHeaders < 2个节表的大小");
      }
      printf(".........start add new sectioncode.......\n");
      
      //开始构造新节表
      strcpy((char*)LastpSectionHeader->Name,(char*)".NewSec");
      LastpSectionHeader->Misc.VirtualSize = sizeof(ShellCodeData);
      
      //节区在内存中的偏移 = 内存中整个PE文件映射的大小
      LastpSectionHeader->VirtualAddress = POptionHeader->SizeOfImage;
      LastpSectionHeader->SizeOfRawData =POptionHeader->SizeOfImage;
      
      LastpSectionHeader->PointerToRawData = (unsigned)PFilebuffer;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
      LastpSectionHeader->PointerToRelocations = 0;
      LastpSectionHeader->PointerToLinenumbers = 0;
      LastpSectionHeader->NumberOfRelocations = 0;
      LastpSectionHeader->NumberOfLinenumbers = 0;
      LastpSectionHeader->Characteristics = 0x60000020;

      PPeHeader->NumberOfSections++;

      
}
*/

BOOL writeMemorytoFile2(char* filePath,LPSTR pNewBuffer,int NewBufferSize)
{

      FILE* fpw = fopen(filePath, "wb+");
      if (fpw == NULL)
      {
                printf("fpw fopen fail");
                return false;
      }
      if (fwrite(pNewBuffer, 1, NewBufferSize, fpw) == 0)
      {
                printf("fpw fwrite fail");
                return false;
      }
      fclose(fpw);               
      fpw = NULL;
      printf("success\n");

      return true;
}



LPSTR ShellCode(int SizeOfFileBuffer,LPSTR ImageBuffer)
{
      PIMAGE_DOS_HEADER pdos= NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER PPeHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 POptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;

      DWORD CallX = NULL;      //即E8后跟的4字节
      DWORD JmpX = NULL;      //即E9后跟的4字节
      
      if (!SizeOfFileBuffer)   //SizeOfFileBuffer == size
      {
                printf("文件读取失败\n");
                return 0;
      }
      if(!ImageBuffer)
      {
                printf("Filebuffer to Imagebuffer failed!\n");
                return 0;
      }

      pdos = (PIMAGE_DOS_HEADER)ImageBuffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pdos+pdos->e_lfanew);
      PPeHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      POptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)PPeHeader+IMAGE_SIZEOF_FILE_HEADER);//nt IS 20 BYTE
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)POptionHeader+PPeHeader->SizeOfOptionalHeader);
      if ( pSectionHeader->Misc.VirtualSize + sizeof(ShellCodeData) > pSectionHeader->SizeOfRawData)
      {
                printf("空间不足");
                free(ImageBuffer);
                return 0;
      }else
      {
                printf("Congratulations,this space can write!\n");
      }
      //那么要跳转的地址即messageboxA地址。E8所在地址即 ImageBase内存运行基址 + VirtualAddress节所在偏移 + VirtualSize 节真正长度即节结束的偏移 再加上8才到E8
      CallX =MESSAGEBOXADDR - ( POptionHeader->ImageBase + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize + 8 +5);
      //jump 要跳转的地址即OEP程序入口点, X = 程序入口点 - (E9所在地址 + 5)
      //这里程序入口点即ImageBase基址 + AddressOfEntryPoint         E9所在地址计算同上
      JmpX = POptionHeader->ImageBase + POptionHeader->AddressOfEntryPoint - (POptionHeader->ImageBase + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize + 13 + 5);
      *(PDWORD)(ShellCodeData + 9) = CallX;
      *(PDWORD)(ShellCodeData + 14) = JmpX;
      
      for(int i = 0;i<sizeof(ShellCodeData);i++)
      {
                printf("%x ", ShellCodeData);
      }
      printf("\n");
      memcpy((void*)((DWORD)ImageBuffer + pSectionHeader->PointerToRawData + pSectionHeader->Misc.VirtualSize), ShellCodeData,sizeof(ShellCodeData));
      
                //修改OEP的值
      POptionHeader->AddressOfEntryPoint = pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize;
      return ImageBuffer;
}






void ReadPefileDos(char* buffer)
{
      PIMAGE_DOS_HEADER pdos= NULL;
      PIMAGE_NT_HEADERS pNTHeader = NULL;
      PIMAGE_FILE_HEADER PPeHeader = NULL;
      PIMAGE_OPTIONAL_HEADER32 POptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;

      pdos = (PIMAGE_DOS_HEADER)buffer;
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)buffer+pdos->e_lfanew);
      PPeHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      POptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)PPeHeader+IMAGE_SIZEOF_FILE_HEADER);//nt IS 20 BYTE
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)POptionHeader+PPeHeader->SizeOfOptionalHeader);
      DWORD numbofsections = PPeHeader->NumberOfSections;

      

      printf("..........................................\n");
      printf("e_magic\t\t\t%04x\n",pdos->e_magic);
      printf("e_lfanew\t\t%08x\n",pdos->e_lfanew);
      printf("..........................................\n");
      printf("Signature\t\t%08x\n",pNTHeader->Signature);
      printf("Machine\t\t\t%04x\n",PPeHeader->Machine);
      printf("PE NUMBER Sections\t%x\n",PPeHeader->NumberOfSections);

      for(DWORD i=0;i<numbofsections;i++,pSectionHeader++)
      {
                printf(".......the %d Sections Name.........\n",i+1);
                for(DWORD j=0;j<IMAGE_SIZEOF_SHORT_NAME;j++)
                {
                        printf("%c",pSectionHeader->Name);
                }
                printf("\r\n");
                printf("Misc:\t\t\t%08x\n",pSectionHeader->Misc);
                printf("VirtualAddress:\t\t%08x\n",pSectionHeader->VirtualAddress);
                printf("SizeOfRawData:\t\t%08x\n",pSectionHeader->SizeOfRawData);
                printf("Characteristics:\t%08x\n",pSectionHeader->Characteristics);
      }

}


```

{:1_906:}
各位师兄有李忠x86保护模式的视频,给师弟我发一份。https://pan.baidu.com/disk/main#/transfer/send?surl=AA4AAAAAAA5lZg
感激不尽!

Huanghousec 发表于 2022-6-2 18:44

writeMemorytoFile2这个函数只是读入内存再读出来,所以是没什么区别的,但是newbuffer那一块我加入了shellcode,那段shellcode是扣的message的代码。所以是不一样的大小的。messagebox的入口是在xp上寻的。如果需要在64上运行,需要重新计算。我现在在回家的路上,需要讲解的话您私聊我,我到家了再讲给你听

addon007 发表于 2022-6-2 15:21

大佬牛逼 十年老兵

email123 发表于 2022-6-2 16:01

试了一下,输出的ipmsg_Imagebuffer.exe和原文件不一样啊

xtkj 发表于 2022-6-2 16:25

学习了。

Huanghousec 发表于 2022-6-2 16:43

email123 发表于 2022-6-2 16:01
试了一下,输出的ipmsg_Imagebuffer.exe和原文件不一样啊

主函数的filepath那里路径改一下就好了,我那里读的是一个dll,用来测导出表的

Huanghousec 发表于 2022-6-2 16:45

email123 发表于 2022-6-2 16:01
试了一下,输出的ipmsg_Imagebuffer.exe和原文件不一样啊

char filepath[] = "c:\\ipmsg.exe"

ymnj11 发表于 2022-6-2 17:47

学习了,感谢大佬分享。

email123 发表于 2022-6-2 18:31

Huanghousec 发表于 2022-6-2 16:45

C:\ant_1.3.4\1.pngiTOTALCM.EXE是原文件,按说写出来的文件应该一样大小,但实际上不一样

Huanghousec 发表于 2022-6-2 18:49

email123 发表于 2022-6-2 18:31
iTOTALCM.EXE是原文件,按说写出来的文件应该一样大小,但实际上不一样

不急的话回去给你调试,我现在在回家的路上,您私聊我就好了
页: [1] 2 3
查看完整版本: PE结构代码