From 5318db49b1b3d2af682e5469dcba4a277825c576 Mon Sep 17 00:00:00 2001 From: Grant Hernandez Date: Thu, 4 Mar 2021 01:45:21 -0800 Subject: [PATCH] No longer require MPU and TCM patterns to match, just prefer them The loader will now just fallback to loading basic TOC sections when it cant determine a memory map from the binary. This makes it so you can at the very least explore the binary, albeit with a lot of undefined memory references. --- .../nx/loader/common/MemoryBlockHelper.java | 12 ++ .../main/java/de/hernan/ShannonLoader.java | 149 +++++++++++------- .../main/java/de/hernan/ShannonMemEntry.java | 12 +- 3 files changed, 113 insertions(+), 60 deletions(-) diff --git a/reversing/ghidra/ShannonLoader/src/main/java/adubbz/nx/loader/common/MemoryBlockHelper.java b/reversing/ghidra/ShannonLoader/src/main/java/adubbz/nx/loader/common/MemoryBlockHelper.java index b3b1917..f19a7a5 100644 --- a/reversing/ghidra/ShannonLoader/src/main/java/adubbz/nx/loader/common/MemoryBlockHelper.java +++ b/reversing/ghidra/ShannonLoader/src/main/java/adubbz/nx/loader/common/MemoryBlockHelper.java @@ -67,6 +67,18 @@ public boolean addUninitializedBlock(String name, long addressOffset, long dataS } } + public boolean addInitializedBlock(String name, long addressOffset, InputStream dataInput, long dataSize, boolean read, boolean write, boolean execute) + { + try { + AddressSpace addressSpace = this.program.getAddressFactory().getDefaultAddressSpace(); + MemoryBlockUtils.createInitializedBlock(program, false, name, addressSpace.getAddress(this.baseAddress + addressOffset), dataInput, dataSize, "", null, read, write, execute, this.log, null); + return true; + } catch (AddressOutOfBoundsException | AddressOverflowException e) { + e.printStackTrace(); + return false; + } + } + public boolean addMergeSection(String name, long addressOffset, InputStream dataInput, long dataSize) throws AddressOverflowException, AddressOutOfBoundsException { AddressSpace addressSpace = this.program.getAddressFactory().getDefaultAddressSpace(); diff --git a/reversing/ghidra/ShannonLoader/src/main/java/de/hernan/ShannonLoader.java b/reversing/ghidra/ShannonLoader/src/main/java/de/hernan/ShannonLoader.java index 0abb169..54b4294 100644 --- a/reversing/ghidra/ShannonLoader/src/main/java/de/hernan/ShannonLoader.java +++ b/reversing/ghidra/ShannonLoader/src/main/java/de/hernan/ShannonLoader.java @@ -18,6 +18,7 @@ import adubbz.nx.loader.common.MemoryBlockHelper; import de.hernan.TOCSectionHeader; import de.hernan.util.PatternFinder; +import de.hernan.util.ByteCharSequence; import ghidra.app.util.Option; import ghidra.app.util.bin.BinaryReader; @@ -152,65 +153,52 @@ protected boolean loadProgramInto(ByteProvider provider, LoadSpec loadSpec, List PatternFinder finder = new PatternFinder(provider.getInputStream(sec_main.getOffset()), sec_main.getSize()); - if (!findShannonPatterns(finder, sec_main)) - return false; - - if (!readMPUTable(reader)) - return false; - - if (!processRelocationTable(reader)) - return false; - - ShannonMemEntry main_tcm_entry = null; + // purely informational for now + discoverSocVersion(finder); - Msg.info(this, String.format("==== Found %d relocation entries ====", memEntries.size())); + findShannonPatterns(finder, sec_main); - for (ShannonMemEntry entry : memEntries) { - Msg.info(this, String.format("%s", entry.toString())); + if (mpuTableOffset != -1) { + if (!readMPUTable(reader)) + return false; - if (entry.getDestinationAddress() == MAIN_TCM_ADDRESS) { - main_tcm_entry = entry; - // don't break so can show all of the things we aren't currently handling - //break; - } + if (!calculateShannonMemoryMap()) + return false; } - Msg.warn(this, "Only the TCM relocation entry is currently supported!"); - // TODO: handle all memory addresses instead of just TCM - if (main_tcm_entry == null) { - Msg.error(this, "Unable to find memory copy operations for TCM region"); - return false; - } + if (relocationTableOffset != -1) { + if (!processRelocationTable(reader)) + return false; - if (!calculateShannonMemoryMap()) - return false; + ShannonMemEntry main_tcm_entry = null; - long tcm_offset = main_tcm_entry.getSourceAddress() - sec_main.getLoadAddress() + sec_main.getOffset(); + Msg.info(this, String.format("==== Found %d relocation entries ====", memEntries.size())); - Msg.info(this, "==== Inflating primary sections ===="); + for (ShannonMemEntry entry : memEntries) { + Msg.info(this, String.format("%s", entry.toString())); - try { - if (!memoryHelper.addMergeSection("TCM", MAIN_TCM_ADDRESS, provider.getInputStream(tcm_offset), - main_tcm_entry.getSize())) - return false; + if (entry.getDestinationAddress() == MAIN_TCM_ADDRESS) { + main_tcm_entry = entry; + // don't break so can show all of the things we aren't currently handling + //break; + } + } - if (!memoryHelper.addMergeSection("BOOT_MIRROR", 0L, - provider.getInputStream(sec_boot.getOffset()), sec_boot.getSize())) - return false; + Msg.warn(this, "Only the TCM relocation entry is currently supported!"); - if (!memoryHelper.addMergeSection("BOOT", sec_boot.getLoadAddress(), - provider.getInputStream(sec_boot.getOffset()), sec_boot.getSize())) + // TODO: handle all memory addresses instead of just TCM + if (main_tcm_entry == null) { + Msg.error(this, "Unable to find memory copy operations for TCM region"); return false; + } - if (!memoryHelper.addMergeSection("MAIN", sec_main.getLoadAddress(), - provider.getInputStream(sec_main.getOffset()), sec_main.getSize())) + if (!addMergeSection(provider, main_tcm_entry, "TCM")) return false; + } - } catch(AddressOverflowException | AddressOutOfBoundsException e) { - e.printStackTrace(); + if (!loadBasicTOCSections(provider, sec_boot, sec_main)) return false; - } Msg.info(this, "==== Finalizing program trees ===="); @@ -220,6 +208,57 @@ protected boolean loadProgramInto(ByteProvider provider, LoadSpec loadSpec, List return true; } + private boolean loadBasicTOCSections(ByteProvider provider, TOCSectionHeader sec_boot, TOCSectionHeader sec_main) + { + Msg.info(this, "==== Inflating primary sections ===="); + + if (sec_boot.getLoadAddress() != 0L) { + if (!addMergeSection(provider, sec_boot, "BOOT_MIRROR", 0L)) + return false; + } + + if (!addMergeSection(provider, sec_boot)) + return false; + + if (!addMergeSection(provider, sec_main)) + return false; + + return true; + } + + private boolean addMergeSection(ByteProvider provider, TOCSectionHeader section) + { + return addMergeSection(provider, section, section.getName(), section.getLoadAddress()); + } + + private boolean addMergeSection(ByteProvider provider, ShannonMemEntry entry, String name) + { + return addMergeSection(provider, entry.getSourceFileOffset(), name, entry.getDestinationAddress(), entry.getSize()); + } + + private boolean addMergeSection(ByteProvider provider, TOCSectionHeader section, String name, long loadAddress) + { + return addMergeSection(provider, section.getOffset(), name, loadAddress, section.getSize()); + } + + private boolean addMergeSection(ByteProvider provider, long offset, String name, long loadAddress, long size) + { + try { + if (mpuEntries.size() == 0) { + Msg.warn(this, String.format("No memory map recovered. Falling back to TOC-only load for section %s", + name)); + return memoryHelper.addInitializedBlock(name, loadAddress, provider.getInputStream(offset), size, + true, true, true); + } else { + return memoryHelper.addMergeSection(name, loadAddress, + provider.getInputStream(offset), size); + } + } catch (AddressOverflowException | AddressOutOfBoundsException | IOException e) { + e.printStackTrace(); + return false; + } + } + private void syncProgramTreeWithMemoryMap(Program program) { // A hack to sync the ProgramTree view and the memory map @@ -347,7 +386,7 @@ private boolean processTOCHeader(BinaryReader reader) } // TODO: add label and types to tables - private boolean findShannonPatterns(PatternFinder finder, TOCSectionHeader fromSection) + private void findShannonPatterns(PatternFinder finder, TOCSectionHeader fromSection) { /* This pattern needs explaining. An MPU entry is a table that Shannon * will process to populate the MPU table of the Cortex-R series CPU. @@ -375,13 +414,12 @@ private boolean findShannonPatterns(PatternFinder finder, TOCSectionHeader fromS mpuTableOffset = finder.find("[\\x00]{8}\\x1c\\x00\\x00\\x00(....){6}\\x01\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x04\\x20"); if (mpuTableOffset == -1) { - Msg.error(this, "Unable to find Shannon MPU table pattern. MPU recovery is essential for correct section permissions which will improve analysis determining what is code and what is data."); - return false; + Msg.warn(this, "Unable to find Shannon MPU table pattern. MPU recovery is essential for correct section permissions which will improve analysis determining what is code and what is data."); + } else { + Msg.info(this, String.format("MPU entry table found in section=MAIN offset=0x%08x (physical address 0x%08x)", + mpuTableOffset, mpuTableOffset+fromSection.getLoadAddress())); } - Msg.info(this, String.format("MPU entry table found in section=MAIN offset=0x%08x (physical address 0x%08x)", - mpuTableOffset, mpuTableOffset+fromSection.getLoadAddress())); - /* This pattern ALSO needs explaining :) * It matches an entry in the boot time relocation table. * @@ -403,14 +441,11 @@ private boolean findShannonPatterns(PatternFinder finder, TOCSectionHeader fromS relocationTableOffset = finder.find("\\x00\\x00\\x80\\x04\\x20\\x0c\\x00\\x00", -0x4); if (relocationTableOffset == -1) { - Msg.error(this, "Unable to find boot-time relocation table pattern. This table is used to unpack the MAIN image during baseband boot, but we need to unpack it at load time in order to capture the TCM region. Without this significant portions of the most critical code will appear to be missing and all xrefs will be broken."); - return false; + Msg.warn(this, "Unable to find boot-time relocation table pattern. This table is used to unpack the MAIN image during baseband boot, but we need to unpack it at load time in order to capture the TCM region. Without this significant portions of the most critical code will appear to be missing and all xrefs will be broken."); + } else { + Msg.info(this, String.format("Boot-time relocation table found in section=MAIN offset=0x%08x (physical address 0x%08x)", + relocationTableOffset, relocationTableOffset+fromSection.getLoadAddress())); } - - Msg.info(this, String.format("Boot-time relocation table found in section=MAIN offset=0x%08x (physical address 0x%08x)", - relocationTableOffset, relocationTableOffset+fromSection.getLoadAddress())); - - return true; } private boolean readMPUTable(BinaryReader reader) @@ -530,7 +565,7 @@ private boolean processRelocationTable(BinaryReader reader) while (true) { try { reader.setPointerIndex(table_address_base); - entry = new ShannonMemEntry(reader); + entry = new ShannonMemEntry(reader, sec_main); } catch (IOException e) { Msg.error(this, "Failed to read relocation table entry (backwards)"); return false; @@ -554,7 +589,7 @@ private boolean processRelocationTable(BinaryReader reader) while (true) { try { // will advance the reader - entry = new ShannonMemEntry(reader); + entry = new ShannonMemEntry(reader, sec_main); } catch (IOException e) { Msg.error(this, "Failed to read relocation table entry (forwards)"); return false; diff --git a/reversing/ghidra/ShannonLoader/src/main/java/de/hernan/ShannonMemEntry.java b/reversing/ghidra/ShannonLoader/src/main/java/de/hernan/ShannonMemEntry.java index 792ab0e..b9f5fab 100644 --- a/reversing/ghidra/ShannonLoader/src/main/java/de/hernan/ShannonMemEntry.java +++ b/reversing/ghidra/ShannonLoader/src/main/java/de/hernan/ShannonMemEntry.java @@ -10,8 +10,10 @@ public class ShannonMemEntry { private long dst; private long size; private long function; + private TOCSectionHeader baseSection; - public ShannonMemEntry(BinaryReader reader) throws IOException { + public ShannonMemEntry(BinaryReader reader, TOCSectionHeader baseSection) throws IOException { + this.baseSection = baseSection; readEntry(reader); } @@ -27,6 +29,10 @@ public long getSourceAddress() { return src; } + public long getSourceFileOffset() { + return getSourceAddress() - baseSection.getLoadAddress() + baseSection.getOffset(); + } + public long getDestinationAddress() { return dst; } @@ -41,7 +47,7 @@ public long getFunction() { @Override public String toString() { - return String.format("ShannonMemEntry", - this.dst, this.src, this.size, this.function); + return String.format("ShannonMemEntry", + this.dst, this.src, this.size, this.function, this.baseSection.getName()); } }