buuctf_reverse:新年快乐

本文详细描述了解决新年快乐exe文件的过程,涉及壳技术(包括压缩壳和加密壳)、ESP堆栈平衡原理以及如何使用硬件断点追踪程序执行。作者通过OllyICE和IDA工具分析,揭示了脱壳和找到程序入口点的方法。
摘要由CSDN通过智能技术生成


前言

本文主要说明新年快乐的解题过程和相关思路

新年快乐

将下载得到的新年快乐.exe放到exeinfoPE中查看,发现其加了UPX的壳

在这里插入图片描述

那么这里尝试手动脱壳,将exe拖入OllyICE中,发现其停留在了0040E2F0的位置,对应的汇编指令是pushad,那么这里我就根据esp堆栈平衡来寻找OEP

在这里插入图片描述

按快捷键F7前进一步,发现此时只有ESP和EIP的内容有变化

在这里插入图片描述

这里就选中ESP的内容0060FF58,右键选择数据窗口中跟随

在这里插入图片描述
接着在左下角的数据窗口中可以看见首行的地址为0060FF58,选中任意的内容,右键设置一个硬件访问断点

在这里插入图片描述

可以在菜单栏的调试中查看已设置的硬件断点

在这里插入图片描述

接着按快捷键F9直接去到硬件断点的位置,可以看到停在了004E486,对应的汇编代码为lea eax, dword ptr [esp-80],并且发现上一条汇编指令为popad

在这里插入图片描述

那么根据ESP堆栈平衡,大概可以猜出OEP的地址为下面第一条JMP指令所指定的地址,即00401280,那么就在其上一行设置一个断点(快捷键F2),并按F9运行到断点处

在这里插入图片描述

再F7往下运行,跳到00401280,并且使用OllyDump插件进行程序入口点的修改,点击Dump转储为一个PE文件

在这里插入图片描述

将转储的文件中IDA打开,找到main函数,发现是字符串比较,那么flag的值应该就是flag{HappyNewYear!}

在这里插入图片描述

相关知识点

1.壳

壳可以理解为对原始的软件所加的一层包装,大致可以将其分为两类:压缩壳加密壳
压缩壳:对原始软件进行了压缩,在添加压缩壳后软件的体积会减小,在软件运行的时候再进行解压
加密壳:对原始软件进行了加密,能够起到保护的作用,在软件运行的时候再进行解密
无论是哪种壳,在运行时都是先运行壳相关的代码,将原始软件解压缩或者解密后,再跳到软件的入口点执行

2.ESP堆栈平衡原理

我对于ESP堆栈平衡原理的理解是,在程序运行时,对于某个函数的调用,对应汇编指令为call,在调用前需要将函数的返回地址先压入栈中,此时ESP会改变,那么当这个函数执行完成,即将返回的时候,对应的汇编指令为ret,会返回到函数调用前所压入的那个返回地址,此时ESP也会改变,并且其值与函数调用前的值相同,这个就称作ESP堆栈平衡
那么加壳程序的运行应该也是类似,在程序装载在内存后,壳相关代码运行前,寄存器会有一些初始值,那么在壳代码进行解压缩或者解密的时候,可能会改变某些寄存器的值,那么这时就需要用到PUSHAD,其作用是按照 EAX、ECX、EDX、EBX、ESP(执行 PUSHAD 之前的值)、EBP、ESI 和 EDI 的顺序,将所有 32 位通用寄存器压入堆栈,那么在PUSHAD后,ESP的值会改变,而与之对应的POPAD就是将上述寄存器的值弹出堆栈,ESP也会改变,并且与PUSHAD之前的值相同。所以,在看见POPAD指令的时候,说明壳相关代码应该是执行完成了,那距离原程序的入口就不远了。

3.硬件断点

硬件断点分为硬件访问断点、硬件写入断点、硬件执行断点,主要使用调试寄存器
其中DR0-DR3 负责存储硬件断点的内存地址,所以最多只能同时使用 4 个硬件断点
那么在本题中,我设置硬件断点的位置为0060FF58,由于栈空间是往低地址增长的,当回到0060FF58这个地址的时候,一般都是壳相关代码执行完准备执行原程序代码的时候。在执行POPAD前,ESP的值为0060FF58,执行POPAD的时候会修改ESP的值,会访问0060FF58这个地址,所以最终停在了POPAD命令的下一行

这段代码是一个 Linux 驱动程序中的函数,用于控制嵌入式系统中的 LED 灯的亮灭。以下是代码注释: ```c // 函数名:keyled_ioctl // 参数:file - 文件指针,cmd - 控制命令,arg - 参数 long keyled_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned int regVal; // 定义一个无符号整型变量 regVal switch(cmd) { // 根据控制命令进行不同的操作 case LED1_REVERSE: // 如果控制命令为 LED1_REVERSE regVal = ioread32(gpj2dat); // 从 gpj2dat 寄存器中读取当前值 regVal ^= (0x1<<0); // 对第 0 位进行异或操作,即将 LED1 灯的状态取反 iowrite32(regVal, gpj2dat); // 将新的值写入 gpj2dat 寄存器中 break; case LED2_REVERSE: // 如果控制命令为 LED2_REVERSE regVal = ioread32(gpj2dat); // 从 gpj2dat 寄存器中读取当前值 regVal ^= (0x1<<1); // 对第 1 位进行异或操作,即将 LED2 灯的状态取反 iowrite32(regVal, gpj2dat); // 将新的值写入 gpj2dat 寄存器中 break; case LED3_REVERSE: // 如果控制命令为 LED3_REVERSE regVal = ioread32(gpj2dat); // 从 gpj2dat 寄存器中读取当前值 regVal |= 0x0f; // 将低四位设置为全 1,即将 LED3、4 灯都点亮 iowrite32(regVal, gpj2dat); // 将新的值写入 gpj2dat 寄存器中 break; case LED4_REVERSE: // 如果控制命令为 LED4_REVERSE regVal = ioread32(gpj2dat); // 从 gpj2dat 寄存器中读取当前值 regVal &= 0xf0; // 将低四位设置为全 0,即将 LED1、2 灯都熄灭 iowrite32(regVal, gpj2dat); // 将新的值写入 gpj2dat 寄存器中 break; } return 0; // 返回操作结果 } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值