-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Android and iOS DBI framework for dynamic analysis of ELF and Mac…
…ho-O binaries
- Loading branch information
1 parent
3ff9892
commit 303e611
Showing
44 changed files
with
570,604 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
# Android Disassembler | ||
# (c) 2024 Torsten Klement, [email protected] | ||
# MIT | ||
|
||
import lief | ||
|
||
from capstone import Cs, CS_ARCH_ARM64, CS_MODE_ARM | ||
|
||
|
||
class AndroidDisassembler: | ||
def __init__(self, disassembly_area, function_list, function_positions): | ||
self.disassembly_area = disassembly_area | ||
self.function_list = function_list | ||
self.function_positions = function_positions | ||
self.recognized_functions = set() # Set zur Vermeidung doppelter Funktionen | ||
|
||
def process_file(self, file_path): | ||
elf = lief.parse(file_path) | ||
|
||
self.insert_text(f"Type: {elf.header.file_type.name}\n", "black") | ||
self.insert_text(f"Architecture: {elf.header.machine_type.name}\n\n", "black") | ||
|
||
self.insert_text("Libraries:\n", "black") | ||
for lib in elf.libraries: | ||
self.insert_text(f"{lib}\n", "black") | ||
|
||
self.insert_text("\nSegments:\n", "black") | ||
for segment in elf.segments: | ||
perm = f"{'r' if segment.has(lief.ELF.SEGMENT_FLAGS.R) else '-'}" + \ | ||
f"{'w' if segment.has(lief.ELF.SEGMENT_FLAGS.W) else '-'}" + \ | ||
f"{'x' if segment.has(lief.ELF.SEGMENT_FLAGS.X) else '-'}" | ||
self.insert_text( | ||
f"{perm} 0x{segment.virtual_address:08x}-0x{segment.virtual_address + segment.virtual_size:08x}\n", | ||
"black") | ||
|
||
self.insert_text("\n") | ||
|
||
for section in elf.sections: | ||
section_type = section.type.name if section.type else "UNKNOWN" | ||
self.insert_text( | ||
f"0x{section.virtual_address:08x}-0x{section.virtual_address + section.size:08x} {section.name} ({section_type}) " | ||
f"{{{'Code' if section.flags == lief.ELF.SECTION_FLAGS.EXECINSTR else 'Read-only data' if section.flags == lief.ELF.SECTION_FLAGS.ALLOC else 'Writable data'}}}\n", | ||
"black") | ||
self.insert_text( | ||
" " + " ".join(f"{byte:02x}" for byte in section.content[:64]) + "\n", | ||
"black") | ||
|
||
self.insert_text("\n\n\n") | ||
|
||
# Disassemblieren der .text Sektion | ||
text_section = elf.get_section(".text") | ||
if text_section is not None: | ||
base_address = text_section.virtual_address | ||
segment_offset = self.get_segment_base_address(elf, base_address) | ||
|
||
code = text_section.content | ||
md = Cs(CS_ARCH_ARM64, CS_MODE_ARM) | ||
md.detail = True | ||
|
||
in_function = False | ||
current_function_instructions = [] | ||
instructions = list(md.disasm(bytes(code), base_address)) | ||
|
||
for i in range(len(instructions)): | ||
insn = instructions[i] | ||
current_function_instructions.append(insn) | ||
|
||
if self.is_potential_function_start(insn): | ||
if not in_function and current_function_instructions: | ||
if current_function_instructions: | ||
return_type, args = self.analyze_function_signature(current_function_instructions) | ||
function_name = f"sub_{instructions[i - 1].address:x}" | ||
|
||
# Vermeidung doppelter Funktionen | ||
if function_name in self.recognized_functions: | ||
continue | ||
|
||
self.recognized_functions.add(function_name) | ||
|
||
start_line = self.get_current_index() | ||
self.function_positions[function_name] = start_line | ||
self.function_list.insert('end', function_name) | ||
self.insert_text( | ||
f"0x{instructions[i - 1].address:08x} {return_type} {function_name}({', '.join(args)})\n", | ||
"function_start") | ||
for instr in current_function_instructions: | ||
self.insert_text( | ||
f"0x{instr.address:08x} {' '.join(f'{b:02x}' for b in instr.bytes):<12} {instr.mnemonic:<7} {instr.op_str}\n", | ||
"asm_code") | ||
self.insert_text("\n") | ||
|
||
in_function = True | ||
current_function_instructions = [insn] | ||
elif insn.mnemonic == "ret": | ||
if in_function: | ||
return_type, args = self.analyze_function_signature(current_function_instructions) | ||
function_name = f"sub_{insn.address:x}" | ||
|
||
# Vermeidung doppelter Funktionen | ||
if function_name in self.recognized_functions: | ||
continue | ||
|
||
self.recognized_functions.add(function_name) | ||
|
||
start_line = self.get_current_index() | ||
self.function_positions[function_name] = start_line | ||
self.function_list.insert('end', function_name) | ||
self.insert_text( | ||
f"0x{insn.address:08x} {return_type} {function_name}({', '.join(args)})\n", | ||
"function_start") | ||
for instr in current_function_instructions: | ||
self.insert_text( | ||
f"0x{instr.address:08x} {' '.join(f'{b:02x}' for b in instr.bytes):<12} {instr.mnemonic:<7} {instr.op_str}\n", | ||
"asm_code") | ||
self.insert_text("\n") | ||
|
||
in_function = False | ||
current_function_instructions = [] | ||
|
||
def analyze_function_signature(self, instructions): | ||
args = [] | ||
return_type = "void" | ||
|
||
arg_registers = ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7'] | ||
register_to_type = {reg: None for reg in arg_registers} | ||
|
||
for insn in instructions: | ||
if insn.mnemonic == 'mov' and insn.op_str == 'x0': | ||
return_type = "int" | ||
elif insn.mnemonic == 'ldr' and 'x0' in insn.op_str: | ||
return_type = "pointer" | ||
|
||
for reg in arg_registers: | ||
if reg in insn.op_str: | ||
if 'ldr' in insn.mnemonic: | ||
register_to_type[reg] = "pointer" | ||
elif 'mov' in insn.mnemonic or 'add' in insn.mnemonic: | ||
register_to_type[reg] = "int32_t" | ||
elif 'str' in insn.mnemonic: | ||
register_to_type[reg] = "int32_t*" | ||
|
||
for reg in arg_registers: | ||
reg_type = register_to_type[reg] | ||
if reg_type: | ||
args.append(f"{reg_type} arg{arg_registers.index(reg) + 1}") | ||
|
||
if not args: | ||
args.append("void") | ||
|
||
return return_type, args | ||
|
||
def get_segment_base_address(self, elf, section_va): | ||
for segment in elf.segments: | ||
if segment.virtual_address <= section_va < (segment.virtual_address + segment.virtual_size): | ||
return segment.virtual_address | ||
return 0 | ||
|
||
def is_potential_function_start(self, insn): | ||
if insn.mnemonic in {'bl', 'blr', 'b', 'br', 'cbz', 'cbnz', 'tbnz', 'tbz'}: | ||
return True | ||
if insn.mnemonic == 'adrp' and ('x' in insn.op_str): | ||
return True | ||
if insn.mnemonic == 'stp' and ('x29, x30' in insn.op_str): | ||
return True | ||
return False | ||
|
||
def insert_text(self, text, tag=None): | ||
self.disassembly_area.insert('end', text, tag) | ||
|
||
def get_current_index(self): | ||
return self.disassembly_area.index('end') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import os | ||
|
||
import tkinter as tk | ||
from tkinter import filedialog, messagebox, simpledialog | ||
import tkinter.scrolledtext as scrolledtext | ||
|
||
class CodeEditor: | ||
def __init__(self, root): | ||
self.root = root | ||
self.filename = None | ||
|
||
# Erstelle das Editor-Fenster | ||
self.editor_window = tk.Toplevel(root) | ||
self.editor_window.title("Code Editor") | ||
self.editor_window.geometry("800x600") | ||
|
||
# Erstelle das Textfeld mit Scrollbalken und Tabs auf 0,5 cm | ||
self.text_area = scrolledtext.ScrolledText(self.editor_window, wrap=tk.WORD, undo=True, tabs=("0.5c")) | ||
self.text_area.pack(fill=tk.BOTH, expand=True) | ||
|
||
# Erstelle das Menü | ||
self.menu = tk.Menu(self.editor_window) | ||
self.editor_window.config(menu=self.menu) | ||
|
||
# Datei-Menü | ||
file_menu = tk.Menu(self.menu, tearoff=0) | ||
self.menu.add_cascade(label="File", menu=file_menu) | ||
file_menu.add_command(label="Open", command=self.open_file) | ||
file_menu.add_command(label="Save", command=self.save_file) | ||
file_menu.add_command(label="Save As", command=self.save_file_as) | ||
file_menu.add_separator() | ||
file_menu.add_command(label="Exit", command=self.editor_window.destroy) | ||
|
||
# Bearbeiten-Menü | ||
edit_menu = tk.Menu(self.menu, tearoff=0) | ||
self.menu.add_cascade(label="Edit", menu=edit_menu) | ||
edit_menu.add_command(label="Undo", command=self.text_area.edit_undo) | ||
edit_menu.add_command(label="Redo", command=self.text_area.edit_redo) | ||
edit_menu.add_separator() | ||
edit_menu.add_command(label="Find", command=self.find_text) | ||
edit_menu.add_command(label="Replace", command=self.replace_text) | ||
|
||
def open_file(self): | ||
self.filename = filedialog.askopenfilename( | ||
defaultextension=".txt", | ||
filetypes=[("Python Files", "*.py"), ("JavaScript Files", "*.js"), ("All Files", "*.*")] | ||
) | ||
if self.filename: | ||
with open(self.filename, "r") as file: | ||
content = file.read() | ||
self.text_area.delete(1.0, tk.END) | ||
self.text_area.insert(tk.INSERT, content) | ||
self.editor_window.title(f"Code Editor - {os.path.normpath(self.filename)}") | ||
|
||
def save_file(self): | ||
if self.filename: | ||
with open(self.filename, "w") as file: | ||
file.write(self.text_area.get(1.0, tk.END)) | ||
else: | ||
self.save_file_as() | ||
|
||
def save_file_as(self): | ||
self.filename = filedialog.asksaveasfilename( | ||
defaultextension=".txt", | ||
filetypes=[("Python Files", "*.py"), ("JavaScript Files", "*.js"), ("All Files", "*.*")] | ||
) | ||
if self.filename: | ||
with open(self.filename, "w") as file: | ||
file.write(self.text_area.get(1.0, tk.END)) | ||
self.editor_window.title(f"Code Editor - {os.path.normpath(self.filename)}") | ||
|
||
def find_text(self): | ||
search_term = simpledialog.askstring("Find", "Enter text to find:") | ||
if search_term: | ||
start_pos = "1.0" | ||
while True: | ||
start_pos = self.text_area.search(search_term, start_pos, stopindex=tk.END) | ||
if not start_pos: | ||
break | ||
end_pos = f"{start_pos}+{len(search_term)}c" | ||
self.text_area.tag_add("highlight", start_pos, end_pos) | ||
self.text_area.tag_config("highlight", background="yellow", foreground="black") | ||
start_pos = end_pos | ||
|
||
def replace_text(self): | ||
search_term = simpledialog.askstring("Find", "Enter text to replace:") | ||
replace_term = simpledialog.askstring("Replace", "Enter replacement text:") | ||
if search_term and replace_term: | ||
content = self.text_area.get(1.0, tk.END) | ||
new_content = content.replace(search_term, replace_term) | ||
self.text_area.delete(1.0, tk.END) | ||
self.text_area.insert(1.0, new_content) |
Oops, something went wrong.