From 1d903adc631e1ed73e00bdc60418fe5afd0ae499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=89=E5=B9=BF?= Date: Tue, 21 Jun 2022 20:08:06 +0800 Subject: [PATCH 1/7] feat[version]version compare use float --- heap_viewer/config.py | 13 ++++++----- heap_viewer/misc.py | 5 ++++- heap_viewer/version/__init__.py | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 heap_viewer/version/__init__.py diff --git a/heap_viewer/config.py b/heap_viewer/config.py index 205c7b6..d65a4c3 100644 --- a/heap_viewer/config.py +++ b/heap_viewer/config.py @@ -4,6 +4,7 @@ # HeapViewer - by @danigargu # +from .version import Version import sys import json import idc @@ -18,7 +19,7 @@ main_arena = None malloc_par = None global_max_fast = None -libc_version = None +libc_version: Version = None libc_base = None stop_during_tracing = None start_tracing_at_startup = None @@ -29,10 +30,11 @@ m = sys.modules[__name__] + def load(): config = None m.ptr_size = get_arch_ptrsize() - m.libc_version = get_libc_version() + m.libc_version = Version(get_libc_version() or '2.33') m.libc_base = get_libc_base() if m.ptr_size == 4: @@ -52,7 +54,8 @@ def load(): m.stop_during_tracing = config.get('stop_during_tracing', True) m.start_tracing_at_startup = config.get('start_tracing_at_startup', False) - m.detect_double_frees_and_overlaps = config.get('detect_double_frees_and_overlaps', True) + m.detect_double_frees_and_overlaps = config.get( + 'detect_double_frees_and_overlaps', True) m.filter_library_calls = config.get('filter_library_calls', False) m.hexdump_limit = config.get('hexdump_limit', 1024) m.libc_offsets = config.get('libc_offsets') @@ -70,7 +73,7 @@ def load(): if malloc_par is not None: malloc_par += m.libc_base - + m.main_arena = main_arena m.malloc_par = malloc_par @@ -92,10 +95,10 @@ def save(): config_json = dump().encode("utf-8") f.write(config_json) + """ def update_file(data): config = json.loads(data) with open(CONFIG_PATH, 'wb') as f: f.write(json.dumps(config, indent=4)) """ - diff --git a/heap_viewer/misc.py b/heap_viewer/misc.py index 74b9e45..d4bbd48 100644 --- a/heap_viewer/misc.py +++ b/heap_viewer/misc.py @@ -22,7 +22,10 @@ def log(msg): # -------------------------------------------------------------------------- def get_struct(address, struct_type): - assert idaapi.is_loaded(address) == True, "Can't access memory at 0x%x" % address + # if not idaapi.is_loaded(address): + # print(f'memory at {hex(address)} is not loaded') + # return None + # assert idaapi.is_loaded(address) == True, "Can't access memory at 0x%x" % address sbytes = idaapi.get_bytes(address, sizeof(struct_type)) struct = struct_type.from_buffer_copy(sbytes) struct._addr = address diff --git a/heap_viewer/version/__init__.py b/heap_viewer/version/__init__.py new file mode 100644 index 0000000..239c934 --- /dev/null +++ b/heap_viewer/version/__init__.py @@ -0,0 +1,40 @@ +class Version(float): + def __init__(self, ver: str = None): + self = ver if isinstance(ver, float) else float(ver) + print('self version', self) + + def __lt__(self, __x: float) -> bool: + if isinstance(__x, str): + __x = float(__x) + print('compare', self, __x) + return super().__lt__(__x) + + def __gt__(self, __x: float) -> bool: + if isinstance(__x, str): + __x = float(__x) + print('compare', self, __x) + return super().__gt__(__x) + + def __eq__(self, __x: object) -> bool: + if isinstance(__x, str): + __x = float(__x) + print('compare', self, __x) + return super().__eq__(__x) + + def __ne__(self, __x: object) -> bool: + if isinstance(__x, str): + __x = float(__x) + print('compare', self, __x) + return super().__ne__(__x) + + def __ge__(self, __x: float) -> bool: + if isinstance(__x, str): + __x = float(__x) + print('compare', self, __x) + return super().__ge__(__x) + + def __le__(self, __x: float) -> bool: + if isinstance(__x, str): + __x = float(__x) + print('compare', self, __x) + return super().__le__(__x) From 896468901870c889fd4752969697fe0b1c60b43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=89=E5=B9=BF?= Date: Tue, 21 Jun 2022 20:08:51 +0800 Subject: [PATCH 2/7] feat[libc-version]version input config --- heap_viewer/config.py | 10 ++++++++-- heap_viewer/misc.py | 5 +---- heap_viewer/widgets/config.py | 21 +++++++++++++-------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/heap_viewer/config.py b/heap_viewer/config.py index d65a4c3..15ea8fd 100644 --- a/heap_viewer/config.py +++ b/heap_viewer/config.py @@ -34,7 +34,6 @@ def load(): config = None m.ptr_size = get_arch_ptrsize() - m.libc_version = Version(get_libc_version() or '2.33') m.libc_base = get_libc_base() if m.ptr_size == 4: @@ -59,6 +58,8 @@ def load(): m.filter_library_calls = config.get('filter_library_calls', False) m.hexdump_limit = config.get('hexdump_limit', 1024) m.libc_offsets = config.get('libc_offsets') + libc_version = get_libc_version() + main_arena = None malloc_par = None @@ -67,7 +68,12 @@ def load(): main_arena = m.libc_offsets.get("main_arena") malloc_par = m.libc_offsets.get("mp_") global_max_fast = m.libc_offsets.get("global_max_fast") - + libc_version = libc_version or m.libc_offsets.get("glibc_version") + if not libc_version: + DEFAULT_LIBC_VERSION = '2.33' + libc_version = DEFAULT_LIBC_VERSION # default libc version + print(f'Warning:libc version fetch fail,you should configure in config-panel manually,default set to {DEFAULT_LIBC_VERSION}') + libc_version = Version(libc_version) if main_arena is not None: main_arena += m.libc_base diff --git a/heap_viewer/misc.py b/heap_viewer/misc.py index d4bbd48..e9529fc 100644 --- a/heap_viewer/misc.py +++ b/heap_viewer/misc.py @@ -22,10 +22,7 @@ def log(msg): # -------------------------------------------------------------------------- def get_struct(address, struct_type): - # if not idaapi.is_loaded(address): - # print(f'memory at {hex(address)} is not loaded') - # return None - # assert idaapi.is_loaded(address) == True, "Can't access memory at 0x%x" % address + assert idaapi.is_loaded(address) , f'memory at {hex(address)} is not loaded.\nthere maybe something wrong with your libc-version detect.' sbytes = idaapi.get_bytes(address, sizeof(struct_type)) struct = struct_type.from_buffer_copy(sbytes) struct._addr = address diff --git a/heap_viewer/widgets/config.py b/heap_viewer/widgets/config.py index 8877a43..8bd7a99 100644 --- a/heap_viewer/widgets/config.py +++ b/heap_viewer/widgets/config.py @@ -14,12 +14,14 @@ from heap_viewer import misc # ----------------------------------------------------------------------- + + class ConfigWidget(CustomWidget): def __init__(self, parent=None): super(ConfigWidget, self).__init__(parent) self._create_gui() - def _create_gui(self): + def _create_gui(self): self.t_config = QtWidgets.QTextEdit() self.t_config.setFixedHeight(440) @@ -29,8 +31,9 @@ def _create_gui(self): self.btn_update_config.clicked.connect(self.update_config) self.btn_dump_config.clicked.connect(self.dump_config) - hbox_update_config = QtWidgets.QHBoxLayout() - hbox_update_config.addWidget(QtWidgets.QLabel("Config file (config.json)")) + hbox_update_config = QtWidgets.QHBoxLayout() + hbox_update_config.addWidget( + QtWidgets.QLabel("Config file (config.json)")) hbox_update_config.addWidget(self.btn_update_config) hbox_update_config.addWidget(self.btn_dump_config) hbox_update_config.addStretch(1) @@ -38,7 +41,8 @@ def _create_gui(self): groupbox_tracer = QtWidgets.QGroupBox("Tracer options") self.opt1 = QtWidgets.QCheckBox("Start tracing at startup") self.opt2 = QtWidgets.QCheckBox("Stop during tracing") - self.opt3 = QtWidgets.QCheckBox("Detect double frees and chunk overlaps") + self.opt3 = QtWidgets.QCheckBox( + "Detect double frees and chunk overlaps") self.opt4 = QtWidgets.QCheckBox("Filter library calls") vbox_tracer = QtWidgets.QVBoxLayout() @@ -60,22 +64,23 @@ def _create_gui(self): form_offsets = QtWidgets.QFormLayout() form_offsets.setSpacing(5) - form_offsets.setLabelAlignment(Qt.AlignLeft|Qt.AlignVCenter) + form_offsets.setLabelAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.t_main_arena = QtWidgets.QLineEdit() self.t_malloc_par = QtWidgets.QLineEdit() self.t_global_max_fast = QtWidgets.QLineEdit() - + self.t_glibc_version = QtWidgets.QLineEdit('2.33') self.offset_widgets = { 'main_arena': self.t_main_arena, 'malloc_par': self.t_malloc_par, - 'global_max_fast': self.t_global_max_fast + 'global_max_fast': self.t_global_max_fast, + 'glibc_version': self.t_glibc_version, } form_offsets.addRow("main_arena", self.t_main_arena) form_offsets.addRow("mp_ (malloc_par)", self.t_malloc_par) form_offsets.addRow("global_max_fast", self.t_global_max_fast) - + form_offsets.addRow("glibc_version", self.glibc_version) groupbox_offsets = QtWidgets.QGroupBox("glibc offsets (optional)") groupbox_offsets.setLayout(form_offsets) From 328c40d409e667cad39082149d714568d10daa96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=89=E5=B9=BF?= Date: Tue, 21 Jun 2022 21:22:39 +0800 Subject: [PATCH 3/7] feat[pyc]ignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd20fdd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +*.pyc From d147be6cf35bcddfa1e1f3d69cc188e1aa41bf62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=89=E5=B9=BF?= Date: Tue, 21 Jun 2022 21:25:41 +0800 Subject: [PATCH 4/7] fix[config]named --- heap_viewer/widgets/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heap_viewer/widgets/config.py b/heap_viewer/widgets/config.py index 8bd7a99..c506dfd 100644 --- a/heap_viewer/widgets/config.py +++ b/heap_viewer/widgets/config.py @@ -80,7 +80,7 @@ def _create_gui(self): form_offsets.addRow("main_arena", self.t_main_arena) form_offsets.addRow("mp_ (malloc_par)", self.t_malloc_par) form_offsets.addRow("global_max_fast", self.t_global_max_fast) - form_offsets.addRow("glibc_version", self.glibc_version) + form_offsets.addRow("glibc_version", self.t_glibc_version) groupbox_offsets = QtWidgets.QGroupBox("glibc offsets (optional)") groupbox_offsets.setLayout(form_offsets) From 7e3deb27cf699a41b133e7fea7295ff268d908a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=89=E5=B9=BF?= Date: Tue, 21 Jun 2022 21:53:49 +0800 Subject: [PATCH 5/7] fix[ptmalloc]should check range-overflow --- heap_viewer/ptmalloc.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/heap_viewer/ptmalloc.py b/heap_viewer/ptmalloc.py index 4f5dea1..17bfe13 100644 --- a/heap_viewer/ptmalloc.py +++ b/heap_viewer/ptmalloc.py @@ -507,7 +507,7 @@ def parse_heap(self, address=None): if not heap_base: return results - heap_size = idc.get_segm_end(heap_base) - heap_base + heap_end = idc.get_segm_end(heap_base) ''' For prevent incorrect parsing in glibc > 2.25 (i386) @@ -521,10 +521,12 @@ def parse_heap(self, address=None): chunk = self.get_chunk(chunk_addr) real_size = chunk.norm_size - if real_size == 0 or real_size > heap_size: - status = 'Corrupt' + if real_size == 0: + status = 'attempt get 0 size chunk' + stop_parse = True + elif chunk_addr + real_size >= heap_end: + status = 'attempt get ptr overflowed chunk' stop_parse = True - elif chunk_addr == arena.top: status = 'arena->top' stop_parse = True From f98c182859cb7c61f066e2c73685add72a2d72ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=89=E5=B9=BF?= Date: Tue, 21 Jun 2022 21:58:32 +0800 Subject: [PATCH 6/7] fix[version]set with default --- heap_viewer/config.py | 37 +++++++++++++++++++-------------- heap_viewer/version/__init__.py | 7 ------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/heap_viewer/config.py b/heap_viewer/config.py index 15ea8fd..432a7dd 100644 --- a/heap_viewer/config.py +++ b/heap_viewer/config.py @@ -4,6 +4,7 @@ # HeapViewer - by @danigargu # +from typing import Dict from .version import Version import sys import json @@ -35,6 +36,26 @@ def load(): config = None m.ptr_size = get_arch_ptrsize() m.libc_base = get_libc_base() + libc_version = get_libc_version() + + try: + with open(CONFIG_PATH, 'rb') as f: + config = json.loads(f.read()) + except Exception as e: + # default config + config = {} + m.libc_offsets = config.get('libc_offsets') + + if isinstance(m.libc_offsets, Dict): + libc_version = libc_version or m.libc_offsets.get("glibc_version") + if not libc_version: + DEFAULT_LIBC_VERSION = '2.33' + libc_version = DEFAULT_LIBC_VERSION # default libc version + print( + f'Warning:libc version fetch fail,you should configure in config-panel manually,default set to {DEFAULT_LIBC_VERSION}') + libc_version = Version(libc_version) + print(f'libc version set to:{libc_versionlibc_version}') + m.libc_version = libc_version if m.ptr_size == 4: m.get_ptr = idc.get_wide_dword @@ -44,22 +65,12 @@ def load(): m.ptr_mask = (1 << 8*m.ptr_size)-1 m.program_module = get_program_module() - try: - with open(CONFIG_PATH, 'rb') as f: - config = json.loads(f.read()) - except Exception as e: - # default config - config = {} - m.stop_during_tracing = config.get('stop_during_tracing', True) m.start_tracing_at_startup = config.get('start_tracing_at_startup', False) m.detect_double_frees_and_overlaps = config.get( 'detect_double_frees_and_overlaps', True) m.filter_library_calls = config.get('filter_library_calls', False) m.hexdump_limit = config.get('hexdump_limit', 1024) - m.libc_offsets = config.get('libc_offsets') - libc_version = get_libc_version() - main_arena = None malloc_par = None @@ -68,12 +79,6 @@ def load(): main_arena = m.libc_offsets.get("main_arena") malloc_par = m.libc_offsets.get("mp_") global_max_fast = m.libc_offsets.get("global_max_fast") - libc_version = libc_version or m.libc_offsets.get("glibc_version") - if not libc_version: - DEFAULT_LIBC_VERSION = '2.33' - libc_version = DEFAULT_LIBC_VERSION # default libc version - print(f'Warning:libc version fetch fail,you should configure in config-panel manually,default set to {DEFAULT_LIBC_VERSION}') - libc_version = Version(libc_version) if main_arena is not None: main_arena += m.libc_base diff --git a/heap_viewer/version/__init__.py b/heap_viewer/version/__init__.py index 239c934..fd7bd2c 100644 --- a/heap_viewer/version/__init__.py +++ b/heap_viewer/version/__init__.py @@ -1,40 +1,33 @@ class Version(float): def __init__(self, ver: str = None): self = ver if isinstance(ver, float) else float(ver) - print('self version', self) def __lt__(self, __x: float) -> bool: if isinstance(__x, str): __x = float(__x) - print('compare', self, __x) return super().__lt__(__x) def __gt__(self, __x: float) -> bool: if isinstance(__x, str): __x = float(__x) - print('compare', self, __x) return super().__gt__(__x) def __eq__(self, __x: object) -> bool: if isinstance(__x, str): __x = float(__x) - print('compare', self, __x) return super().__eq__(__x) def __ne__(self, __x: object) -> bool: if isinstance(__x, str): __x = float(__x) - print('compare', self, __x) return super().__ne__(__x) def __ge__(self, __x: float) -> bool: if isinstance(__x, str): __x = float(__x) - print('compare', self, __x) return super().__ge__(__x) def __le__(self, __x: float) -> bool: if isinstance(__x, str): __x = float(__x) - print('compare', self, __x) return super().__le__(__x) From 1c2d1374137669d4b55e1d44428bd1e2c7e4570c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=89=E5=B9=BF?= Date: Tue, 21 Jun 2022 22:16:19 +0800 Subject: [PATCH 7/7] typo[config] --- heap_viewer/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/heap_viewer/config.py b/heap_viewer/config.py index 432a7dd..7ec3ea9 100644 --- a/heap_viewer/config.py +++ b/heap_viewer/config.py @@ -54,7 +54,7 @@ def load(): print( f'Warning:libc version fetch fail,you should configure in config-panel manually,default set to {DEFAULT_LIBC_VERSION}') libc_version = Version(libc_version) - print(f'libc version set to:{libc_versionlibc_version}') + print(f'libc version set to:{libc_version}') m.libc_version = libc_version if m.ptr_size == 4: