PE添加一个弹窗(MssageBox)

 主要是在一个exe程序中添加一个弹窗

首先需要了解一下PE格式,下面是PE格式图

DOS头是程序最开始的位置

其中比较重要的两个字段e_magic和e_lfanew字段

e_magic 里面值是 “MZ”标记 可以通过这个标记判断是否是可执行文件

e_lfanew 是PE头相对于文件的偏移,通过这个偏移可以找到PE头

DOS头结构如下

typedef struct _IMAE_DOS_HEADER {		//DOS .EXE header                                    位置
	WORD e_magic;						//Magic number;                                      0x00
	WORD e_cblp;                        //Bytes on last page of file                         0x02
	WORD e_cp;                          //Pages in file										 0x04
	WORD e_crlc;                        //Relocations                                        0x06
	WORD e_cparhdr;						//Size of header in paragraphs                       0x08
	WORD e_minalloc;                    //Minimum extra paragraphs needed                    0x0A
	WORD e_maxalloc;					//Maximum extra paragraphs needed                    0x0C
	WORD e_ss;                          //Initial (relative) SS value						 0x0E
	WORD e_sp;							//Initial SP value									 0x10
	WORD e_csum;						//Checksum											 0x12
	WORD e_ip;							//Initial IP value									 0x14
	WORD e_cs;							//Initial (relative) CS value                        0x16
	WORD e_lfarlc;						//File address of relocation table                   0x18
	WORD e_ovno;						//Overlay number                                     0x1A
	WORD e_res[4];						//Reserved words                                     0x1C
	WORD e_oemid;						//OEM identifier (for e_oeminfo)                     0x24
	WORD e_oeminfo;						//OEM information; e_oemid specific                  0x26 
	WORD e_res2[10];					//Reserved words                                     0x28
	LONG e_lfanew;						//File address of new exe header                     0x3C
} IMAGE_DOS-HEADER, *PIMAGE_DOS_HEADER;

NT头包含PE头和可选PE头

Signature 是标识PE 0x00004550

IMAGE_FILE_HEADER  就是pe头

IMAGE_OPTIONAL_HEADER32  是可选PE头

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

下面是PE头

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

PE头下比较重要的属性

NumberOfSections  节表数量

SizeOfOptionalHeader 可选PE头的大小

下面是可选PE头

//
// Optional header format.
//

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

可选PE头下比较重要的属性

ImageBase  文件在内存中的起始地址

SizeOfImage  拉伸后的内存大小

SizeOfHeaders  dos+nt+节表 对齐后的大小

下面是节表

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

节表中比较重要的属性

Misc.VirtualSize 内存中一个节的大小

VirtualAddress  内存中节开始的地址偏移(RVA

SizeOfRawData 磁盘中这个节对齐后的大小

PointerToRawData 磁盘中节开始的地址偏移

简单来说就是使用跳转到MessageBox的地址在跳回来,当然也可以跳转到自己的代码。

首先需要找到MessageBox的地址,打开od,加载一个exe,在命令行输入bp MessageBoxA,这样就会在断点里面看到MessageBox的地址了

其中需要注意的是跳转的地址,e8后面就是需要计算的地址,

  • x是E8后面真正跟着的地址
  • 真正跳转的地址 = E8这条指令的下一行地址 + x
  • x = 真正跳转的地址 - E8这条指令的下一行地址
  • E8的这条指令的下一个地址 是 硬编码E8指令的长度 = 5个字节
  • x = 要跳转的地址  - (E8的地址 + 5)

拉伸是指exe在文件模式下转换到运行模式中的过程

左边FIleBuffer是指exe在文件中状态,右边ImageBuffer是指exe运行中状态,红色部分代表数据区,由此可见 文件中状态的数据区和运行中状态的数据区是不同的,而我们关心的是exe运行后加载一个MessageBox,所以需要进行拉伸。

// PeAddMessage.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//下面是添加一个MessageBox 添加到一个exe程序中!
#define  _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<stdio.h>
#include<stdlib.h>

int                Deviation = 0;        //偏移
PIMAGE_DOS_HEADER DOSHANDER = NULL;//DOS头
PIMAGE_NT_HEADERS NTHEADERS = NULL;//NT头
PIMAGE_SECTION_HEADER        SECTION[100];//节表
BYTE shellcode[] = {
0x6a,00,0x6a,00,0x6a,00,0x6a,00,//6a是push 
0xe8,00,00,00,00,        //e8是call的硬编码
0xe9,00,00,00,00        //e9是jmp的硬编码
};


DWORD CodeAddressp = (DWORD) & MessageBox;  //要跳转的地址
//x = 跳转的地址 - (E8的地址 + 5) 
/*
1.文件加载到内存
    1.1 malloc申请内存
    1.2 memset初始化申请的内存
    1.3 open打开文件
    1.4 frend读取文件到内存
    1.5 给PE结构体赋值
        1.5.1 获取DOS头大小
        1.5.2 获取NT头大小
        1.5.3 获取节表
2.进行拉伸
    2.1 malloc申请内存
    2.2 memset初始化申请的内存
    2.3 SizeOfHeaders拷贝头
        2.4 拷贝节表
3.还原
        3.1 malloc申请内存
        3.2 memset初始化申请的内存
        3.3 拷贝头
        3.4 拷贝节表
4.存盘
*/
char* FileDirectory = (char*)"C:\\Users\\A\\source\\repos\\test\\Debug\\WindowsProject1.exe";    //打开的exe路径
char* FileDirectorytu = (char*)"C:\\Users\\A\\source\\repos\\test\\Debug\\WindowsProject2.exe";    //重新存储的exe路径
//获取文件大小
int _GetFileSize(char* FileRoute)
{
    int size = 0;
    FILE* p = fopen(FileRoute, "r");
    fseek(p, 0L, SEEK_END);
    //获取文件大小
    size = ftell(p);
    fclose(p);
    return size;
}

int size = _GetFileSize(FileDirectory); //文件大小

BYTE* FileBuller(char* FileDirectory)
{
    int Deviation = 0;//偏移
    //读取文件
    BYTE* _FileBuller = (BYTE*)malloc(sizeof(BYTE) * size + 1);//申请内存
    if (_FileBuller == NULL)
    {
        printf("申请内存错误");
    }
    //初始化内存
    memset(_FileBuller, 0, size + 1);

    //打开文件
    FILE* p = fopen(FileDirectory, "rb");
    if (p == NULL)
    {
        printf("读取文件错误");
    }
    //读取文件
    int x = fread(_FileBuller, sizeof(BYTE), size, p);
    //给结构体赋值
    //dos头大小
    DOSHANDER = (PIMAGE_DOS_HEADER)(_FileBuller + Deviation);
    Deviation += DOSHANDER->e_lfanew;
    //nt头大小
    NTHEADERS = (PIMAGE_NT_HEADERS)(_FileBuller + Deviation);
    Deviation += sizeof(IMAGE_NT_HEADERS);
    //获取节表
    for (int f = 0; f < NTHEADERS->FileHeader.NumberOfSections; f++)
    {
        SECTION[f] = (PIMAGE_SECTION_HEADER)(Deviation + _FileBuller);
        Deviation += sizeof(IMAGE_SECTION_HEADER);                    //下一个节表的偏移
    }
    fclose(p);
    return _FileBuller;
}

int nSection = 0;

BYTE* ImageBuffer(BYTE* _FileBuller)//拉伸
{
    //申请内存
    BYTE* _ImageBuffer = (BYTE*)malloc(sizeof(BYTE) * NTHEADERS->OptionalHeader.SizeOfImage + 1);
    if (_ImageBuffer == NULL)
    {
        printf("分配内存失败");
    }
    //初始化内存
    memset(_ImageBuffer, 0, NTHEADERS->OptionalHeader.SizeOfImage);
    //拷贝头
    memcpy(_ImageBuffer, _FileBuller, sizeof(BYTE) * NTHEADERS->OptionalHeader.SizeOfHeaders);
    //拷贝节表
    for (int q = 0; q < NTHEADERS->FileHeader.NumberOfSections; q++)
    {
        int _imageSECTION = SECTION[q]->VirtualAddress;
        int _fileSECTION = SECTION[q]->PointerToRawData;
        memcpy(_ImageBuffer + _imageSECTION, _FileBuller + _fileSECTION, SECTION[q]->SizeOfRawData);
    }
    return _ImageBuffer;
}
void Message(BYTE* _ImageBuffer, BYTE* _FileBuller)
{
    /*
    在一个程序中添加一个MessageBox
    */
    //计算的地址第一个节表空白的地址
    BYTE* PCodeOffset = (BYTE*)(((BYTE*)_ImageBuffer) + SECTION[nSection]->VirtualAddress + SECTION[nSection]->Misc.VirtualSize);
    //OEP要跳转的地址
    int CodeOffset = SECTION[nSection]->VirtualAddress + SECTION[nSection]->Misc.VirtualSize;
    //修改OEP
    DWORD OEP = NTHEADERS->OptionalHeader.AddressOfEntryPoint;
    NTHEADERS->OptionalHeader.AddressOfEntryPoint = CodeOffset;
    //E8CALL
    BYTE* a = shellcode;
    a += 9;//a是数组e8后面的地址
    a = (BYTE*)(CodeAddressp - (DWORD)(((CodeOffset + 8) + 5) + NTHEADERS->OptionalHeader.ImageBase));//把计算出来的地址赋值给a, 要跳转的地址 - (e800000000下一个地址 + ImageBase)因为在内存中运行所以要加ImageBase
    *(DWORD*)(shellcode + 9) = (DWORD)a;                //a在赋值给数组
    memcpy(PCodeOffset, shellcode, 18);        //把数组拷贝到内存
    //E9JMP
    BYTE* b = shellcode;
    b += 14;
    b = (BYTE*)((OEP + NTHEADERS->OptionalHeader.ImageBase) - (DWORD)(((CodeOffset + 13) + 5) + NTHEADERS->OptionalHeader.ImageBase));
    *(DWORD*)(shellcode + 14) = (DWORD)b;
    memcpy(_ImageBuffer, _FileBuller, sizeof(BYTE) * NTHEADERS->OptionalHeader.SizeOfHeaders);
    memcpy(PCodeOffset, shellcode, 18);
}
void NewBuffer(BYTE* _ImageBuffer)
{
    BYTE* _NewBuffer = (BYTE*)malloc(sizeof(BYTE) * size + 1);//申请内存
    if (_NewBuffer == NULL)
    {
        printf("申请内存错误");
    }
    memset(_NewBuffer, 0, size + 1);//初始化内存
    //拷贝头
    memcpy(_NewBuffer, _ImageBuffer, sizeof(BYTE) * NTHEADERS->OptionalHeader.SizeOfHeaders);
    //拷贝节表
    for (int x = 0; x < NTHEADERS->FileHeader.NumberOfSections; x++)
    {
        int _imageSECTION = SECTION[x]->VirtualAddress;
        int _fileSECTION = SECTION[x]->PointerToRawData;
        memcpy(_NewBuffer + _fileSECTION, _ImageBuffer + _imageSECTION, SECTION[x]->SizeOfRawData);
    }
    FILE* p = fopen(FileDirectorytu, "wb+");
    fwrite(_NewBuffer, sizeof(BYTE), sizeof(BYTE) * size + 1, p);
}
void main()
{
    BYTE* x = FileBuller(FileDirectory);        //读取到内存
    BYTE* y = ImageBuffer(x);//内存操作
    Message(y, x);//添加一个弹窗
    NewBuffer(y);//存盘
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值