commit 003147affd515640e65a4c3dd29be5d5ce0d0394 Author: Eljakim Herrewijnen Date: Fri Aug 2 16:05:02 2024 +0200 big update diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a745a80 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +ifeq ($(ANDROID_NDK_ROOT),) +$(error Error : Set the env variable 'ANDROID_NDK_ROOT' with the path of the Android NDK (version 20)) +endif + +CC := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android27-clang +AR := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar +OBJCOPY := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-objcopy +LD := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ld.bfd + +#ARM 32 bit +CC_32 := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi27-clang +AR_32 := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar +OBJCOPY_32 := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-objcopy +LD_32 := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ld.bfd + +#ARM thumb mode +TOOLCHAIN_ARM_T := $(TOOLCHAINENV)/gcc-arm-none-eabi-10-2020-q4-major/bin/arm-none-eabi- +CC_T = $(TOOLCHAIN_ARM_T)gcc +AS_T = $(TOOLCHAIN_ARM_T)as +OBJCOPY_T = $(TOOLCHAIN_ARM_T)objcopy +LD_T = $(TOOLCHAIN_ARM_T)ld.bfd + +CFLAGS := -Werror -Wno-unused-variable -Os +LINKER := /system/bin/linker64 +DEBUG := -g + +#Thumb cflags +all: error + +error: + @echo "Please specify a target to build (-f devices/nvidia_shield_t)" + +clean: + rm -rf bin/* \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..13aeff5 --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +# Gupje +Gupje is a bare metal architecture based stub debugger that helps in post-exploitation steps. Like booting a device after RCE has been achieved. Gupje is also capable of doing hardware-in-the-middle approaches as well as keeping control over a device while it is booting(Hijack trustzone etc.). + +Gupje currently supporting the following architectures: + * ARM64 (good support) + * ARM (minimal) + * ARM Thumb (decent support) + +The goal is to add support to more targets while I work on them. Because I mainly work on phones this list will probably not grow a lot in the short term. But if you have an interesting target and preferably a way to get into it(RCE), let me know and I will look into it. + +The only actual things the debugger can do is: + * Send/Receive (needs to be implemented by the user) + * Read/Write registers + +These functions are enough for a processor to run properly. The code size of the debugger is currently smaller than 4096 bytes(depends a bit on user setup) but will probably grow to include 1 extra page to support custom functionality. Like dumping extra registers and more specific VBAR setups. + +In the future it should also be possible to add fuzzing and same architecture rehosting. Once I find a project to implement this at least. + +## Overview +A simple overview of how Gupje is meant to be used can be seen below: + +![Simple Gupje Target](simple_device.drawio.svg) + +The user is responsible for gaining RCE and setting up Gupje. After this Gupje along with the ``Ghidra-Assistant`` can be used to interact with the device from within python and continue booting. + +### Gupje Setup +Because Gupje attempts to be a architecture based debugger the user only has to provide send/receive functionality to Gupje. Like sahara_tx/sahara_rx in Qualcomm based devices or a raw USB endpoint for the nvidia shield tablet. + +```c + +void send(void *buffer, uint32_t size, uint32_t *num_xfer){ + // TODO implement +} + +int recv(void *buffer, uint32_t size, uint32_t *num_xfer){ + // TODO implement + return 0; +} + +void recv_data(void *data, uint32_t len) { + uint32_t rx_err_code; + uint32_t xfer = 0; + while(1) { + recv(data, len, &xfer); + if(xfer >= len) { + break; + } + } +} + +int mystrlen(char *data) { + int i=0; + while(1) { + if(data[i++] == '\0'){ + break; + } + } + return i-1; +} + +void usb_log(char * msg, uint32_t * error){ + send(msg, mystrlen(msg), error); +} + +void concrete_main(uint32_t debugger){ + // TODO device specific code +} +``` + +Other protocols, like UART, are also possible. I will try to add more reference devices and implementations. + +### Memory layout +Overall 4 pages are always reserved for the debugger. I usually try to place them at the end of a memory region since the chance of the pages being corrupted/used by other functions is smaller. 3 pages are required at least for the debugger to function properly. + +![debugger memory layout](simple_device_memory.drawio.svg) + +## Documentation +The full documentation is covered in the ``documentation`` folder. To build it, navigate to the folder and run: +```bash +make livehtml +``` +Install the python dependencies if they are missing. (TODO add requirements) + +This code works in combination with the ``Ghidra Assistant``, which is another personal project to make Ghidra more instrumentable. + +## TODO + * ARM assembly needs to be completely rewritten + * Add code that allows the host to easily write and execute shellcode on the device. This will significantly decrease the size of the debugger. (extra page required) + * Add a more *minimal* approach to the debugger. That does not store data but can just be used to read/write memory. Usefull for exploitation when there is a very limited constraint on shellcode size. + * Implement code block stepping. + * Build an emulator to explain the debugger + +### ARM64 + * Allow restoring all registers by writing X15 to SP and jump to ELRn to create a *full* restored state. Figure out a way to branch without corrupting X15. + +### Thumb + * headless mode is not supported + * Figure out VBAR to implement single step debugging + +## Building +Download an Android NDK and set it's root path: +```bash +$ export ANDROID_NDK_ROOT=$TOOLCHAINENV/android-ndk-r21_Linux +``` + +Now you can build one of your targets: +```bash +$ make -f devices/pixel3a/Makefile +``` \ No newline at end of file diff --git a/arm64_glitch_stub.S b/arm64_glitch_stub.S new file mode 100644 index 0000000..b128b04 --- /dev/null +++ b/arm64_glitch_stub.S @@ -0,0 +1,43 @@ +.text +.global glitch_registers_loop +glitch_registers_loop: + BL trigger_high + BL trigger_low + BL glitch_dump_registers + RET + +.text +.global glitch_out_loop +glitch_out_loop: + BL trigger_high + MOV X0, #0x1 + glitch_loop: + MOV X1, #0x0 + CMP X1, X0 + b.ne glitch_loop + BL trigger_low + B debugger_main + +.text +.global glitch_dump_registers +glitch_dump_registers: + LDR X15, glitch_storage + STP X0, X1, [X15, #0x0] + STP X2, X3, [X15, #0x10] + STP X4, X5, [X15, #0x20] + STP X6, X7, [X15, #0x30] + STP X8, X9, [X15, #0x40] + STP X10, X11, [X15, #0x50] + STP X12, X13, [X15, #0x60] + STP X14, X15, [X15, #0x70] + STP X16, X17, [X15, #0x80] + STP X18, X19, [X15, #0x90] + STP X20, X21, [X15, #0xa0] + STP X22, X23, [X15, #0xb0] + STP X24, X25, [X15, #0xc0] + STP X26, X27, [X15, #0xd0] + STP X28, X29, [X15, #0xe0] + STP X30, X31, [X15, #0xf0] + RET + +glitch_storage: .quad glitch_storage \ No newline at end of file diff --git a/arm64_stub.S b/arm64_stub.S new file mode 100644 index 0000000..3a1fe34 --- /dev/null +++ b/arm64_stub.S @@ -0,0 +1,416 @@ +start: + LDR X15, addr_debugger_storage + + STR X0, [X15, #0] + STR X1, [X15, #8] + STR X2, [X15, #16] + STR X3, [X15, #24] + STR X4, [X15, #32] + STR X5, [X15, #40] + STR X6, [X15, #48] + STR X7, [X15, #56] + STR X8, [X15, #64] + STR X9, [X15, #72] + STR X10, [X15, #80] + STR X11, [X15, #88] + STR X12, [X15, #96] + STR X13, [X15, #104] + STR X14, [X15, #112] + STR X15, [X15, #120] + STR X16, [X15, #128] + STR X17, [X15, #136] + STR X18, [X15, #144] + STR X19, [X15, #152] + STR X20, [X15, #160] + STR X21, [X15, #168] + STR X22, [X15, #176] + STR X23, [X15, #184] + STR X24, [X15, #192] + STR X25, [X15, #200] + STR X26, [X15, #208] + STR X27, [X15, #216] + STR X28, [X15, #224] + STR X29, [X15, #232] + STR X30, [X15, #240] + MOV X0, SP + STR X0, [X15, #248] + + // Does not override the SP etc. TODO ELHER make configurable in debugger (during setup) + // B debugger_main + + // Overwrite SP and FP with the debugger stack location + LDR X0, addr_debugger_stack + MOV SP, X0 + MOV FP, X0 + + // See if we need to disable the MMU on entry + // LDR X0, [X15, #0xfd0] + // CMP X0, #0x777 //Disable the MMU + // BL disable_mmu + + // Compare to see if we need to jump into the debugger or need to continue the 'normal' execution flow + LDR X0, [X15, #4064] + CMP X0, #0x777 + B.NE debugger_main + + + # Continue 'normal' execution flow + BL sync_processor_state + + // Restore LR and FP + LDR X30, [X15, #240] + LDR X29, [X15, #232] + + // Restore the stack pointer + LDR X0, [X15, #248] + MOV SP, X0 + + // Also restore X0 + LDR X0, [X15, #0] + + LDR X15, [X15, #0xfd8] + BR X15 + +.text +.global disable_mmu +disable_mmu: + MRS X0, SCTLR_EL3 + AND X0, X0, #-0x2 + RET + +.text +.global enable_mmu +enable_mmu: + // TODO crashes on EL1? + MRS X0, SCTLR_EL3 + ORR X0, X0, #0x1 + RET + +.text +.global restore_and_jump +restore_and_jump: + BL sync_processor_state + + //See if we need to enable the MMU + // LDR X0, [X15, #0xfd0] + // CMP X0, #0x777 //Disable the MMU + // BL enable_mmu + + // Restore LR and FP + LDR X30, [X15, #240] + LDR X29, [X15, #232] + + // Restore the stack pointer + LDR X0, [X15, #248] + MOV SP, X0 + + // Also restore X0 + LDR X0, [X15, #0] + + // Load target address and branch to it without setting the LR + // JUMP_ADDR + LDR X15, [X15, #4088] + BR X15 + +.text +.global dump_special_el3 +dump_special_el3: + MRS X0, TTBR0_EL3 + STR X0, [X15, #256] + + MRS X0, SCTLR_EL3 + STR X0, [X15, #280] + + MRS X0, VBAR_EL3 + STR X0, [X15, #304] + + MRS X0, TCR_EL3 + STR X0, [X15, #328] + + MRS X0, ELR_EL3 + STR X0, [X15, #352] + + MRS X0, SPSR_EL3 + STR X0, [X15, #400] + + MRS X0, MAIR_EL3 + STR X0, [X15, #424] + + // Also dump el2, el1 + BL dump_special_el2 + BL dump_special_el1 + RET + +.text +.global dump_special_el2 +dump_special_el2: + MRS X0, TTBR0_EL2 + STR X0, [X15, #264] + + MRS X0, SCTLR_EL2 + STR X0, [X15, #288] + + MRS X0, VBAR_EL2 + STR X0, [X15, #312] + + MRS X0, TCR_EL2 + STR X0, [X15, #336] + + MRS X0, ELR_EL2 + STR X0, [X15, #360] + + MRS X0, SP_EL2 + STR X0, [X15, #376] + + MRS X0, SPSR_EL2 + STR X0, [X15, #408] + + MRS X0, MAIR_EL2 + STR X0, [X15, #432] + + // also dump EL1 + BL dump_special_el1 + RET + +.text +.global dump_special_el1 +dump_special_el1: + // EL1 registers dump + MRS X0, TTBR0_EL1 + STR X0, [X15, #272] + + MRS X0, SCTLR_EL1 + STR X0, [X15, #296] + + MRS X0, VBAR_EL1 + STR X0, [X15, #320] + + MRS X0, TCR_EL1 + STR X0, [X15, #344] + + MRS X0, ELR_EL1 + STR X0, [X15, #368] + + // see https://community.arm.com/support-forums/f/architectures-and-processors-forum/49184/difference-between-sp_el1-and-spsel-mov + // TODO for dumping with interactive shellcode? + // MRS X0, SP_EL1 + // STR X0, [X15, #384] + + MRS X0, SPSR_EL1 + STR X0, [X15, #416] + + MRS X0, MAIR_EL1 + STR X0, [X15, #440] + RET + +.text +.global dump_special_regs +dump_special_regs: + LDR X15, addr_debugger_storage + + MRS X0, CurrentEL + STR X0, [X15, #448] + + cmp X0, #0b1100 // EL3 + BEQ dump_special_el3 + + cmp X0, #0b1000 // EL2 + BEQ dump_special_el2 + + cmp X0, #0b0100 // EL1 + BEQ dump_special_el1 + + // EL0 registers + MRS X0, SP_EL0 + STR X0, [X15, #392] + + RET + +.text +.global write_special_el3 +write_special_el3: + LDR X0, [X15, #256] + MSR TTBR0_EL3, X0 + + LDR X0, [X15, #280] + MSR SCTLR_EL3, X0 + + LDR X0, [X15, #304] + MSR VBAR_EL3, X0 + + LDR X0, [X15, #328] + MSR TCR_EL3, X0 + + LDR X0, [X15, #352] + MSR ELR_EL3, X0 + + LDR X0, [X15, #376] + MSR SP_EL2, X0 + + LDR X0, [X15, #400] + MSR SPSR_EL3, X0 + + LDR X0, [X15, #424] + MSR MAIR_EL3, X0 + + BL write_special_el2 + BL write_special_el1 + + RET + +.text +.global write_special_el2 +write_special_el2: + LDR X0, [X15, #264] + MSR TTBR0_EL2, X0 + + LDR X0, [X15, #288] + MSR SCTLR_EL2, X0 + + LDR X0, [X15, #312] + MSR VBAR_EL2, X0 + + LDR X0, [X15, #336] + MSR TCR_EL2, X0 + + LDR X0, [X15, #360] + MSR ELR_EL2, X0 + + LDR X0, [X15, #384] + MSR SP_EL1, X0 + + LDR X0, [X15, #408] + MSR SPSR_EL2, X0 + + LDR X0, [X15, #432] + MSR MAIR_EL2, X0 + + BL write_special_el1 + + RET + +.text +.global write_special_el1 +write_special_el1: + LDR X0, [X15, #272] + MSR TTBR0_EL1, X0 + + LDR X0, [X15, #296] + MSR SCTLR_EL1, X0 + + LDR X0, [X15, #320] + MSR VBAR_EL1, X0 + + LDR X0, [X15, #344] + MSR TCR_EL1, X0 + + LDR X0, [X15, #368] + MSR ELR_EL1, X0 + + LDR X0, [X15, #392] + MSR SP_EL0, X0 + + LDR X0, [X15, #416] + MSR SPSR_EL1, X0 + + LDR X0, [X15, #440] + MSR MAIR_EL1, X0 + RET + +.text +.global write_special_regs +write_special_regs: + LDR X15, addr_debugger_storage + + MRS X0, CurrentEL + STR X0, [X15, #448] + + cmp X0, #0b1100 // EL3 + BEQ write_special_el3 + + cmp X0, #0b1000 // EL2 + BEQ write_special_el2 + + cmp X0, #0b0100 // EL1 + BEQ write_special_el1 + + RET + + +.text +.global debugger_sync_special_regs +debugger_sync_special_regs: + BL write_special_regs + B debugger_main + +.text +.global debugger_dump_special_regs +debugger_dump_special_regs: + BL dump_special_regs + B debugger_main + +.text +.global sync_processor_state +sync_processor_state: + //Corrupt X15 to use it to restore the rest of the state, except for the SP, LR and FP + LDR X15, addr_debugger_storage + + LDR X1, [X15, #8] + LDR X2, [X15, #16] + LDR X3, [X15, #24] + LDR X4, [X15, #32] + LDR X5, [X15, #40] + LDR X6, [X15, #48] + LDR X7, [X15, #56] + LDR X8, [X15, #64] + LDR X9, [X15, #72] + LDR X10, [X15, #80] + LDR X11, [X15, #88] + LDR X12, [X15, #96] + LDR X13, [X15, #104] + LDR X14, [X15, #112] + LDR X15, [X15, #120] + LDR X16, [X15, #128] + LDR X17, [X15, #136] + LDR X18, [X15, #144] + LDR X19, [X15, #152] + LDR X20, [X15, #160] + LDR X21, [X15, #168] + LDR X22, [X15, #176] + LDR X23, [X15, #184] + LDR X24, [X15, #192] + LDR X25, [X15, #200] + LDR X26, [X15, #208] + LDR X27, [X15, #216] + LDR X28, [X15, #224] + RET + +.text +.global restore_and_return +restore_and_return: + B sync_processor_state + + // Restore LR and FP + LDR X30, [X15, #240] + LDR X29, [X15, #232] + + // Restore the stack pointer + LDR X0, [X15, #248] + MOV SP, X0 + + // Also restore X0 + LDR X0, [X15, #0] + + RET + +.text +.global sync_debugger +sync_debugger: + BL sync_processor_state + B debugger_main + +.align 3 + + +addr_debugger_storage: .quad debugger_storage +addr_debugger_stack: .quad debugger_stack \ No newline at end of file diff --git a/armT_stub.S b/armT_stub.S new file mode 100644 index 0000000..fd12fcf --- /dev/null +++ b/armT_stub.S @@ -0,0 +1,187 @@ +.align 1 +.thumb +start: + @ Store R0 to the stack + push {r0} + + LDR R0, addr_debugger_storage + stmia r0, {r0-r7} + + @ Also store r0 by using r1 + ldr r1, addr_debugger_storage + pop {r0} + str r0, [r1, #0] + # Keep using r0 + LDR R0, addr_debugger_storage + + @ Store R8 to R15, not available directly in thumb mode + mov r1, r8 + str r1, [r0, #0x20] + mov r1, r9 + str r1, [r0, #0x24] + mov r1, r10 + str r1, [r0, #0x28] + mov r1, r11 + str r1, [r0, #0x2c] + mov r1, r12 //ip scratch + str r1, [r0, #0x30] + mov r1, sp //sp + str r1, [r0, #0x34] + mov r1, lr //lr + str r1, [r0, #0x38] + mov r1, pc //pc + str r1, [r0, #0x3c] + + // set debugger stack (r13 sp, r14 lr, r15 pc) + ldr r0, addr_debugger_stack + mov sp, r0 + + // Compare to see if we need to jump into the debugger or need to continue the 'normal' execution flow + // Default is jump in debugger + // CNT_EXEC 0x7f0 + ldr r1, addr_debugger_storage + ldr r0, =0x700 + add r0, #0xf0 + add r0, r0, r1 + + CMP r0, #0x77 + beq start_normal + + @ TODO, use r8, how can I clear it + ldr r2, addr_debugger_main + mov r12, r2 + bx r12 + + // Continue 'normal' execution flow +start_normal: + BL sync_processor_state + + // Restore LR, TODO + @ LDR LR, [r1, #240] + + @ // Restore the stack pointer + @ LDR R0, [r1, #248] + @ MOV SP, R0 + + // Also restore X0 + LDR R0, [r1, #0] + + // 0x7ec DBG_JUMP_TO + @ LDR r1, [r1, #0x7ec] + @ bx r1 + + +.text +.global restore_and_jump +restore_and_jump: + // Restores all registers except for LR and SP + BL sync_processor_state + + // restore SP, LR + ldr r0, addr_debugger_storage + ldr r1, [r0, #0x34] + mov sp, r1 //SP + ldr r1, [r0, #0x38] + mov lr, r1 //LR + + @ Load JUMP_ADDR 0x7fc into r12 + ldr r0, addr_debugger_storage + ldr r1, =0x7fc + add r1, r1, r0 + ldr r1, [r1] @ JUMP_ADDR + mov r12, r1 + + // Restore r0 and r1 + ldr r0, addr_debugger_storage + ldr r1, [r0, #4] + ldr r0, [r0] + + @ At this point everything is restored except for r12, which contains the jump address + bx r12 + +.text +.global debugger_sync_special_regs +debugger_sync_special_regs: + @ mov r4, #0x77 + // TODO, what special regs?? + bx LR + +.text +.global dump_special_regs +dump_special_regs: + // TODO, what special regs?? + bx LR + + +.text +.global debugger_dump_special_regs +debugger_dump_special_regs: + BL dump_special_regs + B debugger_main + + +.text +.global sync_processor_state +sync_processor_state: + @ Syncs general purpose registers back to the cpu and branches to the LR + + @ Load r8-r12 + ldr r0, addr_debugger_storage + ldr r1, [r0, #0x20] + mov r8, r1 + ldr r1, [r0, #0x24] + mov r9, r1 + ldr r1, [r0, #0x28] + mov r10, r1 + ldr r1, [r0, #0x2c] + mov r11, r1 + ldr r1, [r0, #0x30] + mov r12, r1 + + @ Not restoring SP, LR and PC. Left here as reference + @ ldr r1, [r0, #0x34] + @ mov r13, r1 //sp + @ ldr r1, [r0, #0x38] + @ mov r14, r1 //lr + @ ldr r1, [r0, #0x3c] + @ mov r15, r1 //pc + + @ load r0-r7 + ldr r0, addr_debugger_storage + ldmia r0, {r0-r7} + + bx lr + + +.text +.global restore_and_return +restore_and_return: + B sync_processor_state + + // restore SP, LR + ldr r0, addr_debugger_storage + ldr r1, [r0, #0x30] + mov r12, r1 //IP + ldr r1, [r0, #0x34] + mov sp, r1 //SP + ldr r1, [r0, #0x38] + mov lr, r1 //LR + + // Restore r0 and r1 + @ ldr r0, addr_debugger_storage + ldr r1, [r0, #4] + ldr r0, [r0] + + @ At this point everything is restored including the LR. Return to it + BX LR + +.text +.global sync_debugger +sync_debugger: + BL sync_processor_state + b debugger_main + +.align 4 +addr_debugger_storage: .word debugger_storage +addr_debugger_stack: .word debugger_stack +addr_debugger_main: .word debugger_main \ No newline at end of file diff --git a/arm_stub.S b/arm_stub.S new file mode 100644 index 0000000..40c5695 --- /dev/null +++ b/arm_stub.S @@ -0,0 +1,112 @@ +start: + // TODO there is an ARM instruction that pushes all values to the stack + // LDR R15, addr_debugger_storage + STR R0, [R15, #0] + STR R1, [R15, #4] + STR R2, [R15, #8] + STR R3, [R15, #12] + STR R4, [R15, #16] + STR R5, [R15, #20] + STR R6, [R15, #24] + STR R7, [R15, #28] + STR R8, [R15, #64] + STR R9, [R15, #72] + STR R10, [R15, #80] + STR R11, [R15, #88] + STR R12, [R15, #96] + STR R13, [R15, #104] + STR R14, [R15, #112] + MOV R0, SP + STR R0, [R15, #248] + + // Overwrite SP and FP with the debugger stack location + // LDR R0, addr_debugger_stack + MOV SP, R0 + MOV FP, R0 + + B debugger_main + +.text +.global restore_and_jump +restore_and_jump: + BL sync_processor_state + + // Restore the stack pointer + LDR R0, [R15, #248] + MOV SP, R0 + + // Also restore R0 + LDR R0, [R15, #0] + + // Load target address and branch to it + LDR R15, [R15, #4088] + B debugger_main + +.text +.global dump_special_regs +dump_special_regs: + B debugger_main + +.text +.global write_special_regs +write_special_regs: + B debugger_main + + +.text +.global debugger_sync_special_regs +debugger_sync_special_regs: + BL write_special_regs + B debugger_main + +.text +.global debugger_dump_special_regs +debugger_dump_special_regs: + BL dump_special_regs + B debugger_main + +.text +.global sync_processor_state +sync_processor_state: + //Corrupt R15 to use it to restore the rest of the state, eRcept for the SP, LR and FP + // R13 == SP, R14 == LR, R15 == PC (oops) + // LDR R15, addr_debugger_storage + + LDR R1, [R15, #8] + LDR R2, [R15, #16] + LDR R3, [R15, #24] + LDR R4, [R15, #32] + LDR R5, [R15, #40] + LDR R6, [R15, #48] + LDR R7, [R15, #56] + LDR R8, [R15, #64] + LDR R9, [R15, #72] + LDR R10, [R15, #80] + LDR R11, [R15, #88] + LDR R12, [R15, #96] + LDR R13, [R15, #104] + LDR R14, [R15, #112] + bx lr + +.text +.global restore_and_return +restore_and_return: + B sync_processor_state + + // Restore the stack pointer + LDR R0, [R15, #248] + MOV SP, R0 + + // Also restore R0 + LDR R0, [R15, #0] + + BX LR + +.text +.global sync_debugger +sync_debugger: + BL sync_processor_state + B debugger_main + +.align 3 + diff --git a/debugger.c b/debugger.c new file mode 100644 index 0000000..0aca46c --- /dev/null +++ b/debugger.c @@ -0,0 +1,227 @@ +#include +#include "device.h" + + +// These functions must be included in your device.h and device.c files +// extern void send(void*addr, uint32_t size, void *return_addr); //from device to host +// extern int recv(void *data, uint32_t len, uint32_t max_len, uint32_t *err_code, uint32_t type); //from host to device +// extern void recv_data(void *data, uint32_t len); +// extern int mystrlen(char *data); +// extern void usb_log(char * msg, uint32_t * error); + +#ifdef __aarch64__ +#include "debugger_archs/ga_arm64.h" +#elif __arm__ +#include "debugger_archs/ga_arm.h" +#elif __thumb__ +#include "debugger_archs/ga_arm_thumb.h" +#else +#include "debugger_archs/ga_arm64.h" +#endif + +#ifdef GLITCH_ENABLE +#include "glitch_handler.h" +#endif + +// Functions that are implemented in assembly, based on the architecture +extern void restore_and_jump(); +extern void debugger_dump_special_regs(); +extern void sync_debugger(); +extern void debugger_sync_special_regs(); +extern void restore_and_return(); + +extern int debugger_storage; +// uint64_t debugger_storage_values[] = &debugger_storage; +#define GUPJE_BLOCK_SIZE 0x100 + +__attribute__((section(".init"))) +int debugger_main(void){ + #ifdef DEVICE_SETUP + #ifdef __aarch64__ + uint64_t *val = (uint64_t *)((uint64_t)debugger_storage); + + // 0xfc0 + if(val[504] == (uint64_t)0x77){ + void (*custom_func)() = (void*)val[505]; //0xfc8 + // custom_func(); + } + else{ + device_setup(); + } + #endif + // TODO other architectures + #endif + + #ifdef __aarch64__ + uint64_t mem_off; + #else + uint32_t mem_off; + #endif + uint32_t tx_err_code; + uint32_t mem_sz; + uint32_t blk_sz; + char cmd[12]; + char data[0x20]; + usb_log("GiAs", &tx_err_code); + + while(1){ + recv_data(&data, 4); + if(data[0] == 'P' && data[1] == 'I' && data[2] == 'N' && data[3] == 'G'){ + data[1] = 'O'; + send(&data, 4, &tx_err_code); + } + else if(data[0] == 'P' && data[1] == 'E' && data[2] == 'E' && data[3] == 'K') { + // peek, dump memory + recv_data(&data, 12); // Receive uint64_t size and and uint32_t offset + #ifdef __aarch64__ + mem_off = *(uint64_t *)data; + mem_sz = *(uint32_t *)(data+8); + #else + // For ARM and Thumb Mode + // Receive uint32_t size and and uint32_t offset + mem_off = *(uint32_t *)data; + mem_sz = *(uint32_t *)(data+4); + #endif + + for(unsigned int i=0;i<=mem_sz;i+=GUPJE_BLOCK_SIZE) { + if((mem_sz - i) < GUPJE_BLOCK_SIZE) { + blk_sz = mem_sz - i; + } else { + blk_sz = GUPJE_BLOCK_SIZE; + } + send((void *)(mem_off+i), blk_sz, &tx_err_code); + recv_data(&data, 4); + if(!(data[0] == 'A' && data[1] == 'C' && data[2] == 'K')) { + break; + } + } + } + else if(data[0] == 'H' && data[1] == 'W' && data[2] == 'I' && data[3] == 'O') { + //HWIO, write byte by byte + // + recv_data(&data, 0x20); + mem_off = *(uint32_t *)data; + mem_sz = *(uint32_t *)(data+8); + // Data is stored in the rest of the data buffer + // No error checking on size, be carefull! + for(unsigned int i=0;i + +void dump_regs(uint32_t addr){ + +} \ No newline at end of file diff --git a/debugger_archs/ga_arm64.h b/debugger_archs/ga_arm64.h new file mode 100644 index 0000000..3b89082 --- /dev/null +++ b/debugger_archs/ga_arm64.h @@ -0,0 +1,31 @@ +#include + +void invalidate_tlb() +{ + asm( + "dsb sy\n" + "tlbi alle3\n" + "dsb sy\n" + "isb\n" + ); +} + +void sync() +{ + asm( + "dsb sy\n" + "isb\n" + ); +} + +void iciallu(void) +{ + __asm__ __volatile__("ic iallu\n\t" : : :"memory"); + __asm__ __volatile__("ic ialluis\n\t" : : :"memory"); +} + +void cache_flush(){ + // invalidate_tlb(); + sync(); + iciallu(); +} \ No newline at end of file diff --git a/debugger_archs/ga_arm_thumb.h b/debugger_archs/ga_arm_thumb.h new file mode 100644 index 0000000..eac97a0 --- /dev/null +++ b/debugger_archs/ga_arm_thumb.h @@ -0,0 +1,5 @@ +#include + +void dump_regs(uint32_t addr){ + +} \ No newline at end of file diff --git a/documentation/.gitignore b/documentation/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/documentation/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/documentation/.vscode/settings.json b/documentation/.vscode/settings.json new file mode 100644 index 0000000..a7d0fc7 --- /dev/null +++ b/documentation/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "esbonio.sphinx.confDir": "" +} \ No newline at end of file diff --git a/documentation/Makefile b/documentation/Makefile new file mode 100644 index 0000000..a9f815e --- /dev/null +++ b/documentation/Makefile @@ -0,0 +1,27 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SPHINXAUTOBUILD = sphinx-autobuild +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +confluence: + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" -E -a $(O) + +livehtml: + @$(SPHINXAUTOBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) --port 34343 + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/documentation/make.bat b/documentation/make.bat new file mode 100644 index 0000000..747ffb7 --- /dev/null +++ b/documentation/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/documentation/source/architectures/arm/debugger/arm_debugger_storage.rst b/documentation/source/architectures/arm/debugger/arm_debugger_storage.rst new file mode 100644 index 0000000..3372c51 --- /dev/null +++ b/documentation/source/architectures/arm/debugger/arm_debugger_storage.rst @@ -0,0 +1,59 @@ +******************************** +Debugger Storage Overview on ARM +******************************** + +Overview of the storage setup on ARM Thumb for the debugger. +To interact with this storage dump you can either dump the storage location and parse the entries or use the *utils/debugger/debugger_archs/armT_processor_state.py* processor state, which is also passed as an argument in **GA_arm_thumb_debugger**. + +.. note:: All addresses below asume ``STORAGE_LOCATION`` + **Address** + + ++---------+-----------------+--------------------------------------------------------------------------------+ +| Address | Function | Comment | ++=========+=================+================================================================================+ +| 0x0 | R0 | Stores Register R0 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x4 | R1 | Stores Register R1 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x8 | R2 | Stores Register R2 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0xc | R3 | Stores Register R3 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x10 | R4 | Stores Register R4 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x14 | R5 | Stores Register R5 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x18 | R6 | Stores Register R6 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x1c | R7 | Stores Register R7 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x20 | R8 | Stores Register R8 (Indirect Function Call Target ``IFC``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x24 | R9 | Stores Register R9 (Platform Register ``P``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x28 | R10 | Stores Register R10 (Thread Pointer ``TP``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x2c | R11 | Stores Register R11 (Frame Pointer ``FP``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x30 | R12 | Stores Register R12 (Intra-Procedure-call-scratched-Register ``IP``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x34 | R13 | Stores Register R13 (Stack Pointer ``SP``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x38 | R14 | Stores Register R14 (Link Register ``LR``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x3c | R15 | Stores Register R15 (Program Counter ``PC``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| | | | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7d8 | DBG_MMU_DISABLE | **DISABLED** ``DEBUGGER`` Disable the MMU on entry and enable the MMU on leave | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7ec | DBG_JUMP_TO | ``DEBUGGER`` Address to jump to instead of the debugger | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7f0 | DBG_CONT_EXEC | ``DEBUGGER`` Do not jump in debugger but into | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7f4 | TEMP X0 | ``DEBUGGER`` Temporary storage for X0 value | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7f8 | Store X0 | ``DEBUGGER`` Stores exception id for the ``SMC`` call | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7fc | JUMP_ADDR | ``DEBUGGER`` Memory location that instructs the debugger where to jump to | ++---------+-----------------+--------------------------------------------------------------------------------+ \ No newline at end of file diff --git a/documentation/source/architectures/arm/index.rst b/documentation/source/architectures/arm/index.rst new file mode 100644 index 0000000..c3a0e43 --- /dev/null +++ b/documentation/source/architectures/arm/index.rst @@ -0,0 +1,5 @@ +=== +ARM +=== + +.. include:: debugger/arm_debugger_storage.rst \ No newline at end of file diff --git a/documentation/source/architectures/arm64/aarch64_mmu.rst b/documentation/source/architectures/arm64/aarch64_mmu.rst new file mode 100644 index 0000000..20e745e --- /dev/null +++ b/documentation/source/architectures/arm64/aarch64_mmu.rst @@ -0,0 +1,31 @@ +****************************** +Memory Managment Unit on ARM64 +****************************** +This part describes the memory managment unit on ARM64 and how it is used by the debugger. + +Single Level Pagetable at EL3 +============================= +The documentation described here can also be found at the `official ARM documentation `_. + +Translation Regime +****************** +Register ``TCR_ELx`` is used to control the **Tranlation Regime** for the pagetables. The documentation for the ``TCR_EL3`` can be found in the `official ARM documentation `_. + +Translation Table +***************** +The location of the page table is located in register ``ttbr0_el3``. Depending of the configuration of ``TCR_EL3`` the bits for address selection can change. + +More documentation can be found `here `_ + +Pagetable Entry +*************** +The following diagram shows the format of a stage 1 level 1 table entry on EL3. + +.. image:: images/mmu/singlelevel_el3_pte.png + +Automatic Paging +================ +Automatic paging for page walking will be setup in the debugger. +For this the ``ARM64_Concrete_State`` contains a mmu with class ``ARM64_MMU``. + + diff --git a/documentation/source/architectures/arm64/aarch64_vbar.rst b/documentation/source/architectures/arm64/aarch64_vbar.rst new file mode 100644 index 0000000..0df3894 --- /dev/null +++ b/documentation/source/architectures/arm64/aarch64_vbar.rst @@ -0,0 +1,58 @@ +********************** +Vector Tables in ARM64 +********************** +A lot of this documentation can also be found in the `ARM SMC calling convention documentation `_ + +Vector Exception Levels +======================= + +In ARM64 each there is a Vector table for each Exception level, except for EL0. So, in practice there is a Vector table for: + + * EL3 ``Secure Monitor Call (SMC)`` + * EL2 ``Hyper Visor Call (HVC)`` + * EL1 ``Super Visor Call (SVC)`` + +Documentation about this can be found in `the ARM documentation `_ + +.. image:: images/vector_table/vector_table_arm64.png + +This vector table can be allocated and filled for each of the vector tables described above. + +Setting the Vector Base Address +=============================== +To set the location of this vector table a call ``MSR`` call can be done to ``VBAR_ELX`` which will write an address to that register. When an execption call is executed, this address is fetched and execution will move to that page, with the corresponding Execption Level(EL) + +ARM SMC Calling Convention +========================== +When doing an SMC call in arm64 a synchronous exception is generated that is handled by the secure monitor in EL3. +The SMC call can be in both 32 and 64 bit mode, depending on various bits in the instruction. +For most phones this will be in 64 bit mode. + +When doing a SMC call, the register ``ELR_ELn`` is updated to show the location of where the call came from. +This is the address after the call where the exception came from. When doing an ``ERET`` instruction this value is written to the ``PC``. + +Stack Pointers +************** +Each Exception Level has its own stack pointers. The registers for these are: + +* SP_EL0 +* SP_EL1 +* SP_EL2 +* SP_EL3 + +``SP_EL3`` is innacessible in EL3, to read it you need to read the ``SP``. + +**************************** +Debugger VBAR Implementation +**************************** + +The debugger uses a SMC call to insert a breakpoint at any address. When a SMC call is thrown the processor jumps to the address pointed to in the ``VBAR_EL3`` register. +This register **has to ** point to the debugger. +The debugger will first store all the registers in the storage location, overwrite the stack pointer and send the hello message ``b'GiAs'`` to the host. + +An overview of what is happening when a SMC call is dan can be seen below: + +.. image:: images/vector_table/smc_handling_arm64.jpg + +.. warning:: Currently register X15 gets corrupted when an SMC call is handled. + diff --git a/documentation/source/architectures/arm64/debugger/arm64_debugger_storage.rst b/documentation/source/architectures/arm64/debugger/arm64_debugger_storage.rst new file mode 100644 index 0000000..dbf65ec --- /dev/null +++ b/documentation/source/architectures/arm64/debugger/arm64_debugger_storage.rst @@ -0,0 +1,147 @@ +********************************** +Debugger Storage Overview on ARM64 +********************************** +Overview of the storage setup on ARM64 for the debugger. To interact with this storage dump you can either dump the storage location and parse the entries or use the *utils/debugger/debugger_archs/arm64_processor_state.py* processor state, which is also passed as an argument in **GA_arm64_debugger**. + +.. note:: All addresses below asume ``STORAGE_LOCATION`` + **Address** + + ++---------+------------------------+----------------------------------------------------------------------------------------+ +| Address | Function | Comment | ++=========+========================+========================================================================================+ +| 0x0 | X0 | Stores Register X0 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x8 | X1 | Stores Register X1 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x10 | X2 | Stores Register X2 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x18 | X3 | Stores Register X3 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x20 | X4 | Stores Register X4 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x28 | X5 | Stores Register X5 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x30 | X6 | Stores Register X6 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x38 | X7 | Stores Register X7 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x40 | X8 | Stores Register X8 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x48 | X9 | Stores Register X9 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x50 | X10 | Stores Register X10 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x58 | X11 | Stores Register X11 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x60 | X12 | Stores Register X12 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x68 | X13 | Stores Register X13 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x70 | X14 | Stores Register X14 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x78 | X15 | Stores Register X15 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x80 | X16 | Stores Register X16 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x88 | X17 | Stores Register X17 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x90 | X18 | Stores Register X18 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x98 | X19 | Stores Register X19 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xa0 | X20 | Stores Register X20 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xa8 | X21 | Stores Register X21 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xb0 | X22 | Stores Register X22 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xb8 | X23 | Stores Register X23 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xc0 | X24 | Stores Register X24 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xc8 | X25 | Stores Register X25 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xd0 | X26 | Stores Register X26 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xd8 | X27 | Stores Register X27 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xe0 | X28 | Stores Register X28 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xe8 | X29 | Stores the ``Frame Pointer`` | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xf0 | X30 | Stores the ``Link Register`` | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xf8 | SP | Stores the ``Stack Pointer`` | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x100 | TTBR0_EL3 | Stores ``TTBR0_EL3`` | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x108 | TTBR0_EL2 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x110 | TTBR0_EL1 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x118 | SCTLR_EL3 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x120 | SCTLR_EL2 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x128 | SCTLR_EL1 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x130 | VBAR_EL3 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x130 | VBAR_EL2 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x140 | VBAR_EL1 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x148 | TCR_EL3 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x150 | TCR_EL2 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x158 | TCR_EL1 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x160 | ELR_EL3 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x168 | ELR_EL2 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x170 | ELR_EL1 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x178 | SP_EL2 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x180 | SP_EL1 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x188 | SP_EL0 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x190 | SPSR_EL3 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x198 | SPSR_EL2 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x1a0 | SPSR_EL1 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x1a8 | MAIR_EL3 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x1b0 | MAIR_EL2 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x1b8 | MAIR_EL1 | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0x1c0 | CurrentEL | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| | | | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xfc0 | DBG_SETUP_JUMP | ``DEBUGGER`` Set to 0x77 to jump to ``DBG_SETUP_JUMP_ADDRESS`` and when DEVICE_SETUP=1 | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xfc8 | DBG_SETUP_JUMP_ADDRESS | ``DEBUGGER`` Address to jump to when ``DBG_SETUP_JUMP`` is set to *0x77* | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xfd0 | DBG_MMU_DISABLE | **DISABLED** ``DEBUGGER`` Disable the MMU on entry and enable the MMU on leave | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xfd8 | DBG_JUMP_TO | ``DEBUGGER`` Address to jump to instead of the debugger | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xfe0 | DBG_CONT_EXEC | ``DEBUGGER`` Do not jump in debugger but into | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xfe8 | TEMP X0 | ``DEBUGGER`` Temporary storage for X0 value | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xff0 | Store X0 | ``DEBUGGER`` Stores exception id for the ``SMC`` call | ++---------+------------------------+----------------------------------------------------------------------------------------+ +| 0xff8 | JUMP_ADDR | ``DEBUGGER`` Memory location that instructs the debugger where to jump to | ++---------+------------------------+----------------------------------------------------------------------------------------+ + +.. note:: This memory segment is still being updated to add registers + +When ``DBG_CONT_EXEC`` is set to **0x777** the debugger will not enter the debugger_main address, but instead restore the original processor state and jump into ``DBG_JUMP_TO``. This allows the debugger to be run without user interaction. \ No newline at end of file diff --git a/documentation/source/architectures/arm64/images/mmu/singlelevel_el3_pte.png b/documentation/source/architectures/arm64/images/mmu/singlelevel_el3_pte.png new file mode 100644 index 0000000..0d5e5af Binary files /dev/null and b/documentation/source/architectures/arm64/images/mmu/singlelevel_el3_pte.png differ diff --git a/documentation/source/architectures/arm64/images/vector_table/smc_call_arm64.png b/documentation/source/architectures/arm64/images/vector_table/smc_call_arm64.png new file mode 100644 index 0000000..7e42cfe Binary files /dev/null and b/documentation/source/architectures/arm64/images/vector_table/smc_call_arm64.png differ diff --git a/documentation/source/architectures/arm64/images/vector_table/smc_handling_arm64.jpg b/documentation/source/architectures/arm64/images/vector_table/smc_handling_arm64.jpg new file mode 100644 index 0000000..b2e13bf Binary files /dev/null and b/documentation/source/architectures/arm64/images/vector_table/smc_handling_arm64.jpg differ diff --git a/documentation/source/architectures/arm64/images/vector_table/vector_table_arm64.png b/documentation/source/architectures/arm64/images/vector_table/vector_table_arm64.png new file mode 100644 index 0000000..2688752 Binary files /dev/null and b/documentation/source/architectures/arm64/images/vector_table/vector_table_arm64.png differ diff --git a/documentation/source/architectures/arm64/index.rst b/documentation/source/architectures/arm64/index.rst new file mode 100644 index 0000000..a2e9d76 --- /dev/null +++ b/documentation/source/architectures/arm64/index.rst @@ -0,0 +1,9 @@ +===== +ARM64 +===== +Documentation for the ARM64 architecture. + +.. include:: aarch64_vbar.rst +.. include:: aarch64_mmu.rst +.. include:: system_configuration.rst +.. include:: debugger/arm64_debugger_storage.rst \ No newline at end of file diff --git a/documentation/source/architectures/arm64/system_configuration.rst b/documentation/source/architectures/arm64/system_configuration.rst new file mode 100644 index 0000000..444de55 --- /dev/null +++ b/documentation/source/architectures/arm64/system_configuration.rst @@ -0,0 +1,11 @@ +******************** +System Configuration +******************** + +Configuration for the processor can be set in the System Control Register for different exception levels. These registers are: + + * SCTLR_EL3 + * SCTLR_EL2 + * SCTLR_EL1 + +More information about the configuration settings can be found in the `ARM documentation `_ \ No newline at end of file diff --git a/documentation/source/architectures/arm_thumb/debugger/armT_debugger_storage.rst b/documentation/source/architectures/arm_thumb/debugger/armT_debugger_storage.rst new file mode 100644 index 0000000..fbb1ee0 --- /dev/null +++ b/documentation/source/architectures/arm_thumb/debugger/armT_debugger_storage.rst @@ -0,0 +1,95 @@ +*************************************** +Debugger Storage Overview on ARM(Thumb) +*************************************** + +Overview of the storage setup on ARM Thumb for the debugger. +To interact with this storage dump you can either dump the storage location and parse the entries or use the *utils/debugger/debugger_archs/armT_processor_state.py* processor state, which is also passed as an argument in **GA_arm_thumb_debugger**. + +.. note:: All addresses below asume ``STORAGE_LOCATION`` + **Address** + + ++---------+-----------------+--------------------------------------------------------------------------------+ +| Address | Function | Comment | ++=========+=================+================================================================================+ +| 0x0 | R0 | Stores Register R0 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x4 | R1 | Stores Register R1 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x8 | R2 | Stores Register R2 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0xc | R3 | Stores Register R3 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x10 | R4 | Stores Register R4 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x14 | R5 | Stores Register R5 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x18 | R6 | Stores Register R6 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x1c | R7 | Stores Register R7 | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x20 | R8 | Stores Register R8 (Indirect Function Call Target ``IFC``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x24 | R9 | Stores Register R9 (Platform Register ``P``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x28 | R10 | Stores Register R10 (Thread Pointer ``TP``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x2c | R11 | Stores Register R11 (Frame Pointer ``FP``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x30 | R12 | Stores Register R12 (Intra-Procedure-call-scratched-Register ``IP``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x34 | R13 | Stores Register R13 (Stack Pointer ``SP``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x38 | R14 | Stores Register R14 (Link Register ``LR``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x3c | R15 | Stores Register R15 (Program Counter ``PC``) | ++---------+-----------------+--------------------------------------------------------------------------------+ +| | | | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7d8 | DBG_MMU_DISABLE | **DISABLED** ``DEBUGGER`` Disable the MMU on entry and enable the MMU on leave | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7ec | DBG_JUMP_TO | ``DEBUGGER`` Address to jump to instead of the debugger | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7f0 | DBG_CONT_EXEC | ``DEBUGGER`` Do not jump in debugger but into | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7f4 | TEMP X0 | ``DEBUGGER`` Temporary storage for X0 value | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7f8 | Store X0 | ``DEBUGGER`` Stores exception id for the ``SMC`` call | ++---------+-----------------+--------------------------------------------------------------------------------+ +| 0x7fc | JUMP_ADDR | ``DEBUGGER`` Memory location that instructs the debugger where to jump to | ++---------+-----------------+--------------------------------------------------------------------------------+ + +.. note:: This memory segment is still being updated to add registers + +When ``DBG_CONT_EXEC`` is set to **0x77** the debugger will not enter the debugger_main address, but instead restore the original processor state and jump into ``DBG_JUMP_TO``. +This allows the debugger to be run without user interaction. + +.. note:: + + By default `register r12 `_ is corrupted for debugger usage(usually the high registers are not used in thumb mode) + +Low/high registers +------------------ +ARM in thumb mode has low and high registers. The low registers are R0-R7 and the high registers are R8-R15. +The high registers can not be directly accessed in thumb mode. The ``LDR`` and ``STR`` can not be used for accessing the high registers. +The ``MOV`` register however can be used to access these registers, which is enough for the debugger to use these registers. + +.. code-block:: assembly + :caption: Accessing high registers in thumb mode and branch to it. + + ldr r2, =addr_debugger_main + mov r12, r2 + bx r12 + + addr_debugger_main: .word 0x100000 + +Instructions +============ +Some notes on instructions in ``ARM Thumb``. + +Branch Exchange +--------------- +The ``BX`` instruction is used to branch to a new address and exchange the instruction set if required(ARM/Thumb). +The ``BX`` instruction does **not** set the LR. + + + diff --git a/documentation/source/architectures/arm_thumb/index.rst b/documentation/source/architectures/arm_thumb/index.rst new file mode 100644 index 0000000..c3a4cd1 --- /dev/null +++ b/documentation/source/architectures/arm_thumb/index.rst @@ -0,0 +1,6 @@ +============== +ARM Thumb Mode +============== +Documentation for the ARM architecture in ``Thumb`` Mode. + +.. include:: debugger/armT_debugger_storage.rst \ No newline at end of file diff --git a/documentation/source/conf.py b/documentation/source/conf.py new file mode 100644 index 0000000..d23a478 --- /dev/null +++ b/documentation/source/conf.py @@ -0,0 +1,32 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'gupje' +copyright = '2024, Eljakim' +author = 'Eljakim' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ 'myst_parser', + 'sphinx_rtd_theme', + 'sphinx.ext.todo', + 'sphinxcontrib.confluencebuilder', + "sphinxcontrib.drawio", +] + +templates_path = ['_templates'] +exclude_patterns = [] + + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'sphinx_rtd_theme' +html_static_path = ['_static'] diff --git a/documentation/source/images/debugger_flow.drawio.svg b/documentation/source/images/debugger_flow.drawio.svg new file mode 100644 index 0000000..cfeb9a8 --- /dev/null +++ b/documentation/source/images/debugger_flow.drawio.svg @@ -0,0 +1 @@ +
entry
Save state to DEBUGGER_STORAGE
debugger_main
GiAs
Send
Recv
No
Yes
CNT_EXEC
set?
Restore State and jump to DEBUGGER_JUMP
Restore and Return
User commands
\ No newline at end of file diff --git a/documentation/source/images/gupje_overview.drawio.svg b/documentation/source/images/gupje_overview.drawio.svg new file mode 100644 index 0000000..f0add3b --- /dev/null +++ b/documentation/source/images/gupje_overview.drawio.svg @@ -0,0 +1 @@ +
Gupje
Storage
Stack
Target device
Host
my_script.py
ghidra assitant
\ No newline at end of file diff --git a/documentation/source/index.rst b/documentation/source/index.rst new file mode 100644 index 0000000..edb48da --- /dev/null +++ b/documentation/source/index.rst @@ -0,0 +1,23 @@ +.. gupje documentation master file, created by + sphinx-quickstart on Thu Mar 28 15:26:50 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Gupje Architecture based debugger +================================= +This is the documentation for the Gupje debugger. + + +.. toctree:: + :maxdepth: 2 + :caption: Setup: + + overview.rst + +.. toctree:: + :maxdepth: 2 + :caption: Architectures: + + architectures/arm64/index.rst + architectures/arm/index.rst + architectures/arm_thumb/index.rst \ No newline at end of file diff --git a/documentation/source/overview.rst b/documentation/source/overview.rst new file mode 100644 index 0000000..3953c61 --- /dev/null +++ b/documentation/source/overview.rst @@ -0,0 +1,91 @@ +============== +Gupje overview +============== +Gupje is a stub debugger that is designed to be minimal and requires 3 pages(0x1000) of data to be loaded on a target system. +A high level overview of how the memory mapping for this works is shown below. + +.. figure:: images/gupje_overview.drawio.svg + +.. note:: + + In the future the debugger will probably grow to 4 pages, to include an extra page for the debugger to use in custom functionality. + +Features +======== +In a typical usecase the flow of the debugger wuuld look as something like this: + +.. figure:: images/debugger_flow.drawio.svg + +State saving +------------ +Function: ``On enter`` + +The first thing the debugger does when it enters is save it's state into it's storage page. +The state being all the General Purpose registers and some special register, like the stack pointer and link register. +The stack pointer is overwritten to the debugger stack, in order to not taint the original stack. +This is architecture dependent and written in Assembly. +See the documentation in each architecture on how this is performed and if data is lost. + +Memory Read(Peek) +----------------- +Read an address in memory to the host. + +Memory Write(Poke) +------------------ +Write a buffer to an address in memory. + +Get debugger main(SELF) +----------------------- +Get the main entry point of the debugger. This is used to jump to only the debugger without setting up the stack and registers again. +This taints the device but is very usefull for debugging and showing where the debugger is in memory. + +Concrete main(MAIN) +------------------- +Execute the ``concrete_main`` function. This function is fully user customizable and can be used to implement custom functionality. +Like executing boot stages in a Qualcomm bootROM. + +Flush Cache(FLSH) +----------------- +Execute architecture specific instructions in order to flush the cache. + +.. note:: + + Only arm64 is supported for this function. The support is there for arm and thumb but not implemented. + +Jump to address(JUMP) +--------------------- +Simple function that will just jump to an address without restoring the stack or registers. Usefull for testing the debugger or relocating it. + +Dump special registers(SPEC) +---------------------------- +Will dump the special registers to the host. This is architecture dependent and will only dump the registers that are supported. For ARM64 checks for each exception level are implemented. + +Synchronize State(SYNC) +----------------------- +This function can be called from the debugger and will force write the registers from the saved state into the processor. + +Sync Special(SYNS) +------------------ +Will force write the special registers from the saved state into the processor. Usefull for overwriting the ``VBAR_ELN`` and others. +Not all registers are supported here and in the future this will probably be changed to be code pushed from the host to save space and support all special registers. + +.. note:: + + This function is currently only properly implemented for ARM64. + +Restore and Jump(REST) +---------------------- +This function restores the state of the processor from it's internal storage and jump's to the address defined in ``DEBUGGER_JUMP``. + +.. caution:: + + Currently there is always a register corrupted on the jump function(we need to branch to a register). I have not found a good method to mitigate this(maybe ldr pc in arm/thumb but wont work for arm64) + +Restore and Return(RRET) +------------------------ +Does the same as ``Restore and Jump`` but instead of jumping it returns to the address that called the debugger. + +Glitching +========= +A debug flag is added for adding glitching to the debugger. The command ``GLIT`` will jump to the glitch function but this is not very well implemented yet. +The goal is to add several testable glitch cases to the debugger for profiling. \ No newline at end of file diff --git a/glitch_handler.h b/glitch_handler.h new file mode 100644 index 0000000..19f5ec2 --- /dev/null +++ b/glitch_handler.h @@ -0,0 +1,36 @@ +#include + +extern void glitch_registers_loop(); +extern void glitch_out_loop(); + +int glitch_main(uintptr_t cmd_handler){ + uint32_t tx_err_code; + char data[0x20]; + usb_log("GlAs", &tx_err_code); // Send glitcher magic + + while(1){ + recv_data(&data, 4); + if(data[0] == 'P' && data[1] == 'I' && data[2] == 'N' && data[3] == 'G'){ + //PING + data[1] = 'O'; + send(&data, 4, &tx_err_code); + } + if(data[0] == 'D' && data[1] == 'E' && data[2] == 'B' && data[3] == 'G'){ + //DEBG: Jump to debugger + void (*debg)() = ((void *) cmd_handler); + debg(); + } + if(data[0] == 'S' && data[1] == 'E' && data[2] == 'T' && data[3] == 'P'){ + //SETP setup triggers + setup_trigger(); + } + if(data[0] == 'G' && data[1] == 'L' && data[2] == 'I' && data[3] == '1'){ + glitch_registers_loop(); + } + if(data[0] == 'G' && data[1] == 'L' && data[2] == 'I' && data[3] == '2'){ + glitch_out_loop(); + } + } + + return 0; +} \ No newline at end of file diff --git a/null.d b/null.d new file mode 100644 index 0000000..ff21f30 --- /dev/null +++ b/null.d @@ -0,0 +1 @@ +null.o: /dev/null diff --git a/simple_device.drawio.svg b/simple_device.drawio.svg new file mode 100644 index 0000000..eb395c6 --- /dev/null +++ b/simple_device.drawio.svg @@ -0,0 +1 @@ +
Target
2 Jump
BootROM
1 Exploit (Gupje)
Exploit RCE
upload
bootloader
Interact with device
RAM
3 GiAs
Gupje
Patched Bootloader
\ No newline at end of file diff --git a/simple_device_memory.drawio.svg b/simple_device_memory.drawio.svg new file mode 100644 index 0000000..c74894c --- /dev/null +++ b/simple_device_memory.drawio.svg @@ -0,0 +1 @@ +
RAM
Debugger
Reserved
Stack
Debugger Storage
BootROM
\ No newline at end of file