Created
November 5, 2024 21:32
-
-
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
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
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