逆向作业-添加节-合并节-调整节

admin 2023年9月17日08:59:14评论13 views字数 15225阅读50分45秒阅读模式


新增节:加一个MessageBox弹窗

逆向作业-添加节-合并节-调整节

合并节:不加弹窗了

逆向作业-添加节-合并节-调整节

// 滴水3.19.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//
#include <iostream>#include <Windows.h>#include <cstring>
#define MESSAGE_BOX 0x76940F40
//向上取值函数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):逆向作业-添加节-合并节-调整节

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年9月17日08:59:14
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   逆向作业-添加节-合并节-调整节https://cn-sec.com/archives/2043118.html

发表评论

匿名网友 填写信息