起源
万能的鱼塘收了一块板子想看看里面的固件。用swd链接后发现并不友好
jflash链接后警告
Memory Protection Unit(MPU) 简介
可配置内存保护单元,能保护整个Flash内存空间,防止被读出、覆写、擦除。
开启保护的方式
0xFFFF00FF 为开启保护。
绕过原理
nrf51系列的保护只是保护了内存地址对外读取,但是内部调试依然可以正常进行,这里可以使用一些特殊手段把代码段的内容读取到寄存器中,然后通过查看寄存器的值就能拼接出完整的"代码"。
pc寄存器寻找可用的指令,如LDR R3,[R3],这里也称为gadget。
那么可以利用这句LDR R3, [R3],R3可以是任意寄存器。只要猜出某个指令是直接用寄存器寻址,就操控pc一直跑那条指令,控制存地址的寄存器为要读取的内存地址
swd连接目标板子
question@rbp4:/mnt/sda1/iot/nrf51822$ sudo openocd -c "interface jlink" -c "transport select swd" -c "adapter speed 4000" -f
/usr/local/share/openocd/scripts/target/nrf51.cfg
Open On-Chip Debugger 0.11.0+dev-00331-g53556fcde-dirty (2021-08-17-12:34)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
DEPRECATED! use 'adapter driver' not 'interface'
swd
adapter speed: 4000 kHz
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : J-Link V9 compiled May 7 2021 16:26:12
Info : Hardware version: 9.20
Info : VTarget = 3.270 V
Info : clock speed 1000 kHz
Info : SWD DPIDR 0x0bb11477
Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for nrf51.cpu on 3333
Info : Listening on port 3333 for gdb connections
Info : accepting 'gdb' connection on tcp/3333
target halted due to debug-request, current mode: Thread
xPSR: 0x61000000 pc: 0x0000d16c msp: 0x20003a80
Info : nRF51822-QFAA(build code: H0) 256kB Flash, 16kB RAM
Info : dropped 'gdb' connection
question@rbp4:/mnt/sda1/3d/klipper$ gdb-multiarch
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "aarch64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
gdb-peda$ target extended-remote 127.0.0.1:3333
Remote debugging using 127.0.0.1:3333
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x0000d16c in ?? ()
gdb-peda$
gdb中查看RBPCONF
gdb-peda$ x 0x10001004
0x10001004: 0xffff00ff
可以可能到值是0xffff00ff 板子开启了保护。
寻找gadget
寻找过程就是不停的单步找到一个寄存器中保存的是内存地址 执行后能把地址的内容读到寄存器中
question@rbp4:~$ telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Open On-Chip Debugger
> reset halt
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x000006d0 msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0xffffffff
(4) r4 (/32): 0xffffffff
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006d0
(16) xPSR (/32): 0xc1000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
> step
target halted due to single-step, current mode: Thread
xPSR: 0xc1000000 pc: 0x000006d2 msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0xffffffff
(4) r4 (/32): 0xffffffff
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006d2
(16) xPSR (/32): 0xc1000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
> step
target halted due to single-step, current mode: Thread
xPSR: 0xc1000000 pc: 0x000006d4 msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0xffffffff
(4) r4 (/32): 0x00000c00
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006d4
(16) xPSR (/32): 0xc1000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
> step
target halted due to single-step, current mode: Thread
xPSR: 0xc1000000 pc: 0x000006d6 msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0xffffffff
(4) r4 (/32): 0xffffffff
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006d6
(16) xPSR (/32): 0xc1000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
> step
target halted due to single-step, current mode: Thread
xPSR: 0x61000000 pc: 0x000006d8 msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0xffffffff
(4) r4 (/32): 0xffffffff
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006d8
(16) xPSR (/32): 0x61000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
> step
target halted due to single-step, current mode: Thread
xPSR: 0x61000000 pc: 0x000006da msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0xffffffff
(4) r4 (/32): 0xffffffff
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006da
(16) xPSR (/32): 0x61000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
> setp
invalid command name "setp"
> step
target halted due to single-step, current mode: Thread
xPSR: 0x61000000 pc: 0x000006dc msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0x10001014 <-------------看这里
(4) r4 (/32): 0xffffffff
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006dc <-------------看这里
(16) xPSR (/32): 0x61000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
> step
target halted due to single-step, current mode: Thread
xPSR: 0x61000000 pc: 0x000006de msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0x0003b000 <-------------看这里
(4) r4 (/32): 0xffffffff
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006de
(16) xPSR (/32): 0x61000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
可以看到 $pc =0x000006dc ,正是我们需要的。
> reg r3 0x10001004
r3 (/32): 0x10001004
> reg pc 0x000006dc
pc (/32): 0x000006dc
> step
target halted due to single-step, current mode: Thread
xPSR: 0x61000000 pc: 0x000006de msp: 0x000007c0
> reg
===== arm v7m registers
(0) r0 (/32): 0xffffffff
(1) r1 (/32): 0xffffffff
(2) r2 (/32): 0xffffffff
(3) r3 (/32): 0xffff00ff <-------------看这里
(4) r4 (/32): 0xffffffff
(5) r5 (/32): 0xffffffff
(6) r6 (/32): 0xffffffff
(7) r7 (/32): 0xffffffff
(8) r8 (/32): 0xffffffff
(9) r9 (/32): 0xffffffff
(10) r10 (/32): 0xffffffff
(11) r11 (/32): 0xffffffff
(12) r12 (/32): 0xffffffff
(13) sp (/32): 0x000007c0
(14) lr (/32): 0xffffffff
(15) pc (/32): 0x000006de
(16) xPSR (/32): 0x61000000
(17) msp (/32): 0x000007c0
(18) psp (/32): 0xfffffffc
(20) primask (/1): 0x00
(21) basepri (/8): 0x00
(22) faultmask (/1): 0x00
(23) control (/3): 0x00
===== Cortex-M DWT registers
>
dump固件
网上找了个大佬写好的固件。
from pwn import *
import re
p = remote("127.0.0.1", "4444") #openocd telnet
p.recvuntil(">")
p.write("reset halt\n")
p.recvuntil(">")
with open("firmware.bin", "wb") as f:
for addr in range(0, 0x40000, 4):
p.write("reg pc 0x000006dc\n")
p.recvuntil(">")
p.write("reg r3 " + hex(addr) + "\n")
p.recvuntil(">")
p.write("step\n")
p.recvuntil(">")
p.write("reg r3\n")
ret = p.recvuntil(">")
d = re.search('0x[0-9a-fA-F]{8}', ret.decode('utf-8'))[0]
f.write(p32(int(d, 16)))
if addr % 0x100 == 0:
print("reading:", addr)
跑码
查看固件