3
3
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4
4
#
5
5
6
+ import ctypes
6
7
import os , re
7
8
from typing import Any , Callable , Iterator , List , Mapping , MutableSequence , Optional , Pattern , Sequence , Tuple , Union
8
9
11
12
from qiling import Qiling
12
13
from qiling .exception import *
13
14
14
- # tuple: range start, range end, permissions mask, range label, is mmio?
15
- MapInfoEntry = Tuple [int , int , int , str , bool ]
15
+ # tuple: range start, range end, permissions mask, range label, is mmio?, bytearray
16
+ MapInfoEntry = Tuple [int , int , int , str , bool , bytearray ]
16
17
17
18
MmioReadCallback = Callable [[Qiling , int , int ], int ]
18
19
MmioWriteCallback = Callable [[Qiling , int , int , int ], None ]
@@ -80,7 +81,7 @@ def string(self, addr: int, value=None, encoding='utf-8') -> Optional[str]:
80
81
81
82
self .__write_string (addr , value , encoding )
82
83
83
- def add_mapinfo (self , mem_s : int , mem_e : int , mem_p : int , mem_info : str , is_mmio : bool = False ):
84
+ def add_mapinfo (self , mem_s : int , mem_e : int , mem_p : int , mem_info : str , is_mmio : bool = False , data : bytearray = None ):
84
85
"""Add a new memory range to map.
85
86
86
87
Args:
@@ -90,9 +91,8 @@ def add_mapinfo(self, mem_s: int, mem_e: int, mem_p: int, mem_info: str, is_mmio
90
91
mem_info: map entry label
91
92
is_mmio: memory range is mmio
92
93
"""
93
-
94
- self .map_info .append ((mem_s , mem_e , mem_p , mem_info , is_mmio ))
95
- self .map_info = sorted (self .map_info , key = lambda tp : tp [0 ])
94
+ self .map_info .append ((mem_s , mem_e , mem_p , mem_info , is_mmio , data ))
95
+ self .map_info .sort (key = lambda tp : tp [0 ])
96
96
97
97
def del_mapinfo (self , mem_s : int , mem_e : int ):
98
98
"""Subtract a memory range from map.
@@ -104,30 +104,30 @@ def del_mapinfo(self, mem_s: int, mem_e: int):
104
104
105
105
tmp_map_info : MutableSequence [MapInfoEntry ] = []
106
106
107
- for s , e , p , info , mmio in self .map_info :
107
+ for s , e , p , info , mmio , data in self .map_info :
108
108
if e <= mem_s :
109
- tmp_map_info .append ((s , e , p , info , mmio ))
109
+ tmp_map_info .append ((s , e , p , info , mmio , data ))
110
110
continue
111
111
112
112
if s >= mem_e :
113
- tmp_map_info .append ((s , e , p , info , mmio ))
113
+ tmp_map_info .append ((s , e , p , info , mmio , data ))
114
114
continue
115
115
116
116
if s < mem_s :
117
- tmp_map_info .append ((s , mem_s , p , info , mmio ))
117
+ tmp_map_info .append ((s , mem_s , p , info , mmio , data ))
118
118
119
119
if s == mem_s :
120
120
pass
121
121
122
122
if e > mem_e :
123
- tmp_map_info .append ((mem_e , e , p , info , mmio ))
123
+ tmp_map_info .append ((mem_e , e , p , info , mmio , data ))
124
124
125
125
if e == mem_e :
126
126
pass
127
127
128
128
self .map_info = tmp_map_info
129
129
130
- def change_mapinfo (self , mem_s : int , mem_e : int , mem_p : Optional [int ] = None , mem_info : Optional [str ] = None ):
130
+ def change_mapinfo (self , mem_s : int , mem_e : int , mem_p : Optional [int ] = None , mem_info : Optional [str ] = None , data : Optional [ bytearray ] = None ):
131
131
tmp_map_info : Optional [MapInfoEntry ] = None
132
132
info_idx : int = None
133
133
@@ -147,7 +147,7 @@ def change_mapinfo(self, mem_s: int, mem_e: int, mem_p: Optional[int] = None, me
147
147
return
148
148
149
149
if mem_info is not None :
150
- self .map_info [info_idx ] = (tmp_map_info [0 ], tmp_map_info [1 ], tmp_map_info [2 ], mem_info , tmp_map_info [4 ])
150
+ self .map_info [info_idx ] = (tmp_map_info [0 ], tmp_map_info [1 ], tmp_map_info [2 ], mem_info , tmp_map_info [4 ], tmp_map_info [ 5 ] )
151
151
152
152
def get_mapinfo (self ) -> Sequence [Tuple [int , int , str , str , str ]]:
153
153
"""Get memory map info.
@@ -166,7 +166,7 @@ def __perms_mapping(ps: int) -> str:
166
166
167
167
return '' .join (val if idx & ps else '-' for idx , val in perms_d .items ())
168
168
169
- def __process (lbound : int , ubound : int , perms : int , label : str , is_mmio : bool ) -> Tuple [int , int , str , str , str ]:
169
+ def __process (lbound : int , ubound : int , perms : int , label : str , is_mmio : bool , _data : bytearray ) -> Tuple [int , int , str , str , str ]:
170
170
perms_str = __perms_mapping (perms )
171
171
172
172
if hasattr (self .ql , 'loader' ):
@@ -211,7 +211,7 @@ def get_lib_base(self, filename: str) -> Optional[int]:
211
211
212
212
# some info labels may be prefixed by boxed label which breaks the search by basename.
213
213
# iterate through all info labels and remove all boxed prefixes, if any
214
- stripped = ((lbound , p .sub ('' , info )) for lbound , _ , _ , info , _ in self .map_info )
214
+ stripped = ((lbound , p .sub ('' , info )) for lbound , _ , _ , info , _ , _ in self .map_info )
215
215
216
216
return next ((lbound for lbound , info in stripped if os .path .basename (info ) == filename ), None )
217
217
@@ -268,11 +268,10 @@ def save(self):
268
268
"mmio" : []
269
269
}
270
270
271
- for lbound , ubound , perm , label , is_mmio in self .map_info :
271
+ for lbound , ubound , perm , label , is_mmio , data in self .map_info :
272
272
if is_mmio :
273
273
mem_dict ['mmio' ].append ((lbound , ubound , perm , label , * self .mmio_cbs [(lbound , ubound )]))
274
274
else :
275
- data = self .read (lbound , ubound - lbound )
276
275
mem_dict ['ram' ].append ((lbound , ubound , perm , label , bytes (data )))
277
276
278
277
return mem_dict
@@ -393,7 +392,7 @@ def search(self, needle: Union[bytes, Pattern[bytes]], begin: Optional[int] = No
393
392
assert begin < end , 'search arguments do not make sense'
394
393
395
394
# narrow the search down to relevant ranges; mmio ranges are excluded due to potential read size effects
396
- ranges = [(max (begin , lbound ), min (ubound , end )) for lbound , ubound , _ , _ , is_mmio in self .map_info if not (end < lbound or ubound < begin or is_mmio )]
395
+ ranges = [(max (begin , lbound ), min (ubound , end )) for lbound , ubound , _ , _ , is_mmio , _data in self .map_info if not (end < lbound or ubound < begin or is_mmio )]
397
396
results = []
398
397
399
398
# if needle is a bytes sequence use it verbatim, not as a pattern
@@ -439,10 +438,10 @@ def __mapped_regions(self) -> Iterator[Tuple[int, int]]:
439
438
440
439
iter_memmap = iter (self .map_info )
441
440
442
- p_lbound , p_ubound , _ , _ , _ = next (iter_memmap )
441
+ p_lbound , p_ubound , _ , _ , _ , _ = next (iter_memmap )
443
442
444
443
# map_info is assumed to contain non-overlapping regions sorted by lbound
445
- for lbound , ubound , _ , _ , _ in iter_memmap :
444
+ for lbound , ubound , _ , _ , _ , _ in iter_memmap :
446
445
if lbound == p_ubound :
447
446
p_ubound = ubound
448
447
else :
@@ -514,8 +513,8 @@ def find_free_space(self, size: int, minaddr: Optional[int] = None, maxaddr: Opt
514
513
assert minaddr < maxaddr
515
514
516
515
# get gap ranges between mapped ones and memory bounds
517
- gaps_ubounds = tuple (lbound for lbound , _ , _ , _ , _ in self .map_info ) + (mem_ubound ,)
518
- gaps_lbounds = (mem_lbound ,) + tuple (ubound for _ , ubound , _ , _ , _ in self .map_info )
516
+ gaps_ubounds = tuple (lbound for lbound , _ , _ , _ , _ , _ in self .map_info ) + (mem_ubound ,)
517
+ gaps_lbounds = (mem_lbound ,) + tuple (ubound for _ , ubound , _ , _ , _ , _ in self .map_info )
519
518
gaps = zip (gaps_lbounds , gaps_ubounds )
520
519
521
520
for lbound , ubound in gaps :
@@ -582,8 +581,10 @@ def map(self, addr: int, size: int, perms: int = UC_PROT_ALL, info: Optional[str
582
581
if not self .is_available (addr , size ):
583
582
raise QlMemoryMappedError ('Requested memory is unavailable' )
584
583
585
- self .ql .uc .mem_map (addr , size , perms )
586
- self .add_mapinfo (addr , addr + size , perms , info or '[mapped]' , is_mmio = False )
584
+ buf = bytearray (size )
585
+ buf_type = ctypes .c_byte * size
586
+ self .ql .uc .mem_map_ptr (addr , size , perms , buf_type .from_buffer (buf ))
587
+ self .add_mapinfo (addr , addr + size , perms , info or '[mapped]' , is_mmio = False , data = buf )
587
588
588
589
def map_mmio (self , addr : int , size : int , read_cb : Optional [MmioReadCallback ], write_cb : Optional [MmioWriteCallback ], info : str = '[mmio]' ):
589
590
# TODO: mmio memory overlap with ram? Is that possible?
0 commit comments