181 lines
9.2 KiB
Python
181 lines
9.2 KiB
Python
import argparse
|
|
from capstone import *
|
|
from keystone import *
|
|
|
|
# Disassemble ARM64 binary
|
|
def disassemble_arm64(binary_path):
|
|
with open(binary_path, 'rb') as f:
|
|
code = f.read()
|
|
md = Cs(CS_ARCH_ARM64, CS_MODE_ARM)
|
|
instructions = list(md.disasm(code, 0x1000))
|
|
return instructions
|
|
|
|
# Translate ARM64 instructions to x86_64
|
|
def translate_instructions(arm64_instructions):
|
|
translated_instructions = []
|
|
for ins in arm64_instructions:
|
|
x86_instruction = translate_arm64_to_x86(ins)
|
|
translated_instructions.extend(x86_instruction)
|
|
return translated_instructions
|
|
|
|
# Assemble x86_64 instructions into binary
|
|
def assemble_x86_64(instructions, output_path):
|
|
ks = Ks(KS_ARCH_X86, KS_MODE_64)
|
|
encoding, count = ks.asm(' '.join(instructions))
|
|
with open(output_path, 'wb') as f:
|
|
f.write(bytearray(encoding))
|
|
|
|
# Extended translation logic for ARM64 to x86_64
|
|
def translate_arm64_to_x86(arm64_ins):
|
|
reg_mapping = {
|
|
'x0': 'rax', 'x1': 'rbx', 'x2': 'rcx', 'x3': 'rdx',
|
|
'x4': 'rsi', 'x5': 'rdi', 'x6': 'rbp', 'x7': 'rsp',
|
|
'x8': 'r8', 'x9': 'r9', 'x10': 'r10', 'x11': 'r11',
|
|
'x12': 'r12', 'x13': 'r13', 'x14': 'r14', 'x15': 'r15',
|
|
'x16': 'r16', 'x17': 'r17', 'x18': 'r18', 'x19': 'r19',
|
|
'x20': 'r20', 'x21': 'r21', 'x22': 'r22', 'x23': 'r23',
|
|
'x24': 'r24', 'x25': 'r25', 'x26': 'r26', 'x27': 'r27',
|
|
'x28': 'r28', 'x29': 'r29', 'x30': 'r30'
|
|
}
|
|
|
|
x86_instructions = []
|
|
|
|
def generate_x86_instruction(opcode, operands):
|
|
return f"{opcode} {', '.join(operands)}"
|
|
|
|
if arm64_ins.mnemonic == 'mov':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'add':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping and operands[2] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
x86_instructions.append(generate_x86_instruction('add', [reg_mapping[operands[0]], reg_mapping[operands[2]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'sub':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping and operands[2] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
x86_instructions.append(generate_x86_instruction('sub', [reg_mapping[operands[0]], reg_mapping[operands[2]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'set':
|
|
x86_instructions.append('nop ; Setup AMX state')
|
|
|
|
elif arm64_ins.mnemonic == 'clr':
|
|
x86_instructions.append('nop ; Clear AMX state')
|
|
|
|
elif arm64_ins.mnemonic == 'ldx':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[0]], f"[{operands[1]}]"]))
|
|
|
|
elif arm64_ins.mnemonic == 'ldy':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[0]], f"[{operands[1]}]"]))
|
|
|
|
elif arm64_ins.mnemonic == 'ldz':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[0]], f"[{operands[1]}]"]))
|
|
|
|
elif arm64_ins.mnemonic == 'stx':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [f"[{operands[0]}]", reg_mapping[operands[1]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'sty':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [f"[{operands[0]}]", reg_mapping[operands[1]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'stz':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [f"[{operands[0]}]", reg_mapping[operands[1]]]))
|
|
|
|
elif 'fma' in arm64_ins.mnemonic and '(63=0)' in arm64_ins.op_str:
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('vmulps', [reg_mapping[operands[0]], reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
x86_instructions.append(generate_x86_instruction('vaddps', [reg_mapping[operands[0]], reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
elif 'fms' in arm64_ins.mnemonic and '(63=0)' in arm64_ins.op_str:
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('vmulps', [reg_mapping[operands[0]], reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
x86_instructions.append(generate_x86_instruction('vsubps', [reg_mapping[operands[0]], reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
elif 'mac' in arm64_ins.mnemonic and '(63=0)' in arm64_ins.op_str:
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('vmulps', [reg_mapping[operands[0]], reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
x86_instructions.append(generate_x86_instruction('vaddps', [reg_mapping[operands[0]], reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
elif 'vec' in arm64_ins.mnemonic and '(47≠4)' in arm64_ins.op_str:
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('vaddps', [reg_mapping[operands[0]], reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
elif 'vec' in arm64_ins.mnemonic and '(47=4)' in arm64_ins.op_str:
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('vaddps', [reg_mapping[operands[0]], reg_mapping[operands[0]], reg_mapping[operands[0]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'extrx':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'extry':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[1]], reg_mapping[operands[0]]]))
|
|
|
|
# Apple Silicon specific instructions
|
|
elif arm64_ins.mnemonic == 'smulh':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('imul', [reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'umull':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping and operands[2] in reg_mapping and operands[3] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[2]], f"[{reg_mapping[operands[0]]} * {reg_mapping[operands[1]]}]"]))
|
|
x86_instructions.append(generate_x86_instruction('mov', [reg_mapping[operands[3]], f"[{reg_mapping[operands[0]]} * {reg_mapping[operands[1]]}]"]))
|
|
|
|
elif arm64_ins.mnemonic == 'fmov':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('movss', [reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
elif arm64_ins.mnemonic == 'fdiv':
|
|
operands = arm64_ins.op_str.split(', ')
|
|
if operands[0] in reg_mapping and operands[1] in reg_mapping and operands[2] in reg_mapping:
|
|
x86_instructions.append(generate_x86_instruction('divss', [reg_mapping[operands[0]], reg_mapping[operands[1]]]))
|
|
|
|
return x86_instructions
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Translates (Apple) ARM64 binary to x86_64 binary")
|
|
parser.add_argument('-i', '--input', required=True, help="Path to the input ARM64 binary")
|
|
parser.add_argument('-o', '--output', required=True, help="Path to the output x86_64 binary")
|
|
args = parser.parse_args()
|
|
|
|
arm64_binary_path = args.input
|
|
x86_64_binary_path = args.output
|
|
|
|
# Disassemble ARM64 binary
|
|
arm64_instructions = disassemble_arm64(arm64_binary_path)
|
|
|
|
# Translate ARM64 instructions to x86_64
|
|
x86_64_instructions = translate_instructions(arm64_instructions)
|
|
|
|
# Assemble x86_64 instructions into new binary
|
|
assemble_x86_64(x86_64_instructions, x86_64_binary_path)
|
|
print("Translation complete. x86_64 binary created at", x86_64_binary_path)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|