代码比较长,因为第一次写,写的比较乱,也没有整理。
功能就是用代码的方式,增加一个messagebox的弹窗
// 滴水三期0316.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
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作业
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论