PE文件注入
首先开始窝们不得不提一下PE
PE 的意思就是 Portable Executable(可移植的执行体)。它是 Win32环境自身所带的执行体文件格式。它的一些特性继承自 Unix的 Coff (common object file format)文件格式。“portable executable”(可移植的执行体)意味着此文件格式是跨win32平台的 : 即使Windows运行在非Intel的CPU上,任何win32平台的PE装载器都能识别和使用该文件格式。当然,移植到不同的CPU上PE执行体必然得有一些改变。所有 win32执行体 (除了VxD和16位的Dll)都使用PE文件格式,包括NT的内核模式驱动程序(kernel mode drivers)。因而研究PE文件格式给了我们洞悉Windows结构的良机。
这些东西都是由编译器编译的时候做好了的。
而窝们现在做的就是把已经编译好的exe文件加入窝们想要加入的代码。那么窝们就不得不对PE进行解析。
直接上一段代码来进行说明,加入的代码是Win32程序的MessageBoxA()。
代码
function.h
首先是函数声明
#include<Windows.h>
#include <iostream>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<windows.h>
#define MESSAGEBOX 0x76F91060
//读取文件
LPVOID ReadPEFile(LPSTR lpszFile, PDWORD pFileSize);
/*申请内存,返回内存地址*/
LPVOID ImageBuffer(LPVOID pFileBuffer);
/*内存代码注入
返回值说明注入的是哪个节区*/
size_t addCode(LPVOID pImageBuffer);
/*还原成文件格式*/
VOID ImageToFile(LPVOID pFileBuffer,LPVOID pImageBuffer, size_t i);
/*内存存盘*/
VOID FileToExe(LPVOID pFileBuffer, DWORD pFileSize);
接下来是函数实现
使用到目录路径的,窝都用Path代替了,比如要使用ReadPEFile(Path, pFileSize)。
MESSAGEBOX的宏是用静态分析工具找到的函数地址。直接定义为宏方便使用。
function.cpp
#include"function.h"
LPVOID ReadPEFile(LPSTR lpszFile, PDWORD pFileSize) //LPVOID是一个指向任何类型的指
{
FILE* pFile = NULL;
DWORD fileSize = 0;
LPVOID pFileBuffer = NULL;
//打开文件
pFile = fopen(lpszFile, "rb");
if (!pFile)
{
printf(" 无法打开 EXE 文件! ");
return NULL;
}
//读取文件大小
fseek(pFile, 0, SEEK_END);
fileSize = ftell(pFile);
*pFileSize = fileSize;
fseek(pFile, 0, SEEK_SET);
//分配缓冲区
pFileBuffer = malloc(fileSize);
if (!pFileBuffer)
{
printf(" 分配空间失败! ");
fclose(pFile);
return NULL;
}
/*将文件数据读取到缓冲区
ize_t是标准C库中定义的,在64位系统中为long long unsigned int,
非64位系统中为long unsigned int。*/
size_t n = fread(pFileBuffer, fileSize, 1, pFile);
if (!n)
{
printf(" 读取数据失败! ");
free(pFileBuffer);
fclose(pFile);
return NULL;
}
//关闭文件
fclose(pFile);
return pFileBuffer;
}
LPVOID ImageBuffer(LPVOID pFileBuffer) {
LPVOID pImageBuffer = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader =