big update

This commit is contained in:
Eljakim Herrewijnen 2024-08-02 16:05:02 +02:00
commit 003147affd
36 changed files with 1843 additions and 0 deletions

34
Makefile Normal file
View File

@ -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/*

109
README.md Normal file
View File

@ -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
```

43
arm64_glitch_stub.S Normal file
View File

@ -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

416
arm64_stub.S Normal file
View File

@ -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

187
armT_stub.S Normal file
View File

@ -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

112
arm_stub.S Normal file
View File

@ -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

227
debugger.c Normal file
View File

@ -0,0 +1,227 @@
#include <stdint.h>
#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<mem_sz;i++) {
*((uint8_t *)(mem_off+i)) = data[12+i];
}
usb_log("OK", &tx_err_code);
}
else if(data[0] == 'P' && data[1] == 'O' && data[2] == 'K' && data[3] == 'E') {
#ifdef __aarch64__
recv_data(&data, 12); // Receive uint64_t size and and uint32_t offset
mem_off = *(uint64_t *)data;
mem_sz = *(uint32_t *)(data+8);
#else
// For ARM and Thumb mode
recv_data(&data, 12); // 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;
}
recv_data((void *) (mem_off + i), blk_sz);
usb_log("OK", &tx_err_code);
recv_data(&data, 4);
if(!(data[0] == 'A' && data[1] == 'C' && data[2] == 'K')) {
break;
}
}
}
else if(data[0] == 'S' && data[1] == 'E' && data[2] == 'L' && data[3] == 'F') {
#ifdef __aarch64__
mem_off = (uint64_t) &debugger_main;
#else
mem_off = (uint32_t) &debugger_main;
#endif
send(&mem_off, sizeof(mem_off), &tx_err_code);
}
else if(data[0] == 'M' && data[1] == 'A' && data[2] == 'I' && data[3] == 'N') {
#ifdef __aarch64__
mem_off = (uint64_t) &debugger_main;
#else
mem_off = (uint32_t) &debugger_main;
#endif
concrete_main(mem_off);
}
else if(data[0] == 'F' && data[1] == 'L' && data[2] == 'S' && data[3] == 'H') {
//FLSH cache flush
#ifdef __aarch64__
cache_flush();
#else
// Todo for ARM and Thumb
#endif
}
else if(data[0] == 'J' && data[1] == 'U' && data[2] == 'M' && data[3] == 'P') {
//JUMP == jump to function using provided pointer
#ifdef __aarch64__
recv_data(&data, 8);
mem_off = *(uint64_t *)data;
void (*custom_func)() = (void*)mem_off; //mem_off;
custom_func();
#else
recv_data(&data, 4);
mem_off = *(uint32_t *)data;
void (*custom_func)() = (void*)mem_off; //mem_off;
custom_func();
#endif
}
else if(data[0] == 'S' && data[1] == 'Y' && data[2] == 'N' && data[3] == 'C') {
//SYNC: Synchronize registers from memory with actual registers
sync_debugger();
}
else if(data[0] == 'S' && data[1] == 'Y' && data[2] == 'N' && data[3] == 'S') {
//SYNS: Synchronize special registers
debugger_sync_special_regs();
}
else if(data[0] == 'S' && data[1] == 'P' && data[2] == 'E' && data[3] == 'C') {
//SPEC dump special registers
debugger_dump_special_regs();
}
else if(data[0] == 'E' && data[1] == 'R' && data[2] == 'E' && data[3] == 'T') {
#ifdef __aarch64__
__asm__ __volatile__("ERET\n\t");
#endif
}
else if(data[0] == 'R' && data[1] == 'E' && data[2] == 'S' && data[3] == 'T') {
//REST restore stack and jump
restore_and_jump();
}
else if(data[0] == 'R' && data[1] == 'R' && data[2] == 'E' && data[3] == 'T') {
// TODO Remove or change?
restore_and_return();
return 0;
}
else if(data[0] == 'T' && data[1] == 'E' && data[2] == 'S' && data[3] == 'T') {
// Implement any test function here
#ifdef __aarch64__
__asm__ __volatile__("SVC 0x0\n\t");
// disable_mmu();
#endif
}
#ifdef GLITCH_ENABLE
else if(data[0] == 'G' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') {
#ifdef __aarch64__
mem_off = (uint64_t) &debugger_main;
#else
mem_off = (uint32_t) &debugger_main;
#endif
glitch_main(mem_off);
}
#endif
}
return 0;
}
int main(void){
debugger_main();
return 0;
}

5
debugger_archs/ga_arm.h Normal file
View File

@ -0,0 +1,5 @@
#include <unistd.h>
void dump_regs(uint32_t addr){
}

31
debugger_archs/ga_arm64.h Normal file
View File

@ -0,0 +1,31 @@
#include <unistd.h>
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();
}

View File

@ -0,0 +1,5 @@
#include <unistd.h>
void dump_regs(uint32_t addr){
}

1
documentation/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

3
documentation/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"esbonio.sphinx.confDir": ""
}

27
documentation/Makefile Normal file
View File

@ -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)

35
documentation/make.bat Normal file
View File

@ -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

View File

@ -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 |
+---------+-----------------+--------------------------------------------------------------------------------+

View File

@ -0,0 +1,5 @@
===
ARM
===
.. include:: debugger/arm_debugger_storage.rst

View File

@ -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 <https://developer.arm.com/documentation/102416/0100/Single-level-table-at-EL3>`_.
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 <https://developer.arm.com/documentation/ddi0500/d/system-control/aarch64-register-descriptions/translation-control-register--el3>`_.
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 <https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/TTBR0-EL3--Translation-Table-Base-Register-0--EL3->`_
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``.

View File

@ -0,0 +1,58 @@
**********************
Vector Tables in ARM64
**********************
A lot of this documentation can also be found in the `ARM SMC calling convention documentation <https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwitkfqjqNz5AhUJHuwKHZ3vAj4QFnoECBMQAQ&url=https%3A%2F%2Fdocumentation-service.arm.com%2Fstatic%2F5f8ea482f86e16515cdbe3c6%3Ftoken%3D&usg=AOvVaw3QI7Lwrcg6B3BmQ5syZV70>`_
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 <https://developer.arm.com/documentation/100933/0100/AArch64-exception-vector-table>`_
.. 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.

View File

@ -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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -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

View File

@ -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 <https://developer.arm.com/documentation/ddi0601/2020-12/AArch64-Registers/SCTLR-EL3--System-Control-Register--EL3->`_

View File

@ -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 <https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-roles>`_ 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.

View File

@ -0,0 +1,6 @@
==============
ARM Thumb Mode
==============
Documentation for the ARM architecture in ``Thumb`` Mode.
.. include:: debugger/armT_debugger_storage.rst

View File

@ -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']

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -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

View File

@ -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.

36
glitch_handler.h Normal file
View File

@ -0,0 +1,36 @@
#include <stdint.h>
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;
}

1
null.d Normal file
View File

@ -0,0 +1 @@
null.o: /dev/null

1
simple_device.drawio.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB