从iscc的两道题入门vmpwn

概述

vmpwm即模拟虚拟机实现的程序,主要考察对程序的逆向能力

特征是模拟的栈结构,伪机器码,还有pc寄存器和sp寄存器

分析的重点就聚焦于找出栈和上述寄存器是如何进行实现的

从实战分析伪机器码

例题分别是iscc2025的vmpwn和minipwn

vmpwn

0

先来看main函数,不难看出这里op函数就是对输入的伪机器码进行处理的部分,我们先进入op函数看看

1

这里是已经进行修复过的,那就这里而言pushpop是如何分析出来的呢

2

进入函数就是一个大大的Stack,非常没有含金量啊,但这个栈具体是在哪里呢?我们来看bss段

3

这里a1+0x28处储存的就是main函数里malloc返回的指针,所以这里是通过堆来模拟的栈那么a1+0x40自然就是模拟的栈底了

接着来看这里AAAA函数(我当时随便改的函数名)频繁出现,会是做什么的呢

4

v1是储存的存储我们输入的指针,那v2是什么呢,推测是0.

空口无凭,我们通过调试看看

5

这里v2处是0,运行之后v2++,然后返回v1偏移v2地址的数据

到这里就可以推测出这是在模拟pc寄存器了,通过这个函数来获取下一条执行的指令和下一个操作数

这里再列举一下程序模拟的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

case 0:mov a1[x],y

case 1:mov a1[y],*a1[x]

case 2:mov *a1[y],a1[x]

case 3:mov a1[y],a1[x]

case 4:push a1[x]

case 5:pop a1[x]

case 6:(*void)a1[x](*a1)

case 7:jmp a1[x]

case 8:exit

case 9:nop

case a:a1[x] += y

case b:a1[x] -= y

minipwn

还是先来看main函数

6

这里虽然已经重命名过了但还是当作不知道先

可以看出这里有两个输入,会是什么呢,先进vm函数瞧一瞧

7

这里对input的+=操作都能够起到pc寄存器的功能

先来看bss段

8

*(&a3 + 8) = _mm_loadh_ps(&stack);

这行代码将buf指针写入*(&a3+8)处,将buf下面那个指针写入*(&a4)处

9

这样再来看case 1和case 2分支就能判断出是模拟的poppush指令了,main函数那里的输入就是对栈的初始化

这两个分支里的switch函数对应的是poppush的操作对象

分别是:

  1. a1
  2. *(&a1 + 1)
  3. a2
  4. *(&a2 + 1)
  5. a3
  6. *(&a4 + 1)
  7. a4-8(栈顶指针)

接下来看case 3和case 4分支:

这里模拟的是saveload指令

在save过后会将pc寄存器指向如图所示的指令

后面几个分支分别为

case 5:以a1,(&a1+8),a2,a3为rax,rbx,rcx,rdx寄存器调用syscall

case 6:将指定操作对象归零

case 7:inc 8

case 8:dec 8

所以在save过后会先清零寄存器后通过syscall调用read函数后立即回到case 4分支执行load

这里在对状态的处理时还专门分配了一片区域,见过一次后应该不难看出来

漏洞角度

vmpwn

这里是有一个数组越界漏洞,可以通过将数组的索引设为负的来访问数组外的数据,以此来泄露libc通过case a或case b分支得到system和binsh来getshell

minipwn

这里是一个溢出漏洞,在save保存后进行的输入时可以将load中v5处写入0就可以实现在load中将flag赋值为0然后操作四个寄存器调用syscall执行execve(‘/bin/sh’,0,0)来getshell

总结

这种类型的要点就是

  1. 找出pc寄存器是如何实现的
  2. 找出栈是如何实现的
  3. 分析每条指令具体执行的操作是什么