Mips架构逆向初探

Mips架构逆向初探

0x00-Mips指令架构

MIPS架构(英语:MIPS architecture,为Microprocessor without interlocked piped stages architecture的缩写,亦为Millions of Instructions Per Second的双关语),是一种采取精简指令集(RISC)的处理器架构,1981年出现,由MIPS科技公司开发并授权,广泛被使用在许多电子产品、网络设备、个人娱乐装置与商业装置上。最早的MIPS架构是32位,最新的版本已经变成64位。

使用linux下的readelf命令可以了解到文件相关信息

0x01-环境安装

由于程序是MIPS指令架构的,而通常我们使用的电脑是x86架构的,无法直接运行该程序,这时可以借助Qemu模拟器来运行程序。QEMU是运行在用户层的开源全虚拟化解决方案,可以在Intel机器上虚拟出完整的操作系统。QEMU主要有两种运作方式

  • User Mode:即使用者模式,能单独运行那些为不同处理编译的Linux程序
  • System Mode:即系统模式,能够模拟整个操作系统,包括中央处理器及其他周边设备

由于BabyMips程序是通过静态链接生成的,为了方便,在User Mode下使用QEMU来运行该程序

使用下面的命令来安装QEMU

1
2
sudo apt install qemu-user-static
sudo apt install qemu-user

安装qemu对应下的mips64库

1
sudo apt install libc6-mips64-cross

0x01-DDCTF2018-BabyMips

静态分析

readelf读取文件信息-Mips32-小端序

运行试试

出现错误

先使用Ghidra查看反编译代码,也可以使用ida7.5即以上版本反编译,也可以使用jeb-mips

ghidra

ida7.7

jeb

可以看到先让我们输入,然后进入函数进行判断,所以我们需要知道函数进行了什么加密操作

进入函数后发现分析出错了,在最后跳转时跳转到了垃圾数据的位置,所以我们试一下动态调试

动态调试

ida+QEMU调试

首先在ida中选择Remote GDB Debugger

然后Debugger设置好

连接

1
qemu-mipsel -g 23946 Baby_Mips

-g后面跟着端口号+文件名

端口的另一边可以选择IDA也可以选择GDB,这里我选择DIA

在IDA中启动调试

成功断下

接下来定位到刚才出错的地址,下个断点

放开程序

等待我们输入

输入完成后,提示出错

报错

F8也会出现异常

查找lwc1指令的含义,发现是与协处理器相关的指令。通过对后面的代码块进行分析发现,后面并没有用到$f29$t1寄存器的内容

大佬的思路

也就是说E8本来是8位,也就是两个字节,但是mips指令为4字节,所以跳转的时候出错了

使用idc进行Patch

注意idc不支持+=操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<idc.idc>

static main()
{
auto addr=0x4001F0;
auto addr1=0x403234;
for(;addr<=addr1;addr=4+addr)
{
if(Byte(addr)==0xeb && Byte(addr+1)==0x02)
{
PatchByte(addr,0x00);
PatchByte(addr+1,0x00);
PatchByte(addr+2,0x00);
PatchByte(addr+3,0x00);
}

}
//printf("finished");
}

保存之后重新拖进jeb反编译

脚本

十六个方程组,使用z3求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python

from z3 import *

a = [BitVec('a%d' %i, 32) for i in range(16)]

s = Solver()
s.add(0xffffc20e*a[0]-0xbd52*a[1]+0x7f57*a[2]+0x96cd*a[3]-0xac7f*a[4] +0x5d80*a[5]+0xb25e*a[6]+0x2447*a[7]+0xba8a*a[8]+0xbb41*a[9]+0xa3a8*a[10]+0xcb12*a[11]-0x6958*a[12]+0x5821*a[13]+0x77ed*a[14]+0xf7ff*a[15] == 0x162f0ca )
s.add(0xeb44*a[0]-0x0f99*a[1] - 0x40e7*a[2] +0xdf2e*a[3] -0x4b2e*a[4] -0x96b5*a[5] +0x9d66*a[6] -0xafa8*a[7] -0x6e26*a[8] -0xe655*a[9]- 0x9a6e*a[10] +0x57ba*a[11] -0x227c*a[12] +0xbdd1*a[13] +0xb437*a[14] +0x5d3f*a[15]== 0xffec2e48)
s.add(0xe6f1*a[0] +0xa4b2*a[1] -0xfe74*a[2] -0x0f07*a[3] -0x5d22*a[4] -0xb845*a[5] -0x9954*a[6] +0x93ac*a[7] -0x51e4*a[8] -0x4b11*a[9] +0xdc93*a[10] +0x13f8*a[11] +0x246c*a[12] +0xf121*a[13] +0xf09f*a[14] +0x0dfa*a[15] == 0xd3c060)
s.add(0xffff7085*a[0] -0x6623*a[1] +0x0686*a[2] +0x4b2d*a[3] +0x68df*a[4] +0x9be7*a[5] +0x21b4*a[6] +0xe25a*a[7] -0xc807*a[8] +0xf695*a[9] -0x5421*a[10] -0x2469*a[11] +0x9f29*a[12] -0xe311*a[13] +0x78f2*a[14] -0x6bda*a[15] == 0x8bf576)
s.add(0xffff07b8*a[0] -0xd048*a[1] -0x85f1*a[2] +0xee84*a[3] -0x37d1*a[4] +0xb74a*a[5] +0xcfe2*a[6]+ 0x8f1e*a[7] -0xf211*a[8] -0x83bf*a[9] -0x1249*a[10] +0x7ea7*a[11] -0x4294*a[12] -0xb661*a[13] -0x8a73*a[14] -0x5e5c*a[15] == 0xff4ea5b3)
s.add(0xffffd6b5*a[0] -0x2b5f*a[1]+ 0xc981*a[2] -0x60c3*a[3] +0xf8f2*a[4]+ 0xded7*a[5]- 0xf6fb*a[6] +0x1083*a[7]- 0xdc96*a[8]- 0x587e*a[9] -0xb4f5*a[10] +0xf57a*a[11] +0x57d0*a[12] +0xe814*a[13] +0x6169*a[14] +0xf285*a[15] == 0x9dd61e)
s.add(0xcd89*a[0] -0xd43d*a[1] +0xf037*a[2] +0x83a8*a[3] -0xa305*a[4] -0xadef*a[5] +0xcaaa*a[6] -0xf145*a[7]- 0x6073*a[8]- 0x2777*a[9] +0x794f*a[10] +0xf00e*a[11] -0xe7d5*a[12] +0x2654*a[13] -0xbed0*a[14] -0xb8af*a[15] == 0xff6baab3)
s.add(0xffff6108*a[0] -0x6766*a[1] +0xd58e*a[2] -0x5ca3*a[3] +0x2718*a[4] +0x1e2b*a[5] -0xf49e*a[6] +0xcf78*a[7] +0x7c09*a[8] -0x13b7*a[9] -0xbeee*a[10]- 0xe450*a[11] +0x4da3*a[12] -0x8880*a[13] -0x5691*a[14] +0x8bd8*a[15] == 0xff818f06)
s.add(0xffffa564*a[0] -0xa95a*a[1] -0xe643*a[2] +0x0d38*a[3] -0x097a*a[4] -0xeb22*a[5] +0xcac3*a[6] -0x4ed1*a[7] -0x7c8a*a[8] +0xf107*a[9] +0xa59e*a[10]- 0x1213*a[11] +0xb2b5*a[12] -0x7213*a[13] -0x2b83*a[14] -0xa155*a[15] == 0xff8d50e7)
s.add(0xffff6c45*a[0] -0x2752*a[1] -0xbdc3*a[2] -0xf495*a[3] -0x7121*a[4] +0x9c41*a[5] -0x9465*a[6]- 0x6ce3*a[7] -0x4f28*a[8] -0x8350*a[9] -0x176e*a[10] +0x7814*a[11] -0x739a*a[12] +0x5494*a[13] +0x142d*a[14] +0xca55*a[15] == 0xff3f9826)
s.add(0xcf01*a[0] +0xf378*a[1] +0x1064*a[2] -0xd9a7*a[3] -0x077d*a[4]+ 0x6dab*a[5] -0xaf1f*a[6]- 0x3db7*a[7] +0x3554*a[8] -0xcb8e*a[9] -0x9815*a[10]+ 0xf30b*a[11] +0x9c5e*a[12] -0x5d07*a[13] -0x4c31*a[14] +0xeae0*a[15] == 0x213fed)
s.add(0x8bd4*a[0] -0x6d81*a[1] -0xe772*a[2] +0xb6f1*a[3] +0x9b57*a[4] -0x597d*a[5] +0x15d1*a[6]- 0xa55e*a[7]+ 0xfd13*a[8]+ 0x17b4*a[9] +0xec78*a[10] -0xd51a*a[11] +0x56ad*a[12] -0xc319*a[13] +0x9f8e*a[14] +0xfa17*a[15] == 0xa9f0dc)
s.add(0xffffb798*a[0] -0x8bef*a[1] +0x109d*a[2]- 0xf9d4*a[3] +0x4ecf*a[4] +0xa896*a[5] +0x773b*a[6] +0x6e8a*a[7] -0x737c*a[8]+ 0x4979*a[9] +0xc685*a[10] -0x96ae*a[11] +0x0bbd*a[12] +0x8280*a[13] +0xe3a9*a[14] -0x730c*a[15] == 0xbdeb20)
s.add(0x0b20*a[0] +0x9b9c*a[1] +0xb4aa*a[2]+ 0x6176*a[3] +0x9670*a[4] +0x7c9d*a[5] -0x5402*a[6] -0x8cd2*a[7] +0xac82*a[8] +0xa2f5*a[9] -0x8efd*a[10] -0x65f1*a[11] -0x94b9*a[12] +0x8cb8*a[13] +0x1cb5*a[14] +0x4aa1*a[15] == 0x9c7cf5)
s.add(0x57fd*a[0] +0x3d83*a[1] +0xf745*a[2] +0xa5c4*a[3] -0x65fa*a[4] -0x58e9*a[5] +0xbebe*a[6] +0x1820*a[7] -0xd7b9*a[8] -0xb21f*a[9] -0x76a0*a[10] +0xc60d*a[11] +0x168f*a[12] +0x2a96*a[13] +0x31d6*a[14] -0x4b88*a[15] == 0xd08e2)
s.add(0xffff1bae*a[0] -0xc7d4*a[1] -0x1554*a[2] +0x7eea*a[3] -0x684d*a[4] +0x6adb*a[5] +0x8534*a[6] -0x3a36*a[7] +0x29f0*a[8] +0xd3f2*a[9] -0x23e5*a[10] -0x6540*a[11] +0xbcd3*a[12] -0xef9b*a[13] +0xefdb*a[14] -0x774e*a[15] == 0x178803)

for item in a:
s.add(item > 0, item < 127)

if s.check() == sat:
m = s.model()
flag = []
for i in range(16):
flag.append(m[a[i]].as_long())
print(''.join(map(chr, flag)))

注意负数要换成十六进制

参考

https://blog.csdn.net/m0_46362499/article/details/107629918

https://cloud.tencent.com/developer/article/1123681

https://cq674350529.github.io/2018/05/07/Solve-baby-mips-with-angr/