IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> day34.1-扩大节、合并节 -> 正文阅读

[C++知识库]day34.1-扩大节、合并节

作者:https://csdnimg.cn/release/blogv2/dist/components/js/pc_wap_commontools-6cd02ebed1.min.js

一、添加代码的方式

  • 我们现在学过的有:直接在任意节的空白区添加代码;新增节添加代码;扩大最后一个节添加代码;今天要学习合并节并添加代码

二、合并节思路

  • 必须使用拉伸后的合并!因为你要修改节表的字段的,如果使用硬盘上的修改,那么大小和地址都是对不上的

    所以如果我们使用winhex或者UE打开一个文件直接做合并结果肯定是错误的,所以只能拿程序对拉伸后的做修改

  • 合并节就是:把第一个节开始一直到最后一个节的结尾都当成第一个节

  • 但是会造成合并后文件变大,因为如果把所有节合并,那么节与节之间就不再考虑内存对齐或者文件对齐了,由于我们是在文件装载到内存后合并的节,如果内存对齐和文件对齐不一样,那么最后将合并后的文件再还原成硬盘上的状态时,所有的节会当成一个整体,不会再文件对齐了,所以就导致了合并后文件可能会变大

  • 步骤:

    1. NumberOfSections改成1

    2. 修改第一个节表的字段

      • VirtualSize:方法一,SizeOfImage - 第一个节VirtualAddress;方法二,还可以通过最后一个节的VirtualAddress + 最后一个节的VirtualSize内存对齐后的大小 - SizeOfHeader内存对齐后的大小
      • SizeOfRawData:等于VirtualSize
    3. 将第一个节的属性改为包含所有节的属性,即用第一个节的属性与其他的节的属性做运算

三、作业

1.扩大最后一个节,保证程序正常运行(手动)

day33.1中写过用编程实现扩大节,所以今天再试着用手动的方式体会一下扩大节,由于手动的时候是在FileBuffer中操作,所以有些值的计算包括扩大的大小都是需要计算的,没有在ImageBuffer中扩大节那么方便

  • 打开notepad.exe程序,如果我们想扩大0x1000字节,则需要修改SizeOfImage,0x13000 + 0x1000内存对齐后 = 0x14000(我们知道notepad.exe的内存对齐为0x1000;文件对齐为0x200)

    image-20211231114041243
  • 接着找到最后一个节表,修改VirtualSize = 原来的0x8948内存对齐后0x9000 + 0x1000内存对齐后 = 0xA000

  • SizeOfRawData = VirtualSize即可

  • 最后将最后一个节的属性0x40000040与0x60000020亦或得到0x60000060

    image-20211231114508991
  • 最后最关键的一步就是在最后一个节末尾扩大节,我们知道如果在ImageBuffer中扩大节,就直接在末尾加上0x1000字节即可,但是由于现在是在FileBuffer中操作,不能直接扩大0x1000了,不然就跟SizeOfData对不上,我们要通过计算来得到:先得到最后一个节原来在文件中起始偏移地址为PointerToRawData = 0x7800,SizeOfRawData为0x8A00,那么最后一个节的末尾为0x10200。由于扩大后的SizeOfRawData = 0xA000,而PointerToRawData不变还是0x7800,所以扩大后最后一个节的结尾应该为0xA000 + 0x7800 = 0x11800,那么就应该新增的大小为0x11800 - 0x10200 = 0x1600,换算成十进制为5632。所以在文件末尾0x101FF处右键–Edit–Paste Zero Bytes–输入5632即可

    image-20211231115647352
  • 保存运行,再拖入PEtool中查看是否修改成功

    image-20211231114651836

2.编码实现合并节

#include "stdafx.h"
#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首地址返回
}


//FileBuffer到ImageBuffer
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需要的大小(day30没有解决的问题,这里解决了)
    //使用最后一个节的文件偏移地址 + 最后一个节对齐后的大小
    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;
}

//合并节
char* combineSections(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结构体类型指针
    
    //新开辟一块内存
    char* combineImageBuffer = (char*)malloc(opp->SizeOfImage);
    if(NULL == combineImageBuffer){
        printf("动态申请失败\n");
        return NULL;
    }
	for(int k = 0;k < opp->SizeOfImage;k++){
		*(combineImageBuffer + k) = *(imageBufferp + k);
	}
    dosp = (Dos*)combineImageBuffer; //定义DOS结构体类型指针
    filep = (File*)(combineImageBuffer + dosp->e_lfanew + 4);//定义File结构体类型指针
    opp = (Op*)((char*)filep + 20);//定义Op结构体类型指针
    secp = (Sec*)((char*)opp + filep->SizeOfOptionalHeader);//定义Sec结构体类型指针
    
    //修改节的数量
	int tempNumberOfSections = filep->NumberOfSections;
    filep->NumberOfSections = 1;
    
    //修改第一个节表属性
    secp->Misc.VirtualSize = opp->SizeOfImage - secp->VirtualAddress;
    secp->SizeOfRawData = secp->Misc.VirtualSize;
    int characteristics = secp->Characteristics;//先等于第一个节的属性
    for(int j = 1;j < tempNumberOfSections;j++){
        characteristics = characteristics | (secp + j)->Characteristics;
    }
    secp->Characteristics = characteristics;
    
    printf("合并节成功\n");
    return combineImageBuffer;
}

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){
        free(fileBuffer);
        fileBuffer = NULL;
        return 0;
    }
    
    //合并节(ImageBuffer->CombineImageBuffer)
    char* combineImageBuffer = combineSections(imageBuffer);
    if(NULL == combineImageBuffer){
        free(fileBuffer);
    	free(imageBuffer);
        fileBuffer = NULL;
    	imageBuffer = NULL;
        return 0;
    }
    
    //combineImageBuffer到NewBuffer
    char* newBuffer = imageBufferToNewBuffer(combineImageBuffer);
    if(NULL == newBuffer){
        free(fileBuffer);
        free(imageBuffer);
		free(combineImageBuffer);
        fileBuffer = NULL;
    	imageBuffer = NULL;
		combineImageBuffer = NULL;
        return 0;
    }
    
    //存盘
    char destFilePath[] = "D:\\notepad_new.exe";
    int isSuccessed2 = save(destFilePath,newBuffer);
    if(!isSuccessed2){
        free(fileBuffer);
		free(imageBuffer);
		free(newBuffer);
		free(combineImageBuffer);
		fileBuffer = NULL;
		combineImageBuffer = NULL;
		imageBuffer = NULL;
		newBuffer = NULL;
		return 0;
    }
    
    free(fileBuffer);
    free(imageBuffer);
    free(newBuffer);
	free(combineImageBuffer);
    fileBuffer = NULL;
	combineImageBuffer = NULL;
    imageBuffer = NULL;
    newBuffer = NULL;
    return 0;
}

3.定义函数,能够返回对齐后的大小

  • 说明:定义一个函数Align(int x,int y),第一个参数为我们手动输入的字节大小,第二个参数为文件对齐大小或者内存对齐大小,现在功能是如果我们传入0x222字节,文件对齐大小为0x200,那么计算0x222文件对齐后的大小为多少;如果传入0x1222字节,内存对齐大小为0x1000,那么计算0x1222内存对齐后的大小是多少

  • 代码如下:

    #include "stdafx.h"
    int Align(int x,int y){
        if(x <= 0 || y <= 0){
            printf("输入的数据不合法\n");
            return 0;
        }
        return ((x - 1) / y + 1) * y;
    }
    int main(int argc,char* argv[]){
    	printf("%x",Align(0x3700,0x1000)); //0x4000
    	return 0;
    }
    

    为什么x - 1,因为如果y = 0x200,我们传入的x就是0x200的话,理论上最后对齐的大小为0x200,但是如果不减1,0x200 / 0x200 = 1,1 + 1 = 2,2 * 0x200 = 0x400,就变成了0x400,但是我们如果x减1后再做运算,结果就是正确的,而且其他的情况也成立了;还有C语言中/号会自动向下取整

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 10:59:30  更:2022-05-05 11:03:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 4:48:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码