新增节:加一个MessageBox弹窗
合并节:不加弹窗了
// 滴水3.19.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//向上取值函数
size_t AlignUp(size_t value, size_t alignment) {
return (value + alignment - 1) & ~(alignment - 1);
}
//得到文件大小
long GetSize(char* fileName) {
FILE* file = NULL;
long size = 0;
errno_t err = fopen_s(&file, fileName, "rb");
if (err != 0) {
std::cout << "打开文件失败,不能得到文件大小!" << std::endl;
}
else {
fseek(file, 0, SEEK_END);
size = ftell(file);
std::cout << "size:" << size << std::endl;
fseek(file, 0, SEEK_SET);
}
fclose(file);
return size;
}
//把文件读到fileBuffer中
void FileToFileBuffer(char* fileName) {
long size =GetSize(fileName);
FILE* file = NULL;
errno_t err = fopen_s(&file, fileName, "rb");
char* fileBuffer = (char*)malloc(size);
if (!fileBuffer) {
std::cout << "fileBuffer分配内存失败!" << std::endl;
}
else {
fread(fileBuffer, 1, size,file);
std::cout << std::hex << (*(PWORD)fileBuffer) << std::endl;
if ((*(PWORD)fileBuffer) != IMAGE_DOS_SIGNATURE) {
std::cout << "fileBuffer头标记不对!请重新分配!" << std::endl;
return;
}
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
std::cout << "dosHeader = " << dosHeader->e_magic << std::endl;
}
fclose(file);
free(fileBuffer);
}
//把fileBuffer转换成imageBuffer,并插入代码
void fileBufferToImageBuffer(char* fileName) {
long size = GetSize(fileName);
FILE* file = NULL;
errno_t err = fopen_s(&file, fileName, "rb");
if (err != 0) {
std::cout << "文件打开失败!" << std::endl;
fclose(file);
return;
}
char* fileBuffer = (char*)malloc(size);
if (!fileBuffer) {
std::cout << "内存分配失败!" << std::endl;
fclose(file);
free(fileBuffer);
return;
}
fread(fileBuffer, 1, size, file);
if ((*(PWORD)fileBuffer) != IMAGE_DOS_SIGNATURE) {
std::cout << "PE内存不正确!" << std::endl;
fclose(file);
free(fileBuffer);
return;
}
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + dosHeader->e_lfanew);
if (ntHeader->Signature != IMAGE_NT_SIGNATURE) {
std::cout << "NT头不正确!" << std::endl;
fclose(file);
free(fileBuffer);
return;
}
std::cout << "xxx" << std::endl;
PIMAGE_FILE_HEADER fileHeader = &(ntHeader->FileHeader);
//验证,打印14c则说明没问题
//std::cout << std::hex<<fileHeader->Machine << std::endl;
PIMAGE_OPTIONAL_HEADER optionHeader = &(ntHeader->OptionalHeader);
//得到节表
PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)optionHeader + fileHeader->SizeOfOptionalHeader);
//打印第一个节表,如果打印的是.text则说明正确
//std::cout << sectionHeader->Name << std::endl;
//开始拉伸
//1.先得到ImageBuffer的大小,申请内存
//这里申请内存因为我们要添加一个节,所以直接申请多一个节的大小
long long mallocSize = AlignUp(optionHeader->SizeOfImage + sectionHeader->SizeOfRawData, optionHeader->SectionAlignment);
char* imageBuffer = (char*)malloc(mallocSize);
if (!imageBuffer) {
std::cout << "imagebuffer分配失败!" << std::endl;
fclose(file);
free(fileBuffer);
free(imageBuffer);
}
//先复制PE头
memset(imageBuffer, 0, optionHeader->SizeOfImage);
memcpy(imageBuffer, fileBuffer, optionHeader->SizeOfHeaders);
//检查复制是否正确
PIMAGE_DOS_HEADER dosTmp = (PIMAGE_DOS_HEADER)imageBuffer;
if ((*(PWORD)dosTmp) != IMAGE_DOS_SIGNATURE) {
std::cout<<"复制错误!"<<std::endl;
}
std::cout << "复制成功!" << std::endl;
//在复制剩下节数据
int sectionNum = fileHeader->NumberOfSections;
for (int i = 0; i < sectionNum; i++) {
long long 磁盘偏移 = (long long)fileBuffer + (sectionHeader+i)->PointerToRawData;
long long 内存偏移 = (long long)imageBuffer + (sectionHeader+i)->VirtualAddress;
if ((内存偏移 + (sectionHeader + i)->SizeOfRawData )> ((long long)imageBuffer + optionHeader->SizeOfImage)) {
std::cout << "内存复制失败,存在内存偏移后的大小大于SizeOfImage!" << std::endl;
fclose(file);
free(fileBuffer);
free(imageBuffer);
return;
}
memcpy((void*)内存偏移, (void*)磁盘偏移, (sectionHeader + i)->SizeOfRawData);
}
//复制成功之后,开始添加,先判断是如何添加的,是修改e_lfanew还是在末尾添加一个节表,还是修改最后一个节表的大小和属性
//所以先进行判断。因为添加一个节表,要留两个节表的大小。
//所以,1.判断最后一个节表后面的空间大不大于80个字节
//先定义相关变量
PIMAGE_DOS_HEADER imageDosHeader = (PIMAGE_DOS_HEADER)imageBuffer;
PIMAGE_NT_HEADERS imageNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)imageDosHeader + imageDosHeader->e_lfanew);
PIMAGE_FILE_HEADER imageFileHeader = &(imageNtHeader->FileHeader);
imageFileHeader->NumberOfSections++;
PIMAGE_OPTIONAL_HEADER imageOptionHeader = &(imageNtHeader->OptionalHeader);
PIMAGE_SECTION_HEADER imageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)imageOptionHeader + imageFileHeader->SizeOfOptionalHeader);
std::cout << "PE头大小:" << imageOptionHeader->SizeOfHeaders << std::endl;
long long PE头剩余空间 = imageOptionHeader->SizeOfHeaders - (((long long)(imageSectionHeader + sectionNum - 1)) + 40 - (long long)imageBuffer);
std::cout << "PE头剩余空间:" << PE头剩余空间 << std::endl;
if (PE头剩余空间 > 80) {
std::cout << "字节空间不足,无法添加!" << std::endl;
//PE头空间小于80个字节的时候,要么修改e_lfanew的指向,要么修改最后一个
if (imageDosHeader->e_lfanew-64 > 80) {
//将中间的无用数据,设置为0
memset(imageBuffer + 64, 0, imageDosHeader->e_lfanew - 64);
//在修改e_lfanew
int copyPESize = imageOptionHeader->SizeOfHeaders - imageDosHeader->e_lfanew;
//这里要使用c语言提供的函数memmove,这个函数可以处理重叠的部分。
memmove(imageBuffer + 64, (void*)((DWORD_PTR)imageBuffer + imageDosHeader->e_lfanew), copyPESize);
//复制完成之后,就可以开始进行添加一个节了,基本上和下面的逻辑一模一样,所以也没啥好重复写的,如果有人感兴趣,可以自己完善一下,这里就不写了。
imageDosHeader->e_lfanew = 64;
//看一下是否修改完毕,
PIMAGE_NT_HEADERS testNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)imageBuffer + imageDosHeader->e_lfanew);
std::cout << "修改后的NTheader标记:" <<std::hex<< testNTHeader->Signature << std::endl;
}
else {
//修改最后一个节的大小和属性
//这个就更简单了,因为有很多值不用修改,只需要修改内存对齐大小,文件对齐大小,和节的属性修改为可读可写可执行。这里也不写了。修改完毕就是插入shellcode了。
}
}
else {
//空间足够的话,还需要判断最后一个节表结束后的80个字节是否为00,不为00的话说明有值,我们不能修改,需要修改e_lfanew的指向,添加节表
char* lastSection = ((char*)(imageSectionHeader +sectionNum-1))+40;
//设置一个布尔值,来记录是否满足条件
bool isZero = true;
for (int i = 0; i < 80; i++) {
std::cout << "*lastSection:" << *(lastSection + i) << std::endl;
if (*(lastSection + i) != 0x00) {
isZero = false;
break;
}
}
if (isZero) {
std::cout << "可以在最后一个节表后面,添加节表" << std::endl;
memcpy(lastSection, sectionHeader, 0x28);
//复制成功之后,则需要修改其他属性,
//这里修改imageBuffer的值
//在修改最后一个节表的属性:
//因为我复制的是第一个节表,所以要按照第一个的来
//先修改PointerToRawData
std::cout << "修改最后一个节表的PointerToRawData前:" << std::hex<<(imageSectionHeader + sectionNum)->PointerToRawData << std::endl;
(imageSectionHeader + sectionNum)->PointerToRawData = AlignUp((imageSectionHeader +sectionNum-1)->PointerToRawData+ (imageSectionHeader + sectionNum - 1)->SizeOfRawData,optionHeader->FileAlignment);
std::cout << "修改最后一个节表的PointerToRawData后:" << std::hex << (imageSectionHeader + sectionNum)->PointerToRawData << std::endl;
//修改最后的VirtualAddress
std::cout << "修改最后一个节表的VirtualAddress前:" << std::hex << (imageSectionHeader + sectionNum)->VirtualAddress << std::endl;
(imageSectionHeader + sectionNum)->VirtualAddress = AlignUp((imageSectionHeader + sectionNum - 1)->VirtualAddress + (imageSectionHeader + sectionNum - 1)->SizeOfRawData, optionHeader->SectionAlignment);
std::cout << "修改最后一个节表的VirtualAddress后:" << std::hex << (imageSectionHeader + sectionNum)->VirtualAddress << std::endl;
//修改sizeOfImage
std::cout << "修改最后一个节表的SizeOfImage前:" << std::hex << imageOptionHeader->SizeOfImage << std::endl;
imageOptionHeader->SizeOfImage = AlignUp(imageOptionHeader->SizeOfImage + (imageSectionHeader + sectionNum)->SizeOfRawData, optionHeader->SectionAlignment);
std::cout << "修改最后一个节表的SizeOfImage后:" << std::hex << imageOptionHeader->SizeOfImage << std::endl;
std::cout << "节表数量:" << imageFileHeader->NumberOfSections << std::endl;
//修改完毕后,开始进行填充shellcode
//我们填充的是messagebox的shellcode
byte shellcode[] = { 0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,0xE8,0x00,0x00,0x00,0x00,0xE9,0x00,0x00,0x00,0x00 };
//修改节表数量
sectionNum = imageFileHeader->NumberOfSections;
PIMAGE_SECTION_HEADER imageLastSection = (imageSectionHeader + sectionNum - 1);
std::cout << "imageBuffer添加一个section之后的最后一个name:"<<imageLastSection->Name << std::endl;
std::cout << "shellcode大小:" << std::hex<<sizeof(shellcode) << std::endl;
memset(imageBuffer + imageLastSection->VirtualAddress, 0, imageLastSection->SizeOfRawData);
memcpy(imageBuffer + imageLastSection->VirtualAddress, shellcode, sizeof(shellcode));
std::cout << "imageBuffer + imageLastSection->VirtualAddress的值:" << (DWORD)imageBuffer + imageLastSection->VirtualAddress << std::endl;
long long bigenCopyAddr = (long long)((DWORD)imageBuffer + imageLastSection->VirtualAddress);
std::cout << "bigenCopyAddr:" << bigenCopyAddr << std::endl;
//修正E8(CALL)
std::cout << "imageLastSection->VirtualAddress + 0xD的值是:" << imageLastSection->VirtualAddress + 0xD << std::endl;
DWORD nextE8 = MESSAGE_BOX - (imageLastSection->VirtualAddress + 0xD + imageOptionHeader->ImageBase);
std::cout << "打印E8地址:" << nextE8 << std::endl;
*(PDWORD)(bigenCopyAddr + 9) = nextE8;
//修正E9(JMP)
DWORD nextE9 = imageOptionHeader->AddressOfEntryPoint + imageOptionHeader->SizeOfImage - (imageOptionHeader->SizeOfImage + imageLastSection->VirtualAddress + 0x12);
std::cout << "打印E9地址:" << nextE9 << std::endl;
*(PDWORD)(bigenCopyAddr + 0xE) = nextE9;
//修正EntryPoint
std::cout << "EntryPoint修正前:" << imageOptionHeader->AddressOfEntryPoint << std::endl;
imageOptionHeader->AddressOfEntryPoint = imageLastSection->VirtualAddress;
std::cout << "EntryPoint修正后:" << imageOptionHeader->AddressOfEntryPoint << std::endl;
//插入后,开始还原并存盘
long long mallocFileSize = imageLastSection->PointerToRawData + imageLastSection->SizeOfRawData;
std::cout << "mallocFileSize大小为:" << mallocFileSize << std::endl;
char* newFileBuffer = (char*)malloc(mallocFileSize);
if (!newFileBuffer) {
std::cout << "新的newFileBuffer分配失败!" << std::endl;
free(newFileBuffer);
fclose(file);
free(fileBuffer);
free(imageBuffer);
return;
}
memset(newFileBuffer, 0, mallocFileSize);
//先复制头部
memcpy(newFileBuffer, imageBuffer, imageOptionHeader->SizeOfHeaders);
//在循环复制节
std::cout << "sectionNum:" << sectionNum << std::endl;
for (int i = 0; i < sectionNum; i++) {
long long 新的磁盘偏移 = (long long)newFileBuffer + (imageSectionHeader + i)->PointerToRawData;
long long 新的内存偏移 = (long long)imageBuffer + (imageSectionHeader + i)->VirtualAddress;
std::cout << "(imageSectionHeader + i)" << (imageSectionHeader + i)->Name << std::endl;
if ((新的内存偏移 + (imageSectionHeader + i)->SizeOfRawData) > ((long long)imageBuffer + imageOptionHeader->SizeOfImage)) {
std::cout << "内存复制失败,存在内存偏移后的大小大于SizeOfImage!" << std::endl;
fclose(file);
free(fileBuffer);
free(imageBuffer);
return;
}
memcpy((void*)新的磁盘偏移, (void*)新的内存偏移, (imageSectionHeader + i)->SizeOfRawData);
}
FILE* newFile = NULL;
errno_t newErr = fopen_s(&newFile, "C:\Users\zyjsuper\Desktop\test\5.exe", "wb");
if (newErr != 0) {
std::cout << "newFile创建失败!" << std::endl;
fclose(newFile);
free(newFileBuffer);
fclose(file);
free(fileBuffer);
free(imageBuffer);
return;
}
fwrite(newFileBuffer, 1, mallocFileSize, newFile);
std::cout << "写入成功!" << std::endl;
free(newFileBuffer);
}
else {
std::cout << "须修改e_lfanew或者修改最后一个节表的属性,来添加(修改)节表!" << std::endl;
}
}
fclose(file);
free(fileBuffer);
free(imageBuffer);
}
//合并节也比较简单,
void 合并节(char* fileName) {
long size = GetSize(fileName);
FILE* file = NULL;
errno_t err = fopen_s(&file, fileName, "rb");
if (err != 0) {
std::cout << "文件打开失败!" << std::endl;
fclose(file);
return;
}
char* fileBuffer = (char*)malloc(size);
if (!fileBuffer) {
std::cout << "内存分配失败!" << std::endl;
fclose(file);
free(fileBuffer);
return;
}
fread(fileBuffer, 1, size, file);
if ((*(PWORD)fileBuffer) != IMAGE_DOS_SIGNATURE) {
std::cout << "PE内存不正确!" << std::endl;
fclose(file);
free(fileBuffer);
return;
}
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + dosHeader->e_lfanew);
if (ntHeader->Signature != IMAGE_NT_SIGNATURE) {
std::cout << "NT头不正确!" << std::endl;
fclose(file);
free(fileBuffer);
return;
}
std::cout << "xxx" << std::endl;
PIMAGE_FILE_HEADER fileHeader = &(ntHeader->FileHeader);
//验证,打印14c则说明没问题
//std::cout << std::hex<<fileHeader->Machine << std::endl;
PIMAGE_OPTIONAL_HEADER optionHeader = &(ntHeader->OptionalHeader);
//得到节表
PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)optionHeader + fileHeader->SizeOfOptionalHeader);
//打印第一个节表,如果打印的是.text则说明正确
//std::cout << sectionHeader->Name << std::endl;
//开始拉伸
//1.先得到ImageBuffer的大小,申请内存
//这里申请内存因为我们要添加一个节,所以直接申请多一个节的大小
long long mallocSize = AlignUp(optionHeader->SizeOfImage + sectionHeader->SizeOfRawData, optionHeader->SectionAlignment);
char* imageBuffer = (char*)malloc(mallocSize);
if (!imageBuffer) {
std::cout << "imagebuffer分配失败!" << std::endl;
fclose(file);
free(fileBuffer);
free(imageBuffer);
}
//先复制PE头
memset(imageBuffer, 0, optionHeader->SizeOfImage);
memcpy(imageBuffer, fileBuffer, optionHeader->SizeOfHeaders);
//检查复制是否正确
PIMAGE_DOS_HEADER dosTmp = (PIMAGE_DOS_HEADER)imageBuffer;
if ((*(PWORD)dosTmp) != IMAGE_DOS_SIGNATURE) {
std::cout << "复制错误!" << std::endl;
}
std::cout << "复制成功!" << std::endl;
//在复制剩下节数据
int sectionNum = fileHeader->NumberOfSections;
for (int i = 0; i < sectionNum; i++) {
long long 磁盘偏移 = (long long)fileBuffer + (sectionHeader + i)->PointerToRawData;
long long 内存偏移 = (long long)imageBuffer + (sectionHeader + i)->VirtualAddress;
if ((内存偏移 + (sectionHeader + i)->SizeOfRawData) > ((long long)imageBuffer + optionHeader->SizeOfImage)) {
std::cout << "内存复制失败,存在内存偏移后的大小大于SizeOfImage!" << std::endl;
fclose(file);
free(fileBuffer);
free(imageBuffer);
return;
}
memcpy((void*)内存偏移, (void*)磁盘偏移, (sectionHeader + i)->SizeOfRawData);
}
//拉伸成功之后,开始将所有的节合并成一个
//合并节要想清楚,需要修改哪些数据
//sizeofsection要变成1,
//先定义相关变量
PIMAGE_DOS_HEADER imageDosHeader = (PIMAGE_DOS_HEADER)imageBuffer;
PIMAGE_NT_HEADERS imageNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)imageDosHeader + imageDosHeader->e_lfanew);
PIMAGE_FILE_HEADER imageFileHeader = &(imageNtHeader->FileHeader);
//这里就不需要加一个节了
//imageFileHeader->NumberOfSections++;
PIMAGE_OPTIONAL_HEADER imageOptionHeader = &(imageNtHeader->OptionalHeader);
PIMAGE_SECTION_HEADER imageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)imageOptionHeader + imageFileHeader->SizeOfOptionalHeader);
//先修改节内属性,也就是各种对齐和大小的属性,因为这里要考虑内存大小要匹配,所以直接给他设置内存运行时的偏移大小
//long long 合并大小 = (imageSectionHeader + sectionNum - 1)->Misc.VirtualSize > (imageSectionHeader + sectionNum - 1)->SizeOfRawData ? (imageSectionHeader + sectionNum - 1)->Misc.VirtualSize : (imageSectionHeader + sectionNum - 1)->SizeOfRawData;
//std::cout << "合并大小:" << std::hex<<合并大小 << std::endl;
imageSectionHeader->SizeOfRawData = AlignUp(imageOptionHeader->SizeOfImage - imageSectionHeader->VirtualAddress, imageOptionHeader->SectionAlignment);
imageSectionHeader->Misc.VirtualSize = AlignUp(imageOptionHeader->SizeOfImage - imageSectionHeader->VirtualAddress, imageOptionHeader->FileAlignment);
// 属性包含所有节的属性
for (int i = 1; i < imageFileHeader->NumberOfSections; i++)
{
imageSectionHeader[0].Characteristics |= imageSectionHeader[i].Characteristics;
}
//修改节的数量
imageFileHeader->NumberOfSections = 1;
//存盘
char* newFileBuffer = (char*)malloc(imageSectionHeader->PointerToRawData+imageSectionHeader->SizeOfRawData);
if (!newFileBuffer) {
std::cout << "新的newFileBuffer分配失败!" << std::endl;
free(newFileBuffer);
fclose(file);
free(fileBuffer);
free(imageBuffer);
return;
}
memset(newFileBuffer, 0, imageSectionHeader->PointerToRawData + imageSectionHeader->SizeOfRawData);
//先复制头部
memcpy(newFileBuffer, imageBuffer, imageOptionHeader->SizeOfHeaders);
//在循环复制节
std::cout << "sectionNum:" << sectionNum << std::endl;
long long 新的磁盘偏移 = (long long)newFileBuffer + imageSectionHeader ->PointerToRawData;
std::cout << "imageSectionHeader ->PointerToRawData:" << std::hex<<imageSectionHeader->PointerToRawData << std::endl;
long long 新的内存偏移 = (long long)imageBuffer + imageSectionHeader ->VirtualAddress;
std::cout << "(imageSectionHeader ->SizeOfRawData:" << std::hex<<imageSectionHeader->SizeOfRawData << std::endl;
if ((imageSectionHeader->PointerToRawData + imageSectionHeader ->SizeOfRawData) > (imageSectionHeader->VirtualAddress + imageOptionHeader->SizeOfImage)) {
std::cout << "内存复制失败,存在内存偏移后的大小大于SizeOfImage!" << std::endl;
fclose(file);
free(fileBuffer);
free(imageBuffer);
return;
}
memcpy((void*)新的磁盘偏移, (void*)新的内存偏移, imageSectionHeader ->SizeOfRawData);
FILE* newFile = NULL;
errno_t newErr = fopen_s(&newFile, "C:\Users\zyjsuper\Desktop\test\7.exe", "wb");
if (newErr != 0) {
std::cout << "newFile创建失败!" << std::endl;
fclose(newFile);
free(newFileBuffer);
fclose(file);
free(fileBuffer);
free(imageBuffer);
return;
}
fwrite(newFileBuffer, 1, imageSectionHeader->PointerToRawData + imageSectionHeader->SizeOfRawData, newFile);
std::cout << "写入成功!" << std::endl;
free(newFileBuffer);
fclose(file);
free(fileBuffer);
free(imageBuffer);
}
int main()
{
char fileName[] = "C:\Users\zyjsuper\Desktop\test\IPMsg.exe";
//fileBufferToImageBuffer(fileName);
合并节(fileName);
}
以上代码运行后,可以实现相关功能,并且不影响原本程序运行。
原文始发于微信公众号(loochSec):逆向作业-添加节-合并节-调整节
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论