FileBfufer转ImageBuffer【滴水逆向三期43作业源码】

简介: FileBfufer转ImageBuffer【滴水逆向三期43作业源码】

作业要求我们在上一章已经说明了,还有不懂的可以去上一张看一下,这里直接给出源码,代码我们就不做解释了,自己写出来或着自己理解一遍或许对PE会有更好的理解。

编写一个程序,实现从FileBuffer拉升到ImageBuffer再转回FileBuffer并且完成存盘:

这是主函数部分:

#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include "Function.h"
int main(int argc, char** argv) {
  char *File_Buffer,*Image_Buffer,*New_Buffer;
  char filepath[]="E:\\个人\\逆向\\练习.exe";
  //打开文件,读取到File_Buffer
  File_Buffer=ReadToFile_Buffer(filepath);
  //将File_Buffer拉伸存到Image_Buffer 
  Image_Buffer=FileBufferToImageBuffer(File_Buffer);
  //将Image_Buffer再存到New_Buffer
  New_Buffer=ImageBufferToNewBuffer(Image_Buffer);
  //将文件存盘
  char newname[]="NewBuffer.exe";
  save(newname,New_Buffer);
  //释放申请的内存
  free(File_Buffer);
  free(Image_Buffer);
  free(New_Buffer); 
  return 0;
}

这是Function(函数说明部分):

//打开文件,将数据读取到Fiel_Buffer
//该函数返回值为一个指针,指向File_Buffer
char*ReadToFile_Buffer(char *filepath){
  FILE *fp;
  char *File_Buffer=NULL;
  int length;
  //打开文件 
  if((fp=fopen(filepath,"rb"))==NULL){
    printf("文件打开失败!\n");
    exit(0);
  }else{
    printf("打开文件成功。\n");
  }
  //计算文件大小
  fseek(fp,0,SEEK_END);
  length=ftell(fp);
  fseek(fp,0,SEEK_SET);
  //动态申请内存
  File_Buffer=(char*)malloc(length)
  if(File_Buffer==NULL){
    printf("申请内存失败!\n");
  }else{
    printf("申请内存成功。\n");
  }
  //将文件数据读取到File_Buffer
  if(fread(File_Buffer,1,length,fp)){
    printf("读取文件成功。\n"); 
  }else{
    printf("读取文件失败!\n");
  }
  //关闭文件
  if(fclose(fp)){
    printf("关闭文件失败!\n");
    exit(0);
  }else{
    printf("关闭文件成功。\n");
  }
  return File_Buffer;
}
//将Fiel_Buffer读取到Image_Buffer
//该函数返回一个指针,指向Image_Buffer
char *FileBufferToImageBuffer(char *File_Buffer){
  char *Image_Buffer=NULL;
  IMAGE_DOS_HEADER *pDosHeader=(IMAGE_DOS_HEADER*)File_Buffer;
  IMAGE_FILE_HEADER *pFileHeader=(IMAGE_FILE_HEADER*)(File_Buffer+pDosHeader->e_lfanew+4);
  IMAGE_OPTIONAL_HEADER *pOptionalHeader=(IMAGE_OPTIONAL_HEADER*)((char*)pFileHeader+20);
  IMAGE_SECTION_HEADER *pSectionHeader=(IMAGE_SECTION_HEADER*)((char*)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
  //动态申请内存
  Image_Buffer=(char*)malloc(pOptionalHeader->SizeOfImage);
  if(Image_Buffer==NULL){
    printf("内存申请失败!\n");
  }else{
    printf("内存申请成功。\n");
  }
  //初始化申请的内存
  int i=0;
  while(i<=pOptionalHeader->SizeOfImage){
    *(Image_Buffer + i)= 0x00; 
    i++; 
  } 
  //读取数据到Image_Buffer
  //复制所有头
  int j=0;
  for(j=0;j<pOptionalHeader->SizeOfHeaders;j++){
    *(Image_Buffer + j)= *(File_Buffer + j);
  }
  //复制所有节信息
  int k,x;
  for(k=0;k<pOptionalHeader->SizeOfHeaders;k++){
    for(x=0;x<pSectionHeader->SizeOfRawData;x++){
      *(Image_Buffer+pSectionHeader->VirtualAddress)=*(File_Buffer+pSectionHeader->PointerToRawData+x);
    }
    pSectionHeader++;
  }
  return Image_Buffer;
}
//将Image_Buffer存到New_Buffer
//该函数需要一个指向File_Buffer的指针
//该函数返回一个指针,指向New_Buffer 
char *ImageBufferToNewBuffer(char *Image_Buffer){
  char *New_Buffer;
  //定义PE头部结构体
  IMAGE_DOS_HEADER *pDosHeader=(IMAGE_DOS_HEADER*)Image_Buffer;
  IMAGE_FILE_HEADER *pFileHeader=(IMAGE_FILE_HEADER*)(Image_Buffer+pDosHeader->e_lfanew+4);
  IMAGE_OPTIONAL_HEADER *pOptionalHeader=(IMAGE_OPTIONAL_HEADER*)((char*)pFileHeader+20);
  IMAGE_SECTION_HEADER *pSectionHeader=(IMAGE_SECTION_HEADER*)(pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
  //计算所需内存大小
  IMAGE_SECTION_HEADER *temp=pSectionHeader;
  temp=pSectionHeader+pFileHeader->NumberOfSections-1;
  int length=temp->PointerToRawData+temp->VirtualAddress;
  //申请内存
  New_Buffer=(char*)malloc(length);
  //初始化申请的内存
  int i;
  for(i=0;i<length;i++){
    *(New_Buffer+i)=0x00;
  } 
  //复制所有头
  int j;
  for(j=0;j<pOptionalHeader->SizeOfHeaders;j++){
    *(New_Buffer+j)=*(Image_Buffer+j);
  }
  //复制所有节
  int k,x;
  for(k=0;k<pFileHeader->NumberOfSections;k++){
    for(x=0;x<pSectionHeader->SizeOfRawData;x++){
      *(New_Buffer+pSectionHeader->PointerToRawData+x)=*(Image_Buffer+pSectionHeader->PointerToRawData+x);
    }
    pSectionHeader++; 
  }
  return New_Buffer;
}
void save(char *newname,char *New_Buffer){
  //定义PE头部结构
  IMAGE_DOS_HEADER *pDosHeader=(IMAGE_DOS_HEADER*)New_Buffer;
  IMAGE_FILE_HEADER *pFileHeader=(IMAGE_FILE_HEADER*)((char*)New_Buffer+pDosHeader->e_lfanew+4);
  IMAGE_OPTIONAL_HEADER *pOptionalHeader=(IMAGE_OPTIONAL_HEADER*)((char*)pFileHeader+0x20);
  IMAGE_SECTION_HEADER *pSectionHeader=(IMAGE_SECTION_HEADER*)(pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
  //计算New_Buffer大小
  IMAGE_SECTION_HEADER *temp=pSectionHeader;
  temp=pSectionHeader+pFileHeader->NumberOfSections-1; 
  int length=temp->PointerToRawData+temp->VirtualAddress;
  //新建文件
  FILE *fp;
  if((fp=fopen(newname,"wb"))==NULL){
    printf("文件新建失败!\n");
  }else{
    printf("文件新建成功。\n");
  }
  //将New_Buffer读写到文件中
  if(fwrite(New_Buffer,length,1,fp)){
    printf("存盘成功。\n");
  }else{
    printf("存盘失败!\n");
    exit(0);
  }
  if(fclose(fp)){
    printf("关闭文件成功。\n");
  }else{
    printf("关闭文件失败!\n");
  }
}

代码中还有很多可以优化的地方,或者是有一些错误的地方希望大家指出来,我会非常虚心地学习,也希望我们能够共同进步!

在博客中我还发现另一个很不错的源码:day30.1-FileBuffer-ImageBuffer

#include "stdafx.h"
#include "stdlib.h"
#define IMAGE_SIZEOF_SHORT_NAME 8
//*******************************************************************************
#pragma pack(1)
typedef struct DOS_HEADER{  //DOS头字段
    short e_magic;
    short e_cblp;
    short e_cp;
    short e_crlc;
    short e_cparhdr;
    short e_minalloc;
    short e_maxalloc;
    short e_ss;
    short e_sp;
    short e_csum;
    short e_ip;
    short e_cs;
    short e_lfarlc;
    short e_ovno;
    short e_res[4];
    short e_oemid;
    short e_oeminfo;
    short e_res2[10];
    int e_lfanew;  
}Dos;
#pragma pack()
//别忘了中间还有一个PE签名
#pragma pack(1)
typedef struct FILE_HEADER{   //标准PE头字段
    short Machine;
    short NumberOfSections;
    int TimeDateStamp;
    int PointerToSymbolTable;
    int NumberOfSymbols;
    short SizeOfOptionalHeader;
    short Characteristics;
}File;
#pragma pack()
#pragma pack(1)
typedef struct OPTIONAL_HEADER{   //可选PE头字段
    short Magic;
    char MajorLinkerVersion;
    char MinorLinkerVersion;
    int SizeOfCode;
    int SizeOfInitializedData;
    int SizeOfUninitializedData;
    int AddressOfEntryPoint;
    int BaseOfCode;
    int BaseOfData;
    int ImageBase;
    int SectionAlignment;
    int FileAlignment;
    short MajorOperatingSystemVersion;
    short MinorOperatingSystemVersion;
    short MajorImageVersion;
    short MinorImageVersion;
    short MajorSubsystemVersion;
    short MinorSubsystemVersion;
    int Win32VersionValue;
    int SizeOfImage;
    int SizeOfHeaders;
    int CheckSum;
    short Subsystem;
    short DllCharacteristics;
    int SizeOfStackReserve;
    int SizeOfStackCommit;
    int SizeOfHeapReserve;
    int SizeOfHeapCommit;
    int LoaderFlags;
    int NumberOfRvaAndSizes;
    //后面还有几个(16)个结构体,一个结构体8字节,我们先不研究,后面再说
}Op;
#pragma pack()    
#pragma pack(1)
typedef struct _IMAGE_SECTION_HEADER {
    char Name[IMAGE_SIZEOF_SHORT_NAME];  //宏定义使用
    union{
        int PhysicalAddress;
        int VirtualSize;
    }Misc;
    int VirtualAddress;
    int SizeOfRawData;
    int PointerToRawData;
    int PointerToRelocations;
    int PointerToLinenumbers;
    short NumberOfRelocations;
    short NumberOfLinenumbers;
    int Characteristics;
}Sec;
#pragma pack()
//*******************************************************************************
//将硬盘上的可执行文件数据复制一份存入FileBuffer中
char* readInFileBuffer(char* filePath){
    FILE* fp = NULL;
    char* p = NULL;
    fp = fopen(filePath,"rb");
    if(NULL == fp){
        printf("文件打开失败\n");
        fclose(fp);
        return NULL;
    }
    //计算文件长度
    fseek(fp,0,2);
    int len = ftell(fp);
    fseek(fp,0,0);
    //动态申请FileBuffer内存空间
    p = (char*)malloc(len);
    if(NULL == p){
        printf("FileBuffer内存空间分配失败\n");
        fclose(fp);
        return NULL;
    }
    //写入数据
    int isSuccessed = fread(p,len,1,fp);
    if(!isSuccessed){
        printf("写入FileBuffer失败\n");
        fclose(fp);
        free(p);
        return NULL;
    }
    fclose(fp);
    return p;  //将FileBuffer首地址返回
}
//PE装载
char* fileBufferToImageBuffer(char* fileBufferp){
    Dos* dosp = (Dos*)fileBufferp; //定义DOS结构体类型指针
    File* filep = (File*)(fileBufferp + dosp->e_lfanew + 4);//定义File结构体类型指针
    Op* opp = (Op*)((char*)filep + 20);//定义Op结构体类型指针
    Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//定义Sec结构体类型指针
    //动态申请ImageBuffer的内存空间
    char* ip = NULL;
    ip = (char*)malloc(opp->SizeOfImage);
    if(NULL == ip){
        printf("动态申请ImageBuffer内存失败\n");
        return NULL;
    }
    for(int i = 0;i < opp->SizeOfImage;i++){
        *(ip + i) = 0x00;
    }
    //复制所有头
    for(int j = 0;j < opp->SizeOfHeaders;j++){
        *(ip + j) = *(fileBufferp + j);
    }
    //复制所有节
    for(int k = 0;k < filep->NumberOfSections;k++){
        for(int x = 0;x < secp->SizeOfRawData;x++){
            *(ip + secp->VirtualAddress + x) = *(fileBufferp + secp->PointerToRawData + x);
        }
        secp++;
    }
    return ip; //返回ImageBuffer的起始地址
}
//ImageBuffer到NewBuffer
char* imageBufferToNewBuffer(char* imageBufferp){
    Dos* dosp = (Dos*)imageBufferp; //定义DOS结构体类型指针
    File* filep = (File*)(imageBufferp + dosp->e_lfanew + 4);//定义File结构体类型指针
    Op* opp = (Op*)((char*)filep + 20);//定义Op结构体类型指针
    Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//定义Sec结构体类型指针
    //计算newBuffer需要的大小
    //使用最后一个节的文件偏移地址 + 最后一个节对齐后的大小
    Sec* temp = secp;
    secp = secp + filep->NumberOfSections - 1;
    int len = secp->PointerToRawData + secp->SizeOfRawData;
    secp = temp;
    //动态分配NewBuffer内存
    char* np = (char*)malloc(len);
    if(NULL == np){
        printf("NewBuffer内存分配失败\n");
        return NULL;
    }
    for(int i = 0;i < len;i++){
        *(np + i) = 0x00;
    }
    //复制所有头
    for(int j = 0;j < opp->SizeOfHeaders;j++){
        *(np + j) = *(imageBufferp + j);
    }
    //复制所有节
    for(int k = 0;k < filep->NumberOfSections;k++){
        for(int x = 0;x < secp->SizeOfRawData;x++){
            *(np + secp->PointerToRawData + x) = *(imageBufferp + secp->VirtualAddress + x);
        }
        secp++;
    }
    return np; //返回NewBuffer的首地址
}
//将文件存盘
int save(char* savePath,char* newBufferp){
    Dos* dosp = (Dos*)newBufferp; //定义DOS结构体类型指针
    File* filep = (File*)(newBufferp + dosp->e_lfanew + 4);//定义File结构体类型指针
    Op* opp = (Op*)((char*)filep + 20);//定义Op结构体类型指针
    Sec* secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//定义Sec结构体类型指针
    FILE* fp = fopen(savePath,"wb");
    if(NULL == fp){
        printf("文件打开失败\n");
        fclose(fp);
        return 0;
    }
    secp = secp + filep->NumberOfSections - 1;
    int len = secp->PointerToRawData + secp->SizeOfRawData;  //得到newBuffer的大小
    int isSuccessed = fwrite(newBufferp,len,1,fp);
    if(!isSuccessed){
        printf("存盘失败\n");
        fclose(fp);
        return 0;
    }
    fclose(fp);
  printf("存盘成功\n");
    return 1;
}
int main(int argc,char*argv[]){
    //读入FileBuffer
    char filePath[] = "D:\\notepad.exe";
    char* fileBuffer = readInFileBuffer(filePath);
    if(NULL == fileBuffer){
        return 0;
    }
    //FileBuffer到ImageBuffer
    char* imageBuffer = fileBufferToImageBuffer(fileBuffer); 
    if(NULL == imageBuffer){
        printf("PE加载失败");
        free(fileBuffer);
        fileBuffer = NULL;
        return 0;
    }
    //ImageBuffer到NewBuffer
    char* newBuffer = imageBufferToNewBuffer(imageBuffer);
    if(NULL == newBuffer){
        free(fileBuffer);
        free(imageBuffer);
        fileBuffer = NULL;
      imageBuffer = NULL;
        return 0;
    }
    //存盘
    char destFilePath[] = "D:\\notepad_new.exe";
    int isSuccessed2 = save(destFilePath,newBuffer);
    if(!isSuccessed2){
        printf("存盘失败\n");
    }
    free(fileBuffer);
    free(imageBuffer);
    free(newBuffer);
    fileBuffer = NULL;
    imageBuffer = NULL;
    newBuffer = NULL;
    return 0;
}


相关文章
|
存储 前端开发 JavaScript
潮玩宇宙大逃杀无聊猿卷轴模式系统开发详细规则丨步骤需求丨方案项目丨技术架构丨源码功能
确定游戏类型和规则:明确无聊猿卷轴模式游戏类型和游戏规则,包括敌人类型、地图设计、任务类型、战斗机制等。
|
算法 程序员
从《阴阳师》到《原神》,抽卡中的程序算法
收集类的抽卡手游,是玩家们喜闻乐见的一类游戏,他们背后又有哪些程序算法?我们一起来探讨
2787 0
从《阴阳师》到《原神》,抽卡中的程序算法
|
3月前
|
数据可视化 算法 数据挖掘
【2022高教社杯数学建模】C题:古代玻璃制品的成分分析与鉴别方案及代码实现(已经更新完毕)
2022年高教社杯数学建模竞赛C题的详细分析、解题过程和代码实现,题目围绕古代玻璃制品的成分分析与鉴别,涉及表面风化分析、分类规律研究、未知类别鉴别和化学成分关联关系比较等多个问题。
65 1
【2022高教社杯数学建模】C题:古代玻璃制品的成分分析与鉴别方案及代码实现(已经更新完毕)
|
3月前
|
算法 C++
惊爆!KPM算法背后的秘密武器:一行代码揭秘字符串最小周期的终极奥义,让你秒变编程界周期大师!
【8月更文挑战第4天】字符串最小周期问题旨在找出字符串中最短重复子串的长度。KPM(实为KMP,Knuth-Morris-Pratt)算法,虽主要用于字符串匹配,但其生成的前缀函数(next数组)也可用于求解最小周期。核心思想是构建LPS数组,记录模式串中每个位置的最长相等前后缀长度。对于长度为n的字符串S,其最小周期T可通过公式ans = n - LPS[n-1]求得。通过分析周期字符串的特性,可证明该方法的有效性。提供的C++示例代码展示了如何计算给定字符串的最小周期,体现了KPM算法在解决此类问题上的高效性。
81 0
|
6月前
|
数据可视化 Go vr&ar
JCR一区7.4分|教科书般网药四件套+实验验证,廉颇老矣尚能饭否
该文章是一篇发表在《Journal of Translational Medicine》上的研究,探讨了白藜芦醇治疗糖尿病肾病(DKD)的机制。通过网络药理学、分子对接和实验验证,研究发现白藜芦醇可能通过作用于PPARA、SHBG、AKR1B1、PPARG、IGF1R、MMP9、AKT1和INSR等靶点影响DKD。分子对接和细胞实验进一步证实了这些发现,为白藜芦醇在DKD治疗中的应用提供了理论支持。
70 0
新增节添加ShellCode【滴水逆向三期46作业源码】
新增节添加ShellCode【滴水逆向三期46作业源码】
|
存储 编译器
FileBuffer转ImageBuffer【滴水逆向三期43笔记】
FileBuffer转ImageBuffer【滴水逆向三期43笔记】
新增节添加代码【滴水逆向三期46笔记】
新增节添加代码【滴水逆向三期46笔记】
|
存储 编译器
IAT表入门简析【滴水逆向三期52笔记】
IAT表入门简析【滴水逆向三期52笔记】