Skip to content

Instantly share code, notes, and snippets.

@zwade

zwade/disasm.py

Last active May 3, 2021
Embed
What would you like to do?
Tiamat Disassembler
from typing import Dict, List, Optional
from capstone import *
import sys
from capstone.ppc_const import PPC_INS_XVABSSP
sparc_little = Cs(CS_ARCH_SPARC, CS_MODE_V9 | CS_MODE_BIG_ENDIAN)
sparc_big = Cs(CS_ARCH_SPARC, CS_MODE_V9 | CS_MODE_BIG_ENDIAN)
riscv_little = Cs(CS_ARCH_RISCV, CS_MODE_RISCV32)
riscv_big = Cs(CS_ARCH_RISCV, CS_MODE_RISCV32)
arm_little = Cs(CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_LITTLE_ENDIAN)
arm_big = Cs(CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_BIG_ENDIAN)
mips_little = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_LITTLE_ENDIAN)
mips_big = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_BIG_ENDIAN)
all_arch = [
sparc_little,
sparc_big,
riscv_little,
riscv_big,
arm_little,
arm_big,
mips_little,
mips_big,
]
for arch in all_arch:
arch.detail = True
class A:
red = "\x1b[38;5;1m"
green = "\x1b[38;5;2m"
yellow = "\x1b[38;5;3m"
blue = "\x1b[38;5;4m"
gray = "\x1b[38;5;8m"
clear = "\x1b[0m"
def get_arch_by_tmap(i: int):
return all_arch[i]
def get_name_by_tmap(i: int):
return [
"sparc (little)",
"sparc (big) ",
"riscv (little)",
"riscv (big) ",
"arm (little)",
"arm (big) ",
"mips (little)",
"mips (big) ",
][i]
tmap_arch = open("./tmap_arch.bin", "rb").read()
def get_tmap(pc: int):
offset = int((pc - 0x100d0) >> 2)
return tmap_arch[offset]
def get_arch(pc: int):
return get_arch_by_tmap(get_tmap(pc))
def byteswap(i32: bytes):
a, b, c, d = i32
return bytes([d, c, b, a])
program = open("./liccheck.bin", "rb").read()[208:]
def format_program(a: int, b: bytes):
return (b * int(a / 4) + b)
def print_instruction(pc: int, instruction: Optional[CsInsn], refs_to: List[int], refs_from: List[int]):
tmap = get_tmap(pc)
ref_from_str = ""
if len(refs_from) > 0:
fmt_refs = [f"{ref:4x}" for ref in refs_from]
ref_from_str = f" {A.green}(xrefs from: {', '.join(fmt_refs)}){A.clear}"
ref_to_str = ""
if len(refs_to) > 0:
fmt_refs = [f"{ref:4x}" for ref in refs_to]
ref_to_str = f" {A.red}(xrefs to: {', '.join(fmt_refs)}){A.clear}"
if len(refs_from) > 0:
sys.stdout.write(f"\n{A.gray}{'-'*100}{A.clear}\n")
sys.stdout.write(f"{A.gray}{pc:8x}{A.yellow} {get_name_by_tmap(tmap)} {A.clear}")
if instruction is None:
sys.stdout.write(f"{A.red}Failed\n")
return
sys.stdout.write(f"{A.blue}{instruction.mnemonic:8s} {A.clear}{instruction.op_str:20s}{A.clear}{ref_to_str}{ref_from_str}\n")
if instruction.mnemonic == "ret" or len(refs_to) > 0:
sys.stdout.write(f"{A.gray}{'-'*100}{A.clear}\n\n")
def parse_instruction(pc: int, xrefs_to: Dict[int, List[int]], xrefs_from: Dict[int, List[int]]):
arch = get_arch(pc)
tmap = get_tmap(pc)
code = program[(pc - 0x100d0):(pc - 0x100d0 + 4)]
if (tmap & 14 == 2 and tmap & 1) or (tmap & 14 == 0 and not (tmap & 1)):
code = byteswap(code)
try:
instruction = next(arch.disasm(format_program(pc, code), pc, 1))
refs: List[int] = []
if (instruction.mnemonic in ("b",)):
refs.append(instruction.operands[0].value.imm)
if (instruction.mnemonic in ("jal", "j")):
refs.append(instruction.operands[0].value.imm + pc)
if (instruction.mnemonic in ("beqz",)):
refs.append(instruction.operands[1].value.imm + pc)
if (instruction.mnemonic in ("beq", "bge", "bne")):
refs.append(instruction.operands[2].value.imm + pc)
xrefs_from[pc] = refs
for ref in refs:
xrefs_to[ref] = (xrefs_to.get(ref, [])) + [pc]
return instruction
except Exception as e:
return None
back_refs: Dict[int, List[int]] = {}
fwd_refs: Dict[int, List[int]] = {}
insts: List[Optional[CsInsn]] = []
addr = 0x100d0
while addr <= 0x110dc:
insts.append(parse_instruction(addr, fwd_refs, back_refs))
addr += 4
for i, inst in enumerate(insts):
pc = 0x100d0 + i * 4
print_instruction(pc, inst, back_refs.get(pc, []), fwd_refs.get(pc, []))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment