mirror of
https://github.com/cemu-project/GhidraRPXLoader.git
synced 2024-11-22 01:09:17 +01:00
Now rpx/rpl files can be imported directly.
This commit is contained in:
parent
a366f0eafc
commit
f9bc953bd6
@ -6,7 +6,7 @@ This is a (WIP) simple extension to open .rpx and .rpl files with Ghidra.
|
||||
|
||||
Install the extension by using the `Install Extensions` option inside Ghidra or extracting the .zip manually into `[GHIDRA_ROOT]\Ghidra\Extensions`. Make sure to restart the program after installing.
|
||||
|
||||
Once the extension is installed, you can open a .rpx/.rpl via `File->Open File System...`. After opening the file, you should a filetree with a `converted.elf`, right click on it and select `Import`, confirm by pressing `Single file`.
|
||||
Once the extension is installed, you import a .rpx/.rpl via `File->Import...`.
|
||||
|
||||
# Building
|
||||
|
||||
|
5
data/languages/RPX.opinion
Normal file
5
data/languages/RPX.opinion
Normal file
@ -0,0 +1,5 @@
|
||||
<opinions>
|
||||
<constraint loader="Wii U Executable (RPX/RPL)" compilerSpecID="default">
|
||||
<constraint primary="0" processor="PowerPC" endian="big" size="32" />
|
||||
</constraint>
|
||||
</opinions>
|
27
src/main/java/de/mas/ghidra/utils/Utils.java
Normal file
27
src/main/java/de/mas/ghidra/utils/Utils.java
Normal file
@ -0,0 +1,27 @@
|
||||
package de.mas.ghidra.utils;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class Utils {
|
||||
private Utils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Grows a ByteBuffer if needed.
|
||||
*
|
||||
* @param buffer the original buffer
|
||||
* @param size the needed size.
|
||||
* @return A byte buffer with the expected size. If the buffer was big enough,
|
||||
* the original buffer will be returned, otherwise a new one will be
|
||||
* created.
|
||||
*/
|
||||
public static ByteBuffer checkAndGrowByteBuffer(ByteBuffer buffer, long size) {
|
||||
// This probably the worst way to do this.
|
||||
if (buffer.remaining() < size) {
|
||||
ByteBuffer newBuffer = ByteBuffer.allocate((int) (buffer.capacity() + size - buffer.remaining()));
|
||||
newBuffer.put(buffer.array());
|
||||
return newBuffer;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
155
src/main/java/de/mas/ghidra/wiiu/RPXUtils.java
Normal file
155
src/main/java/de/mas/ghidra/wiiu/RPXUtils.java
Normal file
@ -0,0 +1,155 @@
|
||||
package de.mas.ghidra.wiiu;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
import de.mas.ghidra.utils.Utils;
|
||||
import generic.continues.RethrowContinuesFactory;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.elf.ElfConstants;
|
||||
import ghidra.app.util.bin.format.elf.ElfException;
|
||||
import ghidra.app.util.bin.format.elf.ElfHeader;
|
||||
import ghidra.app.util.bin.format.elf.ElfSectionHeader;
|
||||
import ghidra.app.util.bin.format.elf.ElfSectionHeaderConstants;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class RPXUtils {
|
||||
private static byte[] RPX_MAGIC = new byte[] { 0x7F, 0x45, 0x4C, 0x46, 0x01, 0x02, 0x01, (byte) 0xCA, (byte) 0xFE };
|
||||
public static final int SHF_RPL_ZLIB = 0x08000000;
|
||||
public static final int SHT_NOBITS = 0x00000008;
|
||||
|
||||
public static final int SHT_RPL_EXPORTS = 0x80000001;
|
||||
public static final int SHT_RPL_IMPORTS = 0x80000002;
|
||||
public static final int SHT_RPL_CRCS = 0x80000003;
|
||||
public static final int SHT_RPL_FILEINFO = 0x80000004;
|
||||
|
||||
public static byte[] convertRPX(ByteProvider bProvider, TaskMonitor monitor)
|
||||
throws ElfException, IOException, CancelledException, DataFormatException {
|
||||
ElfHeader elfFile = ElfHeader.createElfHeader(RethrowContinuesFactory.INSTANCE, bProvider);
|
||||
elfFile.parse();
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(0);
|
||||
|
||||
long shdr_elf_offset = elfFile.e_ehsize() & 0xFFFFFFFF;
|
||||
long shdr_data_elf_offset = shdr_elf_offset + elfFile.e_shnum() * elfFile.e_shentsize();
|
||||
|
||||
for (ElfSectionHeader h : elfFile.getSections()) {
|
||||
monitor.checkCanceled();
|
||||
long curSize = h.getSize();
|
||||
long flags = h.getFlags();
|
||||
long offset = h.getOffset();
|
||||
|
||||
if (offset != 0) {
|
||||
if ((flags & SHT_NOBITS) != SHT_NOBITS) {
|
||||
byte[] data = h.getData();
|
||||
|
||||
if ((flags & SHF_RPL_ZLIB) == SHF_RPL_ZLIB) {
|
||||
monitor.setMessage("Decompressing section " + h.getTypeAsString());
|
||||
long section_size_inflated = ByteBuffer.wrap(Arrays.copyOf(data, 4)).getInt() & 0xFFFFFFFF;
|
||||
Inflater inflater = new Inflater();
|
||||
inflater.setInput(data, 4, (int) h.getSize() - 4); // the first byte is the size
|
||||
|
||||
byte[] decompressed = new byte[(int) section_size_inflated];
|
||||
|
||||
inflater.inflate(decompressed);
|
||||
|
||||
inflater.end();
|
||||
|
||||
// Is this alignment really necessary?
|
||||
curSize = (section_size_inflated + 0x03) & ~0x3;
|
||||
flags &= ~SHF_RPL_ZLIB;
|
||||
data = decompressed;
|
||||
}
|
||||
long newEnd = shdr_data_elf_offset + curSize;
|
||||
|
||||
buffer = Utils.checkAndGrowByteBuffer(buffer, newEnd);
|
||||
buffer.position((int) shdr_data_elf_offset);
|
||||
// System.out.println("Write data " + String.format("%08X",
|
||||
// shdr_data_elf_offset));
|
||||
buffer.put(data);
|
||||
offset = shdr_data_elf_offset;
|
||||
shdr_data_elf_offset += curSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Hacky way to fix import relocations
|
||||
if (h.getType() == ElfSectionHeaderConstants.SHT_SYMTAB) {
|
||||
monitor.setMessage("Fix import relocations " + h.getTypeAsString());
|
||||
int symbolCount = (int) ((int) (curSize) / h.getEntrySize());
|
||||
long entryPos = 0;
|
||||
for (int i = 0; i < symbolCount; i++) {
|
||||
monitor.checkCanceled();
|
||||
long test_offset = (int) (offset + entryPos + 4);
|
||||
buffer.position((int) test_offset);
|
||||
int val = buffer.getInt();
|
||||
|
||||
if ((val & 0xF0000000L) == 0xC0000000L) {
|
||||
long fixedAddress = val - 0xC0000000L + 0x01000000L;
|
||||
buffer.position((int) test_offset);
|
||||
buffer.putInt((int) fixedAddress);
|
||||
}
|
||||
entryPos += h.getEntrySize();
|
||||
}
|
||||
}
|
||||
|
||||
buffer = Utils.checkAndGrowByteBuffer(buffer, shdr_elf_offset + 0x28);
|
||||
|
||||
monitor.setMessage("Converting section " + h.getTypeAsString());
|
||||
|
||||
buffer.position((int) shdr_elf_offset);
|
||||
System.out.println("Write header " + String.format("%08X", shdr_elf_offset));
|
||||
buffer.putInt(h.getName());
|
||||
if (h.getType() == SHT_RPL_CRCS || h.getType() == SHT_RPL_FILEINFO || h.getType() == SHT_RPL_EXPORTS
|
||||
|| h.getType() == SHT_RPL_IMPORTS) {
|
||||
buffer.putInt(ElfSectionHeaderConstants.SHT_NULL);
|
||||
} else {
|
||||
buffer.putInt(h.getType());
|
||||
}
|
||||
buffer.putInt((int) flags);
|
||||
|
||||
// Hacky way to fix import relocations
|
||||
if ((h.getAddress() & 0xF0000000L) == 0xC0000000L) {
|
||||
long fixedAddress = h.getAddress() - 0xC0000000L + 0x01000000L;
|
||||
buffer.putInt((int) fixedAddress);
|
||||
} else {
|
||||
buffer.putInt((int) h.getAddress());
|
||||
}
|
||||
|
||||
buffer.putInt((int) offset);
|
||||
buffer.putInt((int) curSize);
|
||||
buffer.putInt(h.getLink());
|
||||
buffer.putInt(h.getInfo());
|
||||
buffer.putInt((int) h.getAddressAlignment());
|
||||
buffer.putInt((int) h.getEntrySize());
|
||||
|
||||
shdr_elf_offset += 0x28;
|
||||
}
|
||||
|
||||
monitor.setMessage("Create new ELF header");
|
||||
|
||||
buffer = Utils.checkAndGrowByteBuffer(buffer, 36);
|
||||
|
||||
buffer.position(0);
|
||||
buffer.put(RPX_MAGIC);
|
||||
buffer.position(0x10);
|
||||
buffer.putShort(ElfConstants.ET_EXEC); // e.e_type());
|
||||
buffer.putShort(elfFile.e_machine());
|
||||
buffer.putInt(elfFile.e_version());
|
||||
buffer.putInt((int) elfFile.e_entry());
|
||||
buffer.putInt((int) elfFile.e_phoff());
|
||||
buffer.putInt(elfFile.e_ehsize()); // e.e_shoff());
|
||||
buffer.putInt(elfFile.e_flags());
|
||||
buffer.putShort(elfFile.e_ehsize());
|
||||
buffer.putShort(elfFile.e_phentsize());
|
||||
buffer.putShort(elfFile.e_phnum());
|
||||
buffer.putShort(elfFile.e_shentsize());
|
||||
buffer.putShort(elfFile.e_shnum());
|
||||
buffer.putShort(elfFile.e_shstrndx());
|
||||
|
||||
return buffer.array();
|
||||
}
|
||||
}
|
79
src/main/java/ghidra/app/util/opinion/RPXLoader.java
Normal file
79
src/main/java/ghidra/app/util/opinion/RPXLoader.java
Normal file
@ -0,0 +1,79 @@
|
||||
package ghidra.app.util.opinion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
import de.mas.ghidra.wiiu.RPXUtils;
|
||||
import generic.continues.GenericFactory;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.bin.ByteArrayProvider;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.elf.ElfException;
|
||||
import ghidra.app.util.bin.format.elf.ElfHeader;
|
||||
import ghidra.app.util.importer.MemoryConflictHandler;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.importer.MessageLogContinuesFactory;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class RPXLoader extends ElfLoader {
|
||||
@Override
|
||||
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
|
||||
byte[] header = new byte[] { 0x7F, 0x45, 0x4C, 0x46, 0x01, 0x02, 0x01, (byte) 0xCA, (byte) 0xFE };
|
||||
List<LoadSpec> loadSpecs = new ArrayList<>();
|
||||
|
||||
if (Arrays.equals(provider.readBytes(0, header.length), header)) {
|
||||
List<QueryResult> results = QueryOpinionService.query(getName(), "0", null);
|
||||
|
||||
for (QueryResult result : results) {
|
||||
loadSpecs.add(new LoadSpec(this, 0, result));
|
||||
}
|
||||
if (loadSpecs.isEmpty()) {
|
||||
loadSpecs.add(new LoadSpec(this, 0, true));
|
||||
}
|
||||
return loadSpecs;
|
||||
|
||||
}
|
||||
return loadSpecs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Wii U Executable (RPX/RPL)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoaderTier getTier() {
|
||||
return LoaderTier.SPECIALIZED_TARGET_LOADER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTierPriority() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program,
|
||||
MemoryConflictHandler handler, TaskMonitor monitor, MessageLog log) throws IOException {
|
||||
|
||||
try {
|
||||
GenericFactory factory = MessageLogContinuesFactory.create(log);
|
||||
byte[] data = RPXUtils.convertRPX(provider, monitor);
|
||||
ElfHeader elf = ElfHeader.createElfHeader(factory, new ByteArrayProvider(data));
|
||||
ElfProgramBuilder.loadElf(elf, program, options, log, handler, monitor);
|
||||
} catch (ElfException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
} catch (CancelledException e) {
|
||||
// TODO: Caller should properly handle CancelledException instead
|
||||
throw new IOException(e.getMessage());
|
||||
} catch (DataFormatException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,337 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2019 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
package rpx;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
import org.apache.commons.collections4.map.HashedMap;
|
||||
|
||||
import generic.continues.RethrowContinuesFactory;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.elf.ElfConstants;
|
||||
import ghidra.app.util.bin.format.elf.ElfException;
|
||||
import ghidra.app.util.bin.format.elf.ElfHeader;
|
||||
import ghidra.app.util.bin.format.elf.ElfSectionHeader;
|
||||
import ghidra.app.util.bin.format.elf.ElfSectionHeaderConstants;
|
||||
import ghidra.formats.gfilesystem.FSRL;
|
||||
import ghidra.formats.gfilesystem.FSRLRoot;
|
||||
import ghidra.formats.gfilesystem.FSUtilities;
|
||||
import ghidra.formats.gfilesystem.FileSystemIndexHelper;
|
||||
import ghidra.formats.gfilesystem.FileSystemRefManager;
|
||||
import ghidra.formats.gfilesystem.FileSystemService;
|
||||
import ghidra.formats.gfilesystem.GFile;
|
||||
import ghidra.formats.gfilesystem.GFileSystem;
|
||||
import ghidra.formats.gfilesystem.annotations.FileSystemInfo;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemFactoryFull;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemProbeFull;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@FileSystemInfo(type = "rpx", description = "RPX", factory = RPXFileSystem.RPXFileSystemFactory.class, priority = FileSystemInfo.PRIORITY_HIGH)
|
||||
public class RPXFileSystem implements GFileSystem {
|
||||
|
||||
private static byte[] RPX_MAGIC = new byte[] { 0x7F, 0x45, 0x4C, 0x46, 0x01, 0x02, 0x01, (byte) 0xCA, (byte) 0xFE };
|
||||
public static final int SHF_RPL_ZLIB = 0x08000000;
|
||||
public static final int SHT_NOBITS = 0x00000008;
|
||||
|
||||
public static final int SHT_RPL_EXPORTS = 0x80000001;
|
||||
public static final int SHT_RPL_IMPORTS = 0x80000002;
|
||||
public static final int SHT_RPL_CRCS = 0x80000003;
|
||||
public static final int SHT_RPL_FILEINFO = 0x80000004;
|
||||
|
||||
private final FSRLRoot fsFSRL;
|
||||
private FileSystemIndexHelper<ElfData> fsih;
|
||||
private FileSystemRefManager refManager = new FileSystemRefManager(this);
|
||||
|
||||
private ByteProvider provider;
|
||||
|
||||
/**
|
||||
* File system constructor.
|
||||
*
|
||||
* @param fsFSRL The root {@link FSRL} of the file system.
|
||||
* @param provider The file system provider.
|
||||
*/
|
||||
public RPXFileSystem(FSRLRoot fsFSRL, ByteProvider provider) {
|
||||
this.fsFSRL = fsFSRL;
|
||||
this.provider = provider;
|
||||
this.fsih = new FileSystemIndexHelper<>(this, fsFSRL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts (opens) the file system.
|
||||
*
|
||||
* @param monitor A cancellable task monitor.
|
||||
*/
|
||||
public void mount(TaskMonitor monitor) {
|
||||
monitor.setMessage("Opening " + RPXFileSystem.class.getSimpleName() + "...");
|
||||
try {
|
||||
ElfData data = convertRPX(provider, monitor);
|
||||
fsih.storeFile("converted.elf", 0, false, data.elf_size, data);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on https://github.com/Relys/rpl2elf/blob/master/rpl2elf.c
|
||||
*
|
||||
* @param monitor
|
||||
*
|
||||
* @return
|
||||
* @throws CancelledException
|
||||
*/
|
||||
public static ElfData convertRPX(ByteProvider bProvider, TaskMonitor monitor)
|
||||
throws ElfException, IOException, DataFormatException, CancelledException {
|
||||
ElfHeader elfFile = ElfHeader.createElfHeader(RethrowContinuesFactory.INSTANCE, bProvider);
|
||||
elfFile.parse();
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(0);
|
||||
|
||||
long shdr_elf_offset = elfFile.e_ehsize() & 0xFFFFFFFF;
|
||||
long shdr_data_elf_offset = shdr_elf_offset + elfFile.e_shnum() * elfFile.e_shentsize();
|
||||
|
||||
for (ElfSectionHeader h : elfFile.getSections()) {
|
||||
monitor.checkCanceled();
|
||||
long curSize = h.getSize();
|
||||
long flags = h.getFlags();
|
||||
long offset = h.getOffset();
|
||||
|
||||
if (offset != 0) {
|
||||
if ((flags & SHT_NOBITS) != SHT_NOBITS) {
|
||||
byte[] data = h.getData();
|
||||
|
||||
if ((flags & SHF_RPL_ZLIB) == SHF_RPL_ZLIB) {
|
||||
monitor.setMessage("Decompressing section " + h.getTypeAsString());
|
||||
long section_size_inflated = ByteBuffer.wrap(Arrays.copyOf(data, 4)).getInt() & 0xFFFFFFFF;
|
||||
Inflater inflater = new Inflater();
|
||||
inflater.setInput(data, 4, (int) h.getSize() - 4); // the first byte is the size
|
||||
|
||||
byte[] decompressed = new byte[(int) section_size_inflated];
|
||||
|
||||
inflater.inflate(decompressed);
|
||||
|
||||
inflater.end();
|
||||
|
||||
// Is this alignment really necessary?
|
||||
curSize = (section_size_inflated + 0x03) & ~0x3;
|
||||
flags &= ~SHF_RPL_ZLIB;
|
||||
data = decompressed;
|
||||
}
|
||||
long newEnd = shdr_data_elf_offset + curSize;
|
||||
|
||||
buffer = checkBuffer(buffer, newEnd);
|
||||
buffer.position((int) shdr_data_elf_offset);
|
||||
buffer.put(data);
|
||||
offset = shdr_data_elf_offset;
|
||||
shdr_data_elf_offset += curSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Hacky way to fix import relocations
|
||||
if (h.getType() == ElfSectionHeaderConstants.SHT_SYMTAB) {
|
||||
monitor.setMessage("Fix import relocations " + h.getTypeAsString());
|
||||
int symbolCount = (int) ((int) (curSize) / h.getEntrySize());
|
||||
long entryPos = 0;
|
||||
for (int i = 0; i < symbolCount; i++) {
|
||||
monitor.checkCanceled();
|
||||
long test_offset = (int) (offset + entryPos + 4);
|
||||
buffer.position((int) test_offset);
|
||||
int val = buffer.getInt();
|
||||
|
||||
if ((val & 0xF0000000L) == 0xC0000000L) {
|
||||
long fixedAddress = val - 0xC0000000L + 0x01000000L;
|
||||
buffer.position((int) test_offset);
|
||||
buffer.putInt((int) fixedAddress);
|
||||
}
|
||||
entryPos += h.getEntrySize();
|
||||
}
|
||||
}
|
||||
|
||||
buffer = checkBuffer(buffer, shdr_elf_offset + 0x28);
|
||||
|
||||
monitor.setMessage("Converting section " + h.getTypeAsString());
|
||||
|
||||
buffer.position((int) shdr_elf_offset);
|
||||
System.out.println("Write header " + String.format("%08X", shdr_elf_offset));
|
||||
buffer.putInt(h.getName());
|
||||
if (h.getType() == SHT_RPL_CRCS || h.getType() == SHT_RPL_FILEINFO || h.getType() == SHT_RPL_EXPORTS
|
||||
|| h.getType() == SHT_RPL_IMPORTS) {
|
||||
buffer.putInt(ElfSectionHeaderConstants.SHT_NULL);
|
||||
} else {
|
||||
buffer.putInt(h.getType());
|
||||
}
|
||||
buffer.putInt((int) flags);
|
||||
|
||||
// Hacky way to fix import relocations
|
||||
if ((h.getAddress() & 0xF0000000L) == 0xC0000000L) {
|
||||
long fixedAddress = h.getAddress() - 0xC0000000L + 0x01000000L;
|
||||
buffer.putInt((int) fixedAddress);
|
||||
} else {
|
||||
buffer.putInt((int) h.getAddress());
|
||||
}
|
||||
|
||||
buffer.putInt((int) offset);
|
||||
buffer.putInt((int) curSize);
|
||||
buffer.putInt(h.getLink());
|
||||
buffer.putInt(h.getInfo());
|
||||
buffer.putInt((int) h.getAddressAlignment());
|
||||
buffer.putInt((int) h.getEntrySize());
|
||||
|
||||
shdr_elf_offset += 0x28;
|
||||
}
|
||||
|
||||
monitor.setMessage("Create new ELF header");
|
||||
|
||||
buffer.position(0);
|
||||
buffer.put(RPX_MAGIC);
|
||||
buffer.position(0x10);
|
||||
buffer.putShort(ElfConstants.ET_EXEC); // e.e_type());
|
||||
buffer.putShort(elfFile.e_machine());
|
||||
buffer.putInt(elfFile.e_version());
|
||||
buffer.putInt((int) elfFile.e_entry());
|
||||
buffer.putInt((int) elfFile.e_phoff());
|
||||
buffer.putInt(elfFile.e_ehsize()); // e.e_shoff());
|
||||
buffer.putInt(elfFile.e_flags());
|
||||
buffer.putShort(elfFile.e_ehsize());
|
||||
buffer.putShort(elfFile.e_phentsize());
|
||||
buffer.putShort(elfFile.e_phnum());
|
||||
buffer.putShort(elfFile.e_shentsize());
|
||||
buffer.putShort(elfFile.e_shnum());
|
||||
buffer.putShort(elfFile.e_shstrndx());
|
||||
|
||||
byte[] dataArray = buffer.array();
|
||||
|
||||
return new ElfData(dataArray, (int) bProvider.length());
|
||||
}
|
||||
|
||||
private static ByteBuffer checkBuffer(ByteBuffer buffer, long newEnd) {
|
||||
// This probably the worst way to do this.
|
||||
if (buffer.remaining() < newEnd) {
|
||||
ByteBuffer newBuffer = ByteBuffer.allocate((int) (buffer.capacity() + newEnd - buffer.remaining()));
|
||||
newBuffer.put(buffer.array());
|
||||
return newBuffer;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
refManager.onClose();
|
||||
if (provider != null) {
|
||||
provider.close();
|
||||
provider = null;
|
||||
}
|
||||
fsih.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return fsFSRL.getContainer().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FSRLRoot getFSRL() {
|
||||
return fsFSRL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return provider == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFileCount() {
|
||||
return fsih.getFileCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemRefManager getRefManager() {
|
||||
return refManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GFile lookup(String path) throws IOException {
|
||||
return fsih.lookup(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(GFile file, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
ElfData metadata = fsih.getMetadata(file);
|
||||
return (metadata != null) ? new ByteArrayInputStream(metadata.data) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GFile> getListing(GFile directory) throws IOException {
|
||||
return fsih.getListing(directory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfo(GFile file, TaskMonitor monitor) throws IOException {
|
||||
ElfData metadata = fsih.getMetadata(file);
|
||||
return (metadata == null) ? null : FSUtilities.infoMapToString(getInfoMap(metadata));
|
||||
}
|
||||
|
||||
private Map<String, String> getInfoMap(ElfData metadata) {
|
||||
Map<String, String> infos = new HashedMap<>();
|
||||
infos.put("elf_size", Integer.toString(metadata.elf_size));
|
||||
infos.put("rpx_size", Integer.toString(metadata.rpx_size));
|
||||
return infos;
|
||||
}
|
||||
|
||||
public static class RPXFileSystemFactory implements GFileSystemFactoryFull<RPXFileSystem>, GFileSystemProbeFull {
|
||||
@Override
|
||||
public RPXFileSystem create(FSRL containerFSRL, FSRLRoot targetFSRL, ByteProvider byteProvider,
|
||||
File containerFile, FileSystemService fsService, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
RPXFileSystem fs = new RPXFileSystem(targetFSRL, byteProvider);
|
||||
fs.mount(monitor);
|
||||
return fs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean probe(FSRL containerFSRL, ByteProvider byteProvider, File containerFile,
|
||||
FileSystemService fsService, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
byte[] header = byteProvider.readBytes(0, RPX_MAGIC.length);
|
||||
return Arrays.equals(header, RPX_MAGIC);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ElfData {
|
||||
private byte[] data;
|
||||
private int elf_size;
|
||||
private int rpx_size;
|
||||
|
||||
public ElfData(byte[] data, int rpx_size) {
|
||||
this.data = data;
|
||||
this.elf_size = data.length;
|
||||
this.rpx_size = rpx_size;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user