@@ -385,8 +385,12 @@ def _do_load(self, addr, size):
385385class StoreHook :
386386 @staticmethod
387387 def hook (state ):
388- state .inspect .mem_write_expr = state .solver .BVS ('instrumented_store' ,
389- state .solver .eval (state .inspect .mem_write_length ) * 8 )
388+ write_length = state .inspect .mem_write_length
389+ if write_length is None :
390+ write_length = len (state .inspect .mem_write_expr )
391+ else :
392+ write_length = write_length * state .arch .byte_width
393+ state .inspect .mem_write_expr = state .solver .BVS ('instrumented_store' , write_length )
390394
391395
392396class LoadHook :
@@ -421,6 +425,72 @@ def __init__(self, reg_offset, reg_bits, value):
421425 def hook (self , state ):
422426 state .registers .store (self .reg_offset , state .solver .BVV (self .value , self .reg_bits ))
423427
428+
429+ class BSSHook :
430+ def __init__ (self , project , bss_regions ):
431+ self .project = project
432+ self ._bss_regions = bss_regions
433+ self ._written_addrs = set ()
434+
435+ def bss_memory_read_hook (self , state ):
436+
437+ if not self ._bss_regions :
438+ return
439+
440+ read_addr = state .inspect .mem_read_address
441+ read_length = state .inspect .mem_read_length
442+
443+ if not isinstance (read_addr , int ) and read_addr .symbolic :
444+ # don't touch it
445+ return
446+
447+ concrete_read_addr = state .solver .eval (read_addr )
448+ concrete_read_length = state .solver .eval (read_length )
449+
450+ for start , size in self ._bss_regions :
451+ if start <= concrete_read_addr < start + size :
452+ # this is a read from the .bss section
453+ break
454+ else :
455+ return
456+
457+ if concrete_read_addr not in self ._written_addrs :
458+ # it was never written to before. we overwrite it with unconstrained bytes
459+ for i in range (0 , concrete_read_length , self .project .arch .bytes ):
460+ state .memory .store (concrete_read_addr + i , state .solver .Unconstrained ('unconstrained' ,
461+ self .project .arch .bits ))
462+
463+ # job done :-)
464+
465+ def bss_memory_write_hook (self , state ):
466+
467+ if not self ._bss_regions :
468+ return
469+
470+ write_addr = state .inspect .mem_write_address
471+
472+ if not isinstance (write_addr , int ) and write_addr .symbolic :
473+ return
474+
475+ concrete_write_addr = state .solver .eval (write_addr )
476+ concrete_write_length = state .solver .eval (state .inspect .mem_write_length ) \
477+ if state .inspect .mem_write_length is not None \
478+ else len (state .inspect .mem_write_expr ) // state .arch .byte_width
479+
480+ for start , size in self ._bss_regions :
481+ if start <= concrete_write_addr < start + size :
482+ # hit a BSS section
483+ break
484+ else :
485+ return
486+
487+ if concrete_write_length > 1024 :
488+ l .warning ("Writing more 1024 bytes to the BSS region, only considering the first 1024 bytes." )
489+ concrete_write_length = 1024
490+
491+ for i in range (concrete_write_addr , concrete_write_length ):
492+ self ._written_addrs .add (i )
493+
424494#
425495# Main class
426496#
@@ -578,7 +648,10 @@ def _resolve(self, cfg, addr, func_addr, b):
578648
579649 # any read from an uninitialized segment should be unconstrained
580650 if self ._bss_regions :
581- bss_memory_read_bp = BP (when = BP_BEFORE , enabled = True , action = self ._bss_memory_read_hook )
651+ bss_hook = BSSHook (self .project , self ._bss_regions )
652+ bss_memory_write_bp = BP (when = BP_AFTER , enabled = True , action = bss_hook .bss_memory_write_hook )
653+ start_state .inspect .add_breakpoint ('mem_write' , bss_memory_write_bp )
654+ bss_memory_read_bp = BP (when = BP_BEFORE , enabled = True , action = bss_hook .bss_memory_read_hook )
582655 start_state .inspect .add_breakpoint ('mem_read' , bss_memory_read_bp )
583656
584657 # instrument specified store/put/load statements
@@ -1338,36 +1411,6 @@ def _find_bss_region(self):
13381411 self ._bss_regions .append ((section .vaddr , section .memsize ))
13391412 break
13401413
1341- def _bss_memory_read_hook (self , state ):
1342-
1343- if not self ._bss_regions :
1344- return
1345-
1346- read_addr = state .inspect .mem_read_address
1347- read_length = state .inspect .mem_read_length
1348-
1349- if not isinstance (read_addr , int ) and read_addr .symbolic :
1350- # don't touch it
1351- return
1352-
1353- concrete_read_addr = state .solver .eval (read_addr )
1354- concrete_read_length = state .solver .eval (read_length )
1355-
1356- for start , size in self ._bss_regions :
1357- if start <= concrete_read_addr < start + size :
1358- # this is a read from the .bss section
1359- break
1360- else :
1361- return
1362-
1363- if not state .memory .was_written_to (concrete_read_addr ):
1364- # it was never written to before. we overwrite it with unconstrained bytes
1365- for i in range (0 , concrete_read_length , self .project .arch .bytes ):
1366- state .memory .store (concrete_read_addr + i , state .solver .Unconstrained ('unconstrained' ,
1367- self .project .arch .bits ))
1368-
1369- # job done :-)
1370-
13711414 def _init_registers_on_demand (self , state ):
13721415 # for uninitialized read using a register as the source address, we replace them in memory on demand
13731416 read_addr = state .inspect .mem_read_address
0 commit comments