mirror of
https://codeberg.org/KeybadeBlox/JSRF-Decompilation.git
synced 2026-02-20 02:07:02 +03:00
Compare commits
6 commits
fd6815ae42
...
522bf8be7f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
522bf8be7f | ||
|
|
0b10a02ad7 | ||
|
|
e0313fa0ba | ||
|
|
adc30bb531 | ||
|
|
3c4f0e72b8 | ||
|
|
c020c2e247 |
15 changed files with 502 additions and 396 deletions
|
|
@ -38,11 +38,11 @@ src/JSRF/Jet2.exe: $(OBJ) $(LIB)
|
||||||
|
|
||||||
|
|
||||||
# Header files used for each object
|
# Header files used for each object
|
||||||
src/JSRF/Jet2.obj: src/JSRF/Core.hpp src/Std.hpp src/XDK/D3D.h\
|
src/JSRF/Jet2.obj: src/JSRF/Core.hpp src/XDK/CRT/stddef.h src/XDK/D3D.h\
|
||||||
src/XDK/Win32.h
|
src/XDK/Win32.h
|
||||||
|
|
||||||
src/JSRF/Core.obj: src/JSRF/Core.hpp src/Smilebit/MMatrix.hpp src/Std.hpp\
|
src/JSRF/Core.obj: src/JSRF/Core.hpp src/Smilebit/MMatrix.hpp\
|
||||||
src/XDK/D3D.h src/XDK/Win32.h
|
src/XDK/CRT/stddef.h src/XDK/D3D.h src/XDK/Win32.h
|
||||||
|
|
||||||
src/JSRF/GameData.obj: src/JSRF/GameData.hpp
|
src/JSRF/GameData.obj: src/JSRF/GameData.hpp
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ Game and GameObj classes that form the foundation of the JSRF game code.
|
||||||
|
|
||||||
#pragma bss_seg(".data")
|
#pragma bss_seg(".data")
|
||||||
|
|
||||||
|
#include "../XDK/CRT/stddef.h"
|
||||||
#include "Core.hpp"
|
#include "Core.hpp"
|
||||||
|
|
||||||
// Declarations for symbols not yet defined in their own source files
|
// Declarations for symbols not yet defined in their own source files
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Game and GameObj classes that form the foundation of the JSRF game code.
|
||||||
#define CORE_HPP
|
#define CORE_HPP
|
||||||
|
|
||||||
#include "../Smilebit/MMatrix.hpp"
|
#include "../Smilebit/MMatrix.hpp"
|
||||||
#include "../Std.hpp"
|
#include "../XDK/CRT/stddef.h"
|
||||||
#include "../XDK/D3D.h"
|
#include "../XDK/D3D.h"
|
||||||
#include "../XDK/Win32.h"
|
#include "../XDK/Win32.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ Main function.
|
||||||
|
|
||||||
#pragma bss_seg(".data")
|
#pragma bss_seg(".data")
|
||||||
|
|
||||||
|
#include "../XDK/CRT/stddef.h"
|
||||||
#include "Core.hpp"
|
#include "Core.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Smilebit's stack-based matrix math library.
|
||||||
#pragma bss_seg (".data" )
|
#pragma bss_seg (".data" )
|
||||||
|
|
||||||
|
|
||||||
#include "../Std.hpp"
|
#include "../XDK/CRT/stddef.h"
|
||||||
#include "../XDK/Win32.h"
|
#include "../XDK/Win32.h"
|
||||||
#include "MMatrix.hpp"
|
#include "MMatrix.hpp"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
/* JSRF Decompilation: Std.hpp
|
|
||||||
C(++) standard library definitions. Implemented in the repository instead of
|
|
||||||
linking to an outside stdlib to ensure consistency (this may not actually be
|
|
||||||
possible to accomplish, but we'll go for it for now).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef STD_HPP
|
|
||||||
#define STD_HPP
|
|
||||||
|
|
||||||
#define NULL 0
|
|
||||||
|
|
||||||
#endif
|
|
||||||
8
decompile/src/XDK/CRT/stddef.h
Normal file
8
decompile/src/XDK/CRT/stddef.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
/* JSRF Decompilation: XDK/CRT/stddef.h */
|
||||||
|
|
||||||
|
#ifndef STDDEF_H
|
||||||
|
#define STDDEF_H
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
|
||||||
|
#endif
|
||||||
106
ghidra/ghidra_scripts/ClassFixup.java
Normal file
106
ghidra/ghidra_scripts/ClassFixup.java
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
// Creates classes out namespaces with matching structs, and if they have a
|
||||||
|
// vtable, sets the calling convention of the contained function typdefs to
|
||||||
|
// __thiscall.
|
||||||
|
//
|
||||||
|
// For vtables to be found, they must be defined as structs with names ending
|
||||||
|
// in "Vtbl" and be pointed to by the first member of a class struct.
|
||||||
|
//
|
||||||
|
// @category Data Types
|
||||||
|
|
||||||
|
import ghidra.app.script.GhidraScript;
|
||||||
|
import ghidra.app.util.NamespaceUtils;
|
||||||
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
|
import ghidra.program.model.data.DataTypeComponent;
|
||||||
|
import ghidra.program.model.data.FunctionDefinition;
|
||||||
|
import ghidra.program.model.data.Pointer;
|
||||||
|
import ghidra.program.model.data.Structure;
|
||||||
|
import ghidra.program.model.listing.GhidraClass;
|
||||||
|
import ghidra.program.model.symbol.Namespace;
|
||||||
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
|
||||||
|
|
||||||
|
public class ClassFixup extends GhidraScript {
|
||||||
|
@Override
|
||||||
|
public void run() throws Exception {
|
||||||
|
fixInNamespace(currentProgram.getGlobalNamespace());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fixInNamespace(final Namespace parent) throws Exception {
|
||||||
|
for (final Symbol s : currentProgram.getSymbolTable()
|
||||||
|
.getChildren(parent.getSymbol()))
|
||||||
|
if (s.getObject() instanceof Namespace ns) switch (ns.getType()) {
|
||||||
|
case Namespace.Type.NAMESPACE:
|
||||||
|
if (shouldBeClass(ns)) {
|
||||||
|
println("Converting \"" + ns.getName(true) + "\" to class...");
|
||||||
|
NamespaceUtils.convertNamespaceToClass(ns);
|
||||||
|
|
||||||
|
// Re-fetch namespace to get its new class version
|
||||||
|
ns = getNamespace(parent, ns.getName());
|
||||||
|
} else {
|
||||||
|
fixInNamespace(ns);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Namespace.Type.CLASS: // fallthrough
|
||||||
|
// Any ns that makes it here should be a class
|
||||||
|
// (can't bind via pattern match because of the
|
||||||
|
// fallthrough)
|
||||||
|
final GhidraClass cls = (GhidraClass)ns;
|
||||||
|
|
||||||
|
// Fix up methods if first member is a vtable
|
||||||
|
if (
|
||||||
|
DataTypeUtilities.findExistingClassStruct(
|
||||||
|
currentProgram.getDataTypeManager(),
|
||||||
|
cls
|
||||||
|
) instanceof Structure struct &&
|
||||||
|
struct.getDataTypeAt(0) instanceof DataTypeComponent memberType &&
|
||||||
|
memberType.getDataType() instanceof Pointer ptrType &&
|
||||||
|
ptrType .getDataType() instanceof Structure vtblT_maybe &&
|
||||||
|
vtblT_maybe.getName().endsWith("Vtbl")
|
||||||
|
) fixMethods(vtblT_maybe);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldBeClass(final Namespace ns) throws Exception {
|
||||||
|
/* Determine if a namespace should be converted to a class
|
||||||
|
The heuristic is whether Ghidra can find a struct that it would be
|
||||||
|
linked with if it was a class. The process to do so is admittedly a
|
||||||
|
bit byzantine.
|
||||||
|
*/
|
||||||
|
// Change name so the dummy class won't have a conflict
|
||||||
|
final String name = ns.getName();
|
||||||
|
ns.getSymbol()
|
||||||
|
.setName("__" + ns.getName(), ns.getSymbol().getSource());
|
||||||
|
|
||||||
|
// Create a dummy class to check for a matching struct without
|
||||||
|
// converting the namespace (as classes can't be reverted)
|
||||||
|
final GhidraClass cls = createClass(ns.getParentNamespace(), name);
|
||||||
|
|
||||||
|
// Record whether Ghidra could find a matching struct
|
||||||
|
final boolean ret = DataTypeUtilities.findExistingClassStruct(
|
||||||
|
currentProgram.getDataTypeManager(),
|
||||||
|
cls
|
||||||
|
) != null;
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
cls.getSymbol().delete();
|
||||||
|
ns.getSymbol().setName(name, ns.getSymbol().getSource());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fixMethods(final Structure vtbl) throws Exception {
|
||||||
|
/* Set all the calling conventions in a vtable to __thiscall */
|
||||||
|
for (final DataTypeComponent member : vtbl.getComponents())
|
||||||
|
if (
|
||||||
|
member.getDataType() instanceof Pointer ptr &&
|
||||||
|
ptr .getDataType() instanceof FunctionDefinition method &&
|
||||||
|
!method.getCallingConventionName().equals("__thiscall")
|
||||||
|
) {
|
||||||
|
println("Fixing calling convention of \"" + method.getDataTypePath().toString() + "\"...");
|
||||||
|
method.setCallingConvention("__thiscall");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
public class EnhancedExport extends GhidraScript{
|
public class EnhancedExport extends GhidraScript {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
final FileWriter out = new FileWriter(askFile("Specify output file", "OK"));
|
final FileWriter out = new FileWriter(askFile("Specify output file", "OK"));
|
||||||
|
|
@ -70,14 +70,14 @@ public class EnhancedExport extends GhidraScript{
|
||||||
(f.isInline() ? "inline" : "notinline") + "\t" +
|
(f.isInline() ? "inline" : "notinline") + "\t" +
|
||||||
Optional.ofNullable(f.getCallFixup())
|
Optional.ofNullable(f.getCallFixup())
|
||||||
.orElse("nofixup") + "\t" +
|
.orElse("nofixup") + "\t" +
|
||||||
f.getName(true) + "\t" +
|
f.getName(true) +
|
||||||
String.join(
|
String.join(
|
||||||
"\t",
|
"",
|
||||||
Arrays.stream(f.getSignature(true)
|
Arrays.stream(f.getSignature(true)
|
||||||
.getArguments())
|
.getArguments())
|
||||||
.map(arg ->
|
.map(arg ->
|
||||||
arg.getDataType().getDisplayName() + "\t" +
|
"\t" + arg.getDataType().getDisplayName() +
|
||||||
arg.getName()
|
"\t" + arg.getName()
|
||||||
).toArray(String[]::new)
|
).toArray(String[]::new)
|
||||||
) +
|
) +
|
||||||
(f.hasVarArgs() ? "\t..." : "") + "\n"
|
(f.hasVarArgs() ? "\t..." : "") + "\n"
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.app.services.DataTypeQueryService;
|
import ghidra.app.services.DataTypeQueryService;
|
||||||
|
import ghidra.app.util.NamespaceUtils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.ArrayDataType;
|
import ghidra.program.model.data.ArrayDataType;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
|
@ -27,7 +28,7 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
public class EnhancedImport extends GhidraScript{
|
public class EnhancedImport extends GhidraScript {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
final FileReader in = new FileReader(askFile("Select input file", "OK"));
|
final FileReader in = new FileReader(askFile("Select input file", "OK"));
|
||||||
|
|
@ -86,16 +87,17 @@ public class EnhancedImport extends GhidraScript{
|
||||||
/* Creates namespaces from the given name, returning the deepest one
|
/* Creates namespaces from the given name, returning the deepest one
|
||||||
Returns null if the qualified name is in the global namespace.
|
Returns null if the qualified name is in the global namespace.
|
||||||
*/
|
*/
|
||||||
final String[] parts = qualifiedName.split("::");
|
return qualifiedName.contains("::") ?
|
||||||
|
NamespaceUtils.createNamespaceHierarchy(
|
||||||
if (parts.length < 2) return null;
|
qualifiedName.substring( // Cut off symbol name
|
||||||
|
0,
|
||||||
final String[] names = Arrays.copyOfRange(parts, 0, parts.length - 1);
|
qualifiedName.length() - "::".length() -
|
||||||
|
unqualified(qualifiedName).length()
|
||||||
Namespace ns = null;
|
),
|
||||||
for (final String name : names) ns = createNamespace(ns, name);
|
null,
|
||||||
|
currentProgram,
|
||||||
return ns;
|
SourceType.USER_DEFINED
|
||||||
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<DataType> makeType(final String type) throws Exception {
|
private Optional<DataType> makeType(final String type) throws Exception {
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ import java.util.stream.IntStream;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
|
|
||||||
public class MSVC7Mangle extends GhidraScript{
|
public class MSVC7Mangle extends GhidraScript {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
// Get selected ranges from arguments if invoked headless
|
// Get selected ranges from arguments if invoked headless
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
function fn_ptr(cls, signature, ret, fname, args) {
|
function fn_ptr(cls, signature, ret, fname, args) {
|
||||||
# Convert the given method signature to a function pointer
|
# Convert the given method signature to a function pointer
|
||||||
if ($1 ~ /^~/) # Special case for virtual destructor
|
if ($1 ~ /^~/) # Special case for virtual destructor
|
||||||
return "\t\t" cls " * __attribute__((thiscall)) "\
|
return "\t\t void * __attribute__((thiscall)) "\
|
||||||
"(*scalar_deleting_destructor)("\
|
"(*scalar_deleting_destructor)("\
|
||||||
cls " *, "\
|
cls " *, "\
|
||||||
"BOOL"\
|
"BOOL"\
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ printf '%s\n' '// Automatically generated mass header file for Ghidra' > jsrf.h
|
||||||
# all the headers here by hand in an order that functions properly
|
# all the headers here by hand in an order that functions properly
|
||||||
HEADERS="
|
HEADERS="
|
||||||
Std.hpp
|
Std.hpp
|
||||||
XDK/Win32.hpp
|
XDK/Win32.h
|
||||||
XDK/D3D.hpp
|
XDK/D3D.h
|
||||||
Smilebit/MMatrix.hpp
|
Smilebit/MMatrix.hpp
|
||||||
JSRF/Core.hpp
|
JSRF/Core.hpp
|
||||||
JSRF/GameData.hpp
|
JSRF/GameData.hpp
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Object,Delink?,.text,.text$XC*1,.text$XC*2,.text$x,D3D,DSOUND,MMATRIX,XGRPH,XPP,.rdata,.rdata$x,.data$CRT,.data,DOLBY
|
Object,Delink?,.text,.text$yc,.text$yd,.text$x,D3D,DSOUND,MMATRIX,XGRPH,XPP,.rdata,.rdata$x,.data$CRT,.data,DOLBY
|
||||||
JSRF/Core.obj,true,0x00011000-0x00013FEB,,,0x00186BA0-0x00186C14,,,,,,0x001C4390-0x001C44F9,0x001E4D20-0x001E4DAB,,0x001EB880-0x001EB933,
|
JSRF/Core.obj,true,0x00011000-0x00013FEB,,,0x00186BA0-0x00186C14,,,,,,0x001C4390-0x001C44F9,0x001E4D20-0x001E4DAB,,0x001EB880-0x001EB933,
|
||||||
JSRF/GameData.obj,true,0x00039B50-0x0003B937,0x0018AD60-0x0018AD75,0x0018C9A0-0x0018C9AA,,,,,,,0x001CA16C-0x001CA3DB,,0x001EB790-0x001EB793,0x001EFC88-0x001F7047,
|
JSRF/GameData.obj,true,0x00039B50-0x0003B937,0x0018AD60-0x0018AD75,0x0018C9A0-0x0018C9AA,,,,,,,0x001CA16C-0x001CA3DB,,0x001EB790-0x001EB793,0x001EFC88-0x001F7047,
|
||||||
JSRF/Jet2.obj,true,0x0006F9E0-0x0006FA6F,,,0x00187710-0x00187724,,,,,,,0x001E620C-0x001E622F,,0x0022FCE0-0x0022FCE3,
|
JSRF/Jet2.obj,true,0x0006F9E0-0x0006FA6F,,,0x00187710-0x00187724,,,,,,,0x001E620C-0x001E622F,,0x0022FCE0-0x0022FCE3,
|
||||||
|
|
|
||||||
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue