arrow-left

All pages
gitbookPowered by GitBook
1 of 34

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

CTS devNotes

Development notes of CrackTheSurface

tCover Linux support

I2C0 @ 0x00 Address 0x00 is general call address which makes Cover incompatible with standard I2C drivers.

hashtag
WDSA Table

Name(ABUF, ResourceTemplate()
{
    I2CSerialBus(0, ControllerInitiated, 0x61a80, AddressingMode7Bit, "\\_SB.I2C1", 0, ResourceConsumer, , )
    GpioInt(Level, ActiveLow, Shared, PullDefault, 0, "\\_SB.GPIO", 0, ResourceConsumer, , ) {0x59}
})
Name(EBUF, ResourceTemplate()
{
    I2CSerialBus(0, ControllerInitiated, 0x61a80, AddressingMode7Bit, "\\_SB.I2C1", 0, ResourceConsumer, , )
    GpioInt(Level, ActiveLow, SharedAndWake, PullDefault, 0, "\\_SB.GPIO", 0, ResourceConsumer, , ) {0x75}
})

Address 0x00; Speed 400kHz

GPIO Interrupts: 0x59 -> L1 0x75 -> O5

Captured HID Descriptor without tCover

From 5.1.1 HID Descriptor Format

All important information is set to 0x00. I guess standard I2C HID Driver will have a hard time.

HID Descriptor Address is 0x41. This makes all the Register fields seem legit.

hashtag
Whats wrong here?

It was tested without tCover. Connecting a tCover doesn't change anything.

This should be related to wrong power settings.

Surface RT2 turns on backlight on TypeCover2 when the kernel is booted from UEFI with ACPI.

ACPI does something right according to power settings. Now we need to capture the new HID Descriptor for UEFI boot on Surface RT. Results should show what to do next

hashtag
Observation

Booting Windows without tCover: Windows doesn't send a single byte to tCover. Booting Windows with tCover: Windows does send some non HID bytes before the HID Descriptor is read.

That leads to the conclusion that the SoC has a GPIO which acts as tCover detector.

Leander devNotes

2

bcdVersion

2

01 00

Version 1.00

4

wReportDescLength

2

00 00

x

6

wReportDescRegister

2

00 42

maybe

8

wInputRegister

2

00 43

maybe

10

wMaxInputLength

2

00 00

x

12

wOutputRegister

2

00 44

maybe

14

wMaxOutputLength

2

00 00

x

16

wCommandRegister

2

00 45

maybe

18

wDataRegister

2

00 46

maybe

20

wVendorID

2

00 00

x

22

wProuctID

2

00 00

x

24

wVersionID

2

00 00

x

26

RESERVED

4

00 00 00 00

Offset

Field

Size

Actual Value

Comment

0

wHIDDescLength

2

00 1E

Dec: 30 -> 30 Bytes read

Kernel module

Maybe we have to write a kenel module which will init the tCover IC and hand off controll to I2C-HID Driver

git for dummys [WIP!] (like me)

hashtag
Clone the repo with SSH

git clone git@github.com:Open-Surface-RT/grate-linux.git

hashtag
Add upstream

git remote add upstream https://github.com/grate-driver/linux.git

hashtag
update to upstream

hashtag
edit local commits

hashtag
solve merge conflicts

hashtag
log stat

git log --stat

Configs we already tried

This is a place were we put configurations we tried, and didn't work or did work up to a certain point.

hashtag
Surface RT 1

hashtag
@Leander's trial and fail

Cross Compiling

SurfaceRT or RT2 is ARMv7 (ARM32 / armhf ) Cross compiling is fairly simple when using docker, but you can do it it without.

hashtag
Cross compiler quick setup (platform agnostic mac/linux/windows)

Linux: apt install docker Mac: brew install docker; brew cask install docker; Windows (install docker-ce from docker.com?) docker run --rm dockcross/linux-armv7:latest > dockcross-linux-armv7-latest chmod +x dockcross-linux-armv7-latest To use:

./dockcross-linux-armv7 bash -c make

hashtag
Alternate option (linux debian based - amend for other package managers as needed)

#install req's for cross compiling apt install gcc-arm-linux-gnueabihf bison autoconf autopoint flex build-essential #install random libraries that grub2 seemed to need apt install liblzma5 libarchive-dev freetype2-demos libfreetype-dev fonts-dejavu grub-theme-starfield ttf-dejavu-core libdevmapper-dev libfuse-dev ttf-unifont unifont liblzma-dev #install EDK2 bits apt install acpica-tools uuid-dev nasm python-distutils #install u-boot bits apt install swig libpython3-dev

https://phoenixnap.com/kb/how-to-resolve-merge-conflicts-in-gitarrow-up-right
git fetch upstream --depth=1
git rebase -i HEAD~n
Note to members of the gitbook: I don't know if it is useful to make this person-specific.

hashtag
#001

This hangs at without supplying device tree with dtb= If device tree is supplied, cpuidle complains at printed. [ 0.000000] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2 [ 0.000000] cfg80211: failed to load regulatory.db

circle-info

Testing without device tree from here on

hashtag
#002

Changed:CONFIG_CFG80211=n [ 0.000000] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2 [ 0.000000] cfg80211: failed to load regulatory.db This is issue doesn't exist anymore, it just freezes at [ 0.000000] Freeing unused kernel memory: 1024K

Note the line, clock should be 100kHz[ 0.000000] sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 21474836475000000ns

[ 0.000000] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled [ 0.000000] Warning: unable to open an initial console. It looks like it's using some serial and then is unable to open a console. -> No device tree so it doesn't know /dev/ttyS0 (UART-A)

hashtag
#003

CONFIG_FB_EFI=y CONFIG_CMDLINE="console=ttyS0,115200 console=tty0 earlyprintk initcall_debug sched_debug lpj=10000"

It booted, then disabled uart and printed to the screen. Log only contains print from uart. Stuck at the same line.

hashtag
#004

CONFIG_CMDLINE="console=ttyS0,115200 console=tty0 earlycon earlyprintk initcall_debug sched_debug lpj=10000"

Log should be the same apart from the cmdline. Again, it displayed to display, so log doesn't include that output.

hashtag
#005

CONFIG_CMDLINE="console=ttyS0,115200 earlycon earlyprintk initcall_debug sched_debug lpj=10000"

Screen with a cursor, all output on uart. But because there is no device tree, no console from initrd.

circle-info

Testing with device tree from here on

hashtag
#006

Nothing changed in config. Only added device tree.

Kernel panic: [ 0.000000] Unable to handle kernel NULL pointer dereference at virtual address 00000010Has to do with cpuidle. You can also see complaints about a bad device tree.

hashtag
#007

Only device tree edits.

Screen has no cursor anymore, only backlight is turned on. You can't print something on it with echo hello >> /dev/fb0 or echo hello >> /dev/tty0

Successful boot to Buildroot.

Note: Log has a lot of entries two times.

hashtag
#008

CONFIG_VGA_ARB=n CONFIG_TEGRA_HOST1X=n CONFIG_DRM=n

No different screen behaviour.

Log has some commands at the bottom.

hashtag
#009

No config changed. Only device tree edits. Added nodes to it until dtc didn't complain about anything.

Some strange screen behaviour.

[ 0.000000] tegra20-cpufreq tegra20-cpufreq: operating points not found [ 0.000000] tegra20-cpufreq tegra20-cpufreq: please update your device tree Looks like some cpu frequency nodes have to be added to device tree.

hashtag
#010

Only device tree edits.

Screen still doesn't work.

Boots fine to Buildroot. Log has commands at the bottom.

hashtag
#011

CONFIG_CMDLINE="console=ttyS0,115200 console=tty0 earlyprintk initcall_debug sched_debug lpj=10000"

Found out that screen works, but it gets cleared when Busybox (from ramdisk) starts. At least I think at that point it gets cleared, not 100% sure.

hashtag
#012

CONFIG_CMDLINE="console=ttyS0,115200 earlyprintk initcall_debug sched_debug lpj=10000"

Minimal device tree with sd-card+emmc+uart, it includes tegra30.dtsi

No display output with this command line, but you get log output when adding console=tty0, but afterwards it stops around when Busybox takes over.

hashtag
#013

Added a raspberry pi rootfs. Specifying root= option with efi shell

Display stops working after the line [ 251.431349] tegra-devfreq 6000c800.actmon: Failed to get emc clock

Log contains output from rootfs.

circle-info

Config reseted. Started from a new one.

hashtag
#014

CONFIG_EFI_STUB=y CONFIG_EFI=y CONFIG_CMDLINE="console=ttyS0,115200n8 earlyprintk initcall_debug sched_debug lpj=10000 boot_delay=50" CONFIG_CMDLINE_EXTEND=y CONFIG_SMP=n CONFIG_CACHE_L2X0=n CONFIG_EARLY_PRINTK=y CONFIG_DEBUG_TEGRA_UART=y CONFIG_TEGRA_DEBUG_UARTA=y CONFIG_BOOT_PRINTK_DELAY=y

CONFIG_BOOT_PRINTK_DELAY=y and boot_delay=50(cmdline) are necessary so mmc driver gets loaded early enough.

Log contains a few commands from rootfs.

hashtag
#015

I'm not sure what changed.

Working display with booted raspberry pi os!

hashtag
Surface RT 2

file-download
163KB
.config
arrow-up-right-from-squareOpen
#001 .config
file-download
6KB
tegra30-microsoft-surfaceRT-test1.dts
arrow-up-right-from-squareOpen
#001 device tree
file-download
160KB
.config
arrow-up-right-from-squareOpen
#002 .config
file-download
12KB
log.txt
arrow-up-right-from-squareOpen
#002 log
file-download
159KB
.config
arrow-up-right-from-squareOpen
#003 .config
file-download
5KB
log.txt
arrow-up-right-from-squareOpen
#003 log
file-download
160KB
.config
arrow-up-right-from-squareOpen
#004 .config
file-download
5KB
log.txt
arrow-up-right-from-squareOpen
#004 log
file-download
159KB
.config
arrow-up-right-from-squareOpen
#005 .config
file-download
13KB
log.txt
arrow-up-right-from-squareOpen
#005 log
file-download
159KB
.config
arrow-up-right-from-squareOpen
#006 .config
file-download
18KB
log.txt
arrow-up-right-from-squareOpen
#006 log
file-download
2KB
tegra30-microsoft-surfaceRT.dts
arrow-up-right-from-squareOpen
#006 device tree
file-download
159KB
.config
arrow-up-right-from-squareOpen
#007 .config
file-download
30KB
log.txt
arrow-up-right-from-squareOpen
#007 log
file-download
2KB
tegra30-microsoft-surfaceRT.dts
arrow-up-right-from-squareOpen
#007 device tree
file-download
156KB
.config
arrow-up-right-from-squareOpen
#008 .config
file-download
18KB
log.txt
arrow-up-right-from-squareOpen
#008 log
file-download
2KB
tegra30-microsoft-surfaceRT.dts
arrow-up-right-from-squareOpen
#008 device tree
file-download
155KB
.config
arrow-up-right-from-squareOpen
#009 .config
file-download
17KB
log.txt
arrow-up-right-from-squareOpen
#009 log
file-download
5KB
tegra30-microsoft-surfaceRT.dts
arrow-up-right-from-squareOpen
#009 device tree
file-download
155KB
.config
arrow-up-right-from-squareOpen
#010 .config
file-download
19KB
log.txt
arrow-up-right-from-squareOpen
#010 log
file-download
6KB
tegra30-microsoft-surfaceRT.dts
arrow-up-right-from-squareOpen
#010 device tree
file-download
155KB
.config
arrow-up-right-from-squareOpen
#011 .config
file-download
22KB
log.txt
arrow-up-right-from-squareOpen
#011 log
file-download
6KB
tegra30-microsoft-surfaceRT.dts
arrow-up-right-from-squareOpen
#011 device tree
file-download
155KB
.config
arrow-up-right-from-squareOpen
#012 .config
file-download
25KB
log.txt
arrow-up-right-from-squareOpen
#012 log
file-download
932B
tegra30-microsoft-surfaceRT-test2.dts
arrow-up-right-from-squareOpen
#012 device tree
file-download
155KB
.config
arrow-up-right-from-squareOpen
#013 .config
file-download
29KB
log.txt
arrow-up-right-from-squareOpen
#013 log
file-download
932B
tegra30-microsoft-surfaceRT-test2.dts
arrow-up-right-from-squareOpen
#013 device tree
file-download
166KB
.config
arrow-up-right-from-squareOpen
#014 .config
file-download
36KB
log.txt
arrow-up-right-from-squareOpen
#014 log
file-download
932B
tegra30-microsoft-surfaceRT-test2.dts
arrow-up-right-from-squareOpen
#014 device tree
file-download
166KB
.config
arrow-up-right-from-squareOpen
#015 .config
file-download
47KB
log.txt
arrow-up-right-from-squareOpen
#015 log
file-download
6KB
tegra30-microsoft-surfaceRT-test1.dts
arrow-up-right-from-squareOpen
#015 device tree

Uboot information

uBoot on the Tegra consists of 2 parts. An SPL which will run on the Bootrom and will prepare and setup the transfer from Boot CPU to Main CPU.

hashtag
U-Boot debug output

The file above has the following logging configuration:

CONFIG_LOG_MAX_LEVEL=9 CONFIG_SPL_LOG_MAX_LEVEL=9 CONFIG_TPL_LOG_MAX_LEVEL=9 CONFIG_LOG_DEFAULT_LEVEL=9 CONFIG_LOG_CONSOLE=y CONFIG_SPL_LOG_CONSOLE=y CONFIG_TPL_LOG_CONSOLE=y

Do gifs work?

file-download
69KB
u-boot-max-debug-output.txt
arrow-up-right-from-squareOpen
U-Boot max debug output

!TODO

hashtag
sRT & s2

hashtag
TCOVER

hashtag
AUDIO

hashtag
SENSOR COLLECTION

hashtag
UEFI STUB

hashtag
distro installer

hashtag
after everything is done

check how flipping back tCover brings up screenKeyboard; A: Sensor Collection/Hub
port downstream kernel
  • !TODO for everyone

    hashtag
    ASAP

    Surface RT

    hashtag
    Misc

    hashtag
    APX

    hashtag
    BATTERY

    hashtag
    UEFI

    TZ Exploit - CTS

    hashtag
    Idea

    Write code into TZ mem and jump to it. Hopefully it will execute at EL3.

    hashtag
    Tests

    hashtag
    Read NS-Bit

    page 1697: can only be read from securemode.

    hashtag
    Read EL

    page: 1139

    hashtag
    Read EL from APX

    a custom payload will be used to read the Exception Level from in APX mode. I expect it to be 3.

    Supervisor mode is the default mode to which a Supervisor Call exception is taken.

    hashtag
    Read EL from UEFI

    A normal efi App will be used to read the Execption Level from UEFI. I expect it to be 0.

    FIQ mode is the default mode to which an FIQ interrupt is taken.

    hashtag
    Creating a payload

    We need a relocateable payload since UEFI can give us different load addresses everytime.

    Therefore we need to use Position independent code:

    hashtag
    Step by Step

    hashtag
    Step 1:

    Create payload which reads EL and reports back via serial. Read payload from USB/eMMC to memory. Disable TZ protection. copy payload into TZ mem. override TZ with jumps to payload address. If payload reads EL3 continue.

    hashtag
    Step 2:

    to be continued...

    HID Over I2C Protocol Specification - Windows 10 hardware devMicrosoftLearnchevron-right
    HIDI2C Device-Specific Method (_DSM) - Windows driversMicrosoftLearnchevron-right

    !!! PLEASE READ !!!

    triangle-exclamation

    hashtag
    This is the development section. The stuff you find below is barely tested. Some of it might be even untested. USE FILES/INFORMATION FROM HERE AT YOUR OWN RISK!!!

    Surface 2

    operation performance points (OPP)
  • verify display driver

  • #define CPSR_M_SVC 0x13U

    #define CPSR_M_FIQ 0x11U

    https://developer.arm.com/documentation/ddi0406/latest/arrow-up-right
    https://stackoverflow.com/questions/31787617/what-is-the-current-execution-mode-exception-level-etcarrow-up-right
    http://lioncash.github.io/ARMBook/the_apsr,_cpsr,_and_the_difference_between_them.htmlarrow-up-right
    https://www.keil.com/pack/doc/CMSIS/Core_A/html/group__CMSIS__CPSR.htmlarrow-up-right
    https://www.keil.com/pack/doc/CMSIS/Core_A/html/group__CMSIS__CPSR__M.htmlarrow-up-right
    https://developer.arm.com/documentation/ddi0406/latest/arrow-up-right
    file-download
    8KB
    payload.c
    arrow-up-right-from-squareOpen
    FuseeGelee Payload to read EL from APX
    https://stackoverflow.com/questions/6324257/load-time-base-address-cortex-m3-bare-metalarrow-up-right
    https://stackoverflow.com/questions/5311515/gcc-fpic-optionarrow-up-right
    https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/The-System-Level-Programmers--Model/Exceptions/Exception-vectors-and-the-exception-base-address?lang=enarrow-up-right
    https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjW9vvHiZ7xAhWLh_0HHf3LC2kQFjAAegQIBRAD&url=http%3A%2F%2Fdownload.microsoft.com%2Fdownload%2F7%2Fd%2Fd%2F7dd44bb7-2a7a-4505-ac1c-7227d3d96d5b%2Fhid-over-i2c-protocol-spec-v1-0.docx&usg=AOvVaw32joJ2ViKHgpCbccKBdj2Awww.google.comchevron-right
    Logo
    Logo

    battery

    https://www.kernel.org/doc/html/latest/power/power_supply_class.htmlarrow-up-right
    https://elixir.bootlin.com/linux/latest/source/include/linux/power_supply.h#L96arrow-up-right

    UEFI Privilege Escalation Exploit Documentation

    Yahallo: Free memory accesschevron-right
    UEFI Privilege Escalation: Execute code in Secure modechevron-right
    Removing trustzonechevron-right

    Dump Bootrom

    hashtag
    Idea

    https://media.ccc.de/v/c4.openchaos.2018.06.glitching-the-switcharrow-up-right dumping boot rom seems easy. only need to set the right access bits. which we can do since we have total control over the CPU/memory. Reverse engineering is the hard part. 48kB arm assembler. And only some bits decide from which device is booted from. But we have a good starting point. The provided example patches a function which prevents the bootrom to read the BCT. We need to patch some bits before this instruction is executed. and since reading the BCT is the first thing the bootrom does we should start looking at the begining of the function call chain. only need to figure out to which value we must set the byte. but this should also be easy. the bootdevice is read form a fuse. Nvidia provides a script to burn fuses. this should tell us which fuse is used for bootdevice selection and we should be able to find this address in the bootrom. it should also tell us which value the fusee needs to be to boot from mmc/sd/usb/... the theory part is "done". Need to dump the bootrom and throw the binary into ghidra. find the function which reads the boot device fuse and write an ipatch to patch the bootrom. like disableing security fuse. i hope this allows us to boot selfmade BCTs from other storage devices. luckily we dont have to do some voltage glitching. we could just set the bits to read the bootrom

    hashtag
    Preparation

    hashtag
    Secureboot registers

    Secureboot registers should be located at 6000:c2000

    hashtag
    fusee gelee payload

    Tegra 2
    Tegra 3
    Tegra 4
    Tegra X1
    Tegra 3 secureboot registers

    !TODO

    here
    Compiling kernel
    APIC
    https://discord.com/channels/710026735294349322/710026735730556969/879729337375531051arrow-up-right
    https://discord.com/channels/710026735294349322/723258047878791229/879693368697966602arrow-up-right

    Yahallo: Free memory access

    The Yahallo exploit uses a security vulnerability in the NVIDIA Tegra 3 / Tegra 4 UEFI firmware to disable the SMMU memory protection. As a result you can access all memory.

    Disclaimer Most information only applies to SurfaceRT, but some yahallo information applies to Surface RT 2 too.

    hashtag
    The exploit

    hashtag
    Background story

    Because NVIDIA/Microsoft didn't implement a check for maximum buffer size when using a SMC instruction to register a new shared buffer, it is possible to create a buffer overflow, which is then used to overwrite the area where a BootServices->SetMem UEFI call writes its memory.

    hashtag
    Understand the formular

    This is from the . It gives a brief overview about the parameters, but here is more detail about them:

    First, you need to know which values are used from the SMC in the calculation, we don't care about parameters 1 and 2. Parameter 3 is request_area, so in yahallo source 0x40000000. Parameter 4 is area_slice, so in yahallo source 0x6001e0e0.

    hashtag
    Calculation of the addresses

    The calculation has the following formular: response_area = (request_area + (area_slice >> 1)) Examples: 0x7000_f070 = (0x4000_0000 + (0x6001_e0e0 >> 1) 0x7000_f010 = (0x4000_0000 + (0x6001_e020 >> 1))

    hashtag
    Use the exploit to disable the SMMU

    hashtag
    Tegra 3 SOC: Important information

    The Tegra 3 Technical Reference Manual (TRM) has important information about virtual addressing and configuration registers in section 18. You can download it , but downloading requires a NVIDIA developer account.

    The SMMU (System Memory Managment Unit) is part of the SOC, and not part of the Cortex-A9 cores. The CPU cores have a MMU too, you can simply disable it with a ArmDisableMmu() call in the edk2 source tree. Yahallo reconfigures the SMMU, so all SMMU memory protection is gone. The CPU MMU still protects this memory, but you can easily disable it.

    hashtag
    Disable SMMU

    To disable the SMMU, you need to write 0's to the SMMU Enable Register (0x7000f010). This can only be done when you are in secure mode, so it doesn't work if you just disable the CPU MMU. With the help of the Yahallo exploit we can write to all memory locations in secure mode, because the BootServices->SetMem call executes in secure mode. (UEFI firmware operates in secure mode generally)

    hashtag
    What Yahallo does

    Yahallo writes 32 bytes of 0's to 0x7000f070, so it writes the Secure Region Configuration Base register, Secure Region Configuration Bound register and the Protected Region Configuration Bound register.

    This makes the Trustzone 0MB in size (SMMU side), so you have access to non-trustzone-secured* memory, when CPU doesn't restrict memory access. The CPU restrictions can be removed by disabling the MMU.

    * Some registers are restricted to be only accessible from Trustzone-secured CPU memory access. (e.g. from the SMMU_ENABLE register from TRM: This register can only be accessed by Trustzone-Secured accesses from the CPU.)

    // Register a new shared memory buffer at 0x4000_0000 (IRAM) with size // 0x6001_e0e0. The following algorithm is used to determine the end address // that the QueryVariable call will write over: // response_area = (request_area + (area_slice >> 1));

    Ret = ArmCallSmcHelper(0x03, 0x06, 0x40000000, 0x6001e0e0);

    yahallo source codearrow-up-right
    herearrow-up-right

    EFI linux booting

    Booting linux with UEFI boot is now possible.

    hashtag
    Issues

    • PMIC regulators don't work.

    • Audio, Wireless, Cameras, Sensors .This is also true for APX boot.

    hashtag
    TODO

    • Implement ACPI for arm32. This will help in development for all other devices that run Windows RT too. Why? It removes the need for a device tree and enables us to comunicate with the firmware, which will hopefully enable us to use PMIC stuff. Also we can upstream our ACPI Parking Protocol driver, which is needed for SMP.

    • Get Audio, Wireless, Cameras, Sensors.

    • Possibly more, but we don't know about it yet.

    GDB Debugging

    Debug Linux kernel with GDB

    hashtag
    Compile a correct Linux kernel

    Clone a Linux tree and run make ARCH=arm defconfig to make a generic kernel configuration suited for qemu. Now edit the kernel configuration (.config) and add the following lines at the bottom:

    CONFIG_DEBUG_INFO=y
    CONFIG_GDB_SCRIPTS=y

    Now run make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc) to compile the kernel. If you get asked about anything, just press enter to use the standard value.

    Copy the output zImage (arch/arm/boot/zImage) to efi/boot/bootarm.efi on your EFI partition folder in your qemu directory.

    hashtag
    Prepare GDB for debugging

    hashtag
    Install

    Run sudo apt-get install gdb-multiarch to install GDB on Ubuntu. gdb-mutliarch is required because normal gdb package doesn't have support for ARM.

    hashtag
    Run

    Open up the terminal you want GDB to run in, and change directory to your Linux compilation directory. Then run gdb-multiarch vmlinux., it will open GDB you and you can now connect to a target with target remote localhost:1234. At this point GDB will wait for qemu to start. After that you can now debug with qemu, there are tutorials online to show you how to do this.

    hashtag
    Run qemu

    Go to the directory where your qemu files are located, start qemu as described in , only change is that you need to add a -s parameter, this lets qemu know that it starts a GDB server.

    Qemu emulation

    Qemu emulation

    Run arm32 UEFI in a virtual machine.

    Emulating a arm32 UEFI device is useful for developing Linux and debugging it.

    In the GDB Debugging page you can find instructions on how to compile Linux for this virtual machine.

    circle-info

    A premade ZIP with all required files can be found at the bottom.

    hashtag
    Compile OVMF for qemu

    hashtag
    Install required packages

    Run the following commands to install the required packages.

    You will need other stuff too, but that is probably already installed. (e.g. git)

    hashtag
    Download source

    You need the source code of edk2 and acpica.

    hashtag
    Compile OVMF

    Go to your source directory and run the following commands.

    Your output OVMF firmware file for qemu is$WORKSPACE/Build/ArmVirtQemu-ARM/RELEASEGCC5/FV/QEMU_EFI.fd

    hashtag
    Setup qemu files and run it

    Create a directory, where you want your files to be in. Put your QEMU_EFI.fd firmware file in this directory, compiled in the previous section. Now run the following commands to create some disk images:

    Now create a directory named boot. This will be your EFI partition. You can now easily place your EFI files in there.

    hashtag
    Run qemu

    To start your virtual machine run the following command, and make sure qemu-system-arm is installed.

    This will run qemu with 4 virtual CPU cores. They are Coretx-A15 cores. Used because it works.

    hashtag
    Premade files

    The following ZIP includes all files setup in their proper location. In addition its EFI partition folder has a UEFI shell in it. To run it either execute the run.sh file or enter the command described in .

    hashtag
    References

    Links where the above compiling information is from:

    Removing trustzone

    We tried to get rid of the trustzone with help from yahallo exploit

    hashtag
    Details of the CPU

    The Surface RT's Tegra 3 SOC's CPU uses Cortex-A9 cores. These cores use Virtual Memory System Architecture (VMSA), this means we have a Memory Management Unit (MMU).

    hashtag
    ARM Architecture Reference Manual ARMv7 A & R edition

    This manual describes the ARMv7 A & R architecture (ARMv7 A is important for us) in Application Level Architecture and in System Level Architecture. The System Level Architecture is the interesting part for this type of development. Part B, System Level Architecture, only has 874 pages to read 🥳.

    Download the manual here:

    hashtag
    Why modify page tables?

    The MMU is also used for virtual addressing, not only for protected memory. Virtual addressing is necessary for most applications and operating systems. Linux works without it, but most programs don't work without virtual addressing. Because of that we need to enable the MMU for linux, but when MMU is enabled, it blocks access to trustzone memory, so the trustzone memory needs to be unmapped by modifying the page tables of the Cortex-A9 cores.

    hashtag
    Advantage

    The advantage of completely eliminating UEFI and TrustZone is, that we don't need to modify the linux source code, only a device tree is needed, which can be mainlined. Without getting this way to work, our linux work probably won't be mainlined ever.

    https://developer.arm.com/documentation/ddi0406/latestarrow-up-right
    Run qemu
    file-archive
    2MB
    arm32-uefi-qemu-setup.zip
    archive
    arrow-up-right-from-squareOpen
    Premade qemu setup
    https://developer.arm.com/tools-and-software/open-source-software/firmware/edkii-uefi-firmware/building-edkii-uefi-firmware-for-arm-platformsarrow-up-right
    https://designprincipia.com/virtualize-uefi-on-arm-using-qemu/arrow-up-right
    sudo apt install python python3 python3-distutils
    sudo apt install gcc-arm-none-eabi
    sudo apt install uuid-dev
    sudo apt install build-essential
    sudo apt install bison
    sudo apt install flex
    # Go to the directory you want to work in
    export WORKSPACE=$PWD
    
    # Download edk2 and acpica
    git clone https://github.com/acpica/acpica.git
    git clone https://github.com/tianocore/edk2.git
    
    # Download submodules
    cd edk2
    git submodule update --init
    cd ..
    # Compile acpica tools
    make -C $WORKSPACE/acpica -j$(nproc)
    
    # Set environment variables
    export GCC5_ARM_PREFIX=arm-none-eabi-
    export IASL_PREFIX=$WORKSPACE/acpica/generate/unix/bin/
    export PYTHON_COMMAND=/usr/bin/python3
    
    # Configure the edk2 environment
    source edk2/edksetup.sh
    
    # Compile edk2 BaseTools
    make -C edk2/BaseTools -j$(nproc)
    
    # Compile OVMF
    build -a ARM -t GCC5 -p ArmVirtPkg/ArmVirtQemu.dsc -b RELEASE -j$(nproc)
    rm -f flash0.img flash1.img
    dd if=/dev/zero bs=1M count=64 of=flash0.img
    dd if=/dev/zero bs=1M count=64 of=flash1.img
    dd if=QEMU_EFI.fd bs=1M of=flash0.img conv=notrunc
    qemu-system-arm \ 
        -m 1024 \
        -cpu cortex-a15 \
        -M virt \
        -pflash flash0.img \
        -pflash flash1.img \
        -nographic \
        -drive \
        file=fat:rw:boot/ \
        -smp '4'

    UEFI Privilege Escalation: Execute code in Secure mode

    Replace the Secure Monitor to execute user-defined code in Secure mode by using a Secure Monitor Call (SMC)

    hashtag
    The idea

    Using the Yahallo exploitarrow-up-right we can get access to Trustzone memory. In the Trustzone you can find all of the firmware's functionality, where some code executes in Secure mode. On top of that, some of the memory is marked as secure, so you can execute it from Secure mode.

    The goal is to get rid of Trustzone memory, so the page tables of the Trustzone memory need to be modified. To do this you need to be in the Secure mode.

    But how do you get into Secure mode?

    UEFI firmware provides runtime services to the running operating system. The communication happens with ACPI or other protocols. But also with interrupts, specifically the Secure Monitor Call (SMC). A user can trigger a SMC by executing the smc instruction. See the for more information on how such a call happens.

    When executing a SMC, the processor receives the interrupt and looks in the Monitor Vector Table at the Monitor Vector Base (specified in the Monitor Vector Base Address Register (MVBAR)) for the address of the Secure Monitor and jumps to it. The Secure Monitor is then responsible for reading the variables from the SMC and running the desired function in Secure mode*. Essentially SMCs are used for communicating with the Secure world and the Trustzone kernel.

    When you further think about it, you may notice that we could simply replace the Secure Monitor and put our own code there, by using the Yahallo exploit.

    * The Secure Monitor executes in Monitor mode. Monitor mode ignores the SCR.NS bit and always executes in secure mode. You can use this to modify configurations which are specific to each execution state.

    hashtag
    Finding MVBAR

    To replace the Secure Monitor, you first need to locate it. The Monitor Vector Base Address Register points to the Monitor Vector Table, where the third table entry points to the Secure Monitor

    hashtag
    Reading MVBAR

    So just read the MVBAR, right?

    hashtag
    But what are the Secure PL1 modes?

    So they are only accessible from Secure state. A normal UEFI App executes at PL1 in non-Secure mode.

    So reading the register at runtime won't work. But there are other options to get the address.

    hashtag
    Reverse-engineering the firmware binary

    You can get your UEFI firmware binary from C:\Windows\Firmware\SurfaceRTUEFI.bin.

    For reverse engineering we have used Ghidra. For importing make sure to use ARM:LE:32:V7:default as language.

    mcr p15,0x0,r0,cr12,cr0,0x1 is the instruction which sets MVBAR. Search for it. You should only find one result. The disassembly looks something like this:

    When further analyzing this, you will quickly notice that you will not be able to find out MVBAR by just analyzing the UEFI binary. Maybe it's possible, but only with heavy reverse-engineering.

    As you might have thought, there is an easier way to get the value of MVBAR.

    hashtag
    Analyzing a memory dump

    hashtag
    Dump memory

    To analyze a memory dump you need to create one first. Our also compiles into a memory dump tool, modify if you need to change the memory address.

    hashtag
    Analyzing and importing the dump

    Import the dump to Ghidra. Use the setting from above, but make sure to go to options and set the Base Address to 80000000. This is where the memory dump started from. After this change continue the import as usual.

    But what now? You have Megabytes of memory, and you need to pick an exact point out of it.

    Of course we read the handful of existing and useful blog posts that are on the internet. Including this one:

    It shows how a Monitor Vector Table looks like, when disassembled:

    So only search for some branch instructions, right?

    Not really. There are a lot of jump tables in the memory dump. After hours upon hours of starring at Ghidra and the internet, I managed to find the right one.

    I searched for multiple branch instructions next to each other using this command xxd "trustzone.bin" | grep -E '(.{3}00 00ea){4}' (CTS helped me with that command)

    I just went through the results and found a jump table at 0x811f8000.

    At that point I already had an EFI app which loads a payload into memory, copies it to a desired location in the Trustzone and then fills some memory with an instruction to load the payload location into a register and an instruction to branch to this register. The payload was capable of printing something to UART. I have also tried other jump tables at that time, with no success.

    But this time it was different: The payload started executing.

    So it was clear: MVBAR is 0x811f8000

    hashtag
    The Trustzone payload

    hashtag
    Where to put the payload in memory

    Right now the payload is placed at 0x8011219c. When analyzing a memory dump you will notice that this is right after an instruction is executed which sets SCR.NS. In theory you will not need to place the payload exactly there. You could also place it before the SCR.NS set, you will always execute in secure mode, as described above. In theory you could also just replace a single Secure Monitor "Function" (When you pass paramteres to a SMC you specify what to do in the Secure Monitor).

    TODO: Add picture of Ghidra with the memory location

    hashtag
    Compiling a relocateable payload

    circle-info

    You can find a fully working payload example on . It includes the Makefile, a linker script, an assembly file and a C source file.

    Our payload is position independet, this means it can execute from anywhere in memory. It's really easy to make GCC compile position independet: Just add -fpic to the CFlags. (Yes, the payload is written in C, other languages such as C++ or Rust may be useable too).

    hashtag
    Using Assembler language

    When configuring a large amout of registers, using a seperate .S/.asm file is more convinient than using inline assembly.

    But there is something worth knowing: You need to make sure that your assembly is relocatable, otherwise the code will break. In C the compiler makes the code reloactable, but the assembler can't make the assembly relocateable for you.

    Here is a short example of an assembly file which loads the address of mybuffer into r0:

    What to explain:

    • How the payload works and how it is executed and why exactly the strange memory location

    • verifying that payload executes in Secure mode

    • explain monitor mode a bit more (maybe)

    hashtag
    Additional resources

    1. (Including Monitor Vector Table)

    2. (Figure 3.3)

    EFI Signing / Secure Boot

    circle-info

    Windows bootmanager exploit is deprecated, as you can now disable secure boot. Without secure boot you don't need to sign your EFI binaries. Visit Yahallo for more information.

    SurfaceRT/2 uses UEFI Secure Boot.

    We have a test key that can be used to sign our EFI binaries so that they are trusted by the windows boot manager. (When secure boot is enabled).

    hashtag
    Working Test Key

    5D7630097BE5BDB731FC40CD4998B69914D82EAD CN=Windows OEM Test Cert 2017 (TEST ONLY), O=Microsoft Partner, OU=Windows, L=Redmond, S=Washington, C=US

    can use signtool on windows to sign our EFI builds eg

    signtool.exe sign /tr http://timestamp.digicert.com /td sha1 /fd sha1 /sm /sha1 5d7630097be5bdb731fc40cd4998b69914d82ead *.efi

    what to do now
  • maybe how to use ghidra

  • # This should link into the .text section
    .text
    
    # Define a buffer with the size of 16 bytes
    mybuffer: .word 16
    
    # Make assembly_code available globally (so it can be used in C code)
    .global assembly_code
    .type assembly_code, function
    assembly_code:
        # Push the return address to the stack
        # Do this if you branch
        push {lr}
        
        # Load the address of mybuffer into memory
        # This is the important line.
        # ldr r0, =mybuffer doesn't work
        adr r0, mybuffer
        
        # Get the return address back from the stack
        pop {pc}
    SMC Calling Conventionarrow-up-right
    github repositoryarrow-up-right
    MemoryDumpTool/App.carrow-up-right
    https://fredericb.info/2014/12/analysis-of-nexus-5-monitor-mode.htmlarrow-up-right
    GitHubarrow-up-right
    Structure of Vector Tablesarrow-up-right
    Monitor Vector Base Address Registerarrow-up-right
    ARM Processor Modes and Registersarrow-up-right
    Typical structure of a Monitor Vector Table. Additional Resource #1
    Usage restriction of the MVBAR. Additional Resource #2
    ARM operating modes/states. Additional Resource #3
    Ghidra language setting
    This is the function that sets MVBAR in the SurfaceRTUEFI.bin binary
    Monitor Vector Table disassembled

    VSCode integration

    Debug Linux kernel within Visual Studio Code

    hashtag
    Create configuration files

    The following steps have to be performed in your Linux source directory.

    hashtag
    Create tasks.json

    Create a file called tasks.json in the directory .vscode and paste the following contents into it:

    circle-info

    You may want to change line 26 and 34, as they point to the directory where your qemu files are located.

    See for the documentation about the tasks.json format

    hashtag
    Create launch.json

    Create a file called launch.json in the directory .vscode and paste the following contents into it: Use IntelliSense to learn about possible attributes. Hover to view descriptions of existing attributes. For more information, visit:

    hashtag
    Create c_cpp_properties.json

    Create a file called c_cpp_properties.json in the directory .vscode and paste the following contents into it:

    hashtag
    Debug

    Press F5 to start debugging. The following steps will be performed:

    • Compile Kernel

    • Copy zImage to qemu EFI partition

    • Launch qemu

    The following keys are important:

    • F9 for creating a breakpoint

    • F10 for going a step forward

    • F11 for stepping into a function

    Start GDB debugging
    F12 to step out of a function
    https://go.microsoft.com/fwlink/?LinkId=733558arrow-up-right
    https://go.microsoft.com/fwlink/?linkid=830387arrow-up-right
    tasks.json
    {
      "version": "2.0.0",
      "tasks": [
        {
          "label": "Build Kernel for ARM",
          "type": "shell",
          "command": "make",
          "args": [
              "ARCH=arm",
              "CROSS_COMPILE=arm-linux-gnueabihf-",
              "-j6"
          ],
          "group": {
              "kind": "build",
              "isDefault": true
          },
          "problemMatcher": [
              "$gcc"
          ]
        },
        {
          "label": "Copy zImage",
          "command": "cp",
          "args": [
            "arch/arm/boot/zImage",
            "../emulation/boot/efi/boot/bootarm.efi"
          ],
          "dependsOn":["Build Kernel for ARM"]
        },
        {
          "label": "Run qemu",
          "command": "/usr/bin/qemu-system-arm -m 1024 -cpu cortex-a15 -M virt -pflash flash0.img -pflash flash1.img -nographic -drive file=fat:rw:boot/ -smp '4' -s",
          "options": {
            "cwd": "${workspaceFolder}/../emulation"
          },
          "type": "shell",
          "isBackground": true,
          "problemMatcher": [
            {
              "pattern": [
                {
                  "regexp": ".",
                  "file": 1,
                  "location": 2,
                  "message": 3
              }
              ],
              "background": {
                "activeOnStart": true,
                "beginsPattern": ".",
                "endsPattern": ".",
              }
            }
          ],
          "dependsOn":["Copy zImage"]
        },
        {
          "label": "Terminate All Tasks",
          "command": "echo ${input:terminate}",
          "type": "shell",
          "problemMatcher": []
        }
      ],
      "inputs": [
        {
          "id": "terminate",
          "type": "command",
          "command": "workbench.action.tasks.terminate",
          "args": "terminateAll"
        }
      ]
    } 
    launch.json
    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "(gdb) Run",
                "type": "cppdbg",
                "request": "launch",
                "program": "${workspaceRoot}/vmlinux",
                "miDebuggerServerAddress": "localhost:1234",
                "miDebuggerPath": "/usr/bin/gdb-multiarch",
                "args": [],
                "stopAtEntry": true,
                "cwd": "${workspaceFolder}",
                "environment": [],
                "externalConsole": false,
                "MIMode": "gdb",
                "targetArchitecture": "arm",
                "preLaunchTask": "Run qemu",
                "postDebugTask": "Terminate All Tasks",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            }
        ]
    }
    c_cpp_properties.json
    {
        "configurations": [
            {
                "name": "Linux",
                "includePath": [
                    "${workspaceFolder}",
                    "${workspaceFolder}/include",
                    "${workspaceFolder}/include/uapi",
                    "${workspaceFolder}/include/generated",
                    "${workspaceFolder}/arch/arm/include",
                    "${workspaceFolder}/arch/arm/include/uapi",
                    "${workspaceFolder}/arch/arm/include/generated"
                ],
                "defines": [
                    "__KERNEL__"
                ],
                "compilerPath": "/usr/bin/arm-linux-gnueabihf-gcc",
                "cStandard": "gnu17",
                "cppStandard": "c++17",
                "intelliSenseMode": "linux-gcc-arm",
                "browse": {
                    "path": [
                        "${workspaceFolder}",
                        "${workspaceFolder}/include",
                        "${workspaceFolder}/mm",
                        "${workspaceFolder}/fs",
                        "${workspaceFolder}/kernel"
                    ],
                    "limitSymbolsToIncludedHeaders": true,
                    "databaseFilename": ""
                }
            }
        ],
        "version": 4
    }

    Devicetree information

    ARM kernel maintainers decided that the best way to configure SoC hardware, would be to create a separate description of a particular SoC into something called a device tree filearrow-up-right, in order to keep it out of the kernel.

    In Linux there is a concept of "device trees", which is quite separate from the "/dev" structure & udev. It's available in PC land, although it isn't strictly necessary necessary because of the BIOS. Cursory googling suggests that the device tree is used in EFI (or UEFI?) based boot sequences, which is a kind of modern bootloading alternative to the BIOS.

    A "device tree" is a data structure that is given at boot-time, probably by the 2nd stage bootloader, to the final stage kernel so that it load the right drivers (ie kernel modules) with the right parameters. It's a platform description that iis useful for describing the parameters of standard subcomponents like PCI buses, Brand X ethernet chips, etc. In

    In ARM land there has never been anything like the BIOS, which was tailored to specific hardware (especially motherboards or laptops) but had quite a universal interface across plaforms.. The BIOS was thus able to help the kernel identify the hardware arrangment of the platform. Because ARM has not history of a standard firmware bootloading stage to describe hardware, as PCs have (or had) BIOS, device trees (along with kexecboot or u-boot or barebox etc) are a more essential consideration for arm. A booting ARM core doesn't even know about other cores in the same multi-core CPU. A "device tree" a document (source or compiled bytecode) that can be passed to the kernel at boot that describes the hardware layout of the entire system.

    • dts: Source file specification of a device tree for a platform.

    • dtb: Compiled bytecode representing the device tree, sometimes called a Flattened Devicee Tree (FDT).

    • dtc: The bytecode compiler that turns dts files into dtb file

    jwa4 Notes

    GRUB2 Booting Notes

    circle-check

    hashtag
    Booting Linux with grub is now possible. (But UEFI shell is normally used)

    Starting from Linux Kernel 5.0, it is now possible to enable FrameBuffer. This can be configured in grub with

    grub_cfg
    set grub_mm_debug=1
    insmod efi_gop
    insmod efi_uga
    earlycon=efifb,mem

    More here -

    hashtag
    EFISTUB (Kernel booting)

    triangle-exclamation

    The information bellow is outdated. Visit for information on how to compile & boot a working linux kernel.

    As we are "stuck" inside Microsofts bootarm.efi -> ContextSwitcher -> grub.

    https://forum.xda-developers.com/windows-8-rt/rt-development/wip-secure-boot-linux-surface-rt-t3653848/page13arrow-up-right
    EFI linux booting

    initrd

    file-download
    14MB
    rootfs.cpio.gz
    arrow-up-right-from-squareOpen

    Surface RT & 2 Jailbreak USB

    hashtag
    This guide has been temporarily replaced by:

    Windows Media Builder

    hashtag
    This guide has been temporarily replaced by:

    Interesting Repo's

    hashtag
    Nvidia Linux files

    https://developer.nvidia.com/linux-tegra-rel-16arrow-up-right Tegra3 aka Surface RT https://developer.nvidia.com/linux-tegra-rel-17arrow-up-right Tegra4 aka Surface RT2

    hashtag
    UBOOT Tegra

    Good for reference DTB's etc

    UBoot has Tegra Mainline support:

    hashtag
    Context Switcher for Tegra3

    The ContextSwitcher switches back from the windows Bootmgr environment back to the UEFI environment. Good for patch reference for SurfaceRT Grub2 display. Also setup for VisualC

    hashtag
    QEMU for ARM32

    hashtag
    Fusee Gelee for T30 (Surface RT)

    hashtag
    GRUB BootLoader

    A prepatched GRUB2 ready for SurfaceRT or SurfaceRT2.

    hashtag
    Misc

    I'd also recommend reading Jay Carlson's excellent notes on Embedded Linux here - as an overview.

    https://github.com/OE4T/u-boot-tegraarrow-up-right
    https://gitlab.denx.de/u-boot/u-bootarrow-up-right
    https://github.com/imbushuo/boot-shim-tegra-3arrow-up-right
    https://designprincipia.com/virtualize-uefi-on-arm-using-qemu/arrow-up-right
    https://github.com/coherixmatts/grub-2.04arrow-up-right
    https://jaycarlson.net/embedded-linux/arrow-up-right
    GitBookjwa4.gitbook.iochevron-right
    GitHub - jevinskie/fusee-launcher at b6e03fd7042ba2f1c989c1d007ebee6d4b5165efGitHubchevron-right
    GitBookjwa4.gitbook.iochevron-right
    Logo
    How the ARM32 kernel starts — linuswlinuswchevron-right
    Logo
    Logo
    GitHub - tofurky/tegra30_debrick: fusee-gelee payload, supporting files, and guide for debricking Tegra 3 devices (2012 Nexus 7 and Ouya)GitHubchevron-right
    Logo
    Logo