# 提取共享单车固件 > Question > 来源:https://www.iotsec-zone.com/article/156 # 起源 万能的鱼塘收了一块板子想看看里面的固件。用swd链接后发现并不友好 ![0.png](https://www.iotsec-zone.com/images/MdImg/95532b2c53d015f61f1105a10fc06841.jpg) ## jflash链接后警告 ![1.png](https://www.iotsec-zone.com/images/MdImg/8aa7d891e14151212312b16f9357a394.png) # Memory Protection Unit(MPU) 简介 可配置内存保护单元,能保护整个Flash内存空间,防止被读出、覆写、擦除。 ## 开启保护的方式 ![2.png](https://www.iotsec-zone.com/images/MdImg/0e9724c46ef2dbc94e202840a8ed5768.png) 0xFFFF00FF 为开启保护。 # 绕过原理 nrf51系列的保护只是保护了内存地址对外读取,但是内部调试依然可以正常进行,这里可以使用一些特殊手段把代码段的内容读取到寄存器中,然后通过查看寄存器的值就能拼接出完整的"代码"。 pc寄存器寻找可用的指令,如LDR R3,[R3],这里也称为gadget。 那么可以利用这句LDR R3, [R3],R3可以是任意寄存器。只要猜出某个指令是直接用寄存器寻址,就操控pc一直跑那条指令,控制存地址的寄存器为要读取的内存地址 # swd连接目标板子 ```shell 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 ``` ```shell 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 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: . Find the GDB manual and other documentation resources online at: . 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 ```bash gdb-peda$ x 0x10001004 0x10001004: 0xffff00ff ``` 可以可能到值是0xffff00ff 板子开启了保护。 # 寻找gadget 寻找过程就是不停的单步找到一个寄存器中保存的是内存地址 执行后能把地址的内容读到寄存器中 ```shell 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 ,正是我们需要的。 ```shell > 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固件 网上找了个大佬写好的固件。 ```python 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) ``` 跑码 ![3.png](https://www.iotsec-zone.com/images/MdImg/87883dc337a72432dd31c9d59f3ac470.png) 查看固件 ![4.png](https://www.iotsec-zone.com/images/MdImg/394374da995a300b7c041bfd8ed80052.png)