From cf5e821780bd737b59ab15938dd498283e394507 Mon Sep 17 00:00:00 2001 From: Fulvio di Girolamo Date: Sun, 14 Jun 2020 15:39:53 +0200 Subject: [PATCH 01/17] added linux_slobinfo plugin --- volatility/plugins/linux/slob_info.py | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 volatility/plugins/linux/slob_info.py diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py new file mode 100644 index 000000000..37d82ba99 --- /dev/null +++ b/volatility/plugins/linux/slob_info.py @@ -0,0 +1,45 @@ +import volatility.obj as obj +import volatility.debug as debug +import volatility.plugins.linux.common as linux_common + +class linux_slobinfo(linux_common.AbstractLinuxCommand): + def calculate(self): + linux_common.set_plugin_members(self) + + free_slob_small = self.addr_space.profile.get_symbol("free_slob_small") + free_slob_medium = self.addr_space.profile.get_symbol("free_slob_medium") + free_slob_large = self.addr_space.profile.get_symbol("free_slob_large") + slob_small = obj.Object("list_head", offset = free_slob_small, vm = self.addr_space) + slob_medium = obj.Object("list_head", offset = free_slob_medium, vm = self.addr_space) + slob_large = obj.Object("list_head", offset = free_slob_large, vm = self.addr_space) + slobs = [slob for slob in slob_small.list_of_type("page", "slab_list")] + print 'slob 0 s_mem ' + hex(slobs[0].s_mem) + print 'slob 1 s_mem ' + hex(slobs[1].s_mem) + print 'slob 2 s_mem ' + hex(slobs[2].s_mem) + print 'slob 3 s_mem ' + hex(slobs[3].s_mem) + print 'slob 1 addr ' + hex(slobs[0].slab_list.next) + print 'slob 2 addr ' + hex(slobs[1].slab_list.next) + print 'slob 1 units ' + hex(slobs[1].units) + print 'slob 0 units ' + hex(slobs[0].units) + print 'slob 2 units ' + hex(slobs[2].units) + print 'slob 0 freelist ' + hex(slobs[0].freelist) + print 'slob 1 freelist ' + hex(slobs[1].freelist) + print 'slob 2 freelist ' + hex(slobs[2].freelist) + size = obj.Object('short', offset = slobs[0].freelist, vm = self.addr_space) + print size + off = obj.Object('short', offset = slobs[0].freelist + 2, vm = self.addr_space) + print off + size = obj.Object('short', offset = (slobs[0].freelist & 0xfffffffffffff000) + off*2, vm = self.addr_space) + print size + off = obj.Object('short', offset = (slobs[0].freelist & 0xfffffffffffff000) + off*2 + 2, vm = self.addr_space) + print off + size = obj.Object('short', offset = (slobs[0].freelist & 0xfffffffffffff000) + off*2, vm = self.addr_space) + print size + print len(slobs) + yield(1) + + def render_text(self, outfd, data): + self.table_header(outfd, [("", "<30")]) + + for info in data: + self.table_row(outfd, info) From 9c8e23bb38db0e1cb350241192c1d8cf2cf89bb0 Mon Sep 17 00:00:00 2001 From: Fulvio di Girolamo Date: Sun, 14 Jun 2020 17:09:42 +0200 Subject: [PATCH 02/17] Updated linux_slobinfo --- volatility/plugins/linux/slob_info.py | 61 ++++++++++++++++----------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index 37d82ba99..53a049333 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -3,39 +3,52 @@ import volatility.plugins.linux.common as linux_common class linux_slobinfo(linux_common.AbstractLinuxCommand): + """Information about the status of the SLOB allocator""" + + def __init__(self, config, *args, **kwargs): + linux_common.AbstractLinuxCommand.__init__(self, config, *args, **kwargs) + config.add_option('PAGE_SIZE', short_option = 'p', default = 0x1000, + help = 'The page size of the analyzed system', + action = 'store', type = 'int') + def calculate(self): linux_common.set_plugin_members(self) + # Set the size of a slob unit in bytes depending on the page size + page_size = self._config.PAGE_SIZE + if page_size <= 32767 * 2: + slob_unit_size = 2 + else: + slob_unit_size = 4 + + # Find offsets of the 3 list_head objects for the SLOB page lists free_slob_small = self.addr_space.profile.get_symbol("free_slob_small") free_slob_medium = self.addr_space.profile.get_symbol("free_slob_medium") free_slob_large = self.addr_space.profile.get_symbol("free_slob_large") + + # Create the list_head objects slob_small = obj.Object("list_head", offset = free_slob_small, vm = self.addr_space) slob_medium = obj.Object("list_head", offset = free_slob_medium, vm = self.addr_space) slob_large = obj.Object("list_head", offset = free_slob_large, vm = self.addr_space) - slobs = [slob for slob in slob_small.list_of_type("page", "slab_list")] - print 'slob 0 s_mem ' + hex(slobs[0].s_mem) - print 'slob 1 s_mem ' + hex(slobs[1].s_mem) - print 'slob 2 s_mem ' + hex(slobs[2].s_mem) - print 'slob 3 s_mem ' + hex(slobs[3].s_mem) - print 'slob 1 addr ' + hex(slobs[0].slab_list.next) - print 'slob 2 addr ' + hex(slobs[1].slab_list.next) - print 'slob 1 units ' + hex(slobs[1].units) - print 'slob 0 units ' + hex(slobs[0].units) - print 'slob 2 units ' + hex(slobs[2].units) - print 'slob 0 freelist ' + hex(slobs[0].freelist) - print 'slob 1 freelist ' + hex(slobs[1].freelist) - print 'slob 2 freelist ' + hex(slobs[2].freelist) - size = obj.Object('short', offset = slobs[0].freelist, vm = self.addr_space) - print size - off = obj.Object('short', offset = slobs[0].freelist + 2, vm = self.addr_space) - print off - size = obj.Object('short', offset = (slobs[0].freelist & 0xfffffffffffff000) + off*2, vm = self.addr_space) - print size - off = obj.Object('short', offset = (slobs[0].freelist & 0xfffffffffffff000) + off*2 + 2, vm = self.addr_space) - print off - size = obj.Object('short', offset = (slobs[0].freelist & 0xfffffffffffff000) + off*2, vm = self.addr_space) - print size - print len(slobs) + + # Gather the pages on the free_slob_small list + small_pages = [slob for slob in slob_small.list_of_type("page", "slab_list")] + + # First free object size/offset + for page in small_pages: + free_block_addr = page.freelist + computed_size = 0 + while free_block_addr != 0x0 and computed_size < page.units: + size_or_off = obj.Object('short', offset = free_block_addr, vm = self.addr_space) + if size_or_off > 0: + size = size_or_off + off = obj.Object('short', offset = free_block_addr + slob_unit_size, vm = self.addr_space) + else: + size = 1 + off = -size_or_off + computed_size += size + free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + print len(small_pages) yield(1) def render_text(self, outfd, data): From fee952891956b1c39742948e743cf71de96209a8 Mon Sep 17 00:00:00 2001 From: Fulvio di Girolamo Date: Sun, 14 Jun 2020 17:58:48 +0200 Subject: [PATCH 03/17] Updated linux_slobinfo --- volatility/plugins/linux/slob_info.py | 69 ++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index 53a049333..72ea3de38 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -31,10 +31,13 @@ def calculate(self): slob_medium = obj.Object("list_head", offset = free_slob_medium, vm = self.addr_space) slob_large = obj.Object("list_head", offset = free_slob_large, vm = self.addr_space) - # Gather the pages on the free_slob_small list + # Gather the pages on the lists small_pages = [slob for slob in slob_small.list_of_type("page", "slab_list")] + medium_pages = [slob for slob in slob_medium.list_of_type("page", "slab_list")] + large_pages = [slob for slob in slob_large.list_of_type("page", "slab_list")] - # First free object size/offset + # Enumerate the content of free_slob_small + range_counters = [0] * 4 for page in small_pages: free_block_addr = page.freelist computed_size = 0 @@ -48,11 +51,65 @@ def calculate(self): off = -size_or_off computed_size += size free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 - print len(small_pages) - yield(1) + if size >= 256/slob_unit_size: + continue + range_counters[size/(64/slob_unit_size)] += 1 + yield("free_slob_small", "0-63", range_counters[0]) + yield("free_slob_small", "64-127", range_counters[1]) + yield("free_slob_small", "128-191", range_counters[2]) + yield("free_slob_small", "192-255", range_counters[3]) + + # Enumerate the content of free_slob_medium + range_counters = [0] * 4 + for page in medium_pages: + free_block_addr = page.freelist + computed_size = 0 + while free_block_addr != 0x0 and computed_size < page.units: + size_or_off = obj.Object('short', offset = free_block_addr, vm = self.addr_space) + if size_or_off > 0: + size = size_or_off + off = obj.Object('short', offset = free_block_addr + slob_unit_size, vm = self.addr_space) + else: + size = 1 + off = -size_or_off + computed_size += size + free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + if size >= 1024/slob_unit_size: + continue + range_counters[size/(256/slob_unit_size)] += 1 + yield("free_slob_medium", "0-255", range_counters[0]) + yield("free_slob_medium", "256-511", range_counters[1]) + yield("free_slob_medium", "512-767", range_counters[2]) + yield("free_slob_medium", "768-1023", range_counters[3]) + + # Enumerate the content of free_slob_large + range_counters = [0] * 4 + for page in large_pages: + free_block_addr = page.freelist + computed_size = 0 + while free_block_addr != 0x0 and computed_size < page.units: + size_or_off = obj.Object('short', offset = free_block_addr, vm = self.addr_space) + if size_or_off > 0: + size = size_or_off + off = obj.Object('short', offset = free_block_addr + slob_unit_size, vm = self.addr_space) + else: + size = 1 + off = -size_or_off + computed_size += size + free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + range_counters[size/(1024/slob_unit_size)] += 1 + yield("free_slob_large", "0-1023", range_counters[0]) + yield("free_slob_large", "1024-2047", range_counters[1]) + yield("free_slob_large", "2048-3071", range_counters[2]) + yield("free_slob_large", "3072-4095", range_counters[3]) + + def render_text(self, outfd, data): - self.table_header(outfd, [("", "<30")]) + self.table_header(outfd, [("", "<20"), + ("", "<10"), + ("<# free>", "<10") + ]) for info in data: - self.table_row(outfd, info) + self.table_row(outfd, info[0], info[1], info[2]) From e73b6e72676541f0ceafb9c5270758aaefd2d68a Mon Sep 17 00:00:00 2001 From: Ang Date: Mon, 15 Jun 2020 10:56:35 +0200 Subject: [PATCH 04/17] Update slob_info.py --- volatility/plugins/linux/slob_info.py | 52 +++++++++++++++++++-------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index 72ea3de38..faf9d7ed4 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -7,7 +7,7 @@ class linux_slobinfo(linux_common.AbstractLinuxCommand): def __init__(self, config, *args, **kwargs): linux_common.AbstractLinuxCommand.__init__(self, config, *args, **kwargs) - config.add_option('PAGE_SIZE', short_option = 'p', default = 0x1000, + self._config.add_option('PAGE_SIZE', short_option = 'p', default = 0x1000, help = 'The page size of the analyzed system', action = 'store', type = 'int') @@ -21,7 +21,7 @@ def calculate(self): else: slob_unit_size = 4 - # Find offsets of the 3 list_head objects for the SLOB page lists + # Find offsets of the 3 list_head objects for the SLOB page lists free_slob_small = self.addr_space.profile.get_symbol("free_slob_small") free_slob_medium = self.addr_space.profile.get_symbol("free_slob_medium") free_slob_large = self.addr_space.profile.get_symbol("free_slob_large") @@ -38,6 +38,8 @@ def calculate(self): # Enumerate the content of free_slob_small range_counters = [0] * 4 + free_space = 0 + space_counter = 0 for page in small_pages: free_block_addr = page.freelist computed_size = 0 @@ -51,16 +53,23 @@ def calculate(self): off = -size_or_off computed_size += size free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 - if size >= 256/slob_unit_size: + if size >= 256/slob_unit_size: continue + free_space += size*slob_unit_size + space_counter += 1 range_counters[size/(64/slob_unit_size)] += 1 yield("free_slob_small", "0-63", range_counters[0]) yield("free_slob_small", "64-127", range_counters[1]) yield("free_slob_small", "128-191", range_counters[2]) yield("free_slob_small", "192-255", range_counters[3]) - + print "------------ slob small stats -----------------" + print "free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(small_pages)) + print "-------------------- --------------- ----------" + # Enumerate the content of free_slob_medium range_counters = [0] * 4 + free_space = 0 + space_counter = 0 for page in medium_pages: free_block_addr = page.freelist computed_size = 0 @@ -76,15 +85,23 @@ def calculate(self): free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 if size >= 1024/slob_unit_size: continue + free_space += size*slob_unit_size + space_counter += 1 range_counters[size/(256/slob_unit_size)] += 1 yield("free_slob_medium", "0-255", range_counters[0]) yield("free_slob_medium", "256-511", range_counters[1]) yield("free_slob_medium", "512-767", range_counters[2]) yield("free_slob_medium", "768-1023", range_counters[3]) + print "------------ slob medium stats ----------------" + print "free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(medium_pages)) + print "-------------------- --------------- ----------" # Enumerate the content of free_slob_large - range_counters = [0] * 4 - for page in large_pages: + range_counters = [0] * 5 + free_space = 0 + space_counter = 0 + base = self._config.PAGE_SIZE / 4 + for page in large_pages: free_block_addr = page.freelist computed_size = 0 while free_block_addr != 0x0 and computed_size < page.units: @@ -95,15 +112,22 @@ def calculate(self): else: size = 1 off = -size_or_off - computed_size += size + computed_size += size free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 - range_counters[size/(1024/slob_unit_size)] += 1 - yield("free_slob_large", "0-1023", range_counters[0]) - yield("free_slob_large", "1024-2047", range_counters[1]) - yield("free_slob_large", "2048-3071", range_counters[2]) - yield("free_slob_large", "3072-4095", range_counters[3]) - - + if size >= page_size: + range_counters[4] += 1 + continue + free_space += size*slob_unit_size + space_counter += 1 + range_counters[size/(base/slob_unit_size)] += 1 + yield("free_slob_large", "0-"+str(base-1), range_counters[0]) + yield("free_slob_large", str(base)+"-"+str(base*2-1), range_counters[1]) + yield("free_slob_large", str(base*2)+"-"+str(base*3-1), range_counters[2]) + yield("free_slob_large", str(base*3)+"-"+str(base*4-1), range_counters[3]) + if(range_counters[4]>0): + print "free_slob_large "+str(range_counters[4])+" greater than a page(!?) " + print "------------ slob large stats ----------------" + print "free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(large_pages)) def render_text(self, outfd, data): self.table_header(outfd, [("", "<20"), From c608c40f47aac62802cf85f3ebc0d68e47921387 Mon Sep 17 00:00:00 2001 From: Ang Date: Wed, 24 Jun 2020 14:47:01 +0200 Subject: [PATCH 05/17] Update slob_info.py --- volatility/plugins/linux/slob_info.py | 59 ++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index faf9d7ed4..fbebf77ab 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -10,12 +10,17 @@ def __init__(self, config, *args, **kwargs): self._config.add_option('PAGE_SIZE', short_option = 'p', default = 0x1000, help = 'The page size of the analyzed system', action = 'store', type = 'int') + self._config.add_option('DUMP_FREE_LIST', short_option = 'L', default = None, + help = 'Select the free list to dump (s,m,l)', + action = 'store', type = 'str') def calculate(self): linux_common.set_plugin_members(self) # Set the size of a slob unit in bytes depending on the page size page_size = self._config.PAGE_SIZE + dump_list = self._config.DUMP_FREE_LIST + page_list = None if page_size <= 32767 * 2: slob_unit_size = 2 else: @@ -35,6 +40,36 @@ def calculate(self): small_pages = [slob for slob in slob_small.list_of_type("page", "slab_list")] medium_pages = [slob for slob in slob_medium.list_of_type("page", "slab_list")] large_pages = [slob for slob in slob_large.list_of_type("page", "slab_list")] + + if(dump_list == 's'): + page_list = small_pages + elif(dump_list == 'm'): + page_list = medium_pages + elif(dump_list == 'l'): + page_list = large_pages + if(page_list != None): + for page in page_list: + free_block_addr = page.freelist + computed_size = 0 + while free_block_addr != 0x0 and computed_size < page.units: + size_or_off = obj.Object('short', offset = free_block_addr, vm = self.addr_space) + if size_or_off > 0: + size = size_or_off + off = obj.Object('short', offset = free_block_addr + slob_unit_size, vm = self.addr_space) + # print(off) + + for i in range(size * slob_unit_size / 4): + o = obj.Object('int', offset = free_block_addr + slob_unit_size + i * 4, vm = self.addr_space) + # print(self.addr_space) + # print(size) + # print(free_block_addr + slob_unit_size + i) + print(o) + else: + size = 1 + off = -size_or_off + computed_size += size + free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + # Enumerate the content of free_slob_small range_counters = [0] * 4 @@ -62,10 +97,10 @@ def calculate(self): yield("free_slob_small", "64-127", range_counters[1]) yield("free_slob_small", "128-191", range_counters[2]) yield("free_slob_small", "192-255", range_counters[3]) - print "------------ slob small stats -----------------" - print "free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(small_pages)) - print "-------------------- --------------- ----------" - + print("------------ slob small stats -----------------") + print("free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(small_pages))) + print("-------------------- --------------- ----------") + # Enumerate the content of free_slob_medium range_counters = [0] * 4 free_space = 0 @@ -92,16 +127,16 @@ def calculate(self): yield("free_slob_medium", "256-511", range_counters[1]) yield("free_slob_medium", "512-767", range_counters[2]) yield("free_slob_medium", "768-1023", range_counters[3]) - print "------------ slob medium stats ----------------" - print "free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(medium_pages)) - print "-------------------- --------------- ----------" + print("------------ slob medium stats ----------------") + print("free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(medium_pages))) + print("-------------------- --------------- ----------") # Enumerate the content of free_slob_large range_counters = [0] * 5 free_space = 0 space_counter = 0 base = self._config.PAGE_SIZE / 4 - for page in large_pages: + for page in large_pages: free_block_addr = page.freelist computed_size = 0 while free_block_addr != 0x0 and computed_size < page.units: @@ -112,7 +147,7 @@ def calculate(self): else: size = 1 off = -size_or_off - computed_size += size + computed_size += size free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 if size >= page_size: range_counters[4] += 1 @@ -126,8 +161,10 @@ def calculate(self): yield("free_slob_large", str(base*3)+"-"+str(base*4-1), range_counters[3]) if(range_counters[4]>0): print "free_slob_large "+str(range_counters[4])+" greater than a page(!?) " - print "------------ slob large stats ----------------" - print "free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(large_pages)) + print("------------ slob large stats ----------------") + print("free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(large_pages))) + + def render_text(self, outfd, data): self.table_header(outfd, [("", "<20"), From ac13f35ab26a86f35ab0839d7d218b18e2c9d48c Mon Sep 17 00:00:00 2001 From: Fulvio di Girolamo Date: Thu, 25 Jun 2020 00:43:07 +0200 Subject: [PATCH 06/17] updated slob_info.py --- volatility/plugins/linux/slob_info.py | 99 ++++++++++++++++++--------- 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index fbebf77ab..61328c84b 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -11,8 +11,10 @@ def __init__(self, config, *args, **kwargs): help = 'The page size of the analyzed system', action = 'store', type = 'int') self._config.add_option('DUMP_FREE_LIST', short_option = 'L', default = None, - help = 'Select the free list to dump (s,m,l)', + help = 'Select the free list to dump: (s)mall, (m)edium or (l)arge', action = 'store', type = 'str') + self._config.add_option('DUMP_FILE', short_option = 'D', default = None, + help = 'When using -L specify the name of the dump file') def calculate(self): linux_common.set_plugin_members(self) @@ -20,11 +22,15 @@ def calculate(self): # Set the size of a slob unit in bytes depending on the page size page_size = self._config.PAGE_SIZE dump_list = self._config.DUMP_FREE_LIST - page_list = None + dump_file = self._config.DUMP_FILE + #page_list = None if page_size <= 32767 * 2: slob_unit_size = 2 + size_type = "short" else: slob_unit_size = 4 + # Assuming that sizeof(int) = 4... + size_type = "int" # Find offsets of the 3 list_head objects for the SLOB page lists free_slob_small = self.addr_space.profile.get_symbol("free_slob_small") @@ -41,35 +47,38 @@ def calculate(self): medium_pages = [slob for slob in slob_medium.list_of_type("page", "slab_list")] large_pages = [slob for slob in slob_large.list_of_type("page", "slab_list")] - if(dump_list == 's'): - page_list = small_pages - elif(dump_list == 'm'): - page_list = medium_pages - elif(dump_list == 'l'): - page_list = large_pages - if(page_list != None): - for page in page_list: - free_block_addr = page.freelist - computed_size = 0 - while free_block_addr != 0x0 and computed_size < page.units: - size_or_off = obj.Object('short', offset = free_block_addr, vm = self.addr_space) - if size_or_off > 0: - size = size_or_off - off = obj.Object('short', offset = free_block_addr + slob_unit_size, vm = self.addr_space) + #if(dump_list == 's'): + # page_list = small_pages + #elif(dump_list == 'm'): + # page_list = medium_pages + #elif(dump_list == 'l'): + # page_list = large_pages + #if(page_list != None): + # for page in page_list: + # free_block_addr = page.freelist + # computed_size = 0 + # while free_block_addr != 0x0 and computed_size < page.units: + # size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) + # if size_or_off > 0: + # size = size_or_off + # off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) # print(off) - - for i in range(size * slob_unit_size / 4): - o = obj.Object('int', offset = free_block_addr + slob_unit_size + i * 4, vm = self.addr_space) + # block = self.addr_space.read(free_block_addr, size * slob_unit_size) + #for i in range(size * slob_unit_size / 4): + # o = obj.Object('int', offset = free_block_addr + slob_unit_size + i * 4, vm = self.addr_space) # print(self.addr_space) # print(size) # print(free_block_addr + slob_unit_size + i) - print(o) - else: - size = 1 - off = -size_or_off - computed_size += size - free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 - + #print(block) + # else: + # size = 1 + # off = -size_or_off + # computed_size += size + # free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + + if dump_list != None: + if dump_file != None: + dump = open(dump_file, "wb") # Enumerate the content of free_slob_small range_counters = [0] * 4 @@ -79,10 +88,17 @@ def calculate(self): free_block_addr = page.freelist computed_size = 0 while free_block_addr != 0x0 and computed_size < page.units: - size_or_off = obj.Object('short', offset = free_block_addr, vm = self.addr_space) + size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) if size_or_off > 0: size = size_or_off - off = obj.Object('short', offset = free_block_addr + slob_unit_size, vm = self.addr_space) + off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) + if dump_list == "s" and dump_file != None: + block = self.addr_space.read(free_block_addr, size * slob_unit_size) + header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' + header = header.encode('ascii') + dump.write(header) + dump.write(block) + dump.write(b'\n') else: size = 1 off = -size_or_off @@ -109,10 +125,17 @@ def calculate(self): free_block_addr = page.freelist computed_size = 0 while free_block_addr != 0x0 and computed_size < page.units: - size_or_off = obj.Object('short', offset = free_block_addr, vm = self.addr_space) + size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) if size_or_off > 0: size = size_or_off - off = obj.Object('short', offset = free_block_addr + slob_unit_size, vm = self.addr_space) + off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) + if dump_list == "m" and dump_file != None: + block = self.addr_space.read(free_block_addr, size * slob_unit_size) + header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' + header = header.encode('ascii') + dump.write(header) + dump.write(block) + dump.write(b'\n') else: size = 1 off = -size_or_off @@ -140,10 +163,17 @@ def calculate(self): free_block_addr = page.freelist computed_size = 0 while free_block_addr != 0x0 and computed_size < page.units: - size_or_off = obj.Object('short', offset = free_block_addr, vm = self.addr_space) + size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) if size_or_off > 0: size = size_or_off - off = obj.Object('short', offset = free_block_addr + slob_unit_size, vm = self.addr_space) + off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) + if dump_list == 'l' and dump_file != None: + block = self.addr_space.read(free_block_addr, size * slob_unit_size) + header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' + header = header.encode('ascii') + dump.write(header) + dump.write(block) + dump.write(b'\n') else: size = 1 off = -size_or_off @@ -164,6 +194,9 @@ def calculate(self): print("------------ slob large stats ----------------") print("free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(large_pages))) + if dump_file != None: + dump.close() + def render_text(self, outfd, data): From c17816d063d5145a372c13eade031275befaa8a5 Mon Sep 17 00:00:00 2001 From: Fulvio di Girolamo Date: Thu, 25 Jun 2020 23:00:27 +0200 Subject: [PATCH 07/17] slob_info.py: can now dump free objects to file --- volatility/plugins/linux/slob_info.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index 61328c84b..b48277562 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -11,7 +11,7 @@ def __init__(self, config, *args, **kwargs): help = 'The page size of the analyzed system', action = 'store', type = 'int') self._config.add_option('DUMP_FREE_LIST', short_option = 'L', default = None, - help = 'Select the free list to dump: (s)mall, (m)edium or (l)arge', + help = 'Select the free list to dump: (s)mall, (m)edium, (l)arge or (a)ll', action = 'store', type = 'str') self._config.add_option('DUMP_FILE', short_option = 'D', default = None, help = 'When using -L specify the name of the dump file') @@ -19,6 +19,9 @@ def __init__(self, config, *args, **kwargs): def calculate(self): linux_common.set_plugin_members(self) + SLOB_BREAK1 = 256 + SLOB_BREAK2 = 1024 + # Set the size of a slob unit in bytes depending on the page size page_size = self._config.PAGE_SIZE dump_list = self._config.DUMP_FREE_LIST @@ -92,7 +95,7 @@ def calculate(self): if size_or_off > 0: size = size_or_off off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) - if dump_list == "s" and dump_file != None: + if (dump_list == "s" or dump_list == "a") and dump_file != None and size * slob_unit_size < SLOB_BREAK1: block = self.addr_space.read(free_block_addr, size * slob_unit_size) header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' header = header.encode('ascii') @@ -129,7 +132,7 @@ def calculate(self): if size_or_off > 0: size = size_or_off off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) - if dump_list == "m" and dump_file != None: + if (dump_list == "m" or dump_list == "a") and dump_file != None and size * slob_unit_size >= SLOB_BREAK1 and size * slob_unit_size < SLOB_BREAK2: block = self.addr_space.read(free_block_addr, size * slob_unit_size) header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' header = header.encode('ascii') @@ -167,7 +170,7 @@ def calculate(self): if size_or_off > 0: size = size_or_off off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) - if dump_list == 'l' and dump_file != None: + if (dump_list == "l" or dump_list == "a") and dump_file != None and size * slob_unit_size >= SLOB_BREAK2: block = self.addr_space.read(free_block_addr, size * slob_unit_size) header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' header = header.encode('ascii') From 59603bfdea21f78c0bf97fa8f0b8aba999e85171 Mon Sep 17 00:00:00 2001 From: Ang Date: Sun, 28 Jun 2020 00:50:26 +0200 Subject: [PATCH 08/17] adding SLUBinfo --- volatility/plugins/linux/slab_info.py | 113 +++++++++++++++++++------- 1 file changed, 82 insertions(+), 31 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 7ea9ab210..23abf47c4 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -114,6 +114,27 @@ def __iter__(self): for i in range(self.num): yield self._get_object(slab.s_mem.v() + i * self.buffer_size) +class kmem_cache_slub(kmem_cache): + def get_type(self): + return "slub" + + def get_size(self): + return int(self.size) + + def get_nodes(self): + print("getting nodes") + nodes = obj.Array("kmem_cache_node", offset=self.node, vm = self.obj_vm, parent=self.obj_parent) + return nodes + + def _get_partial_list(self): + nodes = self.get_nodes() + print("getting partials") + for node in nodes: + slabs = obj.Object("list_head", offset= node.partial, vm = self.obj_vm) + listm = "next" + ret = [slab for slab in slabs.list_of_type("page", listm)] + + class LinuxKmemCacheOverlay(obj.ProfileModification): conditions = {'os': lambda x: x == 'linux'} before = ['BasicObjectClasses'] # , 'LinuxVTypes'] @@ -122,6 +143,8 @@ def modification(self, profile): if profile.get_symbol("cache_chain"): profile.object_classes.update({'kmem_cache': kmem_cache_slab}) + elif profile.get_symbol("slab_caches"): + profile.object_classes.update({'kmem_cache': kmem_cache_slub}) class linux_slabinfo(linux_common.AbstractLinuxCommand): """Mimics /proc/slabinfo on a running machine""" @@ -136,8 +159,11 @@ def get_all_kmem_caches(self): listm = "next" ret = [cache for cache in caches.list_of_type("kmem_cache", listm)] elif slab_caches: #slub - debug.info("SLUB is currently unsupported.") - ret = [] + # debug.info("SLUB is currently unsupported.") + caches = obj.Object("list_head", offset = slab_caches, vm = self.addr_space) + listm = "list" + print("testing") + ret = [cache for cache in caches.list_of_type("kmem_cache", listm)] else: debug.error("Unknown or unimplemented slab type.") @@ -150,7 +176,7 @@ def get_kmem_cache(self, cache_name, unalloc, struct_name = ""): for cache in self.get_all_kmem_caches(): if cache.get_name() == cache_name: - cache.newattr("unalloc", unalloc) + cache.newattr("unalloc", unalloc) cache.newattr("struct_type", struct_name) return cache @@ -161,34 +187,59 @@ def calculate(self): linux_common.set_plugin_members(self) for cache in self.get_all_kmem_caches(): - if cache.get_type() == "slab": - active_objs = 0 - active_slabs = 0 - num_slabs = 0 - # shared_avail = 0 - - for slab in cache._get_full_list(): - active_objs += cache.num - active_slabs += 1 - - for slab in cache._get_partial_list(): - active_objs += slab.inuse - active_slabs += 1 - - for slab in cache._get_free_list(): - num_slabs += 1 - - num_slabs += active_slabs - num_objs = num_slabs * cache.num - - yield [cache.get_name(), - active_objs, - num_objs, - cache.buffer_size, - cache.num, - 1 << cache.gfporder, - active_slabs, - num_slabs] + if cache.get_type() == "slab": + active_objs = 0 + active_slabs = 0 + num_slabs = 0 + # shared_avail = 0 + + for slab in cache._get_full_list(): + active_objs += cache.num + active_slabs += 1 + + for slab in cache._get_partial_list(): + active_objs += slab.inuse + active_slabs += 1 + + for slab in cache._get_free_list(): + num_slabs += 1 + + num_slabs += active_slabs + num_objs = num_slabs * cache.num + + yield [cache.get_name(), + active_objs, + num_objs, + cache.buffer_size, + cache.num, + 1 << cache.gfporder, + active_slabs, + num_slabs] + + elif cache.get_type() == "slub": + active_objs = 0 + active_slabs = 0 + num_slabs = 0 + num_objs = 0 + objperslabs = 0 + + for slab in cache._get_partial_list(): + active_objs += slab.objects + active_slabs += 1 + + # for slab in cache._get_free_list(): + # num_slabs += 1 + + yield [cache.get_name(), + active_objs, + num_objs, + cache.size, + cache.objsize, + objperslabs, + active_slabs, + num_slabs] + + def render_text(self, outfd, data): self.table_header(outfd, [("", "<30"), From 2d4b01c66c82479105710d4611e74dd96ab68387 Mon Sep 17 00:00:00 2001 From: Ang Date: Sun, 28 Jun 2020 13:02:24 +0200 Subject: [PATCH 09/17] 2/8 --- volatility/plugins/linux/slab_info.py | 48 +++++++++++++++++++-------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 23abf47c4..2bdd4c6ec 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -115,24 +115,40 @@ def __iter__(self): yield self._get_object(slab.s_mem.v() + i * self.buffer_size) class kmem_cache_slub(kmem_cache): + MAX_SLABS = 500 + MAX_ALIASES = 500 + MAX_NODES = 1024 def get_type(self): return "slub" def get_size(self): - return int(self.size) + return int(self.size()) def get_nodes(self): - print("getting nodes") - nodes = obj.Array("kmem_cache_node", offset=self.node, vm = self.obj_vm, parent=self.obj_parent) + off = self.cpu_slab + inuse = self.size + print("nodes offset"+str(off)) + print("size "+str(inuse)) + nodes = obj.Array("kmem_cache_node", offset=self.node.dereference(), vm = self.obj_vm) return nodes - def _get_partial_list(self): - nodes = self.get_nodes() - print("getting partials") + def _get_partial_list(self, offset): + pNodes = obj.Object(theType = "Pointer", taregtType = "kmem_cache_node", offset = offset + self.obj_offset , vm = self.obj_vm, count = 1, name = "node") + print(type(pNodes)) + nodes = pNodes.dereference_as("kmem_cache_node", length = self.MAX_NODES) + print(type(nodes)) + for node in nodes: - slabs = obj.Object("list_head", offset= node.partial, vm = self.obj_vm) - listm = "next" - ret = [slab for slab in slabs.list_of_type("page", listm)] + print(type(node)) + + # for node in nodes: + # print("ciao") + # print(type(node)) + + + # slabs = obj.Object("int", offset = node.size, vm = self.obj_vm) + # listm = "next" + # ret = [slab for slab in slabs.list_of_type("page", listm)] class LinuxKmemCacheOverlay(obj.ProfileModification): @@ -221,11 +237,15 @@ def calculate(self): active_slabs = 0 num_slabs = 0 num_objs = 0 + # size = obj.Object('int', vm = cache.obj_vm, name = "size") objperslabs = 0 + node_off = self.profile.get_obj_offset("kmem_cache", "node") + # print("nodeoff "+str(node_off)) + # for slab in cache._get_partial_list(node_off): + # active_objs += slab.objects + # active_slabs += 1 - for slab in cache._get_partial_list(): - active_objs += slab.objects - active_slabs += 1 + cache._get_partial_list(node_off) # for slab in cache._get_free_list(): # num_slabs += 1 @@ -233,8 +253,8 @@ def calculate(self): yield [cache.get_name(), active_objs, num_objs, - cache.size, - cache.objsize, + cache.m("size"), + "ciao", objperslabs, active_slabs, num_slabs] From 3f4fef27c4720041ab2d03ab4cc6e61357be91ba Mon Sep 17 00:00:00 2001 From: Fulvio di Girolamo Date: Sun, 28 Jun 2020 19:06:37 +0200 Subject: [PATCH 10/17] testing on slub --- volatility/plugins/linux/slab_info.py | 46 +++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 2bdd4c6ec..7d705d141 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -239,13 +239,53 @@ def calculate(self): num_objs = 0 # size = obj.Object('int', vm = cache.obj_vm, name = "size") objperslabs = 0 - node_off = self.profile.get_obj_offset("kmem_cache", "node") + pagesperslab = 0 + node = cache.m('node') + #print node.d() + cache_node = obj.Object('kmem_cache_node', offset = node[0], vm = self.addr_space) + #print cache_node.nr_partial + #print hex(cache_node.partial.next) + page = obj.Object('page', offset = cache_node.partial.next, vm = self.addr_space) + #print page.objects - page.inuse + #for i in node: + # cache_node = obj.Object('kmem_cache_node', offset = i, vm = self.addr_space) + # if cache_node.is_valid(): + # page = obj.Object('page', offset = cache_node.partial.next, vm = self.addr_space) + # print page.freelist + #print hex(page.freelist) + #while page.next > 0x1000000000000000: + # print page.freelist + #print page.members + # page = obj.Object('page', offset = page.next, vm = self.addr_space) + #print list(self.addr_space.read(0xffff88007d008e00L, 192)) + #print page.freelist + #print page.inuse + #print page.objects + #print page.counters + #if page.index == 0: + # print 0 + #else: + # print page.counters / page.index + #print page.pages + #print page.pobjects + #page2 = obj.Object('page', offset = page.next, vm = self.addr_space) + #print page2.counters + #print page2.inuse + #print page2.freelist + #print list(self.addr_space.read(0xffff88007d002900, 10)) + #print hex(page.freelist) + #print cache.m('node').d() + #for i in cache.members: + # print i + #print cache.members['node'][0] + #print cache.m("name") + #node_off = self.profile.get_obj_offset("kmem_cache", "node") # print("nodeoff "+str(node_off)) # for slab in cache._get_partial_list(node_off): # active_objs += slab.objects # active_slabs += 1 - cache._get_partial_list(node_off) + #cache._get_partial_list(node_off) # for slab in cache._get_free_list(): # num_slabs += 1 @@ -254,8 +294,8 @@ def calculate(self): active_objs, num_objs, cache.m("size"), - "ciao", objperslabs, + pagesperslab, active_slabs, num_slabs] From c81e3b74c6bb79bfea54cd158652b2c5017a6bab Mon Sep 17 00:00:00 2001 From: Fulvio di Girolamo Date: Sun, 28 Jun 2020 19:13:49 +0200 Subject: [PATCH 11/17] testing on slub --- volatility/plugins/linux/slab_info.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 7d705d141..135fb1c92 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -246,6 +246,7 @@ def calculate(self): #print cache_node.nr_partial #print hex(cache_node.partial.next) page = obj.Object('page', offset = cache_node.partial.next, vm = self.addr_space) + print page.inuse #print page.objects - page.inuse #for i in node: # cache_node = obj.Object('kmem_cache_node', offset = i, vm = self.addr_space) @@ -268,7 +269,8 @@ def calculate(self): # print page.counters / page.index #print page.pages #print page.pobjects - #page2 = obj.Object('page', offset = page.next, vm = self.addr_space) + page2 = obj.Object('page', offset = page.next, vm = self.addr_space) + print page2.inuse #print page2.counters #print page2.inuse #print page2.freelist From 63ba95c0e5db6ffd3952b7918610602ab8b4d3b6 Mon Sep 17 00:00:00 2001 From: Ang Date: Mon, 29 Jun 2020 12:33:24 +0200 Subject: [PATCH 12/17] almost done --- volatility/plugins/linux/slab_info.py | 104 +++++++------------------- 1 file changed, 29 insertions(+), 75 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 135fb1c92..ff1413e52 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -24,9 +24,15 @@ """ import volatility.obj as obj +from volatility.obj import Pointer import volatility.debug as debug import volatility.plugins.linux.common as linux_common +MAX_SLABS = 500 +MAX_ALIASES = 500 +MAX_NODES = 1024 +PAGE_SIZE = 4096 + class kmem_cache(obj.CType): def get_type(self): raise NotImplementedError @@ -115,9 +121,7 @@ def __iter__(self): yield self._get_object(slab.s_mem.v() + i * self.buffer_size) class kmem_cache_slub(kmem_cache): - MAX_SLABS = 500 - MAX_ALIASES = 500 - MAX_NODES = 1024 + def get_type(self): return "slub" @@ -132,24 +136,6 @@ def get_nodes(self): nodes = obj.Array("kmem_cache_node", offset=self.node.dereference(), vm = self.obj_vm) return nodes - def _get_partial_list(self, offset): - pNodes = obj.Object(theType = "Pointer", taregtType = "kmem_cache_node", offset = offset + self.obj_offset , vm = self.obj_vm, count = 1, name = "node") - print(type(pNodes)) - nodes = pNodes.dereference_as("kmem_cache_node", length = self.MAX_NODES) - print(type(nodes)) - - for node in nodes: - print(type(node)) - - # for node in nodes: - # print("ciao") - # print(type(node)) - - - # slabs = obj.Object("int", offset = node.size, vm = self.obj_vm) - # listm = "next" - # ret = [slab for slab in slabs.list_of_type("page", listm)] - class LinuxKmemCacheOverlay(obj.ProfileModification): conditions = {'os': lambda x: x == 'linux'} @@ -175,10 +161,8 @@ def get_all_kmem_caches(self): listm = "next" ret = [cache for cache in caches.list_of_type("kmem_cache", listm)] elif slab_caches: #slub - # debug.info("SLUB is currently unsupported.") caches = obj.Object("list_head", offset = slab_caches, vm = self.addr_space) listm = "list" - print("testing") ret = [cache for cache in caches.list_of_type("kmem_cache", listm)] else: debug.error("Unknown or unimplemented slab type.") @@ -237,65 +221,35 @@ def calculate(self): active_slabs = 0 num_slabs = 0 num_objs = 0 - # size = obj.Object('int', vm = cache.obj_vm, name = "size") objperslabs = 0 pagesperslab = 0 + object_size = 0 + metadata = 0 node = cache.m('node') - #print node.d() - cache_node = obj.Object('kmem_cache_node', offset = node[0], vm = self.addr_space) - #print cache_node.nr_partial - #print hex(cache_node.partial.next) - page = obj.Object('page', offset = cache_node.partial.next, vm = self.addr_space) - print page.inuse - #print page.objects - page.inuse - #for i in node: - # cache_node = obj.Object('kmem_cache_node', offset = i, vm = self.addr_space) - # if cache_node.is_valid(): - # page = obj.Object('page', offset = cache_node.partial.next, vm = self.addr_space) - # print page.freelist - #print hex(page.freelist) - #while page.next > 0x1000000000000000: - # print page.freelist - #print page.members - # page = obj.Object('page', offset = page.next, vm = self.addr_space) - #print list(self.addr_space.read(0xffff88007d008e00L, 192)) - #print page.freelist - #print page.inuse - #print page.objects - #print page.counters - #if page.index == 0: - # print 0 - #else: - # print page.counters / page.index - #print page.pages - #print page.pobjects - page2 = obj.Object('page', offset = page.next, vm = self.addr_space) - print page2.inuse - #print page2.counters - #print page2.inuse - #print page2.freelist - #print list(self.addr_space.read(0xffff88007d002900, 10)) - #print hex(page.freelist) - #print cache.m('node').d() - #for i in cache.members: - # print i - #print cache.members['node'][0] - #print cache.m("name") - #node_off = self.profile.get_obj_offset("kmem_cache", "node") - # print("nodeoff "+str(node_off)) - # for slab in cache._get_partial_list(node_off): - # active_objs += slab.objects - # active_slabs += 1 - - #cache._get_partial_list(node_off) - - # for slab in cache._get_free_list(): - # num_slabs += 1 + object_size = cache.m("size") + cache_node = obj.Object('kmem_cache_node', offset = node[0], vm = self.addr_space) + page = obj.Object('page', offset = cache_node.partial.m("next"), vm = self.addr_space) + # if page.freelist > 0x100000000000000: + # ptr = page.freelist.dereference_as("Pointer") + # print(ptr) + # else: + # print (page.freelist) + # print (page.counters) + active_objs = page.counters + active_slabs = cache_node.nr_slabs.counter + num_slabs = cache_node.nr_slabs.counter + num_objs = cache_node.total_objects.counter + if num_slabs != 0: + pagesperslab = int(num_objs * object_size / num_slabs / PAGE_SIZE) + if (num_objs * object_size)%(num_slabs * PAGE_SIZE) != 0: + pagesperslab += 1 + objperslabs = int(PAGE_SIZE * pagesperslab / object_size) + yield [cache.get_name(), active_objs, num_objs, - cache.m("size"), + object_size, objperslabs, pagesperslab, active_slabs, From 19423d4a7596325a9d45fa63e6af4f9a2920c44e Mon Sep 17 00:00:00 2001 From: Ang Date: Tue, 30 Jun 2020 08:39:08 +0200 Subject: [PATCH 13/17] slobinfo added --- volatility/plugins/linux/slab_info.py | 238 ++++++++++++++++++++++++-- volatility/plugins/linux/slob_info.py | 26 ++- 2 files changed, 244 insertions(+), 20 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index ff1413e52..92e594a17 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -17,19 +17,16 @@ # """ -@author: Joe Sylve +@author: SLAB: Joe Sylve; SLUB and SLOB: Fulvio Di Girolamo, Angelo Russi @license: GNU General Public License 2.0 @contact: joe.sylve@gmail.com @organization: Digital Forensics Solutions """ import volatility.obj as obj -from volatility.obj import Pointer import volatility.debug as debug import volatility.plugins.linux.common as linux_common -MAX_SLABS = 500 -MAX_ALIASES = 500 MAX_NODES = 1024 PAGE_SIZE = 4096 @@ -151,6 +148,17 @@ def modification(self, profile): class linux_slabinfo(linux_common.AbstractLinuxCommand): """Mimics /proc/slabinfo on a running machine""" + def __init__(self, config, *args, **kwargs): + linux_common.AbstractLinuxCommand.__init__(self, config, *args, **kwargs) + self._config.add_option('PAGE_SIZE', short_option = 'p', default = 0x1000, + help = 'The page size of the analyzed system', + action = 'store', type = 'int') + self._config.add_option('DUMP_FREE_LIST', short_option = 'L', default = None, + help = 'Select the free list to dump: (s)mall, (m)edium, (l)arge or (a)ll', + action = 'store', type = 'str') + self._config.add_option('DUMP_FILE', short_option = 'D', default = None, + help = 'When using -L specify the name of the dump file') + def get_all_kmem_caches(self): linux_common.set_plugin_members(self) cache_chain = self.addr_space.profile.get_symbol("cache_chain") @@ -164,8 +172,12 @@ def get_all_kmem_caches(self): caches = obj.Object("list_head", offset = slab_caches, vm = self.addr_space) listm = "list" ret = [cache for cache in caches.list_of_type("kmem_cache", listm)] - else: - debug.error("Unknown or unimplemented slab type.") + else: # slob + # debug.error("Unknown or unimplemented slab type.") + free_slob_small = self.addr_space.profile.get_symbol("free_slob_small") + free_slob_medium = self.addr_space.profile.get_symbol("free_slob_medium") + free_slob_large = self.addr_space.profile.get_symbol("free_slob_large") + ret [free_slob_small, free_slob_medium, free_slob_large] return ret @@ -236,9 +248,9 @@ def calculate(self): # print (page.freelist) # print (page.counters) active_objs = page.counters + num_objs = cache_node.total_objects.counter active_slabs = cache_node.nr_slabs.counter num_slabs = cache_node.nr_slabs.counter - num_objs = cache_node.total_objects.counter if num_slabs != 0: pagesperslab = int(num_objs * object_size / num_slabs / PAGE_SIZE) if (num_objs * object_size)%(num_slabs * PAGE_SIZE) != 0: @@ -254,19 +266,207 @@ def calculate(self): pagesperslab, active_slabs, num_slabs] + + else: # slob + SLOB_BREAK1 = 256 + SLOB_BREAK2 = 1024 + + # Set the size of a slob unit in bytes depending on the page size + page_size = self._config.PAGE_SIZE + dump_list = self._config.DUMP_FREE_LIST + dump_file = self._config.DUMP_FILE + #page_list = None + if page_size <= 32767 * 2: + slob_unit_size = 2 + size_type = "short" + else: + slob_unit_size = 4 + # Assuming that sizeof(int) = 4... + size_type = "int" + + # Create the list_head objects + slob_small = obj.Object("list_head", offset = free_slob_small, vm = self.addr_space) + slob_medium = obj.Object("list_head", offset = free_slob_medium, vm = self.addr_space) + slob_large = obj.Object("list_head", offset = free_slob_large, vm = self.addr_space) + + # Gather the pages on the lists + small_pages = [slob for slob in slob_small.list_of_type("page", "slab_list")] + medium_pages = [slob for slob in slob_medium.list_of_type("page", "slab_list")] + large_pages = [slob for slob in slob_large.list_of_type("page", "slab_list")] + + #if(dump_list == 's'): + # page_list = small_pages + #elif(dump_list == 'm'): + # page_list = medium_pages + #elif(dump_list == 'l'): + # page_list = large_pages + #if(page_list != None): + # for page in page_list: + # free_block_addr = page.freelist + # computed_size = 0 + # while free_block_addr != 0x0 and computed_size < page.units: + # size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) + # if size_or_off > 0: + # size = size_or_off + # off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) + # print(off) + # block = self.addr_space.read(free_block_addr, size * slob_unit_size) + #for i in range(size * slob_unit_size / 4): + # o = obj.Object('int', offset = free_block_addr + slob_unit_size + i * 4, vm = self.addr_space) + # print(self.addr_space) + # print(size) + # print(free_block_addr + slob_unit_size + i) + #print(block) + # else: + # size = 1 + # off = -size_or_off + # computed_size += size + # free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + + if dump_list != None: + if dump_file != None: + dump = open(dump_file, "wb") + + # Enumerate the content of free_slob_small + range_counters = [0] * 4 + free_space = 0 + space_counter = 0 + for page in small_pages: + free_block_addr = page.freelist + computed_size = 0 + while free_block_addr != 0x0 and computed_size < page.units: + size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) + if size_or_off > 0: + size = size_or_off + off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) + if (dump_list == "s" or dump_list == "a") and dump_file != None and size * slob_unit_size < SLOB_BREAK1: + block = self.addr_space.read(free_block_addr, size * slob_unit_size) + header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' + header = header.encode('ascii') + dump.write(header) + dump.write(block) + dump.write(b'\n') + else: + size = 1 + off = -size_or_off + computed_size += size + free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + if size >= 256/slob_unit_size: + continue + free_space += size*slob_unit_size + space_counter += 1 + range_counters[size/(64/slob_unit_size)] += 1 + yield("free_slob_small", "0-63", range_counters[0]) + yield("free_slob_small", "64-127", range_counters[1]) + yield("free_slob_small", "128-191", range_counters[2]) + yield("free_slob_small", "192-255", range_counters[3]) + print("------------ slob small stats -----------------") + print("free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(small_pages))) + print("-------------------- --------------- ----------") + + # Enumerate the content of free_slob_medium + range_counters = [0] * 4 + free_space = 0 + space_counter = 0 + for page in medium_pages: + free_block_addr = page.freelist + computed_size = 0 + while free_block_addr != 0x0 and computed_size < page.units: + size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) + if size_or_off > 0: + size = size_or_off + off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) + if (dump_list == "m" or dump_list == "a") and dump_file != None and size * slob_unit_size >= SLOB_BREAK1 and size * slob_unit_size < SLOB_BREAK2: + block = self.addr_space.read(free_block_addr, size * slob_unit_size) + header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' + header = header.encode('ascii') + dump.write(header) + dump.write(block) + dump.write(b'\n') + else: + size = 1 + off = -size_or_off + computed_size += size + free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + if size >= 1024/slob_unit_size: + continue + free_space += size*slob_unit_size + space_counter += 1 + range_counters[size/(256/slob_unit_size)] += 1 + yield("free_slob_medium", "0-255", range_counters[0]) + yield("free_slob_medium", "256-511", range_counters[1]) + yield("free_slob_medium", "512-767", range_counters[2]) + yield("free_slob_medium", "768-1023", range_counters[3]) + print("------------ slob medium stats ----------------") + print("free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(medium_pages))) + print("-------------------- --------------- ----------") + + # Enumerate the content of free_slob_large + range_counters = [0] * 5 + free_space = 0 + space_counter = 0 + base = self._config.PAGE_SIZE / 4 + for page in large_pages: + free_block_addr = page.freelist + computed_size = 0 + while free_block_addr != 0x0 and computed_size < page.units: + size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) + if size_or_off > 0: + size = size_or_off + off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) + if (dump_list == "l" or dump_list == "a") and dump_file != None and size * slob_unit_size >= SLOB_BREAK2: + block = self.addr_space.read(free_block_addr, size * slob_unit_size) + header = 'Address: ' + hex(free_block_addr) + ', Size: ' + str(size * slob_unit_size) + '\n' + header = header.encode('ascii') + dump.write(header) + dump.write(block) + dump.write(b'\n') + else: + size = 1 + off = -size_or_off + computed_size += size + free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 + if size >= page_size: + range_counters[4] += 1 + continue + free_space += size*slob_unit_size + space_counter += 1 + range_counters[size/(base/slob_unit_size)] += 1 + yield("free_slob_large", "0-"+str(base-1), range_counters[0]) + yield("free_slob_large", str(base)+"-"+str(base*2-1), range_counters[1]) + yield("free_slob_large", str(base*2)+"-"+str(base*3-1), range_counters[2]) + yield("free_slob_large", str(base*3)+"-"+str(base*4-1), range_counters[3]) + if(range_counters[4]>0): + print "free_slob_large "+str(range_counters[4])+" greater than a page(!?) " + print("------------ slob large stats ----------------") + print("free space "+str(free_space)+" | free_mean_size "+str(free_space/space_counter)+" | PAGES "+str(len(large_pages))) + + if dump_file != None: + dump.close() def render_text(self, outfd, data): - self.table_header(outfd, [("", "<30"), - ("", "<13"), - ("", "<10"), - ("", "<10"), - ("", "<12"), - ("", "<15"), - ("", "<14"), - ("", "<7"), - ]) - - for info in data: - self.table_row(outfd, info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7]) + cache_chain = self.addr_space.profile.get_symbol("cache_chain") + slab_caches = self.addr_space.profile.get_symbol("slab_caches") + if cache_chain or slab_caches: + self.table_header(outfd, [("", "<30"), + ("", "<13"), + ("", "<10"), + ("", "<10"), + ("", "<12"), + ("", "<15"), + ("", "<14"), + ("", "<7"), + ]) + + for info in data: + self.table_row(outfd, info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7]) + else: #slob + self.table_header(outfd, [("", "<20"), + ("", "<10"), + ("<# free>", "<10") + ]) + + for info in data: + self.table_row(outfd, info[0], info[1], info[2]) diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index b48277562..b418430f6 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -1,3 +1,27 @@ +# Volatility +# +# This file is part of Volatility. +# +# Volatility is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Volatility is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Volatility. If not, see . +# + +""" +@author: Fulvio Di Girolamo - Angelo Russi +@license: GNU General Public License 2.0 + +""" + import volatility.obj as obj import volatility.debug as debug import volatility.plugins.linux.common as linux_common @@ -107,7 +131,7 @@ def calculate(self): off = -size_or_off computed_size += size free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 - if size >= 256/slob_unit_size: + if size >= 256/slob_unit_size: continue free_space += size*slob_unit_size space_counter += 1 From 576a53a054052c35620f4391b390714ab5c80b9e Mon Sep 17 00:00:00 2001 From: Ang Date: Tue, 30 Jun 2020 20:31:08 +0200 Subject: [PATCH 14/17] fixes --- volatility/plugins/linux/slab_info.py | 53 ++++++++++++++------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 92e594a17..28491096e 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -133,6 +133,10 @@ def get_nodes(self): nodes = obj.Array("kmem_cache_node", offset=self.node.dereference(), vm = self.obj_vm) return nodes +class kmem_cache_slob(): + + def get_type(self): + return "slob" class LinuxKmemCacheOverlay(obj.ProfileModification): conditions = {'os': lambda x: x == 'linux'} @@ -153,32 +157,30 @@ def __init__(self, config, *args, **kwargs): self._config.add_option('PAGE_SIZE', short_option = 'p', default = 0x1000, help = 'The page size of the analyzed system', action = 'store', type = 'int') - self._config.add_option('DUMP_FREE_LIST', short_option = 'L', default = None, - help = 'Select the free list to dump: (s)mall, (m)edium, (l)arge or (a)ll', + self._config.add_option('DUMP_FREE_LIST', short_option = 'L', default = None, + help = 'Select the free list to dump: (s)mall, (m)edium, (l)arge or (a)ll', action = 'store', type = 'str') - self._config.add_option('DUMP_FILE', short_option = 'D', default = None, - help = 'When using -L specify the name of the dump file') + self._config.add_option('DUMP_FILE', short_option = 'D', default = None, + help = 'When using -L specify the name of the dump file') def get_all_kmem_caches(self): linux_common.set_plugin_members(self) cache_chain = self.addr_space.profile.get_symbol("cache_chain") slab_caches = self.addr_space.profile.get_symbol("slab_caches") + slob_list = self.addr_space.profile.get_symbol("free_slob_small") if cache_chain: #slab caches = obj.Object("list_head", offset = cache_chain, vm = self.addr_space) listm = "next" ret = [cache for cache in caches.list_of_type("kmem_cache", listm)] - elif slab_caches: #slub + elif slob_list : #slob + obj = kmem_cache_slob() + ret = [obj] + else: # slub caches = obj.Object("list_head", offset = slab_caches, vm = self.addr_space) listm = "list" ret = [cache for cache in caches.list_of_type("kmem_cache", listm)] - else: # slob - # debug.error("Unknown or unimplemented slab type.") - free_slob_small = self.addr_space.profile.get_symbol("free_slob_small") - free_slob_medium = self.addr_space.profile.get_symbol("free_slob_medium") - free_slob_large = self.addr_space.profile.get_symbol("free_slob_large") - ret [free_slob_small, free_slob_medium, free_slob_large] - + return ret def get_kmem_cache(self, cache_name, unalloc, struct_name = ""): @@ -241,22 +243,18 @@ def calculate(self): object_size = cache.m("size") cache_node = obj.Object('kmem_cache_node', offset = node[0], vm = self.addr_space) page = obj.Object('page', offset = cache_node.partial.m("next"), vm = self.addr_space) - # if page.freelist > 0x100000000000000: - # ptr = page.freelist.dereference_as("Pointer") - # print(ptr) - # else: - # print (page.freelist) - # print (page.counters) - active_objs = page.counters + ptr = page.freelist.dereference_as("Pointer") + if ptr.is_valid() == False: + active_objs = "?" + else: + active_objs = page.counters num_objs = cache_node.total_objects.counter active_slabs = cache_node.nr_slabs.counter num_slabs = cache_node.nr_slabs.counter - if num_slabs != 0: - pagesperslab = int(num_objs * object_size / num_slabs / PAGE_SIZE) - if (num_objs * object_size)%(num_slabs * PAGE_SIZE) != 0: - pagesperslab += 1 - objperslabs = int(PAGE_SIZE * pagesperslab / object_size) + order = cache.oo.x >> 16 + pagesperslab = 2**order + objperslab = cache.oo.x ^ ((cache.oo.x >>16) << 16) yield [cache.get_name(), active_objs, @@ -268,6 +266,10 @@ def calculate(self): num_slabs] else: # slob + + free_slob_small = self.addr_space.profile.get_symbol("free_slob_small") + free_slob_medium = self.addr_space.profile.get_symbol("free_slob_medium") + free_slob_large = self.addr_space.profile.get_symbol("free_slob_large") SLOB_BREAK1 = 256 SLOB_BREAK2 = 1024 @@ -447,9 +449,10 @@ def calculate(self): def render_text(self, outfd, data): + linux_common.set_plugin_members(self) cache_chain = self.addr_space.profile.get_symbol("cache_chain") slab_caches = self.addr_space.profile.get_symbol("slab_caches") - if cache_chain or slab_caches: + if (cache_chain or slab_caches) and not self.addr_space.profile.get_symbol("free_slob_small"): self.table_header(outfd, [("", "<30"), ("", "<13"), ("", "<10"), From f6eb52e3eafc29d3085cd8fc063b994ca8f1ee5f Mon Sep 17 00:00:00 2001 From: Ang Date: Wed, 1 Jul 2020 01:24:23 +0200 Subject: [PATCH 15/17] Update slab_info.py --- volatility/plugins/linux/slab_info.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 28491096e..5bf71e938 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -174,8 +174,8 @@ def get_all_kmem_caches(self): listm = "next" ret = [cache for cache in caches.list_of_type("kmem_cache", listm)] elif slob_list : #slob - obj = kmem_cache_slob() - ret = [obj] + slob = kmem_cache_slob() + ret = [slob] else: # slub caches = obj.Object("list_head", offset = slab_caches, vm = self.addr_space) listm = "list" @@ -260,7 +260,7 @@ def calculate(self): active_objs, num_objs, object_size, - objperslabs, + objperslab, pagesperslab, active_slabs, num_slabs] From f62c2cea9927e3e4408a28b963199cde81f3f785 Mon Sep 17 00:00:00 2001 From: Ang Date: Wed, 1 Jul 2020 12:43:07 +0200 Subject: [PATCH 16/17] slob fixes --- volatility/plugins/linux/slab_info.py | 8 -------- volatility/plugins/linux/slob_info.py | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 5bf71e938..8a34b17d4 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -124,14 +124,6 @@ def get_type(self): def get_size(self): return int(self.size()) - - def get_nodes(self): - off = self.cpu_slab - inuse = self.size - print("nodes offset"+str(off)) - print("size "+str(inuse)) - nodes = obj.Array("kmem_cache_node", offset=self.node.dereference(), vm = self.obj_vm) - return nodes class kmem_cache_slob(): diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index b418430f6..76ee6cb69 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -131,7 +131,7 @@ def calculate(self): off = -size_or_off computed_size += size free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 - if size >= 256/slob_unit_size: + if size >= 256/slob_unit_size: continue free_space += size*slob_unit_size space_counter += 1 From 02222aaa2f90ba0db42d2521824b751018a204ca Mon Sep 17 00:00:00 2001 From: Fulvio di Girolamo Date: Thu, 22 Jul 2021 10:25:07 +0200 Subject: [PATCH 17/17] Removed commented out code --- volatility/plugins/linux/slab_info.py | 29 --------------------------- volatility/plugins/linux/slob_info.py | 29 --------------------------- 2 files changed, 58 deletions(-) diff --git a/volatility/plugins/linux/slab_info.py b/volatility/plugins/linux/slab_info.py index 8a34b17d4..e3cc4d078 100644 --- a/volatility/plugins/linux/slab_info.py +++ b/volatility/plugins/linux/slab_info.py @@ -288,35 +288,6 @@ def calculate(self): medium_pages = [slob for slob in slob_medium.list_of_type("page", "slab_list")] large_pages = [slob for slob in slob_large.list_of_type("page", "slab_list")] - #if(dump_list == 's'): - # page_list = small_pages - #elif(dump_list == 'm'): - # page_list = medium_pages - #elif(dump_list == 'l'): - # page_list = large_pages - #if(page_list != None): - # for page in page_list: - # free_block_addr = page.freelist - # computed_size = 0 - # while free_block_addr != 0x0 and computed_size < page.units: - # size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) - # if size_or_off > 0: - # size = size_or_off - # off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) - # print(off) - # block = self.addr_space.read(free_block_addr, size * slob_unit_size) - #for i in range(size * slob_unit_size / 4): - # o = obj.Object('int', offset = free_block_addr + slob_unit_size + i * 4, vm = self.addr_space) - # print(self.addr_space) - # print(size) - # print(free_block_addr + slob_unit_size + i) - #print(block) - # else: - # size = 1 - # off = -size_or_off - # computed_size += size - # free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 - if dump_list != None: if dump_file != None: dump = open(dump_file, "wb") diff --git a/volatility/plugins/linux/slob_info.py b/volatility/plugins/linux/slob_info.py index 76ee6cb69..ac4073802 100644 --- a/volatility/plugins/linux/slob_info.py +++ b/volatility/plugins/linux/slob_info.py @@ -74,35 +74,6 @@ def calculate(self): medium_pages = [slob for slob in slob_medium.list_of_type("page", "slab_list")] large_pages = [slob for slob in slob_large.list_of_type("page", "slab_list")] - #if(dump_list == 's'): - # page_list = small_pages - #elif(dump_list == 'm'): - # page_list = medium_pages - #elif(dump_list == 'l'): - # page_list = large_pages - #if(page_list != None): - # for page in page_list: - # free_block_addr = page.freelist - # computed_size = 0 - # while free_block_addr != 0x0 and computed_size < page.units: - # size_or_off = obj.Object(size_type, offset = free_block_addr, vm = self.addr_space) - # if size_or_off > 0: - # size = size_or_off - # off = obj.Object(size_type, offset = free_block_addr + slob_unit_size, vm = self.addr_space) - # print(off) - # block = self.addr_space.read(free_block_addr, size * slob_unit_size) - #for i in range(size * slob_unit_size / 4): - # o = obj.Object('int', offset = free_block_addr + slob_unit_size + i * 4, vm = self.addr_space) - # print(self.addr_space) - # print(size) - # print(free_block_addr + slob_unit_size + i) - #print(block) - # else: - # size = 1 - # off = -size_or_off - # computed_size += size - # free_block_addr = free_block_addr - free_block_addr % page_size + off * 2 - if dump_list != None: if dump_file != None: dump = open(dump_file, "wb")