diff --git a/decompile/Makefile b/decompile/Makefile index 8691d92..0be07a0 100644 --- a/decompile/Makefile +++ b/decompile/Makefile @@ -31,17 +31,19 @@ src/JSRF/Jet2.exe: $(OBJ) $(LIB) LIB.EXE /NOLOGO /MACHINE:X86 /DEF:$< /OUT:$@ # Compile object files from source +.c.obj: + CL.EXE /nologo /Wall /W4 /Ogityb0 /GfX /Fo$@ /c $< .cpp.obj: CL.EXE /nologo /Wall /W4 /Ogityb0 /GfX /Fo$@ /c $< # Header files used for each object -src/JSRF/Jet2.obj: src/JSRF/Core.hpp src/Std.hpp src/XDK/D3D.hpp\ - src/XDK/Win32.hpp +src/JSRF/Jet2.obj: src/JSRF/Core.hpp src/Std.hpp src/XDK/D3D.h\ + src/XDK/Win32.h src/JSRF/Core.obj: src/JSRF/Core.hpp src/Smilebit/MMatrix.hpp src/Std.hpp\ - src/XDK/D3D.hpp src/XDK/Win32.hpp + src/XDK/D3D.h src/XDK/Win32.h src/JSRF/GameData.obj: src/JSRF/GameData.hpp -src/XDK/CRT/CRT0.obj: src/XDK/Win32.hpp +src/XDK/CRT/CRT0.obj: src/XDK/Win32.h diff --git a/decompile/src/JSRF/Core.hpp b/decompile/src/JSRF/Core.hpp index 7d4f490..984d5fd 100644 --- a/decompile/src/JSRF/Core.hpp +++ b/decompile/src/JSRF/Core.hpp @@ -7,8 +7,8 @@ Game and GameObj classes that form the foundation of the JSRF game code. #include "../Smilebit/MMatrix.hpp" #include "../Std.hpp" -#include "../XDK/D3D.hpp" -#include "../XDK/Win32.hpp" +#include "../XDK/D3D.h" +#include "../XDK/Win32.h" // TODO; move to header for Graphics COM object in Smilebit libraries diff --git a/decompile/src/JSRF/GameData.cpp b/decompile/src/JSRF/GameData.cpp index e9bba24..0efbbbc 100644 --- a/decompile/src/JSRF/GameData.cpp +++ b/decompile/src/JSRF/GameData.cpp @@ -4,7 +4,7 @@ Save data and closely-related runtime data. #pragma bss_seg(".data") -#include "../XDK/Win32.hpp" +#include "../XDK/Win32.h" #include "GameData.hpp" diff --git a/decompile/src/JSRF/GameData.hpp b/decompile/src/JSRF/GameData.hpp index 75f3e65..0169de2 100644 --- a/decompile/src/JSRF/GameData.hpp +++ b/decompile/src/JSRF/GameData.hpp @@ -5,7 +5,7 @@ Save data and closely-related runtime data. #ifndef GAMEDATA_HPP #define GAMEDATA_HPP -#include "../XDK/Win32.hpp" +#include "../XDK/Win32.h" // Data structure actually saved to disk diff --git a/decompile/src/Smilebit/MMatrix.cpp b/decompile/src/Smilebit/MMatrix.cpp index 83b8e07..1bc46d9 100644 --- a/decompile/src/Smilebit/MMatrix.cpp +++ b/decompile/src/Smilebit/MMatrix.cpp @@ -7,7 +7,7 @@ Smilebit's stack-based matrix math library. #include "../Std.hpp" -#include "../XDK/Win32.hpp" +#include "../XDK/Win32.h" #include "MMatrix.hpp" diff --git a/decompile/src/Smilebit/MMatrix.hpp b/decompile/src/Smilebit/MMatrix.hpp index 788740e..9d7354d 100644 --- a/decompile/src/Smilebit/MMatrix.hpp +++ b/decompile/src/Smilebit/MMatrix.hpp @@ -5,7 +5,7 @@ Smilebit's stack-based matrix math library. #ifndef MMATRIX_HPP #define MMATRIX_HPP -#include "../XDK/D3D.hpp" +#include "../XDK/D3D.h" // 4x4 matrix type diff --git a/decompile/src/XDK/CRT/CRT0.cpp b/decompile/src/XDK/CRT/CRT0.c similarity index 67% rename from decompile/src/XDK/CRT/CRT0.cpp rename to decompile/src/XDK/CRT/CRT0.c index c305130..bcaf52d 100644 --- a/decompile/src/XDK/CRT/CRT0.cpp +++ b/decompile/src/XDK/CRT/CRT0.c @@ -1,24 +1,24 @@ -/* JSRF Decompilation: XDK/CRT0.cpp +/* JSRF Decompilation: XDK/CRT0.c C runtime initialization. Like other CRT code, there's some magic here with symbols that get special treatment from the compiler and linker. */ -#include "../Win32.hpp" +#include "../Win32.h" // Every program is supposed to have a main(), so we can just assume its // existence with a declaration here -int main(); +int main(void); - void __stdcall mainCRTStartup (); -static DWORD _mainXapiStartup(LPVOID lpThreadParameter); +void __cdecl mainCRTStartup (void); +DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter); // Address: 0x00148023 // Matching: no -void __stdcall mainCRTStartup() { +void __cdecl mainCRTStartup(void) { /* The true entrypoint of the game, spawning a thread for the rest to run in The linker automatically sets this function to the entrypoint. */ @@ -26,7 +26,7 @@ The linker automatically sets this function to the entrypoint. // Address: 0x00147FB4 // Matching: no -DWORD _mainXapiStartup(LPVOID const lpThreadParameter) { +DWORD __stdcall mainXapiStartup(LPVOID const lpThreadParameter) { /* Runs some initialization and then calls main() */ main(); return 0; diff --git a/decompile/src/XDK/D3D.hpp b/decompile/src/XDK/D3D.h similarity index 55% rename from decompile/src/XDK/D3D.hpp rename to decompile/src/XDK/D3D.h index cea0682..325035f 100644 --- a/decompile/src/XDK/D3D.hpp +++ b/decompile/src/XDK/D3D.h @@ -1,11 +1,16 @@ -/* JSRF Decompilation: XDK/D3D.hpp +/* JSRF Decompilation: XDK/D3D.h Direct3D8 declarations. */ -#ifndef D3D_HPP -#define D3D_HPP +#ifndef D3D_H +#define D3D_H -#include "Win32.hpp" +#include "Win32.h" + + +#ifdef __cplusplus +extern "C" { +#endif typedef DWORD D3DCOLOR; @@ -21,4 +26,10 @@ struct D3DRECT { LONG x1, y1, x2, y2; }; + +#ifdef __cplusplus +} +#endif + + #endif diff --git a/decompile/src/XDK/Win32.hpp b/decompile/src/XDK/Win32.h similarity index 89% rename from decompile/src/XDK/Win32.hpp rename to decompile/src/XDK/Win32.h index ab72d1f..8bb6546 100644 --- a/decompile/src/XDK/Win32.hpp +++ b/decompile/src/XDK/Win32.h @@ -1,9 +1,15 @@ -/* JSRF Decompilation: XDK/Win32.hpp +/* JSRF Decompilation: XDK/Win32.h Definitions normally provided by Windows headers. */ -#ifndef WIN32_HPP -#define WIN32_HPP +#ifndef WIN32_H +#define WIN32_H + + +#ifdef __cplusplus +extern "C" { +#endif + // The famous Win32 typedefs typedef unsigned char UCHAR; @@ -55,4 +61,10 @@ LPVOID __stdcall VirtualAlloc( DWORD flProtect ); + +#ifdef __cplusplus +} +#endif + + #endif diff --git a/ghidra/ghidra_scripts/EnhancedImport.java b/ghidra/ghidra_scripts/EnhancedImport.java index 3bdf040..00fcdcb 100644 --- a/ghidra/ghidra_scripts/EnhancedImport.java +++ b/ghidra/ghidra_scripts/EnhancedImport.java @@ -5,15 +5,20 @@ import ghidra.app.script.GhidraScript; import ghidra.app.services.DataTypeQueryService; import ghidra.program.model.address.Address; +import ghidra.program.model.data.ArrayDataType; import ghidra.program.model.data.DataType; +import ghidra.program.model.data.PointerDataType; import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Function; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.Symbol; +import ghidra.util.StringUtilities; import java.io.FileReader; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -34,7 +39,7 @@ public class EnhancedImport extends GhidraScript{ case "func": importFunc(addr, parts); break; default: throw new Exception( "Symbol type \"" + parts[1] + - "\" on line " + Integer.toString(i) + + "\" on line " + String.valueOf(i) + " is not \"data\" or \"func\"" ); } @@ -45,7 +50,7 @@ public class EnhancedImport extends GhidraScript{ final Address addr, final String[] parts ) throws Exception { - final String name = unqualified(parts[3]); + final String name = unqualified(parts[3]); print("Importing data symbol \"" + parts[3] + "\"..."); @@ -54,21 +59,14 @@ public class EnhancedImport extends GhidraScript{ final Symbol s = Optional.ofNullable(getSymbolAt(addr)) .orElse(createLabel(addr, name, ns, true, SourceType.USER_DEFINED)); - // Create data (TODO: parse type name to get base name, then pass base type to PointerDataType and ArrayDataType constructors to create final type) - final List foundTypes = state.getTool() - .getService(DataTypeQueryService.class) - .findDataTypes(parts[2], null); - if (foundTypes.size() == 0) { - println(" can't find data type \"" + parts[2] + "\", skipping."); - return; - } + // Create data + final Optional t_maybe = makeType(parts[2]); + if (t_maybe.orElse(null) instanceof DataType t) { + clearListing(addr, addr.add(Math.max(t.getLength(), 1) - 1)); + currentProgram.getListing().createData(addr, t); - final DataType t = foundTypes.get(0); // Boldly assume first is right - - clearListing(addr, addr.add(Math.max(t.getLength(), 1) - 1)); - currentProgram.getListing().createData(addr, t); - - println(" done."); + println(" done."); + } else println(", skipping."); } private static String unqualified(final String qualifiedName) { @@ -93,6 +91,64 @@ public class EnhancedImport extends GhidraScript{ return ns; } + private Optional makeType(final String type) throws Exception { + /* Attempt to create the described type from a known base type */ + final String baseName = StringUtilities.findWord(type, 0); + final List foundTypes = state.getTool() + .getService(DataTypeQueryService.class) + .findDataTypes(baseName, null); + if (foundTypes.size() == 0) { + print(" can't find data type \"" + baseName + "\""); + return Optional.empty(); + } + + return Optional.of(derivedType( + foundTypes.get(0), // Boldly assume first is right + type.substring(baseName.length()) + )); + } + + private static DataType derivedType( + final DataType t, + final String modifiers + ) throws Exception { + /* Return the given datatype with given pointer/array modifiers */ + DataType ret = t; + for (int i = 0; i < modifiers.length(); i++) switch (modifiers.charAt(i)) { + case '*': + ret = new PointerDataType(ret); + continue; + + case '[': + // Read array dimensions + final ArrayList dims = new ArrayList<>(); + do { + final String n = StringUtilities.findWord(modifiers, i+1); + i += n.length() + 1; + + dims.add(Integer.valueOf(n)); + } while (modifiers.charAt(i) == '['); + + // Apply array + Collections.reverse(dims); + for (int dim : dims) ret = new ArrayDataType(ret, dim); + + continue; + + case ' ': + continue; + + default: + throw new Exception( + "Unexpected character \"" + + String.valueOf(modifiers.charAt(i)) + + "\" in type modifiers" + ); + } + + return ret; + } + private void importFunc( final Address addr, final String[] parts