最近在看滴水视频,这一节作业老师没有给
需要的拿走,注释应该已经挺详细的了
#include <iostream>
#include "windows.h"
//要加的代码,此处为call messagebox,jmp到原oep
//0x6A 为push
//E8为call E9为jmp
uint8_t shellCode[] = {
0x6A, 0x00,
0x6A, 0x00,
0x6A, 0x00,
0x6A, 0x00,
0xE8, 0x00, 0x00, 0x00, 0x00,
0xE9, 0x00, 0x00, 0x00, 0x00
};
int main()
{
//***********************将文件拉倒内存里*****************************************************************
FILE* pFile = nullptr;
pFile = fopen("***/**.exe", "rb");//二进制方式打开你想修改的文件
//获取文件大小
fseek(pFile, 0, SEEK_END);
uint64_t fileSize = ftell(pFile);
fseek(pFile, 0, SEEK_SET);
// 分配内存空间
PVOID pFileBuffer = malloc(fileSize);
if (!pFileBuffer)
{
printf("分配空间失败!");
fclose(pFile);
return 0;
}
uint32_t n = fread(pFileBuffer, fileSize, 1, pFile);
if (!n)
{
printf("读取数据失败!");
free(pFileBuffer);
fclose(pFile);
return 0;
}
fclose(pFile);
//******************各种节表信息*************************************/
// 获取DOS头信息
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
LONG e_lfanew = pDosHeader->e_lfanew;
// 偏移 : e_lfanew + 4个字节的PE头标识
DWORD offset = e_lfanew + 0x4;
// 获取标准PE头指针
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + offset);
// 可选PE头紧挨着标准PE头, 相对偏移就是 sizeof(IMAGE_FILE_HEADER)
DWORD offsetByFileHeader = sizeof(IMAGE_FILE_HEADER);
PIMAGE_OPTIONAL_HEADER pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + offsetByFileHeader);
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + offset);
DWORD numberOfSection = pFileHeader->NumberOfSections;
if (numberOfSection <= 0)
{
printf("没有节表");
return 0 ;
}
// 通过标准PE头获取可选PE头大小
DWORD offsetByOptionalHeader = (pFileHeader->SizeOfOptionalHeader);
//第一个节表地址、如果想插入其他节,需要自己加偏移
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + offsetByOptionalHeader);
// 检查空白区域是否满足shellcode占用空间
DWORD alignment = pOptionHeader->FileAlignment;
DWORD virtualSize = pSectionHeader->Misc.VirtualSize;
DWORD virtualAvailableSize = alignment - (virtualSize % alignment);
if (virtualAvailableSize < sizeof(shellCode) * sizeof(char))
{
printf("空白空间不足,无法插入ShellCode\n");
return 0;
}
//*************************************编辑shellCode**************************************/
// ShellCode在内存中的位置RVA
DWORD shellCodeRva = pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize;
// ShellCode在内存中的位置VA
DWORD shellCodeVa = shellCodeRva + pOptionHeader->ImageBase;
// ShellCode在文件中的位置FOA, 此处如果需要插入其他节,需要重新计算foa
DWORD shellCodeFoa = pSectionHeader->PointerToRawData + pSectionHeader->Misc.VirtualSize;
// MessageBoxA函数地址 VA . 每次需要重新编译,或者自己找地址
DWORD msgVa = (DWORD)MessageBoxA;
// 计算E8
DWORD callVa = shellCodeFoa + 8; // 跳过前面的4个push
// E8指令操作数
DWORD callOpcode = msgVa - callVa - 5; // 计算差值并减去5个字节(E8指令长度)
// call地址更新shellCode
*(PDWORD)(shellCode + 9) = callOpcode;
// 计算E9
DWORD jmpVa = shellCodeFoa + 13; // 跳过前面的4个push 和 E8-call
// E9指令操作数
DWORD jmpOpcode = shellCodeFoa - jmpVa - -5;// 计算差值并减去5个字节(E9指令长度)
// jmp地址更新shellCode
*(PDWORD)(shellCode + 14) = jmpOpcode;
// 修改OEP
pOptionHeader->AddressOfEntryPoint = shellCodeRva;
//编辑好的shellCode存入buffer
memcpy((char*)((DWORD)pFileBuffer + shellCodeRva), shellCode, sizeof(shellCode));
// 将FileBuffer存盘
FILE* p_file = fopen("./new.exe", "wb");
fwrite(pFileBuffer, fileSize, 1, p_file);
fclose(p_file);
printf("end");
return 0;
}