unicorn
unicorn copied to clipboard
Cannot switch exception level to EL3 in aarch64 (python)
I have a problem with switching to EL3 using Python bindings.
Tried to switch to EL3 via modifying PSTATE
register and CurrentEL
register, but fails.
First CODE
tries to read SCR_EL3
but raises an exception unicorn.unicorn.UcError: Unhandled CPU exception (UC_ERR_EXCEPTION)
.
Second CODE
checks current EL and jumps to the corresponding location with hook enabled.
My output:
CurrentEL: 0
PSTATE: 0x400003C5
address: 0xC0000010
X22: 0x00000004
EL3 test failed
Here is the code:
from dataclasses import dataclass
from unicorn import *
from unicorn.arm64_const import *
@dataclass
class SystemReg:
op0: int
op1: int
crn: int
crm: int
op2: int
def to_tuple(self):
return self.crn, self.crm, self.op0, self.op1, self.op2
def with_value(self, value: int):
return self.to_tuple() + (value,)
def hook_ok(uc: Uc, address, size, user_data):
print(f"address: 0x{address:08X}")
print(f"X22: 0x{uc.reg_read(UC_ARM64_REG_X22):08X}")
print("EL3 test ok")
uc.emu_stop()
def hook_bad(uc, address, size, user_data):
print(f"address: 0x{address:08X}")
print(f"X22: 0x{uc.reg_read(UC_ARM64_REG_X22):08X}")
print("EL3 test failed")
uc.emu_stop()
def main():
uc = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
ADDRESS = 0xC000_0000
MEM_SIZE = 0x20_0000
# Throws an exception: unicorn.unicorn.UcError: Unhandled CPU exception (UC_ERR_EXCEPTION)
CODE = (b"\x20\x00\x80\xd2" # MOV X0, #1
b"\xe1\xff\xbf\xd2" # MOV X1, #0xFFFF0000
b"\x02\x11\x3e\xd5" # MRS X2, SCR_EL3
b"\x02\x11\x1e\xd5" # MSR SCR_EL3, X2
b"\x00\x00\x00\x14") # B .
CODE = (b"\x56\x42\x38\xd5" # MRS X22, CurrentEL
b"\xdf\x32\x00\xf1" # CMP X22, #0xC
b"\x41\x00\x00\x54" # BNE +#0x8
b"\x00\x00\x00\x14" # B . ; EL3
b"\x00\x00\x00\x14") # B . ; Not EL3
uc.mem_map(ADDRESS, MEM_SIZE)
uc.mem_write(ADDRESS, CODE)
CurrentEl = SystemReg(0b11, 0b000, 0b0100, 0b0010, 0b010)
el = uc.reg_read(UC_ARM64_REG_CP_REG, CurrentEl.to_tuple())
print(f"CurrentEL: {el}")
el = 3 << 2
uc.reg_write(UC_ARM64_REG_CP_REG, CurrentEl.with_value(el))
pstate = uc.reg_read(UC_ARM64_REG_PSTATE)
print(f"PSTATE: 0x{pstate:08X}\n")
pstate |= 3 << 2
uc.reg_write(UC_ARM64_REG_PSTATE, pstate)
uc.hook_add(UC_HOOK_CODE, hook_bad, begin=ADDRESS + 0x10, end=ADDRESS + 0x10)
uc.hook_add(UC_HOOK_CODE, hook_ok, begin=ADDRESS + 0xC, end=ADDRESS + 0xC)
uc.emu_start(ADDRESS, ADDRESS + len(CODE))
if __name__ == "__main__":
main()