Open Surface RT
Discord CommunityXDA Page
  • Open Surface RT Home
  • Get started
    • Secure Boot
    • Windows 10
    • Linux
    • Discord
  • Changelog
  • Common
    • Boot Process
      • Special Boot modes
      • Tegra SoC's
        • Fusée Gelée
          • APX Mode (USB Recovery Mode "RCM")
          • Payloads
            • Dump platform key (SBK)
      • UEFI
        • Secure Boot
          • Windows Bootmanager Exploit
          • Yahallo - Disable Secureboot
        • UEFI Boot Sequence
        • FAT32 isn't FAT32
    • Windows RT
      • Jailbreak Exploits
      • Recovery Toolkit
      • Recovery Images
    • Windows 10
      • Software Support
      • Fake Builds
      • Known Issues
  • Tools
    • Windows Media Builder
    • Surface RT & 2 Jailbreak USB
  • Surface RT
    • Linux
      • Devicetree
        • APX devicetree
        • UEFI devicetree
      • Kernel
        • Kernel source
          • grate-driver
          • Mainline
        • Configure & Build
          • Appended devicetree
        • Prebuilt binaries
      • Booting
        • Kernel parameters
        • UEFI boot
        • APX boot
          • Das U-Boot
          • Fusée Gelée
            • BCT Table
            • NvFlash (Modified)
          • Boot Linux
            • Binaries
            • Prepare SD Card
      • Root Filesystem
        • Distributions
          • postmarketOS
          • Raspberry Pi OS
        • Simple RootFS
      • Trouble Shooting
    • Hardware
      • Tegra3 - Technical Reference Manual
      • J14 OEM Debug Connector
      • UART
        • 1.8V UART with Voltage divider
        • Raspberry Pi UART-Setup
      • GPIOs
        • decode - Pin number to Letter
        • GPIOs in Linux
      • IC's
        • SPI Flash
        • MMC
          • 1 - μSD Card
          • 3 - WIFI SDIO: Marvell: 88W8797
          • 4 - eMMC
        • I2C devices
          • Bus 0 - MS HID
            • 0x00 - Microsoft: Type/Touch Cover
            • 0x28 - [WIP] Microsoft: ?SensorCollection?
              • TBC - Ambient Light Sensor
              • TBC - Kionix: KXTJ9 - Accelerometer
          • Bus 1 - 2nd Board
            • 0x2D
            • 0x39 - Display Panel ThermalZone
            • 0x5B - ATMEL: mXT1386E - TouchController
          • Bus 2 - CAMs
          • Bus 3 - HDMI DDC
          • Bus 4 - System
            • 0x0A - ACPI: Control Method Battery
            • 0x1A - Wolfson: WM8962 - AudioCodec
            • 0x2D - TI: TPS659110 - PMIC
            • 0x4C - onsemi: NCT1008 - Temperatur sensor
            • 0x60 - TI: TPS62361B - Processor Supply
        • LVDS Encoder
      • Display
      • Battery
    • Firmware
      • Extract Firmware
      • Decrypt Firmware
      • Encrypt Firmware
      • BCT
      • RPMB partition on EMMC
    • UEFI
      • ACPI Tables
        • DSDT
        • SSDT
        • WDSA
        • MADT / APIC
        • Not interesting (yet)
          • BGRT
          • CSRT
          • DBG2
          • FACP
          • FPDT
          • MSDM
          • RSDP
          • TMP2
          • XSDT
      • Memory Mapping
      • Device Tables
      • PinMux
      • Compiling GRUB2
  • Surface RT2
    • Hardware
      • Specifications
      • ACPI (DSDT) Tables
      • Memory Mapping
      • EFI System Tables
      • BCT Table
      • IC's
      • Display
      • Battery
  • Other devices
    • Lenovo Ideapad Yoga 11
      • Linux
  • Development
    • !!! PLEASE READ !!!
      • !TODO for everyone
      • CTS devNotes
        • initrd
        • !TODO
          • Surface RT
          • Surface 2
        • battery
        • TZ Exploit - CTS
        • tCover Linux support
          • Kernel module
        • Dump Bootrom
        • git for dummys [WIP!] (like me)
      • Leander devNotes
        • !TODO
        • UEFI Privilege Escalation Exploit Documentation
          • Yahallo: Free memory access
          • UEFI Privilege Escalation: Execute code in Secure mode
          • Removing trustzone
        • EFI linux booting
          • Configs we already tried
          • Qemu emulation
            • GDB Debugging
              • VSCode integration
        • EFI Signing / Secure Boot
      • GRUB2 Booting Notes
      • Cross Compiling
      • Interesting Repo's
      • Devicetree information
      • Do gifs work?
      • Uboot information
      • jwa4 Notes
        • Windows Media Builder
        • Surface RT & 2 Jailbreak USB
Powered by GitBook
On this page
  • The idea
  • Finding MVBAR
  • Reading MVBAR
  • Reverse-engineering the firmware binary
  • Analyzing a memory dump
  • The Trustzone payload
  • Where to put the payload in memory
  • Compiling a relocateable payload
  • Additional resources

Was this helpful?

Export as PDF
  1. Development
  2. !!! PLEASE READ !!!
  3. Leander devNotes
  4. UEFI Privilege Escalation Exploit Documentation

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)

PreviousYahallo: Free memory accessNextRemoving trustzone

Last updated 3 years ago

Was this helpful?

The idea

Using the 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 .

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.

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

Reading MVBAR

So just read the MVBAR, right?

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.

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.

Analyzing a memory dump

Dump memory

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.

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

The Trustzone payload

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

Compiling a relocateable payload

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

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:

# 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}

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)

  • what to do now

  • maybe how to use ghidra

Additional resources

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.

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

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

(Including Monitor Vector Table)

(Figure 3.3)

github repository
MemoryDumpTool/App.c
https://fredericb.info/2014/12/analysis-of-nexus-5-monitor-mode.html
GitHub
Structure of Vector Tables
Monitor Vector Base Address Register
ARM Processor Modes and Registers
Yahallo exploit
SMC Calling Convention
Secure mode
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