June 14, 2021
8 min read

Accessing Kernel and Physical RAM from Userland

Corellium VMs offer user programs running inside the CHARM hypervisor a way to access either kernel or physical views of VM RAM. This allows users to write research tools that do not rely on other -- more complex -- paths to gain that privilege, which is normally reserved to the kernel.

Technical Writeups

Corellium VMs offer user programs running inside the CHARM hypervisor a way to access either kernel or physical views of VM RAM. This allows users to write research tools that do not rely on other -- more complex -- paths to gain that privilege, which is normally reserved to the kernel.

The access interface has two parts. The first part allows for obtaining information on the kernel location in memory, as well as current values of relevant Arm system registers. The second part operates like a privileged equivalent to the memcpy function, adding the ability to copy data across typically privileged address space boundaries.

Note that kernel memory page faults are not supported; they will result in partial copy (and return value set appropriately). User page faults are supported.

Only 64-bit EL0 code can use this interface, and is accessed via the use of HVC instructions. The exact syntax form differs slightly between iOS and Android VMs. Both are shown below, and are also available in the Corellium GitHub as guest-tools, along with examples.

iOS EL0 (64-bit)

1 .align 4
2.global _get_kern_info
3_get_kern_info:
4    mrs xzr, cntpct_el0
5    hvc #0x9402
6    ret
7
8.align 4
9.global _unicopy
10_unicopy:
11    uxtb x0, w0
12    orr x5, x0, #0x100
13    mov x4, #0
14    mov x6, #16
151:
16    cbz x3, 2f
17    tst x5, #12
18    bne 4f
19    ldrb w0, [x2]
204:
21    tst x5, #3
22    bne 5f
23    strb w0, [x1]
245: 
25    mov x0, x5
26    mrs xzr, cntpct_el0
27    hvc #0x9402
28    cbnz x0, 3f
29    sub x6, x6, #1
30    cbz x6, 2f
31    b 1b
323:
33    mov x6, #16
34    add x1, x1, x0
35    add x2, x2, x0
36    sub x3, x3, x0
37    add x4, x4, x0
38    b 1b
392: 
40    mov x0, x4
41    ret

Android and Linux EL0 (64-bit)

1.align 4
2.global get_kern_info
3get_kern_info:
4    mrs xzr, pmcr_el0
5    hvc #0x9402
6    ret
7
8.align 4
9.global unicopy
10unicopy:
11    uxtb x0, w0
12    orr x5, x0, #0x100
13    mov x4, #0
14    mov x6, #16
151: 
16    cbz x3, 2f
17    tst x5, #12
18    bne 4f
19    ldrb w0, [x2]
204:
21    tst x5, #3
22    bne 5f
23    strb w0, [x1]
245:
25    mov x0, x5
26    mrs xzr, pmcr_el0
27    hvc #0x9402
28    cbnz x0, 3f
29    sub x6, x6, #1
30    cbz x6, 2f
31    b 1b
323: 
33    mov x6, #16
34    add x1, x1, x0
35    add x2, x2, x0
36    sub x3, x3, x0
37    add x4, x4, x0
38    b 1b
392: 
40    mov x0, x4
41    ret

The following header file declares the interface for both:

1#define KERN_INFO_VA             0x00
2#define KERN_INFO_PA             0x01
3
4#define KERN_INFO_TPIDR_EL1      0x40
5#define KERN_INFO_TTBR0_EL1      0x41
6#define KERN_INFO_TTBR1_EL1      0x42
7#define KERN_INFO_TCR_EL1        0x43
8#define KERN_INFO_VBAR_EL1       0x44
9#define KERN_INFO_CONTEXTIDR_EL1 0x45
10
11// access kernel-specific information based on the specified KERN_INFO_* parameter
12uintptr_t get_kern_info(unsigned int key);
13
14#define UNICOPY_DST_USER   0 // Copy to user virtual address space
15#define UNICOPY_DST_KERN   1 // Copy to kernel virtual address space
16#define UNICOPY_DST_PHYS   2 // Copy to physical address
17#define UNICOPY_SRC_USER   0 // Copy from user virtual address space
18#define UNICOPY_SRC_KERN   4 // Copy from kernel address space
19#define UNICOPY_SRC_PHYS   8 // Copy from physical address
20
21// returns amount of data copied successfully
22// mode: the bitwise OR of a UNICOPY_DST_* and UNICOPY_SRC* parameter, specifying the 
23//       address space to copy to and from.
24// dst:  the address to copy to in the UNICODE_DST_* address space
25// src:  the address to copy from in the UNICODE_SRC_* address space
26// size: the number of bytes to copy from one address space to the other.
27size_t unicopy(unsigned int mode, uintptr_t dst, uintptr_t src, size_t size);

Contributors

Amanda Gorton