移动导出表,移动重定位表【滴水逆向三期51笔记+作业源码】(下)

简介: 移动导出表,移动重定位表【滴水逆向三期51笔记+作业源码】

四.移动重定位表源码:

PEFunction.h:
#include <stdio.h>
#include <windows.h>
#include <string.h>
//*************打开文件函数(将文件二进制读取到FileBuffer) ******************
//该函数需要一个char类型的指针,指向想要打开的文件路径
//该函数返回一个char类型的指针,指向FileBuffer
//该函数完成文件的打开,并且将文件的二进制读取到FIleBuffer
//该函数读取完成后会将文件关闭,避免出现误操作
//该函数会通过移动文件指针获取文件大小
//获取的文件大小用于动态申请内存 
//该函数会动态申请内存,用于存放FileBuffer
//***************************************************************************
char* ReadToFileBuffer(char* filename);
//***************************************获取文件大小函数*********************************
//该函数返回文件大小 
//****************************************************************************************
int SizeOfFile(char* filename);
//*****************************获取PE导出表数据函数**************************
//该函数需要一个指针,指向FileBuffer
//该函数在找到导出表之前,需要定义DOS结构指针,标准PE头结构指针和可选PE头指针,以方便找到导出表
//该函数会在控制台输出函数地址表,函数名称表和函数导出序号表 
//***************************************************************************
void ShowExportDirectory(char* FileBuffer);
//*****************************RVA转换为FOA函数******************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,为要转换的RVA
//该函数返回一个整数,为转换后的FOA地址
//***************************************************************************
int RVAToFOA(IN LPVOID pFileBuffer, IN DWORD dwRva);
//*************************根据函数名称查找函数地址函数**********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByName(char* filename);
//*************************根据函数序号查找函数地址函数**********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByOrdinal(char* filename);
//******************************打印PE重定位表函数***************************
//该函数需要一个指针,指向FIleBuffer
//该函数会在控制台打印出重定位表信息(重定位表偏移,重定位表大小,但不打印重定位表具体项
//***************************************************************************
void ShowBaseRelocation(char* FileBuffer);
//**************************************新增节函数***************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个指针,表示FileBuffer大小 
//该函数需要一个字符串,为原文件文件名 
//该函数完成在PE文件中新增一个节
//该函数在新增节之前,PE头部是否足够新增一个节表
//若PE文件头部内存不够新增一个节表,该函数将会提升所有头部,将DOSstob覆盖掉,并且让e_lfanew指向下一个字节 
//该函数会生成一个exe文件,存放于调用该函数的程序源目录下  
//该函数返回一个指针,指向新增节后的FileBuffer 
//****************************************************************************************
char* AddNewSection(char* FileBuffer,int SizeOfFileBuffer);
//*****************************覆盖DOSstob,抬升NT头和原有节表****************************
//该函数需要一个指针,指向需要改动的FileBuffer
//该函数将FileBuffer中的DOSstob覆盖
//该函数将PE头部中,DOS头以后的内容提升到DOSstob的位置 
//抬升成功后会将最后两个节表的数据全初始化为0 
//若头部抬升失败,则返回0 
//若抬升成功,则返回1 
//****************************************************************************************
int UpFile(char* FileBuffer);
//******************************计算文件对齐后的值函数************************************           
//Align:计算对齐后的值         
//参数说明:               
//x  需要进行对齐的值               
//Alignment 对齐大小            
//返回值说明:              
//返回x进行Alignment值对齐后的值                
//****************************************************************************************  
int Align(int x, int Alignment);
//**************************************移动导出表****************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整形参数,表示FileBuffer大小 
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向NewFileBuffer
//****************************************************************************************
char* RemoveExportDirectory(char* FileBuffer,int SizeOfFileBuffer);
//*************************************移动重定位表***************************************
//该函数需要一个指针,指向FileBuffer 
//该函数需要一个整形参数,表示FileBuffer的大小 
//该函数将在原来节表的基础上新增一个节,用于存放移动后的重定位表
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向移动重定位表后的地址 
//****************************************************************************************
char* RemoveBaseRelocation(char* FileBuffer,int SizeOfFileBuffer); 
PEFuncion.c:
/**************************************************************/ 
//*********************自编PE函数库****************************/
#include "PEFunction.h"
//********打开文件函数(将文件二进制读取到FileBuffer) *******
//函数说明:
//该函数需要一个char类型的指针,指向想要打开的文件路径
//该数返回一个char类型的指针,指向FileBuffer
//该函数完成文件的打开,并且将文件的二进制读取到FIleBuffer
//该函数读取完成后会将文件关闭,避免出现误操作
//该函数会通过移动文件指针获取文件大小
//获取的文件大小用于动态申请内存 
//该函数会动态申请内存,用于存放FileBuffer
//********************************************************* 
char* ReadToFileBuffer(char* filename){
  FILE* fp;
  char* FileBuffer=NULL;
  int length;
  if((fp=fopen(filename,"rb"))==NULL){
    printf("%s打开失败!",filename);
    exit(0);
  }else{
    printf("文件打开成功,正在计算文件大小...\n");
  }
  fseek(fp,0,SEEK_END);
  length=ftell(fp);
  fseek(fp,0,SEEK_SET);
  printf("文件大小:%d字节\n正在申请FileBuffer内存...\n",length);
  FileBuffer=(char*)malloc(length);
  if(FileBuffer!=NULL){
    printf("FileBuffer内存申请成功。准备向FileBuffer写入数据...\n");
  }
  if((fread(FileBuffer,length,1,fp))==0){
    printf("写入数据失败!\n");
    exit(0);
  }else{
    printf("写入数据成功。\n");
  }
  if(fclose(fp)){
    printf("文件关闭失败!\n");
    exit(0);
  }else{
    printf("文件关闭成功。\n");
  }
  return FileBuffer;
}
//***************************************获取文件大小函数*********************************
//该函数返回文件大小 
//****************************************************************************************
int SizeOfFile(char* filename){
  FILE* fp;
  char* FileBuffer=NULL;
  int length;
  if((fp=fopen(filename,"rb"))==NULL){
    printf("%s打开失败!",filename);
    exit(0);
  }else{
    printf("文件打开成功,正在计算文件大小...\n");
  }
  fseek(fp,0,SEEK_END);
  length=ftell(fp);
  fseek(fp,0,SEEK_SET);
  return length;
}
//**********************获取PE导出表数据函数************************************************
//该函数需要一个指针,指向FileBuffer
//该函数在找到导出表之前,需要定义DOS结构指针,标准PE头结构指针和可选PE头指针,以方便找到导出表
//该函数会在控制台输出函数地址表,函数名称表和函数导出序号表 
//********************************************************************************************
void ShowExportDirectory(char* FileBuffer){
  IMAGE_DOS_HEADER* pDosHeader=NULL;
  IMAGE_FILE_HEADER* pFileHeader=NULL;
  IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
  IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
  pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
  if(*((PDWORD)((DWORD)FileBuffer + pDosHeader->e_lfanew))!= IMAGE_NT_SIGNATURE){
    printf("不是有效的PE标志!\n");
  }else{
    printf("检测到有效的PE标志。\n");
  }
  pFileHeader=(IMAGE_FILE_HEADER*)(FileBuffer+pDosHeader->e_lfanew+4);
  pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
  pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
  printf("导出表RVA:%x\n",pOptionalHeader->DataDirectory[0].VirtualAddress);
  printf("导出表大小:%x字节\n",pOptionalHeader->DataDirectory[0].Size);
  printf("导出表FOA:%d\n",RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
  printf("*******************************导出表*********************************\n");
  printf("TimeDataStamp(经加密):%d\n",pExportDirectory->TimeDateStamp);
  printf("Name(导出表文件名字符串):%s\n",FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->Name));
  printf("Base(函数起始序号):%d\n",pExportDirectory->Base);
  printf("NumberOfFunction(导出函数总数):%d\n",pExportDirectory->NumberOfFunctions);
  printf("NumberOfNames(以名称导出函数的总数):%d\n",pExportDirectory->NumberOfNames);
  printf("*****************************函数地址表********************************\n");
  int i=0;
  char* AddressOfFunction;
  AddressOfFunction=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions));
  for(i=0;i<pExportDirectory->NumberOfFunctions;i++){
    printf("下标:%d     函数地址:0x%x\n",i,*(PWORD)((DWORD)AddressOfFunction+i*4));
  }
  printf("*****************************函数名称表********************************\n");
  int* AddressOfNames=NULL;
  char* name=NULL;
  AddressOfNames=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNames));
  for(i=0;i<pExportDirectory->NumberOfNames;i++){
    name=(char*)(FileBuffer+RVAToFOA(FileBuffer,*AddressOfNames));
    printf("下标:%d     函数名称:%s\n",i,name);
    AddressOfNames++;
  }
  printf("*******************************函数序号表*******************************\n");
  char *AddressOfNameOrdinals=NULL;
  char *Ordinal=NULL;
  AddressOfNameOrdinals=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNameOrdinals));
  for(i=0;i<pExportDirectory->NumberOfNames;i++){
    Ordinal=(int*)(FileBuffer+RVAToFOA(FileBuffer,*AddressOfNameOrdinals));
    printf("下标:%d      函数序号(加Base):%d\n",i,*(AddressOfNameOrdinals+i*2)+pExportDirectory->Base);
  } 
}
//*************************RVA转换为FOA函数*************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,为要转换的RVA
//该函数返回一个整数,为转换后的FOA地址
//******************************************************************
int RVAToFOA(IN LPVOID pFileBuffer, IN DWORD dwRva)
{
  PIMAGE_DOS_HEADER pDosHeader = NULL;
  PIMAGE_FILE_HEADER pFileHeader = NULL;
  PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
  PIMAGE_SECTION_HEADER pSectionHeader = NULL;
  PIMAGE_SECTION_HEADER pNextSectionHeader = NULL;
  //DOS头
  pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;  // 强转 DOS_HEADER 结构体指针
  //PE头
  pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4);  //NT头地址 + 4 为 FileHeader 首址
  //可选PE头 
  pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中
  if (dwRva < pOptionalHeader->SizeOfHeaders) //偏移小于头的大小,内存偏移则为文件偏移
  {
    return dwRva;
  }
    //首个节表
  pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
  //下一个节表
  pNextSectionHeader = pSectionHeader + 1;
  //循环遍历节表
  int i;
  for (i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++, pNextSectionHeader++)//注意这里i从1开始 i < NumberOfSections
  { //注意这里的pSectionHeader已经是加了基址的,不是偏移, 是绝对地址。而dwRva是偏移地址
    if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pNextSectionHeader->VirtualAddress)//大于当前节的内存偏移而小于下一节的内存偏移
    { //则dwRva属于当前节,则dwRva - VirtualAddress为dwRva基于当前节的偏移。此偏移加上当前节的文件起始偏移地址 则为dwRva在文件中的偏移
      DWORD PointerToRawData = pSectionHeader->PointerToRawData;
      DWORD VirtualAddress = pSectionHeader->VirtualAddress;
      DWORD aa = pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress;
      return pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress ;
    }
  } //出循环后pSectionHeader指向最后一个节表
  //大于当前节(最后一节)的内存偏移且小于内存映射大小
  if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pOptionalHeader->SizeOfImage)
  { //同上return
    return pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress;
  }
  else //大于内存映射大小
  {
    printf("dwRva大于内存映射大小\n");
    return -1;
  }
}
//*************************根据函数名称查找函数地址函数***********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//****************************************************************************
void GetAddressOfFunctionByName(char* filename){
  char* FileBuffer=NULL;
  char inname[5];
  int i;
  FileBuffer=ReadToFileBuffer(filename);
  IMAGE_DOS_HEADER* pDosHeader=NULL;
  IMAGE_FILE_HEADER* pFileHeader=NULL;
  IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
  IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
  pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
  if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
    printf("检测到有效的PE标志。\n");
  }else{
    printf("未检测到有效的PE标志!\n");
    exit(0);
  }
  pFileHeader=(IMAGE_FILE_HEADER*)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
  pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
  pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
  int* AddressOfNames=NULL;
  char* name=NULL;
  AddressOfNames=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNames));
  printf("请输入您需要查找的函数名:");
  scanf("%s",inname);
  printf("正在查找中...\n");
  for(i=0;i<pExportDirectory->NumberOfNames;i++){
  name=(int*)(FileBuffer+RVAToFOA(FileBuffer,RVAToFOA(FileBuffer,*AddressOfNames)));
    if(!(strcmp("Plus",name))){
      printf("下标为%d的函数名符合。\n",i);
      break;
    }
    AddressOfNames++;
  }
  char* Ordinal=NULL;
  Ordinal=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNameOrdinals)+i*2);
  char* AddressOfFunction=NULL;
  AddressOfFunction=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions)+*Ordinal*4);
  printf("Ordinal(函数导出序号(未加Base)):%d    AddressOfFunction:0x%x",*Ordinal,*(PWORD)((DWORD)AddressOfFunction));
}
//************************根据函数序号查找函数地址函数***********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByOrdinal(char* filename){
  char* FileBuffer=NULL;
  int InOrdinal=0;
  IMAGE_DOS_HEADER* pDosHeader=NULL;
  IMAGE_FILE_HEADER* pFileHeader=NULL;
  IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
  IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
  FileBuffer=ReadToFileBuffer(filename);
  char* AddressOfFunction;
  pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
  if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
    printf("检测到PE标志。");
  }else{
    printf("未检测到PE标志!\n");
    exit(0);
  }
  pFileHeader=(IMAGE_FILE_HEADER*)(FileBuffer+pDosHeader->e_lfanew+4);
  pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
  pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
  printf("请输入您需要查找的函数导出序号:");
  scanf("%d",&InOrdinal);
  InOrdinal=InOrdinal-pExportDirectory->Base;
  AddressOfFunction=(char*)FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions+InOrdinal*4);
  printf("函数导出序号(未加Base):%d       函数地址:0x%x",InOrdinal,*(PWORD)((DWORD)AddressOfFunction));
}
//*************************打印PE重定位表函数*********************************************
//该函数需要一个指针,指向FIleBuffer
//该函数会在控制台打印出重定位表信息(重定位表偏移,重定位表大小,但不打印重定位表具体项*/
//****************************************************************************************
void ShowBaseRelocation(char* FileBuffer){
  int i=1;
  IMAGE_DOS_HEADER* pDosHeader=NULL;
  IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
  IMAGE_BASE_RELOCATION* pBaseRelocation=NULL;
  pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
  if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
    printf("检测到有效的PE标志。\n");
  }else{
    printf("未检测到有效的PE标志!\n");
    exit(0);
  }
  pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)FileBuffer+pDosHeader->e_lfanew+24);
  pBaseRelocation=(IMAGE_BASE_RELOCATION*)((DWORD)FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[5].VirtualAddress));
  printf("%x",pOptionalHeader->DataDirectory[5].VirtualAddress);
  while(pBaseRelocation->VirtualAddress&&pBaseRelocation->SizeOfBlock){
    printf("************                 第%d块                 ************\n",i);
    printf("VirtulaAddress(重定位表在文件中的偏移):0x%x\n",RVAToFOA(FileBuffer,pBaseRelocation->VirtualAddress));
    printf("Size(该块重定位表的大小):%d字节\n",pBaseRelocation->SizeOfBlock);
    printf("重定位表具体项数目:%d\n\n",(pBaseRelocation->SizeOfBlock-8)/2);
    pBaseRelocation = (IMAGE_BASE_RELOCATION*)(pBaseRelocation->SizeOfBlock + (DWORD)pBaseRelocation);
    i++;
  }
}
//**************************************新增节函数***************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,表示FileBuffer大小 
//该函数需要一个字符串,位原文件文件名 
//该函数完成在PE文件中新增一个节
//该函数在新增节之前,PE头部是否足够新增一个节表
//若PE文件头部内存不够新增一个节表,该函数将会提升所有头部,将DOSstob覆盖掉,并且让e_lfanew指向下一个字节 
//该函数会生成一个exe文件,存放于调用该函数的程序源目录下 
//该函数返回一个指针,指向新增节后的FileBuffer 
//****************************************************************************************
char* AddNewSection(char* FileBuffer,int SizeOfFileBuffer){
  printf("新增节执行中...\n");
  int choose1;
  unsigned char ShellCode[100];
  int AddressOfShellCode=0;
  PIMAGE_DOS_HEADER pDosHeader=NULL;
  PIMAGE_FILE_HEADER pFileHeader=NULL;
  PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
  PIMAGE_SECTION_HEADER pSectionHeader=NULL;
  PIMAGE_SECTION_HEADER pNewSectionHeader=NULL;
  int i,j;
  char* NewFileBuffer=NULL;
  pDosHeader=(PIMAGE_DOS_HEADER)FileBuffer;
  if(*(PDWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
    printf("检测到有效的PE标志。\n"); 
  }else{
    printf("未检测到有效的PE标志!\n");
    return 0;
  }
  pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
  pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
  pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
  for(i=1;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
    printf("移动节表指针中...\n");
    printf("%s",pSectionHeader->Name); 
  }
  pNewSectionHeader=pSectionHeader+1;
  for(i=0;i<IMAGE_SIZEOF_SECTION_HEADER*2;i++){
    if((*(PWORD)((DWORD)pNewSectionHeader+i))!=0){
      printf("%x",*(PWORD)((DWORD)pNewSectionHeader+i));
      printf("PE文件头部内存空间不足,需要覆盖DOSstob抬升头部,以保证足够的空间新增节表!\n");
      if(UpFile){
        printf("更新头部指针中...\n");
        pDosHeader=(PIMAGE_DOS_HEADER)FileBuffer;
        pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
        pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
        pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pOptionalHeader->SizeOfHeaders);
        for(i=1;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
          printf("移动节表指针中...\n");
        }
        pNewSectionHeader=pSectionHeader+1;
        break;
      }else{
        printf("抬升失败!\n");
        return 0;
      }
    }else{
      printf("检测数据中...\n");
    }
  }
  if(i==IMAGE_SIZEOF_SECTION_HEADER*2){
    printf("数据检测完毕,未检测到数据,将新增节...\n");
  }
  strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
  printf("******                         请选择是否添加ShellCode                         ******\n");
  printf("******                         0:不添加ShellCode                              ******\n");
  printf("******                         1:添加ShellCode                                 ******\n");
  printf("请输入您的选择:");
  scanf("%d",&choose1);
  switch (choose1){
    case 0:{
      strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
      pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode);
      pNewSectionHeader->VirtualAddress=pOptionalHeader->SizeOfImage;
      printf("FileAligment:%x\n",pOptionalHeader->FileAlignment);
      pNewSectionHeader->SizeOfRawData=Align(sizeof(ShellCode),pOptionalHeader->FileAlignment);
      pNewSectionHeader->PointerToRawData = SizeOfFileBuffer;
//      pNewSectionHeader->PointerToRawData = pSectionHeader->SizeOfRawData+pSectionHeader->PointerToRawData;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
      pNewSectionHeader->PointerToRelocations = 0;
      pNewSectionHeader->PointerToLinenumbers = 0;
      pNewSectionHeader->NumberOfRelocations = 0;
      pNewSectionHeader->NumberOfLinenumbers = 0;
      pNewSectionHeader->Characteristics = 0x60000020;
      pFileHeader->NumberOfSections++;
      printf("SectionAlignment: %x\nSizeOfImage:%x\n", pOptionalHeader->SectionAlignment, pOptionalHeader->SizeOfImage);
      pOptionalHeader->SizeOfImage += Align(sizeof(ShellCode), pOptionalHeader->SectionAlignment);
      printf("SizeOfImage:%x\n", pOptionalHeader->SizeOfImage);
      int SizeOfNewBuffer=SizeOfFileBuffer+pNewSectionHeader->SizeOfRawData;
      NewFileBuffer=(char*)malloc(SizeOfNewBuffer);
      memcpy(NewFileBuffer, FileBuffer, SizeOfFileBuffer);
      memset((void *)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), 0, pNewSectionHeader->SizeOfRawData);
      FILE* fp=NULL;
//      if((fp=(fopen("新增节程序.exe","wb")))==NULL){
//        printf("文件新建失败!\n");
//        exit(0);
//      }else{
//        printf("文件新建成功,正在写入数据...\n");
//        if(fwrite(NewFileBuffer,SizeOfNewBuffer,1,fp)){
//          printf("数据写入成功。\n");
//        }else{
//          printf("数据写入失败!\n");
//          exit(0);
//        }
//      }
//      if(!fclose(fp)){
//        printf("文件保存成功。\n");
//      }else{
//        printf("文件保存失败!");
//        exit(0); 
//      }
      return  NewFileBuffer;
      break;
    }
    case 1:{
      int CallShellCode;
      int JmpShellCode;
      strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
      pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode);
      pNewSectionHeader->VirtualAddress=pOptionalHeader->SizeOfImage;
      printf("FileAligment:%x\n",pOptionalHeader->FileAlignment);
      pNewSectionHeader->SizeOfRawData=Align(sizeof(ShellCode),pOptionalHeader->FileAlignment);
      pNewSectionHeader->PointerToRawData = pSectionHeader->SizeOfRawData+pSectionHeader->PointerToRawData;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
      pNewSectionHeader->PointerToRelocations = 0;
      pNewSectionHeader->PointerToLinenumbers = 0;
      pNewSectionHeader->NumberOfRelocations = 0;
      pNewSectionHeader->NumberOfLinenumbers = 0;
      pNewSectionHeader->Characteristics = 0x60000020;
      pFileHeader->NumberOfSections++;
      printf("SectionAlignment: %x\nSizeOfImage:%x\n", pOptionalHeader->SectionAlignment, pOptionalHeader->SizeOfImage);
      pOptionalHeader->SizeOfImage += Align(sizeof(ShellCode), pOptionalHeader->SectionAlignment);
      printf("SizeOfImage:%x\n", pOptionalHeader->SizeOfImage);
      int SizeOfNewBuffer=SizeOfFileBuffer+pNewSectionHeader->SizeOfRawData;
      NewFileBuffer=(int*)malloc(SizeOfNewBuffer);
      DWORD OddAddressOfEntryPoint = pOptionalHeader->AddressOfEntryPoint;
      pOptionalHeader->AddressOfEntryPoint = pNewSectionHeader->VirtualAddress;
      memcpy(NewFileBuffer, FileBuffer, SizeOfFileBuffer);
      memset((void *)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), 0, pNewSectionHeader->SizeOfRawData);
      printf("请输入ShellCode硬编码:\n");
      printf("!!!特别注意:在输入硬编码后,应输入E8和该ShellCode执行时内存中的地址,程序会自动转换!!!暂时只支持输入100字节以内的硬编码\n");
      for(i=0,j=0;i<100;i++){
        scanf("%x ",ShellCode[i]);
        if(ShellCode[i]==0xE8){
          j=i+1;
        }
        if(i=j+4){
          CallShellCode=*(int*)(ShellCode[j]);
          CallShellCode = CallShellCode - (pOptionalHeader->ImageBase + pNewSectionHeader->VirtualAddress + j-1 + 5);
          *(int*)ShellCode[j] = CallShellCode;
        }
        if(i=j+9){
          JmpShellCode = OddAddressOfEntryPoint - (pNewSectionHeader->VirtualAddress + j+5 + 5);
          *(int*)ShellCode[j+5] = JmpShellCode;
        }
      }
      memcpy((void*)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), ShellCode, sizeof(ShellCode));
//      FILE* fp=NULL;
//      if((fp=(fopen("新增节程序.exe","wb")))==NULL){
//        printf("文件新建失败!\n");
//        exit(0);
//      }else{
//        printf("文件新建成功,正在写入数据...\n");
//        if(fwrite(fp,SizeOfNewBuffer,1,NewFileBuffer)){
//          printf("数据写入成功。\n");
//        }else{
//          printf("数据写入失败!\n");
//          exit(0);
//        }
//      }
      return NewFileBuffer;
      break;
    }
  }
}
//*****************************覆盖DOSstob,抬升NT头和原有节表****************************
//该函数需要一个指针,指向需要改动的FileBuffer
//该函数将FileBuffer中的DOSstob覆盖
//该函数将PE头部中,DOS头以后的内容提升到DOSstob的位置 
//抬升成功后会将最后两个节表的数据全初始化为0 
//若头部抬升失败,则返回0 
//若抬升成功,则返回1 
//****************************************************************************************
int UpFile(char* FileBuffer){
  PIMAGE_DOS_HEADER pDosHeader=NULL;
  PIMAGE_NT_HEADERS32 pNTHeader=NULL; 
  PIMAGE_FILE_HEADER pFileHeader=NULL;
  PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
  PIMAGE_SECTION_HEADER pSectionHeader=NULL;
  char* pNewSectionHeader=NULL;
  int i;
  pDosHeader=(PIMAGE_DOS_HEADER)((DWORD)FileBuffer);
  pNTHeader=(PIMAGE_NT_HEADERS32)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
  if(*(PDWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
    printf("检测到有效的PE标志。\n");
  }else{
    printf("未检测到有效的PE标志!\n");
    return 0;
  }
  pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
  pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((DWORD)FileBuffer+20);
  pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
  for(i=0;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
    printf("移动节表指针中...\n");
  }
  pNewSectionHeader=pSectionHeader+1;
  if ((DWORD)FileBuffer + sizeof(IMAGE_DOS_HEADER) - (DWORD)pNTHeader >= IMAGE_SIZEOF_SECTION_HEADER * 2)
    {
      printf("可抬升NT头\n抬升PE头部中...\n");
      //开始拷贝,将NT头拷贝到DOS头结束之后,长度为NT头开始到最后一个节表结束时的长度,即pNewSectionHeader
      memcpy((void*)((DWORD)FileBuffer + sizeof(IMAGE_DOS_HEADER)), pNTHeader, (DWORD)pNewSectionHeader - (DWORD)pNTHeader);
      //拷贝后重置e_lfanew位置
      printf(" e_lfanew: %x\n", pDosHeader->e_lfanew);
      pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER);
      printf("e_lfanew: %x\n", pDosHeader->e_lfanew);
      //抬升后更新所有被抬升的头指针
      //NT头
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)FileBuffer + pDosHeader->e_lfanew);
      //PE头
      pFileHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4); //NT头地址 + 4 为 FileHeader 首址
      //可选PE头 
      pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中
      //首个节表
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
      for(i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++)  //注意这里i从1开始 i < NumberOfSections
      {}  //出循环后pSectionHeader指向最后一个节表        
      pNewSectionHeader = pSectionHeader + 1;
      //验证代码,判断是否是有效的PE标志
      if (*((PDWORD)((DWORD)FileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)  //基址pFileBuffer + lfanew 为 NTHeader首址
      {
        printf("抬升后验证失败,不是有效的PE标志\n");
        return ;
      }
      printf("抬升成功!\n");
      //抬升成功后将最后一个节表后两个节表位置的空间置零
      memset(pNewSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER * 2);
    }
    return 1;
}
//******************************计算文件对齐后的值函数************************************           
//Align:计算对齐后的值         
//参数说明:               
//x  需要进行对齐的值               
//Alignment 对齐大小            
//返回值说明:              
//返回x进行Alignment值对齐后的值                
//****************************************************************************************  
int Align(int x, int Alignment)
{
  if (x%Alignment==0)
  {
    return x;
  }
  else
  {
    return (1 + (x / Alignment)) * Alignment;
  }
}
//**************************************移动导出表****************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整形参数,表示FileBuffer大小 
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向NewFileBuffer
//****************************************************************************************
char* RemoveExportDirectory(char* FileBuffer,int SizeOfFileBuffer){
  printf("******                         移动导出表程序                         ******\n"); 
  char* NewFileBuffer=NULL;
  int offset=0;
  int i;
  PIMAGE_DOS_HEADER pDosHeader=NULL;
  PIMAGE_FILE_HEADER pFileHeader=NULL;
  PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
  PIMAGE_SECTION_HEADER pSectionHeader=NULL;
  PIMAGE_EXPORT_DIRECTORY pExportDirectory=NULL; 
  NewFileBuffer=AddNewSection(FileBuffer,SizeOfFileBuffer);
  pDosHeader=(PIMAGE_DOS_HEADER)NewFileBuffer;
  int* AddressOfFunctions;
  char* AddressOfNameOrdinals;
  int* AddressOfNames;
  if(*(PWORD)((DWORD)NewFileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
    printf("检测到有效的PE标志。\n");
  }else{
    printf("未检测到有效的PE标志!\n");
  }
  pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)NewFileBuffer+pDosHeader->e_lfanew+4);
  pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
  pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+RVAToFOA(NewFileBuffer,pFileHeader->SizeOfOptionalHeader));
  pExportDirectory=(PIMAGE_EXPORT_DIRECTORY)((char*)NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));
  AddressOfFunctions=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfFunctions));
  AddressOfNameOrdinals=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNameOrdinals));
  AddressOfNames=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNames));
  for(i=1;i<pFileHeader->NumberOfSections;i++){
    pSectionHeader++;
  }
  printf("移动函数地址表中...\n");
  memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfFunctions,pExportDirectory->NumberOfFunctions*4);
  pExportDirectory->AddressOfFunctions=(DWORD)pSectionHeader->VirtualAddress+offset;
  offset=pExportDirectory->NumberOfFunctions*4;
  //移动测试: 
  printf("函数地址表移动测试:\n");
//  printf("%x\n",*AddressOfFunctions);
//  printf("%x\n",*(PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData));
//  AddressOfFunctions=(char*)(NewFileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions));
//  printf("%x",*AddressOfFunctions);
  for(i=0;i<pExportDirectory->NumberOfFunctions;i++){
    printf("下标:%d     函数地址:0x%x\n",i,*(PWORD)((DWORD)AddressOfFunctions+i*4));
  }
  printf("函数地址表移动成功。\n");
  printf("移动函数导出序号表中...\n");
  memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfNameOrdinals,pExportDirectory->NumberOfNames*2);
  pExportDirectory->AddressOfNameOrdinals=pSectionHeader->VirtualAddress+offset;
  offset+=pExportDirectory->NumberOfNames*2;
  printf("函数导出序号表移动测试:\n");
  for(i=0;i<pExportDirectory->NumberOfNames;i++){
    AddressOfNameOrdinals=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNameOrdinals+i*2));
    printf("下标:%d   函数导出序号:0x%x\n",i,*AddressOfNameOrdinals);
  }
  printf("函数导出序号表移动成功。\n");
  offset+=pExportDirectory->NumberOfNames*4;
  printf("移动函数名称表中...\n");
  memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfNames,pExportDirectory->NumberOfNames*4);
  offset+=pExportDirectory->NumberOfNames*2;
  printf("函数名称表移动成功。\n");
  //移动函数名称字符串
  int p=0;
  for (i = 0; i < pExportDirectory->NumberOfNames; i++){
    AddressOfNames=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNames));
    char* Name=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,*(AddressOfNames+i)));
    memcpy((PVOID)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset + p),Name, strlen(Name)+1);
    printf("下标:%d,函数名:%s\n", i, (char*)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset + p));
    p += strlen(Name)+1;
    AddressOfNames += 1;
  }
  printf("函数名称移动成功。\n");
  offset+=p;
  printf("导出表长度:%d\n",sizeof(IMAGE_EXPORT_DIRECTORY));
  //拷贝导出表到新表
  pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = pSectionHeader->VirtualAddress + offset;
  memcpy((PVOID)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset), pExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY));
  offset+=sizeof(IMAGE_SECTION_HEADER);
  printf("%x",pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  return NewFileBuffer;
}
//*************************************移动重定位表***************************************
//该函数需要一个指针,指向FileBuffer 
//该函数需要一个整形参数,表示FileBuffer的大小 
//该函数将在原来节表的基础上新增一个节,用于存放移动后的重定位表
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向移动重定位表后的地址 
//****************************************************************************************
char* RemoveBaseRelocation(char* FileBuffer,int SizeOfFileBuffer){
  char* NewFileBuffer=NULL;
  int offset=0;
  int i;
  int SizeOfRelocation=0; 
  PIMAGE_DOS_HEADER pDosHeader=NULL;
  PIMAGE_FILE_HEADER pFileHeader=NULL;
  PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
  PIMAGE_SECTION_HEADER pSectionHeader=NULL;
  PIMAGE_BASE_RELOCATION pBaseRelocation=NULL;
  NewFileBuffer=AddNewSection(FileBuffer,SizeOfFileBuffer);
  pDosHeader=(PIMAGE_DOS_HEADER)NewFileBuffer;
  if(*(PWORD)((DWORD)NewFileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
    printf("检测到有效的PE标志。\n");
  }else{
    printf("未检测到有效的PE标志!\n");
  }
  pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)NewFileBuffer+pDosHeader->e_lfanew+4);
  pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
  pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+RVAToFOA(NewFileBuffer,pFileHeader->SizeOfOptionalHeader));
  for(i=1;i<pFileHeader->NumberOfSections;i++){
    pSectionHeader++;
  }
  if (!pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
  {
    printf("该文件没有重定向表!\n");
    return;
  }
  pBaseRelocation=(PIMAGE_BASE_RELOCATION)(NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress ));
  while(pBaseRelocation->VirtualAddress&&pBaseRelocation->SizeOfBlock){
    SizeOfRelocation+=pBaseRelocation->SizeOfBlock;
    pBaseRelocation=(PDWORD)((DWORD)pBaseRelocation+pBaseRelocation->SizeOfBlock);
  }
  SizeOfRelocation+=8;
  //memcpy(PVOID((DWORD)pNewFileBuffer + pNewSectionHeader->PointerToRawData ), pRelocationTable, SizeOfRelocationTable);
  memcpy((PVOID)(NewFileBuffer+pSectionHeader->PointerToRawData),NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress),SizeOfRelocation);
  pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress=pSectionHeader->PointerToRawData;
  printf("重定位表移动成功。\n"); 
  //检测重定位表移动
  pBaseRelocation=(PIMAGE_BASE_RELOCATION)(NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress ));
  i=1;
  while(pBaseRelocation->VirtualAddress&&pBaseRelocation->SizeOfBlock){
    printf("******                                          第%d个块                                          ******\n",i);
    printf("VirtualAddress:0x%x\nSizeOfBlock:0x%x\n",pBaseRelocation->VirtualAddress,pBaseRelocation->SizeOfBlock);
    pBaseRelocation = (IMAGE_BASE_RELOCATION*)(pBaseRelocation->SizeOfBlock + (DWORD)pBaseRelocation);
    i++;
  }
  return NewFileBuffer;
}

main.c:

#include <stdio.h>
int main(int argc, char** argv) {
  char filename1[50];
  char filename2[50];
  char* FileBuffer=NULL;
  char* NewFileBuffer=NULL;
  int length;
  FILE* fp;
  printf("请输入您想要操作的文件名:");
  scanf("%s",filename1);
  FileBuffer=ReadToFileBuffer(filename1);
  length=SizeOfFile(filename1);
  NewFileBuffer=RemoveBaseRelocation(FileBuffer,length);
  printf("请输入您想要保存的文件名:");
  if((fp=fopen(filename2,"wb"))==NULL){
    printf("新建文件失败!\n");
    exit(0); 
  }else{
    printf("新建文件成功。\n");
  }
  memcpy(fp,NewFileBuffer,length+1000);
  if(
  fclose(!fp)){
    printf("数据写入成功。");
  }else{
    printf("文件写入失败!");
    exit(0); 
  }
  free(FileBuffer);
  free(NewFileBuffer);
  return 0;
}

文章中若有语法错误或理解错误,还请大家指出来,我会非常虚心地学习,希望大家共同进步!

相关文章
|
8天前
|
存储 缓存 C++
C++链表常用的函数编写(增查删改)内附完整程序
C++链表常用的函数编写(增查删改)内附完整程序
|
8天前
|
关系型数据库 MySQL
Mysql基础第十六天,分组数据
Mysql基础第十六天,分组数据
20 0
|
11月前
|
存储 编译器 数据安全/隐私保护
移动导出表,移动重定位表【滴水逆向三期51笔记+作业源码】(上)
移动导出表,移动重定位表【滴水逆向三期51笔记+作业源码】
|
11月前
|
存储 索引
导入表解析,IAT表解析【滴水逆向三期53笔记】
导入表解析,IAT表解析【滴水逆向三期53笔记】
|
11月前
|
存储 C语言
PE导出表,C语言打印导出表信息【滴水逆向三期49笔记+作业】(上)
PE导出表,C语言打印导出表信息【滴水逆向三期49笔记+作业】
|
11月前
|
存储 C语言
PE导出表,C语言打印导出表信息【滴水逆向三期49笔记+作业】(下)
PE导出表,C语言打印导出表信息【滴水逆向三期49笔记+作业】
|
11月前
新增节添加ShellCode【滴水逆向三期46作业源码】
新增节添加ShellCode【滴水逆向三期46作业源码】
|
11月前
|
编译器
进程4GB空间简析,PE重定位表【滴水逆向三期50笔记+作业】
进程4GB空间简析,PE重定位表【滴水逆向三期50笔记+作业】
|
11月前
|
C语言
【滴水逆向三期41作业】C语言提取文件PE头部信息
【滴水逆向三期41作业】C语言提取文件PE头部信息
|
11月前
|
存储 安全 数据安全/隐私保护
骚操作:隐藏代码到数据区,函数指针【滴水逆向三期37笔记】
骚操作:隐藏代码到数据区,函数指针【滴水逆向三期37笔记】

热门文章

最新文章

相关实验场景

更多