Skip to content

Commit

Permalink
No longer require MPU and TCM patterns to match, just prefer them
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
grant-h committed Mar 4, 2021
1 parent 8ca7322 commit 5318db4
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 ====");

Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -27,6 +29,10 @@ public long getSourceAddress() {
return src;
}

public long getSourceFileOffset() {
return getSourceAddress() - baseSection.getLoadAddress() + baseSection.getOffset();
}

public long getDestinationAddress() {
return dst;
}
Expand All @@ -41,7 +47,7 @@ public long getFunction() {

@Override
public String toString() {
return String.format("ShannonMemEntry<dst=%08x, src=%08x, size=%08x, fn=%08x>",
this.dst, this.src, this.size, this.function);
return String.format("ShannonMemEntry<dst=%08x, src=%08x, size=%08x, fn=%08x, secbase=%s>",
this.dst, this.src, this.size, this.function, this.baseSection.getName());
}
}

0 comments on commit 5318db4

Please sign in to comment.