|
| 1 | +#!/usr/bin/python3 |
| 2 | + |
| 3 | +from capstone import * |
| 4 | +from termcolor import colored |
| 5 | +from elftools.elf.elffile import ELFFile |
| 6 | +import subprocess |
| 7 | +import os |
| 8 | + |
| 9 | +binary = "binary" |
| 10 | +location = "0x000000" |
| 11 | +functions = {} |
| 12 | +CODE = b"\x55\x48\x8b\x05\xb8\x13\x00\x00" |
| 13 | +file = "" |
| 14 | +jumps = {} |
| 15 | +jmp_instructions = ["je", "jb", "jl", "jge", "jle", "jmp", "jne", "jbe"] |
| 16 | +md = Cs(CS_ARCH_X86, CS_MODE_64) |
| 17 | + |
| 18 | +instructions = [] |
| 19 | + |
| 20 | +def main(): |
| 21 | + print("Reading file: " + binary) |
| 22 | + |
| 23 | + with open(binary, "rb") as f: |
| 24 | + elffile = ELFFile(f) |
| 25 | + code = elffile.get_section_by_name(".text") |
| 26 | + opcodes = code.data() |
| 27 | + |
| 28 | + read_instructions(code['sh_addr'], opcodes) |
| 29 | + |
| 30 | + print("Auto analyzing file...") |
| 31 | + analyze() |
| 32 | + |
| 33 | + while True: |
| 34 | + print("[" + location + "]> ", end = '', flush = True) |
| 35 | + command = input().split(" ") |
| 36 | + |
| 37 | + if command[0] == "a": |
| 38 | + analyze() |
| 39 | + elif command[0] == "d": |
| 40 | + dissasemble2(code['sh_addr'], opcodes) |
| 41 | + elif command[0] == "functions": |
| 42 | + print_functions() |
| 43 | + elif command[0] == "head": |
| 44 | + header() |
| 45 | + elif command[0] == "clear": |
| 46 | + os.system("clear") |
| 47 | + |
| 48 | + elif command[0] == "p": |
| 49 | + print("p: print ?") |
| 50 | + print("pd: print disassembly") |
| 51 | + print("pds: print disassembly summary") |
| 52 | + print("pdf: print disassembly function") |
| 53 | + print("pdfs: print disassembly function summary") |
| 54 | + elif command[0] == "pd": |
| 55 | + print_disassembly() |
| 56 | + elif command[0] == "pds": |
| 57 | + print_disassembly_summary() |
| 58 | + elif command[0] == "pdf": |
| 59 | + print_disassembly_function() |
| 60 | + elif command[0] == "pdfs": |
| 61 | + print_disassembly_function_summary() |
| 62 | + |
| 63 | + elif command[0] == "i": |
| 64 | + print("i: info ?") |
| 65 | + print("is: info sections") |
| 66 | + print("if: info functions") |
| 67 | + elif command[0] == "is": |
| 68 | + header() |
| 69 | + elif command[0] == "if": |
| 70 | + print_functions() |
| 71 | + |
| 72 | + |
| 73 | + elif command[0] == "s": |
| 74 | + seek(command[1]) |
| 75 | + elif command[0] == "q": |
| 76 | + exit() |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | +def line(): |
| 81 | + print("=" * 80) |
| 82 | + |
| 83 | +def print_functions(): |
| 84 | + global functions |
| 85 | + |
| 86 | + for f in functions.keys(): |
| 87 | + print(f + " " + functions[f]) |
| 88 | + |
| 89 | +def header(): |
| 90 | + with open(binary, "rb") as f: |
| 91 | + elffile = ELFFile(f) |
| 92 | + #result = result.stdout.decode('utf-8') |
| 93 | + for section in elffile.iter_sections(): |
| 94 | + print(section.name) |
| 95 | + |
| 96 | +def read_instructions(addr, opcodes): |
| 97 | + global instructions |
| 98 | + |
| 99 | + for i in md.disasm(opcodes, addr): |
| 100 | + i = Ins("0x%x" % i.address, i.mnemonic, i.op_str) |
| 101 | + instructions.append(i) |
| 102 | + |
| 103 | +def seek(loc): |
| 104 | + global location |
| 105 | + global functions |
| 106 | + |
| 107 | + for f in functions: |
| 108 | + if functions[f] == loc: |
| 109 | + location = f |
| 110 | + |
| 111 | +def print_instruction(i): |
| 112 | + if i.instruction == "ret": |
| 113 | + print(colored(i, "red")) |
| 114 | + elif i.instruction in jmp_instructions: |
| 115 | + print(colored(i, "green")) |
| 116 | + elif i.instruction == "call": |
| 117 | + print(colored(i, "yellow")) |
| 118 | + else: print(i) |
| 119 | + |
| 120 | +def print_disassembly(): |
| 121 | + global program |
| 122 | + |
| 123 | + for i in instructions: |
| 124 | + print_instruction(i) |
| 125 | + |
| 126 | +def print_disassembly_summary(): |
| 127 | + global program |
| 128 | + |
| 129 | + for i in instructions: |
| 130 | + if i.instruction == "call": |
| 131 | + print_instruction(i) |
| 132 | + |
| 133 | +def print_disassembly_function(): |
| 134 | + global program |
| 135 | + found_start = False |
| 136 | + |
| 137 | + for i in instructions: |
| 138 | + if i.address == location: |
| 139 | + found_start = True |
| 140 | + if found_start == True: |
| 141 | + print_instruction(i) |
| 142 | + if i.instruction == "ret": |
| 143 | + return |
| 144 | + |
| 145 | +def print_disassembly_function_summary(): |
| 146 | + global program |
| 147 | + found_start = False |
| 148 | + |
| 149 | + for i in instructions: |
| 150 | + if i.address == location: |
| 151 | + found_start = True |
| 152 | + if found_start == True: |
| 153 | + if i.instruction == "call": |
| 154 | + print_instruction(i) |
| 155 | + if i.instruction == "ret": |
| 156 | + return |
| 157 | + |
| 158 | +def analyze(): |
| 159 | + global instructions |
| 160 | + global functions |
| 161 | + |
| 162 | + global location |
| 163 | + location = "0x4008d6" |
| 164 | + |
| 165 | + temp_references = {} |
| 166 | + reference_count = 0 |
| 167 | + |
| 168 | + function_str = str(subprocess.run(["nm", "--demangle", binary], stdout=subprocess.PIPE)).split("\\n") |
| 169 | + for f in function_str: |
| 170 | + if " T " in f: |
| 171 | + func = f.split(" ") |
| 172 | + func[0] = "0x" + func[0].lstrip("0") |
| 173 | + functions[func[0]] = func[2] |
| 174 | + #print(func[0] + " " + func[2]) |
| 175 | + print("Found " + str(len(functions)) + " functions") |
| 176 | + |
| 177 | + for i in instructions: |
| 178 | + if i.instruction in jmp_instructions: |
| 179 | + reference_count = reference_count + 1 |
| 180 | + |
| 181 | + temp_references[i.opcode] = i.address |
| 182 | + |
| 183 | + print("Found " + str(reference_count) + " references") |
| 184 | + |
| 185 | + for i in instructions: |
| 186 | + if i.address in temp_references.keys(): |
| 187 | + i.add_reference(temp_references[i.address]) |
| 188 | + if i.address in functions.keys(): |
| 189 | + i.is_function = True |
| 190 | + i.function_name = functions[i.address] |
| 191 | + |
| 192 | + |
| 193 | + |
| 194 | + |
| 195 | +class Ins: |
| 196 | + def __init__(self, address, instruction, opcode): |
| 197 | + self.address = address |
| 198 | + self.instruction = instruction |
| 199 | + self.opcode = opcode |
| 200 | + self.references = [] |
| 201 | + self.is_function = False |
| 202 | + self.function_name = "" |
| 203 | + |
| 204 | + def __str__(self): |
| 205 | + ret_str = "" |
| 206 | + ref_str = "" |
| 207 | + |
| 208 | + if self.is_function: |
| 209 | + ret_str += "\n" + self.function_name + ":\n" |
| 210 | + |
| 211 | + if len(self.references) > 0: |
| 212 | + ref_str = "# Referenced from: " |
| 213 | + |
| 214 | + for r in self.references: |
| 215 | + ref_str = ref_str + r |
| 216 | + |
| 217 | + ret_str += "\t" + self.address + "\t" + self.instruction + "\t" + self.opcode + "\t" + ref_str |
| 218 | + return ret_str |
| 219 | + |
| 220 | + def add_reference(self, reference): |
| 221 | + self.references.append(reference) |
| 222 | + |
| 223 | +main() |
0 commit comments