逆向学习-滴水3.18作业

admin 2024年5月19日02:51:44评论5 views字数 10156阅读33分51秒阅读模式

代码比较长,因为第一次写,写的比较乱,也没有整理。

功能就是用代码的方式,增加一个messagebox的弹窗

// 滴水三期0316.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//
#include <iostream>#include <Windows.h>
#define messageBox 0x75150F40
long getSize(char* fileName,FILE* file) { long size = 0; fseek(file, 0, SEEK_END); size = ftell(file); fseek(file, 0, SEEK_SET); return size;
}
//得到第一个FileBuffer。LPVOID FileBuffer(char* fileName){ FILE* file = NULL; char* fileBuffer = NULL; errno_t err = fopen_s(&file, fileName,"rb"); if (err != 0) { std::cout << "文件打开失败!" << std::endl; } else { //先得到大小 long size = NULL; size = getSize(fileName, file); std::cout << "文件大小为:" << size << std::endl; //申请内存 fileBuffer = (char*)malloc(size); std::cout<<"fileBuffer = "<<(long long)fileBuffer<<std::endl; if (fileBuffer == NULL) { std::cout << "分配内存失败!" << std::endl; } else { fread(fileBuffer, 1, size, file); } } fclose(file); return fileBuffer;}
//得到dos头PIMAGE_DOS_HEADER GET_DOS_HEADER(LPVOID fileBuffer) { if ((*(PWORD)fileBuffer) != IMAGE_DOS_SIGNATURE) { std::cout << "PE文件头不正确!" << std::endl; return 0; } PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuffer; //判断dos头得到是否正确,打印5a4d说明正确 //std::cout << "dosHeader:" << std::hex << dosHeader->e_magic << std::endl; return dosHeader;}
PIMAGE_NT_HEADERS GET_NT_HEADER(LPVOID fileBuffer) { PIMAGE_DOS_HEADER dosHeader = GET_DOS_HEADER(fileBuffer); //得到ntHeader地址,起始位置+dosHeader中的e_lfanew的结果 PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + dosHeader->e_lfanew); //判断是否正确。 //std::cout << "ntHeader:" << ntHeader->Signature << std::endl; return ntHeader;}
//得到标准PE头PIMAGE_FILE_HEADER GET_标准PE_HEADER(LPVOID fileBuffer) { //标准PE头得到比较简单,直接用ntHeader指向就行。 PIMAGE_NT_HEADERS ntHeader = GET_NT_HEADER(fileBuffer); PIMAGE_FILE_HEADER fileHeader = &(ntHeader->FileHeader); std::cout << fileHeader->Machine << std::endl; return fileHeader;}
//得到可选PE头PIMAGE_OPTIONAL_HEADER GET_OPTION_HEADER(LPVOID fileBuffer) { PIMAGE_NT_HEADERS ntHeader = GET_NT_HEADER(fileBuffer); PIMAGE_OPTIONAL_HEADER optionHeader = &(ntHeader->OptionalHeader); //std::cout << "optionheader:" << optionHeader->Magic << std::endl; return optionHeader;}
int GET_SECTION_NUM(LPVOID fileBuffer) { PIMAGE_FILE_HEADER fileHeader = GET_标准PE_HEADER(fileBuffer); //std::cout << "节的数量:" << fileHeader->NumberOfSections << std::endl; return fileHeader->NumberOfSections;}
//遍历节表PIMAGE_SECTION_HEADER GET_SECTION(LPVOID fileBuffer) { PIMAGE_FILE_HEADER fileHeader = GET_标准PE_HEADER(fileBuffer); PIMAGE_OPTIONAL_HEADER optionHeader = GET_OPTION_HEADER(fileBuffer); //PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)optionHeader + fileHeader->SizeOfOptionalHeader); //std::cout << "sectionHeader:" << sectionHeader->Name << std::endl; int sectionNum = GET_SECTION_NUM(fileBuffer); //PIMAGE_SECTION_HEADER sectionHeaders = new PIMAGE_SECTION_HEADER[sectionNum]; PIMAGE_SECTION_HEADER sectionHeader = NULL; //for (int i = 0; i < sectionNum; i++) { // sectionHeaders[i] = (PIMAGE_SECTION_HEADER)((DWORD_PTR)optionHeader + fileHeader->SizeOfOptionalHeader) + i; // //std::cout << "sectionHeader:" << sectionHeaders[i]->Name << std::endl; //} sectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)optionHeader + fileHeader->SizeOfOptionalHeader) ; return sectionHeader;
}

//拉伸节表//LPVOID 拉伸节表(LPVOID fileBuffer) {// //所谓拉伸就是将磁盘对齐转换为内存对齐因此,我们需要先申请一个内存对齐大小的内存。// //1.1先得到SizeOfImage// PIMAGE_OPTIONAL_HEADER optionHeader = GET_OPTION_HEADER(fileBuffer);// char* imageBuffer = (char*)malloc(optionHeader->SizeOfImage);// if (!imageBuffer) {// std::cout << "imageBuffer申请失败!" << std::endl;// }// std::cout << "optionHeader->SizeOfImage:" << optionHeader->SizeOfImage << std::endl;// //申请内存之后,开始复制拉伸// //首先拉伸没有变化的头部,也就是dos+nt+节表,该大小为可选PE头中的sizeofheaders// //2.1,先将申请的内存空间数据设置为0// memset(imageBuffer, 0, optionHeader->SizeOfImage);// std::cout << "optionHeader->SizeOfImage大小:" << optionHeader->SizeOfImage << std::endl;// //2.2.复制头部// memcpy(imageBuffer, fileBuffer, optionHeader->SizeOfHeaders);//// //头部复制完成,我们要复制节了,复制节我们可以弄一个循环// int num = GET_SECTION_NUM(fileBuffer);// std::cout << "num = " << num << std::endl;// PIMAGE_SECTION_HEADER sectionHeader = GET_SECTION(fileBuffer);// std::cout << "(long long)imageBuffer:" << (long long)imageBuffer << std::endl;// std::cout << "*imageBuffer:" << *imageBuffer << std::endl;// for (int i = 0; i < num; i++) {//// //3.1. 在循环内部,我们需要知道如何复制,也就是从哪里开始复制// //文件内存需要从文件的偏移起始地址+文件对齐后的大小 复制到 内存对齐中的偏移起始地址// //因此我们需要计算这两个值// //磁盘对齐需要复制的值:// long long 磁盘偏移 = (long long)fileBuffer + (sectionHeader + i)->PointerToRawData;// //因为是模拟,所以不需要加imagebase// long long 内存偏移 = (long long)imageBuffer + (sectionHeader + i)->VirtualAddress;//// std::cout << "磁盘偏移 =>" << i << " :" << 磁盘偏移 << std::endl;// std::cout << "内存偏移 =>" << i << " :" << 内存偏移 << std::endl;//// //先检测是否分配有效// if ((内存偏移 + (sectionHeader + i)->SizeOfRawData) > ((long long)imageBuffer + optionHeader->SizeOfImage)) {// std::cout << "分配内存超出边界!" << std::endl;// return 0;// } // memcpy((void*)内存偏移, (void*)磁盘偏移, (sectionHeader + i)->SizeOfRawData);// }//// return imageBuffer;////}
//恢复节表和上述代码差不多。LPVOID 还原节表(LPVOID imageBuffer) { //还原节表和拉伸节表差不多 //先得到还原的大小 PIMAGE_OPTIONAL_HEADER optionHeader = GET_OPTION_HEADER(imageBuffer); //输出验证一下,值是否正确 std::cout << std::hex <<optionHeader->Magic << std::endl; PIMAGE_SECTION_HEADER sectionHeader = GET_SECTION(imageBuffer); std::cout << sectionHeader->SizeOfRawData << "--->" << sectionHeader->PointerToRawData << std::endl;
//申请内存大小 int num = GET_SECTION_NUM(imageBuffer); std::cout<< "最后一个偏移:"<< (sectionHeader + num - 1)->PointerToRawData + (sectionHeader + num - 1)->SizeOfRawData;
char* newBuffer = (char*)malloc((sectionHeader + num - 1)->PointerToRawData + (sectionHeader + num - 1)->SizeOfRawData); if (newBuffer == NULL) { std::cout << "分配内存失败" << std::endl; return 0; } memset(newBuffer, 0, (sectionHeader + num - 1)->PointerToRawData); memcpy(newBuffer, imageBuffer, optionHeader->SizeOfHeaders); //头部复制完成,我们要复制节了,复制节我们可以弄一个循环 //int num = GET_SECTION_NUM(imageBuffer); std::cout << "num = " << num << std::endl; std::cout << "(long long)imageBuffer:" << (long long)imageBuffer << std::endl; //std::cout << "*imageBuffer:" << *imageBuffer << std::endl; for (int i = 0; i < num; i++) {
//3.1. 在循环内部,我们需要知道如何复制,也就是从哪里开始复制 //文件内存需要从文件的偏移起始地址+文件对齐后的大小 复制到 内存对齐中的偏移起始地址 //因此我们需要计算这两个值 //磁盘对齐需要复制的值: long long 磁盘偏移 = (long long)newBuffer + (sectionHeader + i)->PointerToRawData; //因为是模拟,所以不需要加imagebase long long 内存偏移 = (long long)imageBuffer + (sectionHeader + i)->VirtualAddress;

std::cout << "磁盘偏移 =>" << i << " :" << 磁盘偏移 << std::endl; std::cout << "内存偏移 =>" << i << " :" << 内存偏移 << std::endl;
//先检测是否分配有效 if ((内存偏移 + (sectionHeader + i)->SizeOfRawData) > ((long long)imageBuffer + optionHeader->SizeOfImage)) { std::cout << "分配内存超出边界!" << std::endl; return 0; } memcpy( (void*)磁盘偏移, (void*)内存偏移,(sectionHeader + i)->SizeOfRawData); }
return newBuffer;
}
//在拉伸状态下插入代码LPVOID 插入代码(LPVOID fileBuffer) { //插入之前先进行拉伸,拉伸之前先分配内存 long long ptxtTemp = NULL; PIMAGE_OPTIONAL_HEADER optionHeader = GET_OPTION_HEADER(fileBuffer); PIMAGE_SECTION_HEADER sectionHeader = GET_SECTION(fileBuffer); int num = GET_SECTION_NUM(fileBuffer); char* imageBuffer = (char*)malloc(optionHeader->ImageBase); if (!imageBuffer) { std::cout << "插入拉伸内存分配失败!" << std::endl; } else { //分配成功之后,先将fileBuffer转换成imageBuffer //得到节的数量 std::cout << "ImageBuffer:" << imageBuffer << std::endl; std::cout << "节的数量:" << num << std::endl; //得到节表 memset(imageBuffer, 0, optionHeader->ImageBase); //先复制头部 memcpy(imageBuffer, fileBuffer, optionHeader->SizeOfHeaders); if (*((PWORD)imageBuffer) != IMAGE_DOS_SIGNATURE) { std::cout << "复制失败!" << std::endl; return 0; } std::cout << "复制成功----!" << std::endl; //头部复制成功后,在复制剩下的 for (int i = 0; i < num; 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 << "复制内存超出边界" << std::endl; } memcpy((void*)内存偏移, (void*)磁盘偏移, (sectionHeader + i)->SizeOfRawData); } std::cout << "所有节都复制成功!" << std::endl; //复制成功后,则需要在imageBuffer中的代码节中插入我们需要的shellcode了。 byte shellcode[] = { 0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,0xE8,0x00,0x00,0x00,0x00,0xE9,0x00,0x00,0x00,0x00 }; if ((sectionHeader->SizeOfRawData - sectionHeader->Misc.VirtualSize) < sizeof(shellcode)) { std::cout << "不能插入!" << std::endl; } else { //.txt节的内存偏移: std::cout << "sectionHeader->VirtualAddress =" << std::hex << sectionHeader->VirtualAddress << std::endl; std::cout << "sectionHeader->SizeOfRawData =" <<std::hex<< sectionHeader->SizeOfRawData << std::endl; ptxtTemp = (long long)((DWORD)imageBuffer + sectionHeader->VirtualAddress + sectionHeader->Misc.VirtualSize); std::cout << "ptxtTemp:" << ptxtTemp << std::endl; memcpy((void*)ptxtTemp, shellcode, sizeof(shellcode)); std::cout << "插入到imageBuffer 成功!" << std::endl; //E8=CALL,E9=JMP //messageBox已经定义过了。 //公式:X = 真实地址-下一个地址 //修正E8 DWORD e8 = messageBox - (optionHeader->ImageBase+(ptxtTemp + 0xD) - (long long)imageBuffer); //DWORD e8 = NULL; *(PDWORD)(ptxtTemp + 9) = e8; //修正E9 DWORD e9 = optionHeader->AddressOfEntryPoint + optionHeader->ImageBase - (optionHeader->ImageBase + (ptxtTemp + 0x12) - (DWORD)imageBuffer); *(PDWORD)(ptxtTemp + 0xE) = e9; std::cout << imageBuffer + sectionHeader->PointerToRawData << std::endl; PIMAGE_OPTIONAL_HEADER x = GET_OPTION_HEADER(imageBuffer); x->AddressOfEntryPoint = ptxtTemp - (long long)imageBuffer; } return imageBuffer; }

}

void 存盘() { char fileName[] = "C:\Users\zyjsuper\Desktop\test\IPMsg.exe"; LPVOID fileBuffer = NULL; fileBuffer = FileBuffer(fileName); LPVOID imageBuffer = 插入代码(fileBuffer); LPVOID newBuffer = 还原节表(imageBuffer); FILE* exe = NULL; //fopen("C:\Users\zyjsuper\Desktop\test\3.exe", "wb"); errno_t err = fopen_s(&exe, "C:\Users\zyjsuper\Desktop\test\4.exe", "wb"); std::cout << "xxx" << std::endl; if (err != 0) { std::cout << "打开文件失败!<" << std::endl; return; } FILE* file = NULL; //long long size = getSize(fileName, file);
PIMAGE_OPTIONAL_HEADER optionHeader = GET_OPTION_HEADER(imageBuffer); //输出验证一下,值是否正确 std::cout << std::hex << optionHeader->Magic << std::endl; PIMAGE_SECTION_HEADER sectionHeader = GET_SECTION(imageBuffer); std::cout << sectionHeader->SizeOfRawData << "--->" << sectionHeader->PointerToRawData << std::endl;
//申请内存大小 int num = GET_SECTION_NUM(imageBuffer); //long size = getSize("C:\Users\zyjsuper\Desktop\test\fg.exe", file2); fwrite(newBuffer, 1, (sectionHeader + num - 1)->PointerToRawData + (sectionHeader + num - 1)->SizeOfRawData, exe); free(fileBuffer); free(imageBuffer); //存盘((char*)newBuffer); free(newBuffer); fclose(exe); //fclose(file);}
int main(){ char fileName[] = "C:\Users\zyjsuper\Desktop\test\fg.exe"; //LPVOID fileBuffer = NULL; //fileBuffer = FileBuffer(fileName); //byte shellcode[] = { 0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,0xE8,0x00,0x00,0x00,0x00,0xE9,0x00,0x00,0x00,0x00 }; //std::cout << "size:" <<std::hex<< sizeof(shellcode) << std::endl; //LPVOID imageBuffer = 拉伸节表(fileBuffer); //LPVOID newBuffer = 还原节表((char*)imageBuffer); //插入代码(fileBuffer); 存盘(); //free(fileBuffer); //free(imageBuffer); //存盘((char*)newBuffer); //free(newBuffer);}




测试已成功,需要自行修改messagebox的地址。

原文始发于微信公众号(loochSec):逆向学习-滴水3.18作业

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月19日02:51:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   逆向学习-滴水3.18作业https://cn-sec.com/archives/2038559.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息