MIPS架构下的逆向初探

0x00 前言

本人是新接触mips下的逆向,本文参考了网上众多大佬的文章,权当是个人的学习总结,如有问题还请斧正。

本文主要是借助4道ctf里的题目来阐述。

参考文章:

https://blog.csdn.net/hit_shaoqi/article/details/53559914

https://blog.csdn.net/ck404/article/details/21403203

http://www.elecfans.com/d/1213039.html

https://blog.csdn.net/phunxm/article/details/8938123

https://bbs.pediy.com/thread-259892.htm

https://www.anquanke.com/post/id/169503#h2-4

 

0x01 静态分析的问题与总结

在x86下IDA的反编译非常的给力,但是在mips下,IDA即使有Retdec插件的帮助,但是局限也比较大(mips64此插件就反编译不了),所以推荐用ghidra。

我们用一道ctf举例(RCTF-cipher)

静态——RCTF-cipher

一位看雪的师傅写的wp:https://bbs.pediy.com/thread-259892.htm

     1.首先查看文件的信息

在虚拟机里用readelf指令查看;

readelf -h cipher

可以看出来是 mips64 大端,起始位置为0x120000c00(暂时只用这些信息)

2.我们可以到ghidra看一下:

我们可以非常简单的寻找到main函数:

 和在x86下申请内存的函数相似:

还有setvbuf

 (截的别的文章的图,找不到了)

第一句“&_gp”这是gp寄存器的重定位,之后会详细说明,暂时不管

main函数大致的意思是读入一个文件,然后继续进入cipher()函数,我们跟进:

cipher函数:

首先,第一个奇怪的地方就是CONCAT44,可以看一下帮助文档:

在这个位置:

我i们出现的问题是concat44:

CONCATxy(x,y的值可以变)系列的函数其实就是拼接函数,比如说CONCAT31(0xaabbcc, 0xdd) = 0xaabbccdd

至于为什么会出现这种东西?

内部反编译器的功能偶尔,反编译器可能会使用几个内部反编译器函数中的一个,这些函数不会被转换成更像“C”的表达式。使用这些参数可以指示pcode不正确,或者需要“调优”以使反编译器的输出更好。这也可能意味着反编译器需要一个额外的简化规则来处理特定的情况。

这就是我们静态时第一个要注意的问题:内部反编译器函数(稍后会有总结)

所以我们这句话的意思:就是把ciphertxt的数 / 16,之后的组数,(先减一再移位最后再加一的作用是让不足一组的算作一组)

之后往下看:

得到了两个随机数,然后扔到param[0]和param[1]的位置

这时要注意一下param的定义是undefined,也就是说,这块的定义反编译时有问题,这是我们静态时需要注意的第二个问题

Ps:指令的主要任务就是对操作数进行运算,操作数有不同的类型和长度,MIPS32 提供的基本数据类型如下:
(1)位(b):长度是 1bit。
(2)字节(Byte):长度是 8bit。
(3)半字(Half Word):长度是 16bit。
(4)字(Word):长度是 32bit。
(5)双字(Double Word):长度是 64bit。
(6)此外,还有 32 位单精度浮点数、64 位双精度浮点数等。

我们注意到这两个随机数都是单字节(8位):

seb: seb指令是Sign-Extend Byte 单字节拓展(这里有猫腻)

当把第一个数存到栈里时之后,栈帧加的是0x01,在压入第二个,相当于把这两个数组合到了一起。静态比较难读懂,推荐动调。(动调在下面说)。

(我的理解:然而后面的指令ld是双字(64位)移入,把ghidra搞蒙了)具体mips汇编,会在下文总结

之后进入循环,调用cipher,每次循环处理一组数据(16个字节,2个无符号长整型)。

我们来看cipher传入的参数 

第一个参数:acStack104+偏移--->逆向老司机一猜就知道是我们的flag

第二个参数:就是刚刚分组的ciphertxt

(这个时候有个奇怪的地方,就是刚刚的随机数哪去了,发现好像没用过,其实这里就是ghidra反编译的错误,估计是因为上面对param的定义有错误造成的,参数不正确是静态时要注意的第三个问题

带着问题,我们先进encrypt函数

逻辑非常简单,但是很明显uStack32不知道是什么

这时就考虑看汇编或者动调,动调在下一个阶段来讲,这里看一下汇编:

(用的wp里的图)

我们得知:in_a2在栈中0x08的位置,即stack[-0x8],结合划线处,我们可以判断,encrypt是有三个参数的,第三个参数就是in_a2,是一个指针。根据指令ld(load double word)判断,应该是个longlong*或者ulonglong*类型的指针

发现其实栈里存了三个参数,我们可以修改函数:

往前翻一下,可以看出就是随机数的地址:

 捋一下逻辑:(这里wp里的)

def decrypt(byte16, fc, fd):
    v48 = struct.unpack('>Q', byte16[:8])[0]
    v40 = struct.unpack('>Q', byte16[8:])[0]
    v32, v24 = fc, fd
    for i in range(0x1e, -1, -1):
        v48 = rol64(v48 ^ v40, 0x3d)
        v40 = rol64(ull((v40 ^ v32) - v48), 8)
        v32 = rol64(v32 ^ v24, 0x3d)
        v24 = rol64(ull((v24 ^ i) - v32), 8)
    v48 = rol64(v48 ^ v40, 0x3d)
    v40 = rol64(ull((v40 ^ v32) - v48), 8)
    return v48, v40

之后脚本参考看雪大佬里的wp

 

问题总结:

小小总结一下ghidra静态碰到的问题

1. 内部反编译器函数

2.当遇到 undefined定义时,要注意看汇编和动调,有可能影响下面的传参

3.修改函数

4. 有时ghidra里的got表反编译有问题,在这道题里没有体现。

0x02 动态分析的问题与总结

用IDA反编译

确实可以用ida来反编译,但是会有许多问题

依然那刚刚那道题(rctf-cipher)来举例

首先我们先装好qemu和qemu里对应的mips64的库

apt install qemu-user-static
sudo apt install libc6-mips64-cross

之后可以尝试运行:

qemu-mips64-static -L /usr/mips64-linux-gnuabi64/ cipher

-static参数,显示更多的调试信息

-L 因为是动态链接所以要指定libc库的路径

不过运行时会出现如下报错,这问题我们和下一道题一起解释。

qemu: uncaught target signal 11 (Segmentation fault) - core dumped
段错误 (核心已转储)

ida远程动态调试

动态——rctf_cipher

这个我们用wp里的方法https://bbs.pediy.com/thread-259892.htm

服务端:

qemu-mips64 -L /usr/mips64-linux-gnuabi64/ -g 23946 ./cipher > out

-g在23946端口开一个gdb调试

客户端:

Debugger->attach->remote GDB debugger

之后我们勾选

之后可以跑了

IDA动调问题:

1.在看雪那篇里提到了:

2.当我们继续往下调时,会出现这个情况,这也是刚刚我们运行不了的问题

 这个我们先放在这,这个和们下一道题出的问题相似,我们一起说

(之后cipher如何动调的,请参考看雪的那篇wp)

动态——ddctf_babymips

这道题的wp参考:https://kabeor.cn/DDCTF2018%20Reverse%20writeup(1)%20baby_mips/

我们查一下文件信息:

mips32小端

悄悄静态看一下:

  1. 在ida里搜索,很轻松就定位为main函数
  2. 可以在Ghidra里找到对应位置看反编译

可以判断出主要的加密在FUN_00400420里(不过此函数里对比汇编发现有很多都没有反编译出来)

我们尝试跑一下:因为是静态链接,静态链接的程序可以像正常程序一样运行

同样发现了“段错误”的报错

我们用同样的方法把它连到ida上:

qemu-mipsel -g 23946 baby_mips

插一句:qemu-你需要的指令集 -g 端口 文件名

原理:qemu -g port指令开启一个gdbserver。port另一端可以由IDA或gdb连接调试。

连上之后我们一路单步,来到运行时报错的位置

ida跳出:

和上面一道的错误如出一辙

我们来看一下机器码:

因为是小端,所以这块就是 “EB 02 0A E7”

而mips下一条指令无论如何都是4字节,所以我们尝试把这个地方的eb02  nop掉

之后会发现,依然有这个报错

我们再次查看汇编,发现还是机器码在eb02处出相同的问题

那我们来仔细看一下解析一下这个“EB02”

因为我们是在x86下模拟的mips,而在x86指令级下/xEB是jmp的意思

而02则是相对的偏移

举个例子:

地址  机器码   

00     EB02     #jmp 0x04

02     0AE7     # 又因为一条mips指令为4字节 EB 02 0A E7  相当于跳到

                      #下一条指令

04     .......

‘02’机器码是在这个02地址基础上偏移,所以jmp的地址为 02 + 02 = 04

而mips下一条指令固定是4字节,所以造成了段错误(简而言之就是访问了不该访问的地址),姑且可以看作花指令,

这个东西不止导致动调失败,也会导致静态反编译失败

ps:上一道的段错误也应该是相似的原因(具体我还没有细看)

 (这是cipher发生段错时的情况)

 

之后我们的办法就是把所有的eb02都nop掉

idapython:

‘cq674350529’

把它保存到baby_mips_Patch里,再运行,ok了

 

这时候再反编译,原来的400420里有了算法

太大了放不下了

(还有好多)

是16个方程求解

果断z3:(当然方法很多)

from z3 import *

a = [BitVec("a%d"%i, 32) for i in range(16)]
s = Solver()
s.add(0xca6a*a[0] -0xd9ee*a[1] +0xc5a7*a[2] +0x19ee*a[3] +0xb223*a[4] +0x42e4*a[5] +0xc112*a[6] -0xcf45*a[7] +0x260d*a[8] +0xd78d*a[9] +0x99cb*a[10] -0x3e58*a[11] -0x97cb*a[12] +0xfba9*a[13] -0xdc28*a[14] +0x859b*a[15]  == 0xaa2ed7)
s.add(0xf47d*a[0] +0x12d3*a[1] -0x4102*a[2] +0xcedf*a[3] -0xafcf*a[4] -0xeb20*a[5] -0x2065*a[6] +0x36d2*a[7] -0x30fc*a[8] -0x7e5c*a[9] +0xeea8*a[10] +0xd8dd*a[11] -0xae2*a[12] +0xc053*a[13] +0x5158*a[14] -0x8d42*a[15]  =
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
反汇编带符号表的32位/64位ELF目标文件,CPU类型:ARM PowerPC MIPS X86 操作菜单选择:文件解析 Alx+P ELF文件解析 Alt+E 另有文本比较等杂项功能。V1.26.01相对上一版本,增加ARM64反汇编、64位core文件解析;V1.26.00相对上一版本,增强EXE反汇编,增加dbx老邮件解析、二维码功能;V1.25.07相对上一版本,增加二进制反汇编、IQ数据解析功能,完善MIPS反汇编,修复小BUG;V1.25.05相对上一版本,增加内存数据按数据类型解析功能;V1.25.04相对上一版本,完善X86反汇编,修复小BUG;V1.25.02相对上一版本,COREDUMP统计、匹配目标文件等相关功能优化,修复小BUG;V1.25.00相对上一版本,相关功能支持动态库文件,查询代码支持无符号目标文件+有符号目标文件,COREDUMP统计、与问题单关联、目标文件/CORE文件/问题单同步;V1.24.02相对上一版本,针对进程主动捕捉异常的信息定制处理进一步完善COREDUMP文件解析与应用,增强软件管理;V1.24.01相对上一版本,进一步完善COREDUMP文件解析与应用,提供部分ARM Thumb指令反汇编;V1.24.00相对上一版本,进一步完善COREDUMP文件解析与应用,提供堆栈调用关系分析;V1.23.03相对上一版本,提供32位X86反汇编;V1.23.02相对上一版本,提供源代码行查询指令地址,OBJ/COREDUMP文件解析,sprintf函数参数特定检查,完善文件拖放操作,修复小BUG;V1.23.01相对上一版本,提供ELF文件指令修改,修复ARM MLS指令反汇编错误等BUG;V1.23.00相对上一版本,提供程序地址对应源代码行查询,修复MIPS调试信息错误;V1.22相对上一版本,修复MIPS小端字节序反汇编错误,网上最新版本提示;V1.21相对上一版本,菜单调整,完善64位ELF文件解析,解析调试信息;另部分增强功能的菜单操作设有密码,如有兴趣欢迎咨询。欢迎大家反馈相关软件使用过程中的问题!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值