继上一篇手动添加shellcode,这篇以代码来实现,要思路的话还请去上一篇看,这篇为纯代码
#pragma once
#include "FileUtil.h"
#include "ImageUtil.h"
int main()
{
unsigned int size;
char* buf = ReadFile("D:\\project\\cpp\\test.exe", &size);
// 检查是否读取成功
if (buf == nullptr)
{
printf("read file error\n");
return -1;
}
// 检查是否是PE文件
if (!IsPE(buf))
{
printf("not a PE file\n");
return -1;
}
char* memoryBuf = ImageStretch(buf);
delete[] buf;
buf = nullptr;
char shellCode[18] = { 0x6A, 0x00, 0x6A, 0x00, 0x6A ,0x00 ,0x6A ,0x00,
0xE8, 0x00, 0x00, 0x00, 0x00,
0xE9, 0x00, 0x00, 0x00, 0x00 };
InjectShellCode(memoryBuf, shellCode, 18, 2);
DWORD PhysicalSize = CalculateDiskSize(memoryBuf);
char* PhysicalBuf = ImageCompress(memoryBuf, PhysicalSize);
delete[] memoryBuf;
memoryBuf = nullptr;
WriteFile("D:\\project\\cpp\\test1.exe", PhysicalBuf, PhysicalSize);
delete[] PhysicalBuf;
PhysicalBuf = nullptr;
return 0;
}
#pragma once
#include
char* ReadFile(const char* path, unsigned int* size);
bool WriteFile(const char* path, char* buf, unsigned int size);
#include "FileUtil.h"
/*
* 读取文件
* @param path 文件路径
* @param size 要返回的文件大小指针
* @return 文件内容
*/
char* ReadFile(const char* path, unsigned int* size)
{
FILE* file;
errno_t err = fopen_s(&file, path, "rb");
if (err != 0)
{
return nullptr;
}
// 将文件指针移动到文件末尾
fseek(file, 0, SEEK_END);
*size = ftell(file);
if (*size == -1) {
perror("Failed to get file length");
fclose(file);
return nullptr;
}
// 将文件指针移动到文件开头
fseek(file, 0, SEEK_SET);
char* buf = new char[*size];
size_t bytesRead = fread(buf, 1, *size, file);
if (bytesRead != *size)
{
perror("Failed to read file");
fclose(file);
return nullptr;
}
// 关闭文件
fclose(file);
file = nullptr;
return buf;
}
/*
* 写入文件
* @param path 文件路径
* @param buf 文件内容
* @param size 文件大小
* @return 是否写入成功
*/
bool WriteFile(const char* path, char* buf, unsigned int size)
{
FILE* writeFile;
errno_t err = fopen_s(&writeFile, path, "wb+");
if (err != 0)
{
return false;
}
fwrite(buf, 1, size, writeFile);
//delete[] buf;
//buf = nullptr;
// 关闭文件
fclose(writeFile);
writeFile = nullptr;
return true;
}
#pragma once
#include
#include
#include
#include "StringUtil.h"
bool IsPE(char* buff);
char* ImageStretch(char* buff);
bool InjectShellCode(char* buff, char* shellcode, DWORD injectSize, DWORD sectionHeaderIndex);
DWORD CalculateDiskSize(char* buff);
char* ImageCompress(char* buff, DWORD size);
#include "ImageUtil.h"
/*
* 判断是否为PE文件
*/
bool IsPE(char* buff)
{
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)buff;
// 判断开头是否为MZ
if (IMAGE_DOS_SIGNATURE != dosHeader->e_magic)
{
return false;
}
// 64位
/*if (IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
PIMAGE_NT_HEADERS64 ntHeader = (PIMAGE_NT_HEADERS64)((DWORD64)dosHeader + dosHeader->e_lfanew);
return ntHeader->Signature == IMAGE_NT_SIGNATURE;
}*/
// 32位
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(buff + dosHeader->e_lfanew);
return ntHeader->Signature == IMAGE_NT_SIGNATURE;
}
/*
* 拉伸
*
* buff 未拉伸状态的文件数据
* return 拉伸后的文件数据
*/
char* ImageStretch(char* buff)
{
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)buff;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(buff + dosHeader->e_lfanew);
// 申请内存
char* memoryBuf = new char[ntHeader->OptionalHeader.SizeOfImage];
memset(memoryBuf, 0, ntHeader->OptionalHeader.SizeOfImage);
// 拷贝头
memcpy(memoryBuf, buff, ntHeader->OptionalHeader.SizeOfHeaders);
// 拷贝节表
int optionalHeaderOffset = dosHeader->e_lfanew + sizeof(ntHeader->Signature) + sizeof(ntHeader->FileHeader) + ntHeader->FileHeader.SizeOfOptionalHeader;
PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)(buff + optionalHeaderOffset);
for (size_t i = 0; i < ntHeader->FileHeader.NumberOfSections; i++)
{
DWORD VirtualAddress = sectionHeader[i].VirtualAddress;
char* section = buff + sectionHeader[i].PointerToRawData;
memcpy(memoryBuf + VirtualAddress, section, sectionHeader[i].SizeOfRawData);
int a = 0;
}
return memoryBuf;
}
/*
* 注入shellcode
*
* buff 拉伸状态的文件数据
* shellcode shellcode数据
* injectSize shellcode数据大小
* sectionHeaderIndex 节表索引
* return true 注入成功 false 注入失败
*/
bool InjectShellCode(char* buff, char* shellcode, DWORD injectSize, DWORD sectionHeaderIndex)
{
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)buff;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(buff + dosHeader->e_lfanew);
// 判断在节表是否超出
if (sectionHeaderIndex >= ntHeader->FileHeader.NumberOfSections)
{
printf("[!] InjectShellCode: sectionHeaderIndex is out of range\n");
return false;
}
// 判断这个节剩余空间是否足够注入该shellcode
int optionalHeaderOffset = dosHeader->e_lfanew + sizeof(ntHeader->Signature) + sizeof(ntHeader->FileHeader) + ntHeader->FileHeader.SizeOfOptionalHeader;
PIMAGE_SECTION_HEADER firstHeader = (PIMAGE_SECTION_HEADER)(buff + optionalHeaderOffset);
PIMAGE_SECTION_HEADER sectionHeader = firstHeader + sectionHeaderIndex;
if (sectionHeader->SizeOfRawData - sectionHeader->Misc.VirtualSize < injectSize)
{
printf("[!] InjectShellCode: sectionHeader[sectionHeaderIndex].SizeOfRawData < injectSize\n");
return false;
}
// 计算要插入字节的位置
DWORD injectOffset = sectionHeader->VirtualAddress + sectionHeader->Misc.VirtualSize;
// 插入shellcode
memcpy(buff + injectOffset, shellcode, injectSize);
// 修复E8后面的字节 这里只以call MessageBoxA为例
DWORD msgBoxAdr = 0x771E8380;
DWORD E8Address = injectOffset + 8;
// 计算公式 msgBoxAdr = ImageBase + E8Address + 5 + E8FixValue; => E8FixValue = msgBoxAdr - ImageBase - E8Address - 5;
DWORD E8FixValue = msgBoxAdr - ntHeader->OptionalHeader.ImageBase - E8Address - 5;
*(LPDWORD)(buff + E8Address + 1) = E8FixValue;
// 修复E9后面的字节 ImageBase + AddressOfEntryPoint = ImageBase + E9Address + 5 + E9FixValue; => E9FixValue = AddressOfEntryPoint - E9Address - 5;
DWORD E9Address = E8Address + 5;
DWORD E9FixValue = ntHeader->OptionalHeader.AddressOfEntryPoint - E9Address - 5;
*(LPDWORD)(buff + E9Address + 1) = E9FixValue;
// 如果不是代码节,赋予权限
char textName[] = ".text";
for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++)
{
PIMAGE_SECTION_HEADER tempHeader = firstHeader + i;
char* sectionName = (char*)tempHeader->Name;
if (StringCmp(textName, sectionName))
{
if (sectionHeaderIndex != i)
{
sectionHeader->Characteristics |= tempHeader->Characteristics;
}
}
}
// 修复入口点
ntHeader->OptionalHeader.AddressOfEntryPoint = injectOffset;
}
/*
* 计算压缩的磁盘大小
* buff 拉伸状态的文件数据
* return 磁盘文件大小
*/
DWORD CalculateDiskSize(char* buff) {
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)buff;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(buff + dosHeader->e_lfanew);
// 获取节表指针
int optionalHeaderOffset = dosHeader->e_lfanew + sizeof(ntHeaders->Signature) + sizeof(ntHeaders->FileHeader) + ntHeaders->FileHeader.SizeOfOptionalHeader;
PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)(buff + optionalHeaderOffset);
int index = ntHeaders->FileHeader.NumberOfSections - 1;
// 获取最后一个节表的指针和数据大小
DWORD PointerToRawData = sectionHeader[index].PointerToRawData;
DWORD SizeOfRawData = sectionHeader[index].SizeOfRawData;
return PointerToRawData + SizeOfRawData;
}
/*
* 压缩
* buff 拉伸状态的文件数据
* size 磁盘文件大小
* return 压缩状态的文件数据
*/
char* ImageCompress(char* buff, DWORD size)
{
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)buff;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(buff + dosHeader->e_lfanew);
// 申请内存
char* PhysicalBuf = new char[size];
memset(PhysicalBuf, 0, size);
// 拷贝头
memcpy(PhysicalBuf, buff, ntHeader->OptionalHeader.SizeOfHeaders);
// 拷贝节表
int optionalHeaderOffset = dosHeader->e_lfanew + sizeof(ntHeader->Signature) + sizeof(ntHeader->FileHeader) + ntHeader->FileHeader.SizeOfOptionalHeader;
PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)(buff + optionalHeaderOffset);
for (size_t i = 0; i < ntHeader->FileHeader.NumberOfSections; i++)
{
DWORD PointerToRawData = sectionHeader[i].PointerToRawData;
memcpy(PhysicalBuf + PointerToRawData, buff + sectionHeader[i].VirtualAddress, sectionHeader[i].SizeOfRawData);
}
return PhysicalBuf;
}
#pragma once
int StringSize(const char* str);
bool StringCmp(char* str1, char* str2);
#include "StringUtil.h"
int StringSize(const char* str)
{
int len = 0;
while (*str)
{
len++;
str++;
}
return len;
}
bool StringCmp(char* str1, char* str2)
{
int len1 = StringSize(str1);
int len2 = StringSize(str2);
if (len1 != len2) return false;
int i = 0;
while (str1[i] == str2[i])
{
i++;
}
return len1 == (i-1);
}