33# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44#
55
6- import math , copy , os
6+ from __future__ import annotations
7+ from typing import Optional , Mapping , Iterable , Union
8+
9+ import copy , math , os
710from contextlib import contextmanager
811
912from qiling .const import QL_ARCH
10- from .utils import dump_regs , get_arm_flags , disasm
11- from .const import color
13+
14+ from .utils import dump_regs , get_arm_flags , disasm , parse_int
15+ from .const import *
1216
1317
1418# read data from memory of qiling instance
15- def examine_mem (ql , addr , fmt ):
19+ def examine_mem (ql : Qiling , line : str ) -> Union [bool , (str , int , int )]:
20+
21+ _args = line .split ()
22+ DEFAULT_FMT = ('x' , 4 , 1 )
23+
24+ if line .startswith ("/" ): # followed by format letter and size letter
25+
26+ def get_fmt (text ):
27+ def extract_count (t ):
28+ return "" .join ([s for s in t if s .isdigit ()])
29+
30+ f , s , c = DEFAULT_FMT
31+ if extract_count (text ):
32+ c = int (extract_count (text ))
33+
34+ for char in text .strip (str (c )):
35+ if char in SIZE_LETTER .keys ():
36+ s = SIZE_LETTER .get (char )
37+
38+ elif char in FORMAT_LETTER :
39+ f = char
40+
41+ return (f , s , c )
42+
43+ fmt , addr = line .strip ("/" ).split ()
44+
45+ fmt = get_fmt (fmt )
46+
47+ elif len (_args ) == 1 : # only address
48+ addr = _args [0 ]
49+ fmt = DEFAULT_FMT
50+
51+ else :
52+ return False
53+
54+ addr = addr .strip ('$' )
55+
56+ if ql .archtype in (QL_ARCH .ARM , QL_ARCH .ARM_THUMB ):
57+ addr = addr .replace ("fp" , "r11" )
58+
59+ elif ql .archtype == QL_ARCH .MIPS :
60+ addr = addr .replace ("fp" , "s8" )
61+
62+ addr = getattr (ql .reg , addr ) if addr in ql .reg .register_mapping .keys () else parse_int (addr )
1663
1764 def unpack (bs , sz ):
1865 return {
@@ -29,7 +76,7 @@ def unpack(bs, sz):
2976 for offset in range (addr , addr + ct * 4 , 4 ):
3077 line = disasm (ql , offset )
3178 if line :
32- print ("0x{:x}: {}\t {}" . format ( line .address , line . mnemonic , line . op_str ) )
79+ print (f "0x{ line . address :x} : { line . mnemonic } \t { line .op_str } " )
3380
3481 print ()
3582
@@ -40,27 +87,29 @@ def unpack(bs, sz):
4087
4188 for line in range (lines ):
4289 offset = line * sz * 4
43- print ("0x{:x}:\t " . format ( addr + offset ) , end = "" )
90+ print ("0x{addr+offset :x}:\t " , end = "" )
4491
45- idx = line * 4
46- for each in mem_read [idx :idx + 4 ]:
92+ idx = line * ql . pointersize
93+ for each in mem_read [idx :idx + ql . pointersize ]:
4794 data = unpack (each , sz )
4895 prefix = "0x" if ft in ("x" , "a" ) else ""
4996 pad = '0' + str (sz * 2 ) if ft in ('x' , 'a' , 't' ) else ''
5097 ft = ft .lower () if ft in ("x" , "o" , "b" , "d" ) else ft .lower ().replace ("t" , "b" ).replace ("a" , "x" )
5198
52- print ("{}{{:{}{}}} \t ". format ( prefix , pad , ft ). format ( data ) , end = "" )
99+ print (f" { prefix } { data :{ pad }{ ft } } \t " , end = "" )
53100
54101 print ()
55102
103+ return True
104+
56105
57106# get terminal window height and width
58- def get_terminal_size ():
107+ def get_terminal_size () -> Iterable :
59108 return map (int , os .popen ('stty size' , 'r' ).read ().split ())
60109
61110
62111# try to read data from ql memory
63- def _try_read (ql , address , size ) :
112+ def _try_read (ql : Qiling , address : int , size : int ) -> Optional [ bytes ] :
64113 try :
65114 result = ql .mem .read (address , size )
66115 except :
@@ -71,14 +120,14 @@ def _try_read(ql, address, size):
71120
72121# divider printer
73122@contextmanager
74- def context_printer (ql , field_name , ruler = "=" ):
123+ def context_printer (ql : Qiling , field_name : str , ruler : str = "=" ) -> None :
75124 _height , _width = get_terminal_size ()
76125 print (field_name , ruler * (_width - len (field_name ) - 1 ))
77126 yield
78127 print (ruler * _width )
79128
80129
81- def context_reg (ql , saved_states = None , * args , ** kwargs ):
130+ def context_reg (ql : Qiling , saved_states : Optional [ Mapping [ str , int ]] = None , / , * args , ** kwargs ) -> None :
82131
83132 # context render for registers
84133 with context_printer (ql , "[Registers]" ):
@@ -104,7 +153,7 @@ def context_reg(ql, saved_states=None, *args, **kwargs):
104153 line = "{}{}: 0x{{:08x}} {}\t " .format (_colors [(idx - 1 ) // 4 ], r , color .END )
105154
106155 if _diff and r in _diff :
107- line = "{}{}" . format ( color .UNDERLINE , color .BOLD ) + line
156+ line = f" { color .UNDERLINE } { color .BOLD } { line } "
108157
109158 if idx % 4 == 0 and idx != 32 :
110159 line += "\n "
@@ -152,45 +201,61 @@ def context_reg(ql, saved_states=None, *args, **kwargs):
152201 _val = ql .mem .read (_addr , ql .pointersize )
153202 print (f"$sp+0x{ idx * 4 :02x} |[0x{ _addr :08x} ]=> 0x{ ql .unpack (_val ):08x} " , end = "" )
154203
155- try : # try to deference wether its a pointer
156- _deref = ql .mem .read (_addr , 4 )
204+ try : # try to deference wether its a pointer
205+ _deref = ql .mem .read (_addr , ql . pointersize )
157206 except :
158207 _deref = None
159208
160209 if _deref :
161210 print (f" => 0x{ ql .unpack (_deref ):08x} " )
162211
163212
164- def print_asm (ql , instructions ):
165- for ins in instructions :
166- fmt = (ins .address , ins .mnemonic .ljust (6 ), ins .op_str )
167- if ql .reg .arch_pc == ins .address :
168- print (f"PC ==> 0x{ fmt [0 ]:x} \t { fmt [1 ]} { fmt [2 ]} " )
169- else :
170- print (f"\t 0x{ fmt [0 ]:x} \t { fmt [1 ]} { fmt [2 ]} " )
213+ def print_asm (ql : Qiling , ins : CsInsn ) -> None :
214+ fmt = (ins .address , ins .mnemonic .ljust (6 ), ins .op_str )
215+ if ql .reg .arch_pc == ins .address :
216+ print (f"PC ==> 0x{ fmt [0 ]:x} \t { fmt [1 ]} { fmt [2 ]} " )
217+ else :
218+ print (f"\t 0x{ fmt [0 ]:x} \t { fmt [1 ]} { fmt [2 ]} " )
171219
172220
173- def context_asm (ql , address , size , * args , ** kwargs ) :
221+ def context_asm (ql : Qiling , address : int ) -> None :
174222
175223 with context_printer (ql , field_name = "[Code]" ):
176- md = ql .create_disassembler ()
177224
178225 # assembly before current location
179226
180- pre_tmp = _try_read (ql , address - 0x10 , 0x10 )
181- if pre_tmp :
182- pre_ins = md .disasm (pre_tmp , address - 0x10 )
183- print_asm (ql , pre_ins )
227+ past_list = []
228+
229+ if ql .archtype in (QL_ARCH .MIPS , QL_ARCH .ARM , QL_ARCH .ARM_THUMB ):
230+
231+ line = disasm (ql , address - 0x10 )
232+
233+ while line :
234+ if line .address == address :
235+ break
236+
237+ addr = line .address + line .size
238+ line = disasm (ql , addr )
239+
240+ if not line :
241+ break
242+
243+ past_list .append (line )
244+
245+ # print four insns before current location
246+ for line in past_list [:- 1 ][:4 ]:
247+ print_asm (ql , line )
184248
185- # assembly for current locaton
249+ # assembly for current location
186250
187- tmp = ql .mem .read (address , size )
188- cur_ins = md .disasm (tmp , address )
251+ cur_ins = disasm (ql , address )
189252 print_asm (ql , cur_ins )
190253
191- # assembly after current locaton
254+ # assembly after current location
192255
193- pos_tmp = _try_read (ql , address + 4 , 0x10 )
194- if pos_tmp :
195- pos_ins = md .disasm (pos_tmp , address + 4 )
196- print_asm (ql , pos_ins )
256+ forward_insn_size = cur_ins .size
257+ for _ in range (5 ):
258+ forward_insn = disasm (ql , address + forward_insn_size )
259+ if forward_insn :
260+ print_asm (ql , forward_insn )
261+ forward_insn_size += forward_insn .size
0 commit comments