滴水逆向三期实践6:扩大节

本文介绍了如何通过扩大PE文件的节区来植入ShellCode,并详细阐述了扩展过程,包括内存逻辑拉伸、分配新空间、修改节区属性、计算新SizeOfImage等步骤。此外,还展示了注入弹窗代码的实现,以及如何确保被扩节具有执行权限。最后,文章提供了C代码示例,演示了整个过程。
摘要由CSDN通过智能技术生成

扩大节:

1、拉伸到内存(只是逻辑上,实际代码操作并不需要这一步),需要注入的代码为 ShellCode

2、分配一块新的空间:SizeOfImage + sizeof ( ShellCode)

3、扩大节,修改最后一个节的 SizeOfRawData 和 VirtualSize

   OrgSecSize = max ( SizeOfRawData 或 VirtualSize内存对齐后的值 ) 

   ∵ 有些初始化数据未全部写入文件,VirtualSize 可能比 SizeOfRawData 大,必须保证添加的代码不影响到原程序

   VirtualSize = OrgSecSize + sizeof ( ShellCode)

   SizeOfRawData = ( OrgSecSize + sizeof(ShellCode) ) 按文件对齐后的值

4、修改SizeOfImage大小

   SizeOfImage = (最后一节 VirtualAddress + VirtualSize) 按内存对齐后的值

这里依然在扩大节中植入弹窗代码,和前面一样的操作,详见前面的文章

注意,这里因为要使被扩节 执行代码, 所以需要在被扩节的Characteristics 按位或 一份可执行的设置

这里为  | 0x60000020  

上代码附详细注释:

用到的所有自定义函数均可在前面的章节找到


#include "windows.h"
#include "stdio.h"

#define MESSAGEBOXADDR 0x76AF39A0   //这个值需要将任一exe文件拖入OD打开,搜索 MessageBoxA 记录它的地址到这里(每次开机都不同)

unsigned char ShellCode320[] =
{
	0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,
	0xE8,0x00,0x00,0x00,0x00,
	0xE9,0x00,0x00,0x00,0x00
};

void h320()
{
	char FilePath[] = "CrackHead.exe";	//CRACKME.EXE        CrackHead.exe
	char CopyFilePath[] = "CrackHeadcopy.exe";	//CRACKMEcopy.EXE       CrackHeadcopy.exe
	LPVOID pFileBuffer = NULL;				//会被函数改变的 函数输出之一
	LPVOID* ppFileBuffer = &pFileBuffer;	//传进函数的形参
	LPVOID pNewFileBuffer = NULL;
	int SizeOfFileBuffer;
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	DWORD CallX = NULL;	//即E8后跟的4字节
	DWORD JmpX = NULL;	//即E9后跟的4字节

	SizeOfFileBuffer = ReadPEFile(FilePath, ppFileBuffer);	//pFileBuffer即指向已装载到内存中的exe首部
	if (!SizeOfFileBuffer)
	{
		printf("文件读取失败\n");
		return;
	}

	//Dos头
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;	// 强转 DOS_HEADER 结构体指针
	//NT头
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
	//PE头
	pFileHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);	//NT头地址 + 4 为 FileHeader 首址
	//可选PE头	
	pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中
	//首个节表
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
	for (int i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++)	//注意这里i从1开始 i < NumberOfSections
	{}	
	//出循环后pSectionHeader指向最后一个节表	

	// OrgSecSize 为 该节的原始大小 (最后一个节的原始大小
	printf("VirtualSize: %x\nSizeOfRawData: %x\n", pSectionHeader->Misc.VirtualSize, pSectionHeader->SizeOfRawData);
	DWORD OrgSecSize = max(pSectionHeader->Misc.VirtualSize, pSectionHeader->SizeOfRawData);
	printf("OrgSecSize: %x\n", OrgSecSize);
	
	//ShallCode即放在节区头起Size之后,这里先计算地址,再修改PE中的值与开辟空间
	//X即E8后的数 = 要跳转的地址 - (E8所在地址 + 5)            (E8 所在地址+5 即 call指令的下一条指令的地址)
	//那么要跳转的地址即messageboxA地址。E8所在地址即 ImageBase内存运行基址 + VirtualAddress节所在偏移+Size +8 才到E8 (∵ShallCode就在节开头)
	CallX = MESSAGEBOXADDR - (pOptionalHeader->ImageBase + pSectionHeader->VirtualAddress + OrgSecSize + 8 + 5);
	
	//jump 要跳转的地址即OEP程序入口点, X = 程序入口点 - E9所在地址 + 5
	//这里程序入口点即ImageBase基址 + 修改前的OddAddressOfEntryPoint         E9所在地址计算同上   下式是化简后约去了ImageBase
	//ImageBase + AddressOfEntryPoint - (ImageBase + VirtualAddress +13 +5 )
	JmpX = pOptionalHeader->AddressOfEntryPoint - (pSectionHeader->VirtualAddress + OrgSecSize + 13 + 5);
	
	//将上述计算后的值放入ShellCode320
	*(PDWORD)(ShellCode320 + 9) = CallX;
	*(PDWORD)(ShellCode320 + 14) = JmpX;
	for (int i = 0; i < sizeof(ShellCode320); i++)
	{
		printf("%x ", ShellCode320[i]);
	}
	printf("\n");
	
	//计算完地址后 计算新节表值  VirtualSize以Size + ShellCode长度 按内存对齐(其实VirtualSize可以不用内存对齐),SizeOfRawData同理
	int NewVirtualSize = OrgSecSize + sizeof(ShellCode320);
	int NewSizeOfRawData = Align(OrgSecSize + sizeof(ShellCode320), pOptionalHeader->FileAlignment);
	printf("NewSizeOfRawData%x, NewVirtualSize:%x\n", NewSizeOfRawData, NewVirtualSize);
	
	// 在修改节表值之前需要用到新旧值 ∴上述节表新值暂不真正修改只作记录。
	// 修改SizeOfImage值
	pOptionalHeader->SizeOfImage = Align(pSectionHeader->VirtualAddress + NewVirtualSize, pOptionalHeader->SectionAlignment);
	
	//在修改节表值之前新空间长度   原空间长度  减去 旧SizeOfRawData  加上新SizeOfRawData 
	int SizeOfNewFileBuffer = SizeOfFileBuffer - pSectionHeader->SizeOfRawData + NewSizeOfRawData;
	
	//修改入口点
	pOptionalHeader->AddressOfEntryPoint = pSectionHeader->VirtualAddress + OrgSecSize;
	
    //Characteristics
	printf("Characteristics:%x\n", pSectionHeader->Characteristics);
	pSectionHeader->Characteristics = pSectionHeader->Characteristics  | 0x60000020;
	printf("Characteristics:%x\n", pSectionHeader->Characteristics);
	
	//修改节表值
	pSectionHeader->Misc.VirtualSize = NewVirtualSize;
	pSectionHeader->SizeOfRawData = NewSizeOfRawData;
	//printf("VirtualSize: %x\nSizeOfRawData: %x\n", pSectionHeader->Misc.VirtualSize, pSectionHeader->SizeOfRawData);
	
	//修改值后开始重新分配空间
	pNewFileBuffer = malloc(SizeOfNewFileBuffer);
	memset(pNewFileBuffer, 0, SizeOfNewFileBuffer);
	memcpy(pNewFileBuffer, pFileBuffer, SizeOfFileBuffer);	//复制原空间
	printf("SizeOfFileBuffer:%x\nSizeOfNewFileBuffer:%x\n", SizeOfFileBuffer, SizeOfNewFileBuffer);

	// 复制新空间
	memcpy((void*)((DWORD)pNewFileBuffer + pSectionHeader->PointerToRawData + OrgSecSize), ShellCode320, sizeof(ShellCode320));
	
	//memcpy((void*)((DWORD)pNewFileBuffer + SizeOfFileBuffer), ShellCode320, sizeof(ShellCode320));	//复制ShellCode
	//剩余部分填充0
	//memset((void*)((DWORD)pNewFileBuffer + SizeOfFileBuffer + sizeof(ShellCode320)), 0, (SizeOfNewFileBuffer - SizeOfFileBuffer - sizeof(ShellCode320)));
	MemeryToFile(pNewFileBuffer, SizeOfNewFileBuffer, CopyFilePath);
	free(pNewFileBuffer);
	free(pFileBuffer);
}

运行程序打印内容如下:

VirtualSize: 468
SizeOfRawData: 600
OrgSecSize: 600
6a 0 6a 0 6a 0 6a 0 e8 93 f3 6e 76 e9 ee c9 ff ff
NewSizeOfRawData800, NewVirtualSize:612
Characteristics:c0000040
Characteristics:e0000060
SizeOfFileBuffer:1600
SizeOfNewFileBuffer:1800
success

打开程序有弹窗,确定后程序正常运行

原exe程序 PETool 查看

修改后:

 

第1讲:2015-01-12(进制01) 第2讲:2015-01-13(进制02) 第3讲:2015-01-14(数据宽度-逻辑运算03) 第4讲:2015-01-15(通用寄存器-内存读写04) 第5讲:2015-01-16(内存寻址-堆栈05) 第6讲:2015-01-19(EFLAGS寄存器06) 第7讲:2015-01-20(JCC) 第8讲:2015-01-21(堆栈图) 第8讲:2015-01-21(宝马问题) 第9讲:2015-01-22(堆栈图2) 第10讲:2015-01-23(C语言01_后半段) 第10讲:2015-01-23(C语言完整版) 第11讲:2015-01-26(C语言02_数据类型) 第12讲:2015-01-27(C语言03_数据类型_IF语句) 第13讲:2015-01-28(C语言04_IF语句逆向分析上) 第14讲:2015-01-28(C语言04_IF语句逆向分析下) 第15讲:2015-01-29(C语言04_正向基础) 第16讲:2015-01-30(C语言05_循环语句) 第17讲:2015-02-02(C语言06_参数_返回值_局部变量_数组反汇编) 第18讲:2015-02-02(2015-01-30课后练习) 第19讲:2015-02-03(C语言07_多维数组) 第20讲:2015-02-03(2015-02-02课后练习) 第21讲:2015-02-04(C语言08_结构体) 第22讲:2015-02-05(C语言09_字对齐_结构体数组) 第23讲:2015-02-06(C语言10_Switch语句反汇编) 第24讲:2015-02-26(C语言11_指针1) 第25讲:2015-02-27(C语言11_指针2) 第26讲:2015-02-28(C语言11_指针3) 第27讲:2015-02-28(C语言11_指针4) 第28讲:2015-03-02(C语言11_指针5) 第29讲:2015-03-03(C语言11_指针6) 第30讲:2015-03-04(C语言11_指针7) 第31讲:2015-03-06(C语言11_指针8) 第32讲:2015-03-09(位运算) 第33讲:2015-03-10(内存分配_文件读写) 第34讲:2015-03-11(PE头解析_手动) 第35讲:2015-03-12(PE头字段说明) 第36讲:2015-03-13(PE节表) 第37讲:2015-03-16(FileBuffer转ImageBuffer) 第38讲:2015-03-17(代码空白区添加代码) 第39讲:2015-03-18(任意空白区添加代码) 第40讲:2015-03-19(新增添加代码) 第41讲:2015-03-20(扩大-合并-数据目录) 第42讲:2015-03-23(静态连接库-动态链接库) 第43讲:2015-03-24(导出表) 第44讲:2015-03-25(重定位表) 第45讲:2015-03-26(移动导出表-重定位表) 第46讲:2015-03-27(IAT表) 第47讲:2015-03-27(导入表) 第48讲:2015-03-30(绑定导入表) 第49讲:2015-03-31(导入表注入) 第50讲:2015-04-01(C++ this指针 类 上) 第51讲:2015-04-01(C++ this指针 类 下) 第52讲:2015-04-02(C++ 构造-析构函数 继承) 第53讲:2015-04-03(C++ 权限控制) 第54讲:2015-04-07(C++ 虚函数表) 第55讲:2015-04-08(C++ 动态绑定-多态-上) 第56讲:2015-04-08(C++ 动态绑定-多态-下) 第57讲:2015-04-09(C++ 模版) 第58讲:2015-04-10(C++ 引用-友元-运算符重载) 第59讲:2015-04-13(C++ new-delete-Vector) 第60讲:2015-04-14(C++Vector实现) 第61讲:2015-04-15(C++链表) 第62讲:2015-04-16(C++链表实现) 第63讲:2015-04-16(C++二叉树) 第64讲:2015-04-17(C++二叉树实现) 第65讲:2015-04-20(Win32 宽字符) 第66讲:2015-04-21(Win32 事件-消息-消息处理函数) 第67讲:2015-04-22(Win32 ESP寻址-定位回调函数-条件断点) 第68讲:2015-04-23(Win32 子窗口-消息处理函数定位) 第69讲:2015-04-24(Win32 资源文件-消息断点) 第70讲:2015-04-27(Win32 提取图标-修改标题) 第71讲:2015-04-28(Win32 通用控件-VM_NOTIFY) 第72讲:2015-04-29(Win32 PE查看器-项目要求) 项目一:PE查看器 开发周期(5天) 需求文档 第73讲:2015-05-07(Win32 创建线程) 第74讲:2015-05-08(Win32 线程控制_CONTEXT) 第75讲:2015-05-11(Win32 临界区) 第76讲:2015-05-12(Win32 互斥体) 第77讲:2015-05-13(Win32 事件) 第78讲:2015-05-14(Win32 信号量) 第79讲:2015-05-15(Win32 线程同步与线程互斥) 第80讲:2015-05-18(Win32 进程创建_句柄表) 第81讲:2015-05-20(Win32 以挂起形式创建进程) 第82讲:2015-05-21(Win32 加密壳_项目说明) 项目二:加密壳 开发周期(5天) 需求文档 第83讲:2015-05-28(Win32 枚举窗口_鼠标键盘事件) 第84讲:2015-05-29(Win32 CE练习) 第85讲:2015-06-01(Win32 OD练习) 第86讲:2015-06-03(Win32 ShellCode_远程线程注入) 第87讲:2015-06-04(Win32 加载EXE_模块隐藏) 第88讲:2015-06-09(Win32 IAT_HOOK) 第89讲:2015-06-10(Win32 InlineHook) 第90讲:2015-06-11(Win32 进程通信) 第91讲:2015-06-11(Win32 进程监控_项目说明) 项目三:进程监控 开发周期(5天) 需求文档 第92讲:2015-06-15(硬编码_01) 第93讲:2015-06-16(硬编码_02) 第94讲:2015-06-17(硬编码_03) 第95讲:2015-06-18(硬编码_04) 第96讲:2015-06-19(硬编码_05)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值