SimpleSMC writeup

将文件拖到IDA中,首先查看函数列表

准备分析

  1. 只有start等几个命名函数,其他都是匿名函数。说明这是一个静态链接文件,并且经过strip。
  2. 我们需要找到关键的几个函数进行分析,忽略其他libc函数。
  3. 有.init_array段

简单分析

  1. 从start函数,我们可以快速定位main函数,因为main函数地址作为参数传入_libc_start_main函数

该文件的start函数:
在这里插入图片描述
其他非静态链接的start函数:
在这里插入图片描述
通过对比,我们确认 sub_400D45是main函数

  1. 分析main函数
    在这里插入图片描述
    main函数逻辑比较简单,首先读取flag,经过两个函数判断,均返回1则成功。
  2. 查看400BAC函数
    在这里插入图片描述
    这边有很奇怪的跳转,猜测是junk code。
    因为两个跳转都是跳转到400BC8+1,因此400BC8处将不会被执行(但是反汇编器还是将其视为代码,因此产生了一个奇怪的call指令)。将400BC8地址字节填充NOP,函数汇编代码正常,重新创建函数。
    在这里插入图片描述
    反编译之后:
    在这里插入图片描述

该函数对地址400AA6进行写操作,400AA6处在main函数中被调用,因此400AA6是self-modified code(SMC)。

SMC 分析和代码复原。

  1. 查看400AA6函数
    查看400AA6地址的引用,除了刚刚的400BAC,还有400C48函数。
    在这里插入图片描述
  2. 分析400C48函数
    查看函数汇编代码,发现junk code:
    在这里插入图片描述
    使用上述同样手段修复,即400CD9处填充NOP,令IDA重新分析函数代码(即先undefine->再code)。
    在这里插入图片描述
    代码对400AA6处进行了异或和写的操作。那么该函数什么时候执行的呢? 我们查看对该函数的引用:
    在这里插入图片描述
    可以看到该函数在 .init_array段,在该段的函数,于main函数执行之前就会被调用执行。

复原

总结来讲,400AA6处代码被两个函数进行了改写,分别是0x400C48 和 0x400BAC。其中0x400C48函数操作是确定的,即使用400AA6开头的数据和41E1B0开头数据进行异或操作。随后的改写操作由函数0x400BAC完成。但是在0x400BAC中,使用了用户输入中的7个字节进行异或操作。这7个字节是未知量,待恢复的函数内容也是未知量,如何解决这个问题呢?

考虑到函数的开头(prologue)都是一样的,即

push    rbp
mov     rbp, rsp
sub     rsp, xxh

这几条指令由固定的7个字节组成:55 48 89 E5 48 83 EC。因此,可以通过函数的prologue倒推用户输入。

有了思路之后,通过IDA Python脚本来进行400AA6的函数恢复。

  1. 首先推测用户输入的7个字节:
import idc

func_addr = 0x400aa6


# 首先执行函数400c48的异或操作

i = 0
while idc.get_db_byte(func_addr+i) != 0xc3:

    b1 = idc.get_db_byte(func_addr+i)
    b2 = idc.get_db_byte(0x41E1B0 + i)
    idc.patch_byte(func_addr+i, b1^b2)
    i+=1


# 使用 prologue 倒推用户输入

prolog = [0x55,0x48,0x89, 0xE5,0x48,0x83,0xEC]

input_bytes = []

for i in range(7):
    b1 = idc.get_db_byte(func_addr + i)
    input_bytes.append(b1^prolog[i])

print([chr(x) for x in input_bytes])
print(input_bytes)

输出:

['F', '1', '@', 'g', 'C', 'h', 'e']
[70, 49, 64, 103, 67, 104, 101]
  1. 使用推测出的7个字节继续恢复函数0x400aa6
import idc

func_addr = 0x400aa6

inp = [70, 49, 64, 103, 67, 104, 101]

i = 0

while idc.get_db_byte(func_addr + i) != 0xc3:
    idc.patch_byte(func_addr + i, idc.get_db_byte(func_addr + i) ^ inp[i%7])
    i += 1

恢复之后的函数:
在这里插入图片描述

输入求解

x = [102, 10, 7, 11, 29, 8, 81, 56, 31, 92, 20, 56, 48, 10, 26, 40, 57, 89, 12, 36, 36, 34, 1, 31, 30, 115, 29, 58, 8, 5, 21, 0x0a]

def foo(s, n):

    print(n, s)
    if (n==32):
        return
    
    for i in range(n):
        s[n+i] ^= s[i]
    foo(s, n<<1)

foo(x, 1)

print("".join([chr(i) for i in x]))

参考文章

https://www.secpulse.com/archives/75049.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值