|
3 | 3 | # Cross Platform and Multi Architecture Advanced Binary Emulation Framework |
4 | 4 | # |
5 | 5 |
|
6 | | -from unicorn import * |
7 | | -from unicorn.arm_const import * |
8 | | - |
9 | | -from qiling.const import * |
10 | | -from .arch import QlArch |
11 | | -from .arm_const import * |
| 6 | +from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UC_MODE_THUMB, UC_MODE_BIG_ENDIAN |
| 7 | +from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CS_MODE_THUMB |
| 8 | +from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KS_MODE_THUMB |
12 | 9 |
|
| 10 | +from qiling import Qiling |
| 11 | +from qiling.const import QL_ARCH, QL_ENDIAN |
| 12 | +from qiling.arch.arch import QlArch |
| 13 | +from qiling.arch.arm_const import * |
| 14 | +from qiling.exception import QlErrorArch |
13 | 15 |
|
14 | 16 | class QlArchARM(QlArch): |
15 | | - def __init__(self, ql): |
16 | | - super(QlArchARM, self).__init__(ql) |
17 | | - register_mappings = [ |
18 | | - reg_map |
19 | | - ] |
| 17 | + def __init__(self, ql: Qiling): |
| 18 | + super().__init__(ql) |
| 19 | + |
| 20 | + reg_maps = ( |
| 21 | + reg_map, |
| 22 | + ) |
20 | 23 |
|
21 | | - for reg_maper in register_mappings: |
| 24 | + for reg_maper in reg_maps: |
22 | 25 | self.ql.reg.expand_mapping(reg_maper) |
23 | 26 |
|
24 | 27 | self.ql.reg.create_reverse_mapping() |
25 | | - |
26 | 28 | self.ql.reg.register_sp(reg_map["sp"]) |
27 | 29 | self.ql.reg.register_pc(reg_map["pc"]) |
| 30 | + |
28 | 31 | self.arm_get_tls_addr = 0xFFFF0FE0 |
29 | 32 |
|
30 | | - def stack_push(self, value): |
31 | | - self.ql.reg.sp -= 4 |
32 | | - self.ql.mem.write(self.ql.reg.sp, self.ql.pack32(value)) |
33 | | - return self.ql.reg.sp |
| 33 | + # get initialized unicorn engine |
| 34 | + def get_init_uc(self) -> Uc: |
| 35 | + if self.ql.archendian == QL_ENDIAN.EB: |
| 36 | + mode = UC_MODE_ARM + UC_MODE_BIG_ENDIAN |
34 | 37 |
|
| 38 | + elif self.ql.archtype == QL_ARCH.ARM_THUMB: |
| 39 | + mode = UC_MODE_THUMB |
35 | 40 |
|
36 | | - def stack_pop(self): |
37 | | - data = self.ql.unpack32(self.ql.mem.read(self.ql.reg.sp, 4)) |
38 | | - self.ql.reg.sp += 4 |
39 | | - return data |
| 41 | + elif self.ql.archtype == QL_ARCH.ARM: |
| 42 | + mode = UC_MODE_ARM |
40 | 43 |
|
| 44 | + else: |
| 45 | + raise QlErrorArch(f'unsupported arch type {self.ql.archtype}') |
41 | 46 |
|
42 | | - def stack_read(self, offset): |
43 | | - return self.ql.unpack32(self.ql.mem.read(self.ql.reg.sp + offset, 4)) |
| 47 | + return Uc(UC_ARCH_ARM, mode) |
44 | 48 |
|
45 | 49 |
|
46 | | - def stack_write(self, offset, data): |
47 | | - return self.ql.mem.write(self.ql.reg.sp + offset, self.ql.pack32(data)) |
| 50 | + # get PC |
| 51 | + def get_pc(self) -> int: |
| 52 | + append = 1 if self.check_thumb() == UC_MODE_THUMB else 0 |
48 | 53 |
|
| 54 | + return self.ql.reg.pc + append |
| 55 | + |
| 56 | + def __is_thumb(self) -> bool: |
| 57 | + cpsr_v = { |
| 58 | + QL_ENDIAN.EL : 0b100000, |
| 59 | + QL_ENDIAN.EB : 0b100000 # FIXME: should be: 0b000000 |
| 60 | + }[self.ql.archendian] |
| 61 | + |
| 62 | + return bool(self.ql.reg.cpsr & cpsr_v) |
| 63 | + |
| 64 | + def create_disassembler(self) -> Cs: |
| 65 | + # note: we do not cache the disassembler instance; rather we refresh it |
| 66 | + # each time to make sure thumb mode is taken into account |
| 67 | + |
| 68 | + if self.ql.archtype == QL_ARCH.ARM: |
| 69 | + # FIXME: mode should take endianess into account |
| 70 | + mode = CS_MODE_THUMB if self.__is_thumb() else CS_MODE_ARM |
49 | 71 |
|
50 | | - # get initialized unicorn engine |
51 | | - def get_init_uc(self): |
52 | | - if self.ql.archendian == QL_ENDIAN.EB: |
53 | | - uc = Uc(UC_ARCH_ARM, UC_MODE_ARM + UC_MODE_BIG_ENDIAN) |
54 | 72 | elif self.ql.archtype == QL_ARCH.ARM_THUMB: |
55 | | - uc = Uc(UC_ARCH_ARM, UC_MODE_THUMB) |
56 | | - elif self.ql.archtype == QL_ARCH.ARM: |
57 | | - uc = Uc(UC_ARCH_ARM, UC_MODE_ARM) |
| 73 | + mode = CS_MODE_THUMB |
| 74 | + |
58 | 75 | else: |
59 | | - uc = None |
60 | | - return uc |
| 76 | + raise QlErrorArch(f'unexpected arch type {self.ql.archtype}') |
61 | 77 |
|
| 78 | + return Cs(CS_ARCH_ARM, mode) |
| 79 | + |
| 80 | + |
| 81 | + def create_assembler(self) -> Ks: |
| 82 | + # note: we do not cache the assembler instance; rather we refresh it |
| 83 | + # each time to make sure thumb mode is taken into account |
| 84 | + |
| 85 | + if self.ql.archtype == QL_ARCH.ARM: |
| 86 | + # FIXME: mode should take endianess into account |
| 87 | + mode = KS_MODE_THUMB if self.__is_thumb() else KS_MODE_ARM |
| 88 | + |
| 89 | + elif self.ql.archtype == QL_ARCH.ARM_THUMB: |
| 90 | + mode = KS_MODE_THUMB |
62 | 91 |
|
63 | | - # get PC |
64 | | - def get_pc(self): |
65 | | - mode = self.ql.arch.check_thumb() |
66 | | - if mode == UC_MODE_THUMB: |
67 | | - append = 1 |
68 | 92 | else: |
69 | | - append = 0 |
70 | | - |
71 | | - return self.ql.reg.pc + append |
| 93 | + raise QlErrorArch(f'unexpected arch type {self.ql.archtype}') |
72 | 94 |
|
| 95 | + return Ks(KS_ARCH_ARM, mode) |
73 | 96 |
|
74 | | - def enable_vfp(self): |
| 97 | + def enable_vfp(self) -> None: |
75 | 98 | self.ql.reg.c1_c0_2 = self.ql.reg.c1_c0_2 | (0xf << 20) |
| 99 | + |
76 | 100 | if self.ql.archendian == QL_ENDIAN.EB: |
77 | 101 | self.ql.reg.fpexc = 0x40000000 |
78 | 102 | #self.ql.reg.fpexc = 0x00000040 |
79 | 103 | else: |
80 | 104 | self.ql.reg.fpexc = 0x40000000 |
81 | | - self.ql.log.debug("Enable ARM VFP") |
82 | | - |
83 | 105 |
|
84 | 106 | def check_thumb(self): |
85 | | - reg_cpsr = self.ql.reg.cpsr |
86 | | - if self.ql.archendian == QL_ENDIAN.EB: |
87 | | - reg_cpsr_v = 0b100000 |
88 | | - # reg_cpsr_v = 0b000000 |
89 | | - else: |
90 | | - reg_cpsr_v = 0b100000 |
91 | | - |
92 | | - mode = UC_MODE_ARM |
93 | | - if (reg_cpsr & reg_cpsr_v) != 0: |
94 | | - mode = UC_MODE_THUMB |
95 | | - self.ql.log.debug("Enable ARM THUMB") |
96 | | - return mode |
| 107 | + return UC_MODE_THUMB if self.__is_thumb() else UC_MODE_ARM |
0 commit comments