Skip to content

Commit

Permalink
Added support for decompressed NSOs, did some build cleanup too
Browse files Browse the repository at this point in the history
  • Loading branch information
Adubbz committed Mar 22, 2019
1 parent a126faf commit a5f2e6a
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 18 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ A loader for Ghidra supporting a variety of Nintendo Switch file formats.

## Installation
- Copy the zip file to ``<Ghidra install directory>/Extensions/Ghidra``.
- Start Ghidra and use the "Install Extensions" dialog to finish the installation. (File -> Install Extensions...).
- Start Ghidra and use the "Install Extensions" dialog to finish the installation. (``File -> Install Extensions...``).
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ dependencies {
}

task buildExtension (type: Zip, overwrite: true) {
baseName "${project.name}"
baseName "${project.name}".replace(' ', '_') + "-${project.version}"
extension 'zip'
destinationDir DISTRIBUTION_DIR
version ''
Expand Down
2 changes: 1 addition & 1 deletion extension.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name=Switch Loader
name=@extname@
description=A loader for Nintendo Switch file formats.
author=Adubbz
createdOn=9/3/2019
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version=1.0.0
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = "Switch Loader"
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,6 @@ protected void setupRelocations() throws NotFoundException, IOException, MemoryA

if (good)
this.memBlockHelper.addSection(".got", pltGotEnd, this.memoryByteProvider.getInputStream(pltGotEnd), gotEnd - pltGotEnd, true, false, false);

Msg.warn(this, "Got DT_JMPREL. This probably needs to be handled!");
}

// TODO: Handle imports
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/adubbz/switchloader/kip1/KIP1Header.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public long getSectionFileOffset(SectionType type)
}
}

public int getCompressedSectionSize(SectionType type)
{
return this.sectionHeaders[type.ordinal()].getCompressedSize();
}

public boolean isSectionCompressed(SectionType type)
{
int index = type.ordinal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ protected void loadDefaultSegments(TaskMonitor monitor) throws IOException, Addr

if (this.kip1.isSectionCompressed(SectionType.TEXT))
{
byte[] compressedText = this.fileByteProvider.readBytes(this.kip1.getSectionFileOffset(SectionType.TEXT), textHeader.getCompressedSize());
byte[] compressedText = this.fileByteProvider.readBytes(this.kip1.getSectionFileOffset(SectionType.TEXT), this.kip1.getCompressedSectionSize(SectionType.TEXT));
decompressedText = new byte[this.textSize];
ByteUtil.kip1BlzDecompress(decompressedText, compressedText);
}
Expand All @@ -77,7 +77,7 @@ protected void loadDefaultSegments(TaskMonitor monitor) throws IOException, Addr

if (this.kip1.isSectionCompressed(SectionType.RODATA))
{
byte[] compressedRodata = this.fileByteProvider.readBytes(this.kip1.getSectionFileOffset(SectionType.RODATA), rodataHeader.getCompressedSize());
byte[] compressedRodata = this.fileByteProvider.readBytes(this.kip1.getSectionFileOffset(SectionType.RODATA), this.kip1.getCompressedSectionSize(SectionType.RODATA));
decompressedRodata = new byte[this.rodataSize];
ByteUtil.kip1BlzDecompress(decompressedRodata, compressedRodata);
}
Expand All @@ -90,7 +90,7 @@ protected void loadDefaultSegments(TaskMonitor monitor) throws IOException, Addr

if (this.kip1.isSectionCompressed(SectionType.DATA))
{
byte[] compressedData = this.fileByteProvider.readBytes(this.kip1.getSectionFileOffset(SectionType.DATA), dataHeader.getCompressedSize());
byte[] compressedData = this.fileByteProvider.readBytes(this.kip1.getSectionFileOffset(SectionType.DATA), this.kip1.getCompressedSectionSize(SectionType.DATA));
decompressedData = new byte[this.dataSize];
ByteUtil.kip1BlzDecompress(decompressedData, compressedData);
}
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/adubbz/switchloader/nso0/NSO0Header.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.io.IOException;

import adubbz.switchloader.common.SectionType;
import adubbz.switchloader.kip1.KIP1SectionHeader;
import ghidra.app.util.bin.BinaryReader;
import ghidra.util.Msg;

Expand Down Expand Up @@ -76,6 +77,24 @@ public NSO0SectionHeader getSectionHeader(SectionType type)
}
}

public long getSectionFileOffset(SectionType type)
{
switch (type)
{
case TEXT:
return this.textHeader.getFileOffset();

case RODATA:
return this.rodataHeader.getFileOffset();

case DATA:
return this.dataHeader.getFileOffset();

default:
return 0;
}
}

public int getCompressedSectionSize(SectionType type)
{
switch (type)
Expand All @@ -97,6 +116,17 @@ public int getCompressedSectionSize(SectionType type)
}
}

public boolean isSectionCompressed(SectionType type)
{
int index = type.ordinal();

if (index > 2)
return false;

int flagMask = 1 << index;
return (this.flags & flagMask) > 0;
}

public int getBssSize()
{
return this.bssSize;
Expand Down
46 changes: 36 additions & 10 deletions src/main/java/adubbz/switchloader/nso0/NSO0ProgramBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import adubbz.switchloader.common.SectionType;
import adubbz.switchloader.common.SwitchProgramBuilder;
import adubbz.switchloader.util.ByteUtil;
import ghidra.app.util.bin.ByteArrayProvider;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.importer.MemoryConflictHandler;
Expand Down Expand Up @@ -59,20 +58,47 @@ protected void loadDefaultSegments(TaskMonitor monitor) throws IOException, Addr

// The data section is last, so we use its offset + decompressed size
byte[] full = new byte[this.dataOffset + this.dataSize];
byte[] decompressedText;
byte[] decompressedRodata;
byte[] decompressedData;

if (this.nso0.isSectionCompressed(SectionType.TEXT))
{
byte[] compressedText = this.fileByteProvider.readBytes(this.nso0.getSectionFileOffset(SectionType.TEXT), this.nso0.getCompressedSectionSize(SectionType.TEXT));
decompressedText = new byte[this.textSize];
decompressor.decompress(compressedText, decompressedText);
}
else
{
decompressedText = this.fileByteProvider.readBytes(this.nso0.getSectionFileOffset(SectionType.TEXT), this.textSize);
}

byte[] compressedText = this.fileByteProvider.readBytes(textHeader.getFileOffset(), this.nso0.getCompressedSectionSize(SectionType.TEXT));
byte[] decompressedText = new byte[this.textSize];
decompressor.decompress(compressedText, decompressedText);
System.arraycopy(decompressedText, 0, full, this.textOffset, this.textSize);

byte[] compressedRodata = this.fileByteProvider.readBytes(rodataHeader.getFileOffset(), this.nso0.getCompressedSectionSize(SectionType.RODATA));
byte[] decompressedRodata = new byte[this.rodataSize];
decompressor.decompress(compressedRodata, decompressedRodata);
if (this.nso0.isSectionCompressed(SectionType.RODATA))
{
byte[] compressedRodata = this.fileByteProvider.readBytes(this.nso0.getSectionFileOffset(SectionType.RODATA), this.nso0.getCompressedSectionSize(SectionType.RODATA));
decompressedRodata = new byte[this.rodataSize];
decompressor.decompress(compressedRodata, decompressedRodata);
}
else
{
decompressedRodata = this.fileByteProvider.readBytes(this.nso0.getSectionFileOffset(SectionType.RODATA), this.rodataSize);
}

System.arraycopy(decompressedRodata, 0, full, this.rodataOffset, this.rodataSize);

byte[] compressedData = this.fileByteProvider.readBytes(dataHeader.getFileOffset(), this.nso0.getCompressedSectionSize(SectionType.DATA));
byte[] decompressedData = new byte[this.dataSize];
decompressor.decompress(compressedData, decompressedData);
if (this.nso0.isSectionCompressed(SectionType.DATA))
{
byte[] compressedData = this.fileByteProvider.readBytes(this.nso0.getSectionFileOffset(SectionType.DATA), this.nso0.getCompressedSectionSize(SectionType.DATA));
decompressedData = new byte[this.dataSize];
decompressor.decompress(compressedData, decompressedData);
}
else
{
decompressedData = this.fileByteProvider.readBytes(this.nso0.getSectionFileOffset(SectionType.DATA), this.dataSize);
}

System.arraycopy(decompressedData, 0, full, this.dataOffset, this.dataSize);
this.memoryByteProvider = new ByteArrayProvider(full);
}
Expand Down

0 comments on commit a5f2e6a

Please sign in to comment.