-
Notifications
You must be signed in to change notification settings - Fork 778
Expand file tree
/
Copy pathutils.py
More file actions
119 lines (92 loc) · 4.23 KB
/
utils.py
File metadata and controls
119 lines (92 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#
"""
This module is intended for general purpose functions that are only used in qiling.arch
"""
from typing import Tuple
from os.path import basename
from functools import lru_cache
from keystone import (Ks, KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_MIPS, KS_ARCH_X86, KS_ARCH_PPC,
KS_MODE_ARM, KS_MODE_THUMB, KS_MODE_MIPS32, KS_MODE_PPC32, KS_MODE_16, KS_MODE_32, KS_MODE_64,
KS_MODE_LITTLE_ENDIAN, KS_MODE_BIG_ENDIAN)
from qiling import Qiling
from qiling.const import QL_ARCH, QL_ENDIAN, QL_VERBOSE
class QlArchUtils:
def __init__(self, ql: Qiling):
self.ql = ql
self._disasm_hook = None
self._block_hook = None
@lru_cache(maxsize=64)
def get_base_and_name(self, addr: int) -> Tuple[int, str]:
for begin, end, _, name, _, _ in self.ql.mem.map_info:
if begin <= addr < end:
return begin, basename(name)
return addr, '-'
def disassembler(self, ql: Qiling, address: int, size: int):
data = ql.mem.read(address, size)
# knowing that all binary sections are aligned to page boundary allows
# us to 'cheat' and search for the containing image using the aligned
# address instead of the actual one.
#
# also, the locality property determines that consequent instructions
# are most likely to reside at the same page in memory, so the containing
# page of the current instruction is probably the same as the previous
# one.
#
# both assumptions make it possible to cache the search results and pull
# them off by lru, which provides about 20% speed-up in this case
ba, name = self.get_base_and_name(ql.mem.align(address))
anibbles = ql.arch.bits // 4
for insn in ql.arch.disassembler.disasm(data, address):
offset = insn.address - ba
ql.log.info(f'{insn.address:0{anibbles}x} [{name:20s} + {offset:#08x}] {insn.bytes.hex(" "):20s} {insn.mnemonic:20s} {insn.op_str}')
if ql.verbose >= QL_VERBOSE.DUMP:
for reg in ql.arch.regs.register_mapping:
ql.log.info(f'{reg:10s} : {ql.arch.regs.read(reg):#x}')
def setup_output(self, verbosity: QL_VERBOSE):
def ql_hook_block_disasm(ql: Qiling, address: int, size: int):
self.ql.log.info(f'\nTracing basic block at {address:#x}')
if self._disasm_hook:
self._disasm_hook.remove()
self._disasm_hook = None
if self._block_hook:
self._block_hook.remove()
self._block_hook = None
if verbosity >= QL_VERBOSE.DISASM:
try: # monkey patch disassembler
from qiling.extensions.r2 import R2
r2 = R2(self.ql)
self._disasm_hook = self.ql.hook_code(r2.disassembler)
except (ImportError, ModuleNotFoundError):
self._disasm_hook = self.ql.hook_code(self.disassembler)
if verbosity >= QL_VERBOSE.DUMP:
self._block_hook = self.ql.hook_block(ql_hook_block_disasm)
# used by qltool prior to ql instantiation. to get an assembler object
# after ql instantiation, use the appropriate ql.arch method
def assembler(arch: QL_ARCH, endianess: QL_ENDIAN, is_thumb: bool) -> Ks:
"""Instantiate an assembler object for a specified architecture.
Args:
arch: architecture type
endianess: architecture endianess
is_thumb: thumb mode for ARM (ignored otherwise)
Returns: an assembler object
"""
endian = {
QL_ENDIAN.EL : KS_MODE_LITTLE_ENDIAN,
QL_ENDIAN.EB : KS_MODE_BIG_ENDIAN
}[endianess]
thumb = KS_MODE_THUMB if is_thumb else 0
asm_map = {
QL_ARCH.ARM : (KS_ARCH_ARM, KS_MODE_ARM + endian + thumb),
QL_ARCH.ARM64 : (KS_ARCH_ARM64, KS_MODE_ARM),
QL_ARCH.MIPS : (KS_ARCH_MIPS, KS_MODE_MIPS32 + endian),
QL_ARCH.A8086 : (KS_ARCH_X86, KS_MODE_16),
QL_ARCH.X86 : (KS_ARCH_X86, KS_MODE_32),
QL_ARCH.X8664 : (KS_ARCH_X86, KS_MODE_64),
QL_ARCH.PPC : (KS_ARCH_PPC, KS_MODE_PPC32 + KS_MODE_BIG_ENDIAN)
}
if arch in asm_map:
return Ks(*asm_map[arch])
raise NotImplementedError