66import os , re
77from typing import Any , List , MutableSequence , Optional , Sequence , Tuple
88
9+ from unicorn import UC_PROT_NONE , UC_PROT_READ , UC_PROT_WRITE , UC_PROT_EXEC , UC_PROT_ALL
10+
911from qiling import Qiling
1012from qiling .const import *
1113from qiling .exception import *
1214
1315# tuple: range start, range end, permissions mask, range label
1416MapInfoEntry = Tuple [int , int , int , str ]
1517
16- from unicorn import (
17- UC_PROT_ALL ,
18- UC_PROT_EXEC ,
19- UC_PROT_NONE ,
20- UC_PROT_READ ,
21- UC_PROT_WRITE ,
22- )
23-
2418class QlMemoryManager :
2519 """
2620 some ideas and code from:
@@ -79,43 +73,56 @@ def string(self, addr: int, value=None, encoding='utf-8') -> Optional[str]:
7973 self .__write_string (addr , value , encoding )
8074
8175 def add_mapinfo (self , mem_s : int , mem_e : int , mem_p : int , mem_info : str ):
82- tmp_map_info = []
76+ """Add a new memory range to map.
77+
78+ Args:
79+ mem_s: memory range start
80+ mem_e: memory range end
81+ mem_p: permissions mask
82+ mem_info: map entry label
83+ """
84+
85+ tmp_map_info : MutableSequence [MapInfoEntry ] = []
8386 insert_flag = 0
8487 map_info = self .map_info
88+
8589 if len (map_info ) == 0 :
86- tmp_map_info .append ([ mem_s , mem_e , mem_p , mem_info ] )
90+ tmp_map_info .append (( mem_s , mem_e , mem_p , mem_info ) )
8791 else :
8892 for s , e , p , info in map_info :
8993 if e <= mem_s :
90- tmp_map_info .append ([ s , e , p , info ] )
94+ tmp_map_info .append (( s , e , p , info ) )
9195 continue
96+
9297 if s >= mem_e :
9398 if insert_flag == 0 :
9499 insert_flag = 1
95- tmp_map_info .append ([mem_s , mem_e , mem_p , mem_info ])
96- tmp_map_info .append ([s , e , p , info ])
100+ tmp_map_info .append ((mem_s , mem_e , mem_p , mem_info ))
101+
102+ tmp_map_info .append ((s , e , p , info ))
97103 continue
104+
98105 if s < mem_s :
99- tmp_map_info .append ([ s , mem_s , p , info ] )
106+ tmp_map_info .append (( s , mem_s , p , info ) )
100107
101108 if s == mem_s :
102109 pass
103110
104111 if insert_flag == 0 :
105112 insert_flag = 1
106- tmp_map_info .append ([ mem_s , mem_e , mem_p , mem_info ] )
113+ tmp_map_info .append (( mem_s , mem_e , mem_p , mem_info ) )
107114
108115 if e > mem_e :
109- tmp_map_info .append ([ mem_e , e , p , info ] )
116+ tmp_map_info .append (( mem_e , e , p , info ) )
110117
111118 if e == mem_e :
112119 pass
120+
113121 if insert_flag == 0 :
114- tmp_map_info .append ([ mem_s , mem_e , mem_p , mem_info ] )
122+ tmp_map_info .append (( mem_s , mem_e , mem_p , mem_info ) )
115123
116124 self .map_info = tmp_map_info
117125
118-
119126 def del_mapinfo (self , mem_s : int , mem_e : int ):
120127 """Subtract a memory range from map.
121128
@@ -124,7 +131,7 @@ def del_mapinfo(self, mem_s: int, mem_e: int):
124131 mem_e: memory range end
125132 """
126133
127- tmp_map_info = []
134+ tmp_map_info : MutableSequence [ MapInfoEntry ] = []
128135
129136 for s , e , p , info in self .map_info :
130137 if e <= mem_s :
@@ -187,11 +194,9 @@ def show_mapinfo(self):
187194 for lbound , ubound , perms , label , container in self .get_mapinfo ():
188195 self .ql .log .info (f'{ lbound :08x} - { ubound :08x} { perms :5s} { label :12s} { container or "" } ' )
189196
197+ # TODO: relying on the label string is risky; find a more reliable method
190198 def get_lib_base (self , filename : str ) -> int :
191- for s , e , p , info in self .map_info :
192- if os .path .split (info )[1 ] == filename :
193- return s
194- return - 1
199+ return next ((s for s , _ , _ , info in self .map_info if os .path .split (info )[1 ] == filename ), - 1 )
195200
196201 def align (self , addr : int , alignment : int = 0x1000 ) -> int :
197202 """Round up to nearest alignment.
@@ -202,17 +207,20 @@ def align(self, addr: int, alignment: int = 0x1000) -> int:
202207 """
203208
204209 # rounds up to nearest alignment
205- mask = ((1 << self .ql .archbit ) - 1 ) & - alignment
210+ mask = self .max_mem_addr & - alignment
211+
206212 return (addr + (alignment - 1 )) & mask
207213
208214 # save all mapped mem
209215 def save (self ):
210216 mem_dict = {}
211217 seq = 1
218+
212219 for start , end , perm , info in self .map_info :
213- mem_read = self .read (start , end - start )
220+ mem_read = self .read (start , end - start )
214221 mem_dict [seq ] = start , end , perm , info , mem_read
215222 seq += 1
223+
216224 return mem_dict
217225
218226 # restore all dumped memory
@@ -257,16 +265,17 @@ def read_ptr(self, addr: int, size: int=None) -> int:
257265 if not size :
258266 size = self .ql .pointersize
259267
260- if size == 1 :
261- return self .ql .unpack8 (self .read (addr , 1 ))
262- elif size == 2 :
263- return self .ql .unpack16 (self .read (addr , 2 ))
264- elif size == 4 :
265- return self .ql .unpack32 (self .read (addr , 4 ))
266- elif size == 8 :
267- return self .ql .unpack64 (self .read (addr , 8 ))
268- else :
269- raise QlErrorStructConversion (f"Unsupported pointer size: { size } " )
268+ __unpack = {
269+ 1 : self .ql .unpack8 ,
270+ 2 : self .ql .unpack16 ,
271+ 4 : self .ql .unpack32 ,
272+ 8 : self .ql .unpack64
273+ }.get (size )
274+
275+ if __unpack :
276+ return __unpack (self .read (addr , size ))
277+
278+ raise QlErrorStructConversion (f"Unsupported pointer size: { size } " )
270279
271280 def write (self , addr : int , data : bytes ) -> None :
272281 """Write bytes to a memory.
@@ -280,8 +289,8 @@ def write(self, addr: int, data: bytes) -> None:
280289 self .ql .uc .mem_write (addr , data )
281290 except :
282291 self .show_mapinfo ()
283- self .ql .log .debug (" addresss write length: " + str ( len (data )) )
284- self .ql .log .error (" addresss write error: " + hex ( addr ) )
292+ self .ql .log .debug (f' addresss write length: { len (data ):d } ' )
293+ self .ql .log .error (f' addresss write error: { addr :#x } ' )
285294 raise
286295
287296 def search (self , needle : bytes , begin : int = None , end : int = None ):
@@ -320,15 +329,13 @@ def unmap(self, addr: int, size: int) -> None:
320329 self .del_mapinfo (addr , addr + size )
321330 self .ql .uc .mem_unmap (addr , size )
322331
323-
324332 def unmap_all (self ):
325333 """Reclaim the entire memory space.
326334 """
327335
328- for region in list (self .ql .uc .mem_regions ()):
329- if region [0 ] and region [1 ]:
330- return self .unmap (region [0 ], ((region [1 ] - region [0 ])+ 0x1 ))
331-
336+ for begin , end , _ in self .ql .uc .mem_regions ():
337+ if begin and end :
338+ self .unmap (begin , end - begin + 1 )
332339
333340 def is_available (self , addr , size ):
334341 '''
@@ -525,26 +532,28 @@ def __init__(self, ql: Qiling, start_address: int, end_address: int):
525532 self .current_use = 0
526533 # save all memory regions allocated
527534 self .mem_alloc = []
528-
529- def save (self ):
530- saved_state = {}
531- saved_state ['chunks' ] = self .chunks
532- saved_state ['start_address' ] = self .start_address
533- saved_state ['end_address' ] = self .end_address
534- saved_state ['page_size' ] = self .page_size
535- saved_state ['current_alloc' ] = self .current_alloc
536- saved_state ['current_use' ] = self .current_use
537- saved_state ['mem_alloc' ] = self .mem_alloc
535+
536+ def save (self ) -> Mapping [str , Any ]:
537+ saved_state = {
538+ 'chunks' : self .chunks ,
539+ 'start_address' : self .start_address ,
540+ 'end_address' : self .end_address ,
541+ 'page_size' : self .page_size ,
542+ 'current_alloc' : self .current_alloc ,
543+ 'current_use' : self .current_use ,
544+ 'mem_alloc' : self .mem_alloc
545+ }
546+
538547 return saved_state
539548
540- def restore (self , saved_state ):
541- self .chunks = saved_state ['chunks' ]
542- self .start_address = saved_state ['start_address' ]
543- self .end_address = saved_state ['end_address' ]
544- self .page_size = saved_state ['page_size' ]
545- self .current_alloc = saved_state ['current_alloc' ]
546- self .current_use = saved_state ['current_use' ]
547- self .mem_alloc = saved_state ['mem_alloc' ]
549+ def restore (self , saved_state : Mapping [ str , Any ] ):
550+ self .chunks = saved_state ['chunks' ]
551+ self .start_address = saved_state ['start_address' ]
552+ self .end_address = saved_state ['end_address' ]
553+ self .page_size = saved_state ['page_size' ]
554+ self .current_alloc = saved_state ['current_alloc' ]
555+ self .current_use = saved_state ['current_use' ]
556+ self .mem_alloc = saved_state ['mem_alloc' ]
548557
549558 def alloc (self , size : int ):
550559 # Find the heap chunks that best matches size
0 commit comments