Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust Qiling to comply with latest changed in Unicorn 2.1.2 #1499

Open
wants to merge 15 commits into
base: dev
Choose a base branch
from
Open
13 changes: 11 additions & 2 deletions qiling/arch/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from qiling import Qiling
from qiling.arch.arch import QlArch
from qiling.arch import arm_const
from qiling.arch.cpr import QlCprManager
from qiling.arch.models import ARM_CPU_MODEL
from qiling.arch.register import QlRegisterManager
from qiling.const import QL_ARCH, QL_ENDIAN
Expand Down Expand Up @@ -69,6 +70,13 @@ def is_thumb(self) -> bool:
def endian(self) -> QL_ENDIAN:
return QL_ENDIAN.EB if self.regs.cpsr & (1 << 9) else QL_ENDIAN.EL

@cached_property
def cpr(self) -> QlCprManager:
"""Coprocessor Registers.
"""

return QlCprManager(self.uc)

@property
def effective_pc(self) -> int:
"""Get effective PC value, taking Thumb mode into account.
Expand Down Expand Up @@ -119,6 +127,7 @@ def assembler(self) -> Ks:

def enable_vfp(self) -> None:
# set full access to cp10 and cp11
self.regs.c1_c0_2 = self.regs.c1_c0_2 | (0b11 << 20) | (0b11 << 22)
cpacr = self.cpr.read(*arm_const.CPACR)
self.cpr.write(*arm_const.CPACR, cpacr | (0b11 << 20) | (0b11 << 22))

self.regs.fpexc = (1 << 30)
self.regs.fpexc = (0b1 << 30)
8 changes: 8 additions & 0 deletions qiling/arch/arm64.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from qiling import Qiling
from qiling.arch.arch import QlArch
from qiling.arch import arm64_const
from qiling.arch.cpr64 import QlCpr64Manager
from qiling.arch.models import ARM64_CPU_MODEL
from qiling.arch.register import QlRegisterManager
from qiling.const import QL_ARCH, QL_ENDIAN
Expand Down Expand Up @@ -56,6 +57,13 @@ def regs(self) -> QlRegisterManager:
def endian(self) -> QL_ENDIAN:
return QL_ENDIAN.EL

@cached_property
def cpr(self) -> QlCpr64Manager:
"""Coprocessor Registers.
"""

return QlCpr64Manager(self.uc)

@cached_property
def disassembler(self) -> Cs:
return Cs(CS_ARCH_ARM64, CS_MODE_ARM)
Expand Down
27 changes: 25 additions & 2 deletions qiling/arch/arm64_const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@

from unicorn.arm64_const import *


# coprocessor registers
TPIDR_EL0 = (3, 3, 13, 0, 2)
TPIDRRO_EL0 = (3, 3, 13, 0, 3)
TPIDR_EL1 = (3, 0, 13, 0, 4)
ELR_EL1 = (3, 0, 4, 0, 1)
ELR_EL2 = (3, 4, 4, 0, 1)
ELR_EL3 = (3, 6, 4, 0, 1)
SP_EL0 = (3, 0, 4, 1, 0)
SP_EL1 = (3, 4, 4, 1, 0)
SP_EL2 = (3, 6, 4, 1, 0)
TTBR0_EL1 = (3, 0, 2, 0, 0)
TTBR1_EL1 = (3, 0, 2, 0, 1)
ESR_EL1 = (3, 0, 5, 2, 0)
ESR_EL2 = (3, 4, 5, 2, 0)
ESR_EL3 = (3, 6, 5, 2, 0)
FAR_EL1 = (3, 0, 6, 0, 0)
FAR_EL2 = (3, 4, 6, 0, 0)
FAR_EL3 = (3, 6, 6, 0, 0)
PAR_EL1 = (3, 0, 7, 4, 0)
MAIR_EL1 = (3, 0, 10, 2, 0)
VBAR_EL1 = (3, 0, 12, 0, 0)
VBAR_EL2 = (3, 4, 12, 0, 0)
VBAR_EL3 = (3, 6, 12, 0, 0)

reg_map = {
"x0": UC_ARM64_REG_X0,
"x1": UC_ARM64_REG_X1,
Expand Down Expand Up @@ -41,8 +66,6 @@
"pc": UC_ARM64_REG_PC,
"lr": UC_ARM64_REG_LR,
"cpacr_el1": UC_ARM64_REG_CPACR_EL1,
"tpidr_el0": UC_ARM64_REG_TPIDR_EL0,
"pstate": UC_ARM64_REG_PSTATE
}

reg_map_b = {
Expand Down
36 changes: 20 additions & 16 deletions qiling/arch/arm_const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,31 @@

from unicorn.arm_const import *


CPACR = (15, 0, 1, 0, 2, 0, False)
TPIDRURO = (15, 0, 13, 0, 3, 0, False)

reg_map = {
"r0": UC_ARM_REG_R0,
"r1": UC_ARM_REG_R1,
"r2": UC_ARM_REG_R2,
"r3": UC_ARM_REG_R3,
"r4": UC_ARM_REG_R4,
"r5": UC_ARM_REG_R5,
"r6": UC_ARM_REG_R6,
"r7": UC_ARM_REG_R7,
"r8": UC_ARM_REG_R8,
"r9": UC_ARM_REG_R9,
"r0": UC_ARM_REG_R0,
"r1": UC_ARM_REG_R1,
"r2": UC_ARM_REG_R2,
"r3": UC_ARM_REG_R3,
"r4": UC_ARM_REG_R4,
"r5": UC_ARM_REG_R5,
"r6": UC_ARM_REG_R6,
"r7": UC_ARM_REG_R7,
"r8": UC_ARM_REG_R8,
"r9": UC_ARM_REG_R9,
"r10": UC_ARM_REG_R10,
"r11": UC_ARM_REG_R11,
"r12": UC_ARM_REG_R12,
"sp": UC_ARM_REG_SP,
"lr": UC_ARM_REG_LR,
"pc": UC_ARM_REG_PC,
"sp": UC_ARM_REG_SP,
"lr": UC_ARM_REG_LR,
"pc": UC_ARM_REG_PC,

"cpsr": UC_ARM_REG_CPSR,
"c1_c0_2": UC_ARM_REG_C1_C0_2,
"c13_c0_3": UC_ARM_REG_C13_C0_3,
"apsr": UC_ARM_REG_APSR,
"cpsr": UC_ARM_REG_CPSR,
"spsr": UC_ARM_REG_SPSR,
"fpexc": UC_ARM_REG_FPEXC
}

Expand Down
73 changes: 27 additions & 46 deletions qiling/arch/arm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

from typing import Mapping

from qiling import Qiling
from qiling.const import QL_ENDIAN


def init_linux_traps(ql: Qiling, address_map) -> None:
def init_linux_traps(ql: Qiling, address_map: Mapping[str, int]) -> None:
# If the compiler for the target does not provides some primitives for some
# reasons (e.g. target limitations), the kernel is responsible to assist
# with these operations.
Expand All @@ -16,51 +18,32 @@ def init_linux_traps(ql: Qiling, address_map) -> None:
# https://elixir.bootlin.com/linux/latest/source/arch/arm/kernel/entry-armv.S#L899

trap_map = {
'memory_barrier':
# @ 0xffff0fa0
# mcr p15, 0, r0, c7, c10, 5
# nop
# mov pc, lr
'''
ba 0f 07 ee
00 f0 20 e3
0e f0 a0 e1
''',
'memory_barrier': bytes.fromhex(
'ba 0f 07 ee' # mcr p15, 0, r0, c7, c10, 5
'00 f0 20 e3' # nop
'0e f0 a0 e1' # mov pc, lr
),

'cmpxchg':
# @ 0xffff0fc0
# ldr r3, [r2]
# subs r3, r3, r0
# streq r1, [r2]
# rsbs r0, r3, #0
# mov pc, lr
'''
00 30 92 e5
00 30 53 e0
00 10 82 05
00 00 73 e2
0e f0 a0 e1
''',
'cmpxchg': bytes.fromhex(
'00 30 92 e5' # ldr r3, [r2]
'00 30 53 e0' # subs r3, r3, r0
'00 10 82 05' # streq r1, [r2]
'00 00 73 e2' # rsbs r0, r3, #0
'0e f0 a0 e1' # mov pc, lr
),

'get_tls':
# @ 0xffff0fe0
# ldr r0, [pc, #(16 - 8)]
# mov pc, lr
# mrc p15, 0, r0, c13, c0, 3
# padding (e7 fd de f1)
# data:
# "\x00\x00\x00\x00"
# "\x00\x00\x00\x00"
# "\x00\x00\x00\x00"
'''
08 00 9f e5
0e f0 a0 e1
70 0f 1d ee
e7 fd de f1
00 00 00 00
00 00 00 00
00 00 00 00
'''
'get_tls': bytes.fromhex(
'08 00 9f e5' # ldr r0, [pc, #(16 - 8)]
'0e f0 a0 e1' # mov pc, lr
'70 0f 1d ee' # mrc p15, 0, r0, c13, c0, 3
'e7 fd de f1' # padding (e7 fd de f1)
'00 00 00 00' # data
'00 00 00 00' # data
'00 00 00 00' # data
)
}

if address_map:
Expand All @@ -74,16 +57,14 @@ def init_linux_traps(ql: Qiling, address_map) -> None:

ql.mem.map(base, size, info="[arm_traps]")

for trap_name, trap_hex in trap_map.items():
trap_code = bytes.fromhex(trap_hex)

if ql.arch.endian == QL_ENDIAN.EB:
for trap_name, trap_code in trap_map.items():
if ql.arch.endian is QL_ENDIAN.EB:
trap_code = swap_endianness(trap_code)

if trap_name in address_map:
ql.mem.write(address_map[trap_name], trap_code)

ql.log.debug(f'Set kernel trap: {trap_name} at {address_map[trap_name]:#x}')
ql.log.debug(f'Setting kernel trap {trap_name} at {address_map[trap_name]:#x}')


def swap_endianness(s: bytes, blksize: int = 4) -> bytes:
Expand Down
60 changes: 60 additions & 0 deletions qiling/arch/cpr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

from __future__ import annotations

import weakref

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from unicorn import Uc


class QlCprManager:
"""Enables access to ARM coprocessor registers.
"""

# for more information about various aarch32 coprocessor register, pelase refer to:
# https://developer.arm.com/documentation/ddi0601/latest/AArch32-Registers

def __init__(self, uc: Uc) -> None:
self.uc: Uc = weakref.proxy(uc)

def read(self, coproc: int, opc1: int, crn: int, crm: int, opc2: int, el: int, is_64: bool) -> int:
"""Read a coprocessor register value.

Args:
coproc : coprocessor to access, value varies between 0 and 15
opc1 : opcode 1, value varies between 0 and 7
crn : coprocessor register to access (CRn), value varies between 0 and 15
crm : additional coprocessor register to access (CRm), value varies between 0 and 15
opc2 : opcode 2, value varies between 0 and 7
el : the exception level the coprocessor register belongs to, value varies between 0 and 3
is_64 : indicates whether this is a 64-bit register

Returns: value of coprocessor register
"""

return self.uc.cpr_read(coproc, opc1, crn, crm, opc2, el, is_64)

def write(self, coproc: int, opc1: int, crn: int, crm: int, opc2: int, el: int, is_64: bool, value: int) -> None:
"""Write a coprocessor register value.

Args:
coproc : coprocessor to access, value varies between 0 and 15
opc1 : opcode 1, value varies between 0 and 7
crn : coprocessor register to access (CRn), value varies between 0 and 15
crm : additional coprocessor register to access (CRm), value varies between 0 and 15
opc2 : opcode 2, value varies between 0 and 7
el : the exception level the coprocessor register belongs to, value varies between 0 and 3
is_64 : indicates whether this is a 64-bit register
value : value to write
"""

self.uc.cpr_write(coproc, opc1, crn, crm, opc2, el, is_64, value)


__all__ = ['QlCprManager']
56 changes: 56 additions & 0 deletions qiling/arch/cpr64.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

from __future__ import annotations

import weakref

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from unicorn import Uc


class QlCpr64Manager:
"""Enables access to ARM64 coprocessor registers.
"""

# for more information about various aarch32 coprocessor register, pelase refer to:
# https://developer.arm.com/documentation/ddi0601/latest/AArch64-Registers

def __init__(self, uc: Uc) -> None:
self.uc: Uc = weakref.proxy(uc)

def read(self, op0: int, op1: int, crn: int, crm: int, op2: int) -> int:
"""Read a coprocessor register value.

Args:
op0 : opcode 0, value varies between 0 and 3
op1 : opcode 1, value varies between 0 and 7
crn : coprocessor register to access (CRn), value varies between 0 and 15
crm : additional coprocessor register to access (CRm), value varies between 0 and 15
op2 : opcode 2, value varies between 0 and 7

Returns: value of coprocessor register
"""

return self.uc.cpr_read(op0, op1, crn, crm, op2)

def write(self, op0: int, op1: int, crn: int, crm: int, op2: int, value: int) -> None:
"""Write a coprocessor register value.

Args:
op0 : opcode 0, value varies between 0 and 3
op1 : opcode 1, value varies between 0 and 7
crn : coprocessor register to access (CRn), value varies between 0 and 15
crm : additional coprocessor register to access (CRm), value varies between 0 and 15
op2 : opcode 2, value varies between 0 and 7
value : value to write
"""

self.uc.cpr_write(op0, op1, crn, crm, op2, value)


__all__ = ['QlCpr64Manager']
11 changes: 9 additions & 2 deletions qiling/arch/msr.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

from unicorn import Uc
from __future__ import annotations

import weakref

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from unicorn import Uc


class QlMsrManager:
"""Enables access to Intel MSR.
"""

def __init__(self, uc: Uc) -> None:
self.uc = uc
self.uc: Uc = weakref.proxy(uc)

def read(self, msr: int) -> int:
"""Read a model-specific register value.
Expand Down
Loading
Loading