device update
This commit is contained in:
parent
217abe3bc6
commit
1ab8b08a18
43
README.md
43
README.md
@ -1,5 +1,5 @@
|
|||||||
# Gupje
|
# 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 is a bare metal architecture based stub debugger that helps in ``post-exploitation`` steps. Like booting a smartphone 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:
|
Gupje currently supporting the following architectures:
|
||||||
* ARM64 (good support)
|
* ARM64 (good support)
|
||||||
@ -10,7 +10,7 @@ The goal is to add support to more targets while I work on them. Because I mainl
|
|||||||
|
|
||||||
The only actual things the debugger can do is:
|
The only actual things the debugger can do is:
|
||||||
* Send/Receive (needs to be implemented by the user)
|
* Send/Receive (needs to be implemented by the user)
|
||||||
* Read/Write registers
|
* Read/Write *some* 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.
|
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.
|
||||||
|
|
||||||
@ -21,11 +21,13 @@ A simple overview of how Gupje is meant to be used can be seen below:
|
|||||||
|
|
||||||
![Simple Gupje Target](simple_device.drawio.svg)
|
![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.
|
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(or extract Crypte Engine keys or whatever).
|
||||||
|
|
||||||
### Gupje Setup
|
### 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.
|
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.
|
||||||
|
|
||||||
|
Example C code for running gupje:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
||||||
void send(void *buffer, uint32_t size, uint32_t *num_xfer){
|
void send(void *buffer, uint32_t size, uint32_t *num_xfer){
|
||||||
@ -67,10 +69,21 @@ void concrete_main(uint32_t debugger){
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 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/rpi4/Makefile
|
||||||
|
```
|
||||||
|
|
||||||
Other protocols, like UART, are also possible. I will try to add more reference devices and implementations.
|
Other protocols, like UART, are also possible. I will try to add more reference devices and implementations.
|
||||||
|
|
||||||
### Memory layout
|
### 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.
|
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 these 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)
|
![debugger memory layout](simple_device_memory.drawio.svg)
|
||||||
|
|
||||||
@ -79,11 +92,19 @@ The full documentation is covered in the ``documentation`` folder. To build it,
|
|||||||
```bash
|
```bash
|
||||||
make livehtml
|
make livehtml
|
||||||
```
|
```
|
||||||
Install the python dependencies if they are missing. (TODO add requirements)
|
Install the python dependencies if they are missing.
|
||||||
|
|
||||||
This code works in combination with the ``Ghidra Assistant``, which is another personal project to make Ghidra more instrumentable.
|
This code works in combination with the ``Ghidra Assistant``, which is another personal project to make Ghidra more instrumentable.
|
||||||
|
|
||||||
|
## Example devices
|
||||||
|
Several example devices are under development to show what the Gupje is capable off:
|
||||||
|
* Nvidia Shield Tablet(boot bricked device)
|
||||||
|
* Nintendo Switch to add?
|
||||||
|
* Samsung S7 (boot and hijack trustzone)
|
||||||
|
* Raspberry Pi4(UART)
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
* ARM assembly needs to be completely rewritten
|
* 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 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.
|
* 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.
|
||||||
@ -91,19 +112,9 @@ This code works in combination with the ``Ghidra Assistant``, which is another p
|
|||||||
* Build an emulator to explain the debugger
|
* Build an emulator to explain the debugger
|
||||||
|
|
||||||
### ARM64
|
### 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.
|
* 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. (ELR?)
|
||||||
|
|
||||||
### Thumb
|
### Thumb
|
||||||
* headless mode is not supported
|
* headless mode is not supported
|
||||||
* Figure out VBAR to implement single step debugging
|
* 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
|
|
||||||
```
|
|
38
debugger.c
38
debugger.c
@ -9,6 +9,14 @@
|
|||||||
// extern int mystrlen(char *data);
|
// extern int mystrlen(char *data);
|
||||||
// extern void usb_log(char * msg, uint32_t * error);
|
// extern void usb_log(char * msg, uint32_t * error);
|
||||||
|
|
||||||
|
#if INTPTR_MAX == INT32_MAX
|
||||||
|
#define BIT32
|
||||||
|
#elif INTPTR_MAX == INT64_MAX
|
||||||
|
#define BIT64
|
||||||
|
#else
|
||||||
|
#error "Environment not 32 or 64-bit."
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __aarch64__
|
#ifdef __aarch64__
|
||||||
#include "debugger_archs/ga_arm64.h"
|
#include "debugger_archs/ga_arm64.h"
|
||||||
#elif __arm__
|
#elif __arm__
|
||||||
@ -16,7 +24,7 @@
|
|||||||
#elif __thumb__
|
#elif __thumb__
|
||||||
#include "debugger_archs/ga_arm_thumb.h"
|
#include "debugger_archs/ga_arm_thumb.h"
|
||||||
#else
|
#else
|
||||||
#include "debugger_archs/ga_arm64.h"
|
#error "Unsupported architecture"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef GLITCH_ENABLE
|
#ifdef GLITCH_ENABLE
|
||||||
@ -31,13 +39,18 @@ extern void debugger_sync_special_regs();
|
|||||||
extern void restore_and_return();
|
extern void restore_and_return();
|
||||||
|
|
||||||
extern int debugger_storage;
|
extern int debugger_storage;
|
||||||
// uint64_t debugger_storage_values[] = &debugger_storage;
|
|
||||||
|
// Custom block sizes should be somewhat supported.
|
||||||
|
#ifdef GUPJE_BLOCK_SIZE
|
||||||
|
#else
|
||||||
#define GUPJE_BLOCK_SIZE 0x100
|
#define GUPJE_BLOCK_SIZE 0x100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
__attribute__((section(".init")))
|
__attribute__((section(".init")))
|
||||||
int debugger_main(void){
|
int debugger_main(void){
|
||||||
#ifdef DEVICE_SETUP
|
#ifdef DEVICE_SETUP
|
||||||
#ifdef __aarch64__
|
#ifdef BIT64
|
||||||
uint64_t *val = (uint64_t *)((uint64_t)debugger_storage);
|
uint64_t *val = (uint64_t *)((uint64_t)debugger_storage);
|
||||||
|
|
||||||
// 0xfc0
|
// 0xfc0
|
||||||
@ -52,7 +65,7 @@ int debugger_main(void){
|
|||||||
// TODO other architectures
|
// TODO other architectures
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __aarch64__
|
#ifdef BIT64
|
||||||
uint64_t mem_off;
|
uint64_t mem_off;
|
||||||
#else
|
#else
|
||||||
uint32_t mem_off;
|
uint32_t mem_off;
|
||||||
@ -66,14 +79,15 @@ int debugger_main(void){
|
|||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
recv_data(&data, 4);
|
recv_data(&data, 4);
|
||||||
|
// PING, PEEK, HWIO, POKE, SELF, MAIN, FLUSH, JUMP, SYNC, SYNS, SPEC, ERET, REST, RET, TEST
|
||||||
if(data[0] == 'P' && data[1] == 'I' && data[2] == 'N' && data[3] == 'G'){
|
if(data[0] == 'P' && data[1] == 'I' && data[2] == 'N' && data[3] == 'G'){
|
||||||
data[1] = 'O';
|
data[1] = 'O';
|
||||||
send(&data, 4, &tx_err_code);
|
send(&data, 4, &tx_err_code);
|
||||||
}
|
}
|
||||||
else if(data[0] == 'P' && data[1] == 'E' && data[2] == 'E' && data[3] == 'K') {
|
else if(data[0] == 'P' && data[1] == 'E' && data[2] == 'E' && data[3] == 'K') {
|
||||||
// peek, dump memory
|
// PEEK, dump memory
|
||||||
recv_data(&data, 12); // Receive uint64_t size and and uint32_t offset
|
recv_data(&data, 12); // Receive uint64_t size and and uint32_t offset
|
||||||
#ifdef __aarch64__
|
#ifdef BIT64
|
||||||
mem_off = *(uint64_t *)data;
|
mem_off = *(uint64_t *)data;
|
||||||
mem_sz = *(uint32_t *)(data+8);
|
mem_sz = *(uint32_t *)(data+8);
|
||||||
#else
|
#else
|
||||||
@ -109,7 +123,7 @@ int debugger_main(void){
|
|||||||
usb_log("OK", &tx_err_code);
|
usb_log("OK", &tx_err_code);
|
||||||
}
|
}
|
||||||
else if(data[0] == 'P' && data[1] == 'O' && data[2] == 'K' && data[3] == 'E') {
|
else if(data[0] == 'P' && data[1] == 'O' && data[2] == 'K' && data[3] == 'E') {
|
||||||
#ifdef __aarch64__
|
#ifdef BIT64
|
||||||
recv_data(&data, 12); // Receive uint64_t size and and uint32_t offset
|
recv_data(&data, 12); // Receive uint64_t size and and uint32_t offset
|
||||||
mem_off = *(uint64_t *)data;
|
mem_off = *(uint64_t *)data;
|
||||||
mem_sz = *(uint32_t *)(data+8);
|
mem_sz = *(uint32_t *)(data+8);
|
||||||
@ -136,7 +150,7 @@ int debugger_main(void){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(data[0] == 'S' && data[1] == 'E' && data[2] == 'L' && data[3] == 'F') {
|
else if(data[0] == 'S' && data[1] == 'E' && data[2] == 'L' && data[3] == 'F') {
|
||||||
#ifdef __aarch64__
|
#ifdef BIT64
|
||||||
mem_off = (uint64_t) &debugger_main;
|
mem_off = (uint64_t) &debugger_main;
|
||||||
#else
|
#else
|
||||||
mem_off = (uint32_t) &debugger_main;
|
mem_off = (uint32_t) &debugger_main;
|
||||||
@ -144,7 +158,7 @@ int debugger_main(void){
|
|||||||
send(&mem_off, sizeof(mem_off), &tx_err_code);
|
send(&mem_off, sizeof(mem_off), &tx_err_code);
|
||||||
}
|
}
|
||||||
else if(data[0] == 'M' && data[1] == 'A' && data[2] == 'I' && data[3] == 'N') {
|
else if(data[0] == 'M' && data[1] == 'A' && data[2] == 'I' && data[3] == 'N') {
|
||||||
#ifdef __aarch64__
|
#ifdef BIT64
|
||||||
mem_off = (uint64_t) &debugger_main;
|
mem_off = (uint64_t) &debugger_main;
|
||||||
#else
|
#else
|
||||||
mem_off = (uint32_t) &debugger_main;
|
mem_off = (uint32_t) &debugger_main;
|
||||||
@ -152,8 +166,8 @@ int debugger_main(void){
|
|||||||
concrete_main(mem_off);
|
concrete_main(mem_off);
|
||||||
}
|
}
|
||||||
else if(data[0] == 'F' && data[1] == 'L' && data[2] == 'S' && data[3] == 'H') {
|
else if(data[0] == 'F' && data[1] == 'L' && data[2] == 'S' && data[3] == 'H') {
|
||||||
//FLSH cache flush
|
// TODO, flush specific cache (code/data)
|
||||||
#ifdef __aarch64__
|
#ifdef BIT64
|
||||||
cache_flush();
|
cache_flush();
|
||||||
#else
|
#else
|
||||||
// Todo for ARM and Thumb
|
// Todo for ARM and Thumb
|
||||||
@ -161,7 +175,7 @@ int debugger_main(void){
|
|||||||
}
|
}
|
||||||
else if(data[0] == 'J' && data[1] == 'U' && data[2] == 'M' && data[3] == 'P') {
|
else if(data[0] == 'J' && data[1] == 'U' && data[2] == 'M' && data[3] == 'P') {
|
||||||
//JUMP == jump to function using provided pointer
|
//JUMP == jump to function using provided pointer
|
||||||
#ifdef __aarch64__
|
#ifdef BIT64
|
||||||
recv_data(&data, 8);
|
recv_data(&data, 8);
|
||||||
mem_off = *(uint64_t *)data;
|
mem_off = *(uint64_t *)data;
|
||||||
void (*custom_func)() = (void*)mem_off; //mem_off;
|
void (*custom_func)() = (void*)mem_off; //mem_off;
|
||||||
|
@ -14,7 +14,7 @@ author = 'Eljakim'
|
|||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
extensions = [ 'myst_parser',
|
extensions = [ 'myst_parser',
|
||||||
'sphinx_rtd_theme',
|
'sphinx_wagtail_theme',
|
||||||
'sphinx.ext.todo',
|
'sphinx.ext.todo',
|
||||||
'sphinxcontrib.confluencebuilder',
|
'sphinxcontrib.confluencebuilder',
|
||||||
"sphinxcontrib.drawio",
|
"sphinxcontrib.drawio",
|
||||||
@ -28,5 +28,5 @@ exclude_patterns = []
|
|||||||
# -- Options for HTML output -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
||||||
html_theme = 'sphinx_rtd_theme'
|
html_theme = 'sphinx_wagtail_theme'
|
||||||
html_static_path = ['_static']
|
html_static_path = ['_static']
|
||||||
|
32
documentation/source/getting_started.rst
Normal file
32
documentation/source/getting_started.rst
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
===============
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
|
||||||
|
Clone gupje somewhere on your system:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
git clone https://git.herreweb.nl/EljakimHerrewijnen/Gupje
|
||||||
|
|
||||||
|
|
||||||
|
Cross compiler
|
||||||
|
--------------
|
||||||
|
You will also need a cross compiler for the target you are going to debug.
|
||||||
|
For this we use the ``Android NDK``. Download one from the `official website <https://developer.android.com/ndk>`_ and extract it somewhere on your system.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
wget https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip
|
||||||
|
unzip android-ndk-r21e-linux-x86_64.zip
|
||||||
|
|
||||||
|
Now set the ``ANDROID_NDK_ROOT`` environment variable:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
export ANDROID_NDK_ROOT=/path/to/android-ndk-r21e
|
||||||
|
|
||||||
|
Target Setup
|
||||||
|
------------
|
||||||
|
Gupje is compiled against a specific target. This means that you need to download a target or build one.
|
||||||
|
The Raspberry pi 4 is a good example target to start with. Please see the `Raspberry Pi 4 target <targets/rpi4.html>`_ for more information.
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 14 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.1 KiB |
@ -5,14 +5,23 @@
|
|||||||
|
|
||||||
Gupje Architecture based debugger
|
Gupje Architecture based debugger
|
||||||
=================================
|
=================================
|
||||||
This is the documentation for the Gupje debugger.
|
This is the documentation for the ``Gupje`` debugger.
|
||||||
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 3
|
||||||
:caption: Setup:
|
:caption: Setup:
|
||||||
|
|
||||||
overview.rst
|
overview.rst
|
||||||
|
getting_started.rst
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Example Targets:
|
||||||
|
|
||||||
|
targets/rpi4.rst
|
||||||
|
targets/nvidia_shield.rst
|
||||||
|
targets/samsung_s7.rst
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
@ -10,21 +10,22 @@ A high level overview of how the memory mapping for this works is shown below.
|
|||||||
|
|
||||||
In the future the debugger will probably grow to 4 pages, to include an extra page for the debugger to use in custom functionality.
|
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
|
Inner workings
|
||||||
========
|
--------------
|
||||||
In a typical usecase the flow of the debugger wuuld look as something like this:
|
When the debugger is entered it will save the state of the processor into it's storage page. This is done in assembly and is architecture dependent.
|
||||||
|
When a new architecture is added the first thing that needs to be done is to implement these functionalities.
|
||||||
|
|
||||||
.. figure:: images/debugger_flow.drawio.svg
|
.. figure:: images/debugger_flow.drawio.svg
|
||||||
|
|
||||||
State saving
|
The debugger will then wait for commands from the host. The host can send commands to the debugger to read/write memory, jump to an address, etc.
|
||||||
------------
|
|
||||||
Function: ``On enter``
|
|
||||||
|
|
||||||
The first thing the debugger does when it enters is save it's state into it's storage page.
|
When the user is done it will send the ``REST`` command to the debugger. This will restore the state of the processor and jump to the address defined in ``DEBUGGER_JUMP``.
|
||||||
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.
|
The debugger also uses a stack that is defined in the debugger. This is done to not taint the original stack of the processor.
|
||||||
This is architecture dependent and written in Assembly.
|
|
||||||
See the documentation in each architecture on how this is performed and if data is lost.
|
API
|
||||||
|
===
|
||||||
|
The debugger has a simple API that is used to communicate with the device. The following commands are supported:
|
||||||
|
|
||||||
Memory Read(Peek)
|
Memory Read(Peek)
|
||||||
-----------------
|
-----------------
|
||||||
@ -50,7 +51,7 @@ Execute architecture specific instructions in order to flush the cache.
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Only arm64 is supported for this function. The support is there for arm and thumb but not implemented.
|
Only arm64 is supported for this function. The support is there for arm and thumb but not implemented. Probably there will be a change here to support data/code cache flushes.
|
||||||
|
|
||||||
Jump to address(JUMP)
|
Jump to address(JUMP)
|
||||||
---------------------
|
---------------------
|
||||||
@ -83,9 +84,17 @@ This function restores the state of the processor from it's internal storage and
|
|||||||
|
|
||||||
Restore and Return(RRET)
|
Restore and Return(RRET)
|
||||||
------------------------
|
------------------------
|
||||||
Does the same as ``Restore and Jump`` but instead of jumping it returns to the address that called the debugger.
|
Does the same as ``Restore and Jump`` but instead of jumping it returns to the address that called the debugger(LR).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Glitching
|
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.
|
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.
|
The goal is to add several testable glitch cases to the debugger for profiling.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
========
|
||||||
|
In a typical usecase the flow of the debugger would look as something like this:
|
||||||
|
3
documentation/source/targets/nvidia_shield.rst
Normal file
3
documentation/source/targets/nvidia_shield.rst
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
====================
|
||||||
|
Nvidia Shield Tablet
|
||||||
|
====================
|
86
documentation/source/targets/rpi4.rst
Normal file
86
documentation/source/targets/rpi4.rst
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
==============
|
||||||
|
Raspberry Pi 4
|
||||||
|
==============
|
||||||
|
|
||||||
|
The Raspberry Pi 4 is a single-board computer developed by the ``Raspberry Pi Foundation``. It is freely available and requires no exploit to run code on it.
|
||||||
|
On top of that it is well supported in ``Qemu``, making this the cheapest and easiest target for gupje.
|
||||||
|
|
||||||
|
Code
|
||||||
|
----
|
||||||
|
The github code for this `is here <https://github.com/EljakimHerrewijnen/rpi4_gupje>`_.
|
||||||
|
|
||||||
|
.. hint::
|
||||||
|
|
||||||
|
The code that runs on the Raspberry Pi4 is based on `this awesome repository <https://github.com/ethanfaust/rpi4-baremetal-uart>`_.
|
||||||
|
|
||||||
|
Clone this repository *somewhere* and link the cloned folder in the ``devices/`` folder of gupje.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
git clone --recursive https://github.com/EljakimHerrewijnen/rpi4_gupje
|
||||||
|
cd /path/to/gupje/devices
|
||||||
|
ln -s /path/to/rpi4_gupje rpi4
|
||||||
|
|
||||||
|
You can now build the target by running the following command from gupje's root directory directory:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cd /path/to/gupje
|
||||||
|
make -f devices/rpi4/Makefile
|
||||||
|
|
||||||
|
In ``bin/rpi4/`` you will find the ``debugger.bin`` file, which will be used by the ``qemu.py`` script.
|
||||||
|
|
||||||
|
Running Qemu
|
||||||
|
############
|
||||||
|
From ``devices/rpi4`` navigate to ``rpi4-baremetal-uart/`` folder and run make with a cross compiler.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
cd /path/to/gupje/devices/rpi4/rpi4-baremetal-uart
|
||||||
|
ARCH=arm64 PREFIX=aarch64-linux-gnu- make
|
||||||
|
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
==============
|
||||||
|
Only send and receive need to be implemented for this target. For this target UART is used.
|
||||||
|
|
||||||
|
The debugger expects send/recv to be handled by the user so we need to build some logic to know that the data has been send and that the amount of expected data has been received. The following C code implements the send/recv for UART.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void recv_data(void *address, uint32_t size){
|
||||||
|
for(int i=0; i < size; i++){
|
||||||
|
*((char *)address + i) = uart_get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(void *address, uint64_t size, uint32_t *error){
|
||||||
|
for(int i=0; i < size; i++){
|
||||||
|
uart_send(*((char *)address + i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
However, in this implementation the debugger will need to link the uart_get and uart_send functions. In order to do that we copy the functions from the elf file and add them to the symbols.txt file.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ readelf -a kernel8.elf | grep uart_
|
||||||
|
25: 00000000000803a8 36 FUNC GLOBAL DEFAULT 1 uart_get
|
||||||
|
27: 0000000000080384 36 FUNC GLOBAL DEFAULT 1 uart_send
|
||||||
|
34: 0000000000080400 88 FUNC GLOBAL DEFAULT 1 uart_puts
|
||||||
|
35: 000000000008024c 312 FUNC GLOBAL DEFAULT 1 uart_init
|
||||||
|
36: 0000000000080458 84 FUNC GLOBAL DEFAULT 1 uart_hex
|
||||||
|
39: 00000000000803cc 52 FUNC GLOBAL DEFAULT 1 uart_getc
|
||||||
|
|
||||||
|
Add the symbols uart_get and uart_send to the symbols.txt file, along with the debugger regions:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
debugger_storage = 0x85000;
|
||||||
|
debugger_stack = 0x83000;
|
||||||
|
debugger_entry = 0x81000;
|
||||||
|
uart_get = 0x00000000000803a8;
|
||||||
|
uart_send = 0x0000000000080384;
|
||||||
|
|
||||||
|
See the makefile for details on how the linking is done.
|
||||||
|
|
5
documentation/source/targets/samsung_s7.rst
Normal file
5
documentation/source/targets/samsung_s7.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
==========
|
||||||
|
Samsung S7
|
||||||
|
==========
|
||||||
|
|
||||||
|
Exploitation done by Frederick in `his blog <https://fredericb.info/2020/06/exynos-usbdl-unsigned-code-loader-for-exynos-bootrom.html>`_.
|
0
requirements.txt
Normal file
0
requirements.txt
Normal file
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 10 KiB |
Loading…
Reference in New Issue
Block a user