Skip to content

Instantly share code, notes, and snippets.

@ndeadly
Created November 5, 2024 21:32
Show Gist options
  • Save ndeadly/25df9fd1d71fe1af87666a1df709c609 to your computer and use it in GitHub Desktop.
Save ndeadly/25df9fd1d71fe1af87666a1df709c609 to your computer and use it in GitHub Desktop.
IDA script for dumping the broadcom patchram data from the bluetooth module of Nintendo Switch firmware
import os
import ida_funcs
import ida_search
import idautils
BASE_ADDR = 0x7100000000
def search_imm(value):
offsets = []
ea_addr = BASE_ADDR
while True:
ea_addr, found = ida_search.find_imm(ea_addr, ida_search.SEARCH_DOWN, value)
if not found:
break;
offsets.append(ea_addr)
return offsets
def get_parent_function_address(address):
xrefs = list(idautils.CodeRefsTo(address, True))
calling_func = ida_funcs.get_func(xrefs[0])
return calling_func.start_ea
# Find where 0xFC2E is loaded as first argument (W0) to BTM_VendorSpecificCommand
w0_addr = None
for address in search_imm(0xFC2E):
if print_insn_mnem(address) == 'MOV' and idaapi.get_reg_name(get_operand_value(address, 0), 4) == 'W0':
w0_addr = address
break
# Find address of parent function BRCM_PrmInit
calling_func_addr = get_parent_function_address(w0_addr)
# Search forward from beginning of BRCM_PrmInit for first ADRP instruction
adrp_addr = None
search_addr = calling_func_addr
while search_addr < w0_addr:
if print_insn_mnem(search_addr) == 'ADRP':
adrp_addr = search_addr
break
search_addr += 4
# Get the ADRP operand
adrp_operand = get_operand_value(adrp_addr, 1)
# Search forward to find the matching LDR instruction
ldr_addr = None
while search_addr < w0_addr:
if print_insn_mnem(search_addr) == 'LDR':
ldr_addr = search_addr
break
search_addr += 4
# Get the lDR operand
ldr_operand = get_operand_value(ldr_addr, 1)
# Compute got offset to brcm_prm_cb structure
got_offset = adrp_operand + ldr_operand
# Follow pointer to patchram data location
xrefs = list(idautils.DataRefsFrom(got_offset))
patchram_addr = xrefs[0]
# Search forward to find the MOV instruction that sets the size
patchram_size = None
while search_addr < w0_addr:
if print_insn_mnem(search_addr) == 'MOV' and get_operand_value(search_addr, 1) > 1:
patchram_size = get_operand_value(search_addr, 1)
break
search_addr += 4
# Dump the patchram data to file
out_file = 'brcm_patchram.bin'
patchram_data = get_bytes(patchram_addr, patchram_size)
with open(out_file, 'wb') as f:
f.write(patchram_data)
print('patchram data dumped to {}/{}'.format(os.getcwd().replace('\\', '/'), out_file))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment