From 35232ec7a4aee4d17aa81a9769ba192904d28c2f Mon Sep 17 00:00:00 2001 From: Hyungseok Kim Date: Wed, 25 May 2022 23:42:04 +0900 Subject: [PATCH] Improve Jump Table Entry Algorithm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I observed that RetroWrite missed some jump table entries when they refers to the function boundary. The following assembly code that gcc-9 compiler emitted represents the error case. Since the second jump table entry refers to label .LBB38_624, which was defined at the function boundary, RetroWrite misses 6 jump table entries. I added is_located_at_the_end_of_function() method to check function boundary and define additional label to symbolize jump table entry. Also, I revised symbolize_switch_tables() method to resolve the error. ``` get_machine_flags:     # ...     leaq    .LJTI38_6(%rip), %rax     movslq  (%rax,%r15,4), %rcx     addq    %rax, %rcx     jmpq    *%rcx     # ...     jmp .LBB38_535 #end of get_machine_flags .LBB38_624:     .cfi_endproc .LJTI38_6:     .long   .LBB38_47-.LJTI38_6     .long   .LBB38_624-.LJTI38_6 # Miss     .long   .LBB38_355-.LJTI38_6 # Miss     .long   .LBB38_624-.LJTI38_6 # Miss     .long   .LBB38_360-.LJTI38_6 # Miss     .long   .LBB38_624-.LJTI38_6 # Miss     .long   .LBB38_353-.LJTI38_6 # Miss ``` --- librw_x64/container.py | 13 ++++++++++++- librw_x64/rw.py | 11 +++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/librw_x64/container.py b/librw_x64/container.py index 0523a617..70549df7 100644 --- a/librw_x64/container.py +++ b/librw_x64/container.py @@ -162,7 +162,7 @@ def __init__(self, name, start, sz, bytes, bind="STB_LOCAL"): def set_instrumented(self): self.instrumented = True - + @property def true_name(self): if self.is_mangled and not self._true_name: @@ -189,6 +189,17 @@ def is_valid_instruction(self, address): return False + def is_located_at_the_end_of_function(self, address): + assert self.cache, "Function not disassembled!" + + for instruction in self.cache: + if instruction.address + instruction.sz == address: + if ".LLC%x:"%(address) not in instruction.after: + instruction.after.append(".LLC%x:"%(address)) + return True + + return False + def instruction_of_address(self, address): assert self.cache, "Function not disassembled!" diff --git a/librw_x64/rw.py b/librw_x64/rw.py index 66273d7b..5212bbb0 100644 --- a/librw_x64/rw.py +++ b/librw_x64/rw.py @@ -627,10 +627,17 @@ def symbolize_switch_tables(self, container, context): break value = (value + swbase) & 0xFFFFFFFF - if not fn.is_valid_instruction(value): + + if fn.is_valid_instruction(value): + swlbl = ".LC%x-.LC%x" % (value, swbase) + # Switch table entry might refer to the end of function boundary + # Thus, we check whether the value refers to the end of function + elif fn.is_located_at_the_end_of_function(value): + # is_located_at_the_end_of_function() have created .LLCXXX label + swlbl = ".LLC%x-.LC%x" % (value, swbase) + else: break - swlbl = ".LC%x-.LC%x" % (value, swbase) rodata.replace(slot, 4, swlbl) def _adjust_target(self, container, target):