lab313ru / ghidra_psx_ldr Goto Github PK
View Code? Open in Web Editor NEWSony Playstation PSX executables loader for GHIDRA
Sony Playstation PSX executables loader for GHIDRA
Hey, installed 6.3
to ~/ghidraRun
. I get the below when trying to import a file. Not sure what's really going on.
Could not initialize class ghidra.formats.gfilesystem.factory.FileSystemFactoryMgr$Singleton
java.lang.NoClassDefFoundError: Could not initialize class ghidra.formats.gfilesystem.factory.FileSystemFactoryMgr$Singleton
at ghidra.formats.gfilesystem.factory.FileSystemFactoryMgr.getInstance(FileSystemFactoryMgr.java:46)
at ghidra.formats.gfilesystem.FileSystemService.<init>(FileSystemService.java:144)
at ghidra.formats.gfilesystem.FileSystemService.<init>(FileSystemService.java:159)
at ghidra.formats.gfilesystem.FileSystemService.getInstance(FileSystemService.java:63)
at ghidra.plugin.importer.ImporterPlugin.importFile(ImporterPlugin.java:177)
at ghidra.plugin.importer.ImporterPlugin.doSingleImportAction(ImporterPlugin.java:346)
at ghidra.plugin.importer.ImporterPlugin$1.actionPerformed(ImporterPlugin.java:216)
at docking.ExecutableAction.execute(ExecutableAction.java:40)
at docking.action.MultipleKeyAction.actionPerformed(MultipleKeyAction.java:142)
at java.desktop/javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1810)
at docking.KeyBindingOverrideKeyEventDispatcher.actionInProgress(KeyBindingOverrideKeyEventDispatcher.java:219)
at docking.KeyBindingOverrideKeyEventDispatcher.dispatchKeyEvent(KeyBindingOverrideKeyEventDispatcher.java:117)
at java.desktop/java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1133)
at java.desktop/java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:1009)
at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:835)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4892)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
---------------------------------------------------
Build Date: 2021-Dec-22 0027 CET
Ghidra Version: 10.1.1
Java Home: /usr/lib/jvm/java-11-openjdk
JVM Version: Oracle Corporation 11.0.13
OS: Linux 5.16.0-arch1-1 amd64
Workstation: sanic.local
By default, we should have certain memory address spaces always created. System RAM at 0x00000000, Expansion 1 at 0x1F000000, ScratchPad at 0x1F800000-3FF, MMIO at 0x1F801000-1FFF. Expansion 2 at 0x1F802000-7F(IIRC), Expansion 3 at 0x1FA00000-0x1FBFFFFF. BIOS/Boot/ROM at 0x1FC00000. And there's the odd cache control stuff at 0xFFFE0130 which I don't know the full size of so might want to have 0xFFFE0000-0xFFFEFFFF mapped for that?
See my other issue about memory address mirroring as well.
The game I'm working on has overlays, and because of the overlays, there are certain functions in the executable which are not detected as functions by Ghidra when initially loaded, because they are only referenced by overlays which are not loaded initially.
When I use the 'D' keybind to disassemble the data, ghidra_psx_loader does not seem to handle this properly, as the references to $gp are not turned into their global references, and instead are represented as "iGp" + the offset from $gp. This is quite annoying, as this requires manually looking up what data a particular piece of code is accessing.
https://github.com/sanctuary/sym
https://github.com/Gh0stBlade/symdump
Could be enough info you'd need to implement this
Doesn't work with latest GHIDRA.
Hi, I'm not familiar with the Ghidra plugin system. Do you think you could provide some instructions on how this set this loader up?
Some games have CPE's too, its especially common with non-retail releases
First of all, thanks you very much for all of your excellent work!
I'm trying to analyze the Team Buddies game (SCES-01923). It was a really fun game, and especially a really well designed game. Two papers have been written about its internal design:
The game uses overlays, and I can understand the way it does but also load the overlays into Ghidra and reference the functions into them.
But I face some problems and I wonder if it's from the game instructions or me not doing the right thing.
In the main
function, an OVERLAY.DAT
file is loaded, it contains entries of 48 bytes each. Every entry have a name (e.g. SYS.BIN
) and it seem to also have an offset.
The struggle comes when calling a function which is inside an overlay. When the jal
instruction is used it's easy, I just have to patch the instruction with the right address and reference the overlay. But sometimes the jalr
instruction is used, so the address is computed from the memory.
FUN_8001a474("\\OVERLAY.DAT;1");
DAT_80010204 = (code **)&DAT_80010184;
$loadOverlayEntry(0);
(*DAT_80010204[6])();
(*DAT_80010204[7])();
(*DAT_80010204[9])();
$loadOverlayEntry(1);
$loadOverlayEntry(3);
(**DAT_80010204)();
(*DAT_80010204[6])();
(the $loadOverlayEntry
was renamed by me)
At the moment, to get the right addresses used by the jalr
instructions, I use no$psx
to debug the game and read the address from the register.
So have you ever encounter such behaviours? If so, how do you deal with them?
I've not attached any of the game file here but I can if you want.
There are 6 store/load instructions for the GTE (LWC2
, SWC2
, MTC2
, MFC2
, CTC2
, and CFC2
) that come in 3 forms:
LWC2 gd, imm(base)
MTC2 rt, gd
CTC2 rt, gc
where gd
is a GTE data register (0-31) and gc
is a GTE control register (0-31). Using the plugin, Ghidra disassembles these instructions interpreting the first operands as either CPU registers
or constant values, however. This leads to disassembly that looks like:
Notice that MTC2
's second operand is listed as 0x0
, where it should be the data register gd0
, which happens to be the VXY0
register. For the LWC2
command, the gd
operand is interpreted as CPU register 1 (at
) instead of GTE data register 1 (VZ0
).
The decompiled code is similarly affected:
Here, iVar1
and iVar8
just happen to be associated with CPU registers 0 and 1, and so they get placed in the function call incorrectly.
Just a disclaimer, I'm a real novice with Ghidra so I'm not sure if this is a problem with the plugin, Ghidra itself, or just me!
The Parallel I/O port on the back of the console maps to memory address 0x1F000000. Valid ROMs can be identified with offsets:
0x00000004: "Licensed by Sony Computer Entertainment, Inc."
0x00000084: "Licensed by Sony Computer Entertainment, Inc."
By default, the BIOS creates a memory region of 0x1F000000-0x1F07FFFF for the PIO port but software can easily change the size anywhere between 1 and 0x00800000 bytes. I would suggest and "uninitialized" segment be used and 0x00800000 be the size.
Entry points will be the 32-bit addresses at offset 0x00000000 and 0x00000080. If value is NULL(0x00000000) that entry point wont be used.
Upon trying to decompile King's Field (USA)'s GAME.EXE, running the PsyQ signatures applier (both manually and automatically) yields no reuslts. Here's a comparison between the result obtained with Ghidra 9.1.2 + latest git ghidra_psx_ldr vs the REDAsm identification for the PsyQ functions.
Ghidra 9.1.2 + latest git ghidra_psx_ldr:
LAB_80013634 XREF[1]: 8004a630(j)
80013634 e8 ff bd 27 addiu sp,sp,-0x18
80013638 10 00 bf af sw ra,0x10(sp)=>DAT_801fffe8 = ??
8001363c 88 29 01 0c jal FUN_8004a620 undefined FUN_8004a620(void)
80013640 00 00 00 00 _nop
80013644 1f 80 05 3c lui param_2,0x801f
80013648 00 80 a5 34 ori param_2,param_2,0x8000
8001364c 1e 80 04 3c lui param_1,0x801e
80013650 5c af 84 24 addiu param_1=>DAT_801daf5c,param_1,-0x50a4 = ??
80013654 35 2a 01 0c jal FUN_8004a8d4 undefined FUN_8004a8d4(undefined
80013658 23 28 a4 00 _subu param_2,param_2,param_1
8001365c d0 30 01 0c jal FUN_8004c340 undefined FUN_8004c340(undefined
80013660 00 00 00 00 _nop
80013664 43 7d 01 0c jal FUN_8005f50c undefined FUN_8005f50c(undefined
80013668 21 20 00 00 _clear param_1
8001366c 26 2b 01 0c jal FUN_8004ac98 undefined FUN_8004ac98(void)
80013670 01 00 04 34 _ori param_1,zero,0x1
80013674 25 80 01 0c jal FUN_80060094 undefined FUN_80060094(void)
80013678 21 20 00 00 _clear param_1
8001367c 3d 80 01 0c jal FUN_800600f4 undefined FUN_800600f4(void)
80013680 00 00 00 00 _nop
80013684 a7 4d 00 0c jal FUN_8001369c undefined FUN_8001369c()
80013688 00 00 00 00 _nop
8001368c 10 00 bf 8f lw ra,0x10(sp)=>DAT_801fffe8 = ??
80013690 00 00 00 00 nop
80013694 08 00 e0 03 jr ra
80013698 18 00 bd 27 _addiu sp,sp,0x18
REDasm 2.1.1-20190523.8848416:
loc_80013634:
TEXT:80013634 addiu $sp, $sp, -18
TEXT:80013638 sw $ra, 10($sp)
TEXT:8001363C jal nullsub_8004A620
TEXT:80013640 nop
TEXT:80013644 lui $a1, 801F
TEXT:80013648 ori $a1, $a1, 8000
TEXT:8001364C lui $a0, 801E
TEXT:80013650 addiu $a0, $a0, -50A4
TEXT:80013654 jal sub_8004a8d4
TEXT:80013658 subu $a1, $a1, $a0
TEXT:8001365C jal sub_8004c340
TEXT:80013660 nop
TEXT:80013664 jal sub_8005f50c
TEXT:80013668 move $a0, $zero
TEXT:8001366C jal LIBCARD.InitCARD2
TEXT:80013670 ori $a0, $zero, 1
TEXT:80013674 jal LIBAPI.ChangeClearPAD
TEXT:80013678 move $a0, $zero
TEXT:8001367C jal LIBAPI.ExitCriticalSection
TEXT:80013680 nop
TEXT:80013684 jal sub_8001369c
TEXT:80013688 nop
TEXT:8001368C lw $ra, 10($sp)
TEXT:80013690 nop
TEXT:80013694 jr $ra
TEXT:80013698 addiu $sp, $sp, 18
Ghidra/plugin output:
/* File: E:\DATA\MGS\MGS_REVERSING\SRC\JIMCTRL_KILL_8003853C.C */
void jimctrl_kill_8003853C(void *pJimCtrl)
{
sub_80038004();
dword_8009E280.m[2]._0_4_ = 0;
sub_80024098();
return;
}
Original code:
typedef struct
{
int dword_8009E280;
int dword_8009E284;
int dword_8009E288;
int dword_8009E28C;
} unk_8009E280;
unk_8009E280 dword_8009E280 = {0, 0, 0, 0};
void jimctrl_kill_8003853C(void *pJimCtrl)
{
sub_80038004(pJimCtrl);
dword_8009E280.dword_8009E28C = 0;
sub_80024098();
}
Binary and symbol file attached for repro.
I couldn't find any documents that I can use psx debugger.
The upper 3 bits of address space indicate the virtual address segment. They all map to the same physical addresses. 0x0.. 0x8... 0xA.. all reference the same physical memory(0x00000000). 0x1F800000 ... 0x9F800000 ... 0xBF800000 all reference 0x1F800000. The only difference is how the caches are applied which don't matter for our purposes anyway. So I suggest that for all memory segments that are added, you create a physical segment that is the base representation, for example (addr & 0x1FFFFFFF). Then create byte mapped segments or whatever you wanna do to make base_addr == (base_addr | 0x80000000) == (base_addr | 0xA0000000). I don't know if ghidra needs to be informed of this in some way so that it doesn't treat them as unique memory space.
I built the current repository per directions, and everything seems to work except the suite of things under the Tools bar in the code browser is completely missing - of primary note, the Overlay Manager. It's definitely possible I did some step of the process wrong but any guidance/troubleshooting on this would be greatly appreciated.
Due to the fact that there are differences between console(RAM size, BIOS, extra hardware), it would be nice if System Configurations could be defined. Basically templates that can be mixed and matched which define memory maps and the data/hw mapped to them. Support for ghidra scripting to allow for emulating hardware using read/write hooks on their memory address(es) would be fucking awesome. :)
It doesn't seem possible to access the PSX Overlay Manager from the Tools menu in macOS.
Is it possible in the future to implement debugger compatibility with pcsx redux gdb server, as well as fix data output in COP0, COP2Data, COPControl tabs (at the moment they are not output at all)?
For now FunctionID doesn't meet my requirements: xrefs, small functions (like BIOS calls - it requires modifying GHIDRA source code). So, I think it will be some custom format (similar to PAT). PAT: Yes I know, it was here already, but signs were generated by Flair utilities, and they're not full.
File can be identified using offsets:
0x00000000: 13 00 08 3C
0x00000108 "Sony Computer Entertainment Inc."
NOTE:Not all BIOSes are loaded to 0xBFC00000. Check offset 0x70 as a 32-bit little endian unsigned int and do load addr = ((val << 2) & 0x3FFFF000). It's almost always going to give you a result of 0x1FC00000 but 0x1FA00000 is also known(for dev hardware).
Ghidra 9.2.3 gives this error with the latest plugin:
file psyq/patches.json does not exist in module ghidra_psx_ldr
java.io.FileNotFoundException: file psyq/patches.json does not exist in module ghidra_psx_ldr
at ghidra.framework.Application.getDataFileInModule(Application.java:361)
at ghidra.framework.Application.getModuleDataFile(Application.java:874)
at psx.PsxAnalyzer.applyPsyqSignaturesByVersion(PsxAnalyzer.java:108)
at psx.PsxAnalyzer.added(PsxAnalyzer.java:89)
at ghidra.app.plugin.core.analysis.AnalysisScheduler.runAnalyzer(AnalysisScheduler.java:186)
at ghidra.app.plugin.core.analysis.AnalysisTask.applyTo(AnalysisTask.java:39)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager$AnalysisTaskWrapper.run(AutoAnalysisManager.java:688)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:788)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:667)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:632)
at ghidra.app.plugin.core.analysis.AnalysisBackgroundCommand.applyTo(AnalysisBackgroundCommand.java:58)
at ghidra.framework.plugintool.mgr.BackgroundCommandTask.run(BackgroundCommandTask.java:102)
at ghidra.framework.plugintool.mgr.ToolTaskManager.run(ToolTaskManager.java:315)
at java.base/java.lang.Thread.run(Thread.java:831)
As well, the extension doesn't seem to want to stay installed.
When I try to compile the loader, it says "GHIDRA_INSTALL_DIR is not defined!" despite filling it out. I'm on Windows 10.
This is my command and I'm using Powershell: cmd /C "set "GHIDRA_INSTALL_DIR=C:\Ghidra\Ghidra" && gradle buildExtension"
Subj. Example: libsn.lib
Tomb Raider: Chronicles gets an error when the main binary is analysed.
Sample files attached:
TRC.zip
I'm having trouble trying to compile on Gentoo. Using openjdk-bin-11, ghidra-9.1.2 and gradle-6.3.
$ env GHIDRA_INSTALL_DIR=/usr/share/ghidra gradle-6.3 buildExtension -g gradle-user-home
> Task :compileJava FAILED
/spare/home/lucas/ghidra_psx_ldr/src/main/java/pat/PatParser.java:12: error: cannot access DisassembleCommand
import ghidra.app.cmd.disassemble.DisassembleCommand;
^
bad class file: /usr/share/ghidra/Ghidra/Features/Base/lib/Base.jar(ghidra/app/cmd/disassemble/DisassembleCommand.class)
class file has wrong version 55.0, should be 52.0
Please remove or make sure it appears in the correct subdirectory of the classpath.
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.3/userguide/command_line_interface.html#sec:command_line_warnings
Subj.
Try loading GS_001.OBJ from LIBGS.LIB. Under IDA, you'll get the following:
COMM:00000040
COMM:00000040 # Segment type: Communal definitions
COMM:00000040 .comm PSDIDX # DATA XREF: GsInitGraph+40↓w
COMM:00000040 # sub_3F8+80↓w ...
COMM:00000044 .comm GsDRAWENV:0x17 # DATA XREF: sub_274+58↓o
COMM:00000044 # sub_274+60↓o ...
COMM:00000048 .comm GsDISPENV:5 # DATA XREF: sub_274+90↓o
COMM:00000048 # sub_274+9C↓w ...
COMM:0000004C .comm PSDGPU # DATA XREF: sub_274+68↓w
COMM:0000004C # sub_274+A4↓w ...
COMM:00000050 .comm PSDBASEX:2 # DATA XREF: sub_274+78↓w
COMM:00000050 # sub_274+98↓o ...
COMM:00000054 .comm PSDBASEY:2 # DATA XREF: sub_274+70↓w
COMM:00000054 # sub_274+B4↓w ...
COMM:00000058 .comm POSITION:2 # DATA XREF: sub_274+7C↓w
COMM:00000058 # sub_274+E0↓w ...
COMM:0000005C .comm CLIP2:4 # DATA XREF: sub_274+8C↓w
COMM:0000005C # GsInitGraph2+28↓w ...
COMM:00000060 .comm PSDCNT:2 # DATA XREF: sub_3F8+20C↓w
COMM:00000060 # sub_3F8+214↓w ...
COMM:00000064 .comm PSDOFSX:2 # DATA XREF: GsSortClear+6C↓r
COMM:00000068 .comm PSDOFSY:2 # DATA XREF: GsSortClear+8C↓r
COMM:0000006C .comm GsORGOFSX:2
COMM:00000070 .comm GsORGOFSY:2
Which are data import relocations. Even though each symbol is 4 bytes apart, their actual sizes can be much larger, like the GsDRAWENV
symbol which is of type DRAWENV
:
/*
* Rectangle:
*/
typedef struct {
short x, y; /* offset point on VRAM */
short w, h; /* width and height */
} RECT;
/*
* Environment
*/
typedef struct {
u_long tag;
u_long code[15];
} DR_ENV; /* Packed Drawing Environment */
typedef struct {
RECT clip; /* clip area */
short ofs[2]; /* drawing offset */
RECT tw; /* texture window */
u_short tpage; /* texture page */
u_char dtd; /* dither flag (0:off, 1:on) */
u_char dfe; /* flag to draw on display area (0:off 1:on) */
u_char isbg; /* enable to auto-clear */
u_char r0, g0, b0; /* initital background color */
DR_ENV dr_env; /* reserved */
} DRAWENV;
But ghidra treats as if the data WAS in the relocation segment instead, which result in really wrong code:
void FUN_000001ac(undefined2 param_1,undefined2 param_2,uint param_3,byte param_4,undefined param_5)
{
int iVar1;
undefined4 uVar2;
uVar2 = 0;
if ((param_3 >> 4 & 3) == 3) {
uVar2 = 3;
}
ResetGraph(uVar2);
GsDRAWENV._10_2_ = 0;
GsDRAWENV._8_2_ = 0;
GsDRAWENV._18_2_ = 0;
GsDRAWENV._16_2_ = 0;
GsDRAWENV._14_2_ = 0;
GsDRAWENV._12_2_ = 0;
GsDRAWENV._20_2_ = 0;
GsDRAWENV.field_0x17 = 0;
GsDRAWENV.field_0x18 = 0;
GsDRAWENV.field_0x16 = param_4;
PutDrawEnv((undefined *)&GsDRAWENV);
GsDRAWENV._0_2_ = 0;
GsDRAWENV._2_2_ = 0;
GsDRAWENV._8_2_ = 0;
GsDRAWENV._10_2_ = 0;
GsDRAWENV._12_2_ = 0;
GsDRAWENV._14_2_ = 0;
GsDRAWENV._4_2_ = param_1;
GsDRAWENV._6_2_ = param_2;
iVar1 = GetVideoMode();
if (iVar1 == 1) {
GsDRAWENV._10_2_ = 0x18;
GsDRAWENV._18_2_ = GsDRAWENV._18_2_ & 0xff00 | 1;
}
GsDRAWENV._0_2_ = (ushort)param_3 & 4;
GsDRAWENV._16_2_ = CONCAT11(param_5,(char)param_3) & 0xff01;
PutDispEnv((undefined *)&GsDRAWENV);
return;
}
In this case, the PutDrawEnv
is being called on the GsDRAWENV
location, but PutDispEnv
is supposed to be called on the GsDISPENV
location, which isn't what the import currently is doing here. It's using GsDISPENV
again.
It's also visible in the disassembly window:
IDA:
.text:00000304 la $s0, GsDISPENV
.text:0000030C addiu $v0, $s0, (PSDBASEX - 0x48)
.text:00000310 sh $zero, (GsDISPENV - 0x48)($s0)
ghidra:
00000240 9c 06 10 26 addiu s0,s0,0x69c
00000244 08 00 02 26 addiu v0,s0,0x8
00000248 00 00 00 a6 sh zero,0x0(s0)=>GsDRAWENV =
Even though the IDA output is a bit more confusing, it's properly referencing GsDISPENV
instead of GsDRAWENV
.
Hi.
Using the last version 10.0.4 i encounter an issue when starting the analyse task.
It seems there is an issue regarding the path of the signatures
I think the path needs to be updated, To see if my theory was correct i simply created a copy of psyq470.gdt
and renamed it psyq47.gdt
inside ghidra_10.0.4_PUBLIC_20211023_ghidra_psx_ldr.zip\ghidra_psx_ldr\data\
and the same for the folder 470
i renamed it 47
inside ghidra_10.0.4_PUBLIC_20211023_ghidra_psx_ldr.zip\ghidra_psx_ldr\data\psyq\
And indeed this fixes it (no error pop up and type recognised):
Hope that helps.
I tried out using the latest 9.0.4 update and Ghidra now accepts the extension and it appears properly in the extensions list. However, when I try to decompile anything it only shows the option to decompile using raw binary and not as a PSX Executable. So either I did something wrong on my end, or something needs to be updated again in the extension. But I did try reinstalling it and using a fresh 9.0.4 install but it changed nothing.
Original code:
void System_init_80015AF4(int index, int bIsDynamic, void* pMemory, unsigned int size)
{
GV_Heap* pHeap = &gv_heaps_800AD2F0[index];
GV_MemoryAllocation* pAllocs = &pHeap->mAllocs[0];
unsigned char* alignedEndPtr = ((unsigned char*)pMemory) + (size & 0xfffffff0); // align
pHeap->mFlags = bIsDynamic != 0;
pHeap->mStartAddr = pMemory;
pHeap->mEndAddr = alignedEndPtr;
pHeap->mUnitsCount = 1;
// First entry is free
pAllocs[0].mPDataStart = pMemory;
pAllocs[0].mAllocType = GV_MemoryAllocation_States_Free_0;
// Second is used and is the entire space
pAllocs[1].mPDataStart = alignedEndPtr;
pAllocs[1].mAllocType = GV_MemoryAllocation_States_Used_2;
}
Decompiled code:
/* File: E:\DATA\MGS\MGS_REVERSING\SRC\SYSTEM_INIT_80015AF4.C */
void System_init_80015AF4(int index,int bIsDynamic,void *pMemory,uint size)
{
int iVar1;
iVar1 = (int)pMemory + (size & 0xfffffff0);
*(uint *)(&_group_gv_heaps_800AD2F0_obj + index * 0x1010) = (uint)(bIsDynamic != 0);
*(void **)(&DAT_800ad2f4 + index * 0x404) = pMemory;
(&DAT_800ad2f8)[index * 0x404] = iVar1;
(&DAT_800ad2fc)[index * 0x404] = 1;
*(void **)(&DAT_800ad300 + index * 0x404) = pMemory;
(&DAT_800ad304)[index * 0x404] = 0;
*(int *)(&DAT_800ad308 + index * 0x1010) = iVar1;
(&DAT_800ad30c)[index * 0x404] = 2;
return;
}
As you can see the type of _group_gv_heaps_800AD2F0_obj isn't correct. Likely because it was put into its own section and so some compiler added symbols also got added?
800AD2F0 __gv_heaps_800AD2F0_obj
800B0320 __gv_heaps_800AD2F0_objend
800AD2F0 __gv_heaps_800AD2F0_org
800B0320 __gv_heaps_800AD2F0_orgend
00003030 __gv_heaps_800AD2F0_size
800AD2F0 gv_heaps_800AD2F0
The last entry and its type is the correct one to use. _obj,_objend,_orgend and _size are generated by the tool chain.
Zip of exe + sym attached for repro:
Currently it's not allowed to load overlays outside regular memory area. But some games detect if they are running on debug hardware and load overlays to additional 6mb area (>80200000).
Subj. Requires some unknown Ghidra functionality.
The pop up that says do you have a SYM file for this executable is not showing on latest release.
While unlike the CPE the final PSX EXE doesn't contain the section info in the header it does however have code referencing it.
If you check a binary with a linker map you can find these references. SN_ENTRY_POINT in SNMAIN.C in the PSX SDK references these section starts and ends for example.
Per the same code gp is set to .sdata section start location.
This could possibly be a accompanying java or python script with the loader as the section reference points could be different per developer.
A option to reconstruct sections from a list? should someone have the matching linker map could be useful too.
Trying to start the PSX Debugger results in the following error:
`Cannot connect to debugger server!
java.util.concurrent.ExecutionException: java.net.ConnectException: Conexão recusada
at java.base/sun.nio.ch.PendingFuture.get(PendingFuture.java:183)
at psx.debug.DebuggerCore.(DebuggerCore.java:22)
at psx.debug.DebuggerProvider.startDebugger(DebuggerProvider.java:51)
at psx.debug.DebuggerProvider.lambda$setBtnActions$0(DebuggerProvider.java:186)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279)
at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6636)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342)
at java.desktop/java.awt.Component.processEvent(Component.java:6401)
at java.desktop/java.awt.Container.processEvent(Container.java:2263)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5012)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4844)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4919)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4548)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4489)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2764)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4844)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.net.ConnectException: Conexão recusada
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.checkConnect(Native Method)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finishConnect(UnixAsynchronousSocketChannelImpl.java:254)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finish(UnixAsynchronousSocketChannelImpl.java:200)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.onEvent(UnixAsynchronousSocketChannelImpl.java:215)
at java.base/sun.nio.ch.EPollPort$EventHandlerTask.run(EPollPort.java:306)
at java.base/java.lang.Thread.run(Thread.java:832)
Build Date: 2020-Feb-12 1149 EST
Ghidra Version: 9.1.2
Java Home: /usr/lib/jvm/java-14-openjdk-14.0.0.36-3.rolling.fc33.x86_64
JVM Version: N/A 14
OS: Linux 5.7.0-0.rc0.git8.2.fc33.x86_64 amd64
Workstation: SolidStateSurvivor`
"Conexão recusada" means "Connection refused". Tested on latest git.
I've noticed that as of the latest update ghidra_psx_ldr is identifying the syscalls, but it seems like they don't always have the correct signatures. B0:36, for example, is set to void FileClose(void)
, when it should be set to the Unix-style syscall int close(int fd)
. I've been using this document to correct syscalls signatures. Is it feasible to correct this behavior?
Thanks again for the excellent work on this extension!
Attempting to load certain executables with the PS1 loader causes an IllegalArgumentException
to be thrown:
Error importing file: SLUS_010.66
java.lang.IllegalArgumentException: Split cannot be done on block start address
at ghidra.program.database.mem.MemoryMapDB.split(MemoryMapDB.java:816)
at psx.PsxLoader.findAndAppyMain(PsxLoader.java:466)
at psx.PsxLoader.load(PsxLoader.java:225)
at ghidra.app.util.opinion.AbstractLibrarySupportLoader.doLoad(AbstractLibrarySupportLoader.java:346)
at ghidra.app.util.opinion.AbstractLibrarySupportLoader.loadProgram(AbstractLibrarySupportLoader.java:83)
at ghidra.app.util.opinion.AbstractProgramLoader.load(AbstractProgramLoader.java:112)
at ghidra.plugin.importer.ImporterUtilities.importSingleFile(ImporterUtilities.java:401)
at ghidra.plugin.importer.ImporterDialog.lambda$okCallback$7(ImporterDialog.java:351)
at ghidra.util.task.TaskLauncher$1.run(TaskLauncher.java:90)
at ghidra.util.task.Task.monitoredRun(Task.java:126)
at ghidra.util.task.TaskRunner.lambda$startTaskThread$1(TaskRunner.java:94)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:830)
---------------------------------------------------
Build Date: 2019-Dec-18 1306 EST
Ghidra Version: 9.1.1
Java Home: C:\jdk-13.0.1
JVM Version: Oracle Corporation 13.0.1
OS: Windows 10 10.0 amd64
Workstation: SpencerComputer
This happens with Tony Hawk's Pro Skater (SLUS-00860) and Tony Hawk's Pro Skater 2 (SLUS-01066), but not the German demo version (all demo versions?) of THPS2. Both executables load fine using the raw binary loader.
Some games have non default region.
I can't seem to build the extension. I keep getting the following error:
C:\Users\Kapsey\Documents\Disassembly\ghidra_psx_ldr-master\ghidra_psx_ldr-master>cmd /C "set "GHIDRA_INSTALL_DIR=C:\Users\Kapsey\Documents\Disassembly\ghidra_9.2.2_PUBLIC_20201229\ghidra_9.2.2_PUBLIC" && gradle buildExtension"
FAILURE: Build failed with an exception.
* Where:
Script 'C:\Users\Kapsey\Documents\Disassembly\ghidra_9.2.2_PUBLIC_20201229\ghidra_9.2.2_PUBLIC\support\buildExtension.gradle' line: 36
* What went wrong:
A problem occurred evaluating script.
> Could not find method compile() for arguments [directory 'lib'] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
It's probably an error on my end. Is there something I'm doing incorrectly?
subj.
It doesn't work on any of the psx binaries i tried that it worked on before.
v1.2.3 still works, later ones just offer Raw Binary as the loader option
Some of the bins im having the issue with(remove log, for some reason i can't upload zip :/ )
psxbins.zip.log
Then i try to analyz Vigilante 8(USA) got error:
Analysis Task: PSYQ Signatures - Invalid address specified for new Label symbol: Stack[-0x8]
java.lang.IllegalArgumentException: Invalid address specified for new Label symbol: Stack[-0x8]
at ghidra.program.database.symbol.SymbolManager.checkAddressAndNameSpaceValidForSymbolType(SymbolManager.java:2585)
at ghidra.program.database.symbol.SymbolManager.validateNamespace(SymbolManager.java:2486)
at ghidra.program.database.symbol.SymbolManager.createCodeSymbol(SymbolManager.java:2352)
at ghidra.program.database.symbol.SymbolManager.createLabel(SymbolManager.java:2335)
at ghidra.program.database.symbol.SymbolManager.createLabel(SymbolManager.java:2323)
at pat.PatParser.setInstrRefName(PatParser.java:225)
at pat.PatParser.applySignatures(PatParser.java:105)
at psx.PsxAnalyzer.added(PsxAnalyzer.java:85)
at ghidra.app.plugin.core.analysis.AnalysisScheduler.runAnalyzer(AnalysisScheduler.java:185)
at ghidra.app.plugin.core.analysis.AnalysisTask.applyTo(AnalysisTask.java:39)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager$AnalysisTaskWrapper.run(AutoAnalysisManager.java:685)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:785)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:664)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:629)
at ghidra.app.plugin.core.analysis.AnalysisBackgroundCommand.applyTo(AnalysisBackgroundCommand.java:62)
at ghidra.framework.plugintool.mgr.BackgroundCommandTask.run(BackgroundCommandTask.java:101)
at ghidra.framework.plugintool.mgr.ToolTaskManager.run(ToolTaskManager.java:315)
at java.base/java.lang.Thread.run(Thread.java:834)
---------------------------------------------------
Build Date: 2019-Feb-28 1236 EST
Ghidra Version: 9.0
Java Home: C:\Program Files\Java\jdk-11.0.2
JVM Version: Oracle Corporation 11.0.2
OS: Windows 7 6.1 amd64
Workstation: VBKesha_Z370
Now, there's no file format that exists that I know of that quite describes this but emulators could definitely generate these. Basically a "System Configuration"(see other feature request) that has been made from a save state of an emulator. Basically coredump including RAM(0x0-0x001FFFFF/0x007FFFFF), ScratchPad(0x1F800000-0x3FF), BIOS(0xBFC00000-0x7FFFF(by default but can be up to 0x00400000 bytes in size), Expansion 1(0x1F000000-0x0007FFFF(by default but can be up to 0x00800000 bytes in size), Expansion 2(0x1F802000-0x7F though size may vary), Expansion 3(0x1FA00000-0x0007FFFF though ca be up to 0x00200000 bytes long). And hardware registers at 0x1F801000-1FFF.
It's possible. And I have them for Brigandine. Algo is easy.
Ghidra 9.2.3 was released lately and I need to make sure there's a compatible loader.
I recently moved my project from ghidra 9.1.x to the latest version, I exported my data and re-imported it to a fresh ghidra 10.1 installation. After the installation I installed your beloved plugin downloaded from github.
I don't remember exactly my steps but Importing the old project brought the references of the old plugin, it wasn't a problem, I just removed the psyq lib from the data type manager, I saved and reopened the file.
At this step I clicked the Auto Analysis and I got this error
(These messages are also written to the application log file)
data/psyq/43 does not exist in module ghidra_psx_ldr
java.io.FileNotFoundException: data/psyq/43 does not exist in module ghidra_psx_ldr
at ghidra.framework.Application.getDataSubDirectoryInModule(Application.java:415)
at ghidra.framework.Application.getModuleDataSubDirectory(Application.java:854)
at psx.PsxAnalyzer.added(PsxAnalyzer.java:86)
at ghidra.app.plugin.core.analysis.AnalysisScheduler.runAnalyzer(AnalysisScheduler.java:186)
at ghidra.app.plugin.core.analysis.AnalysisTask.applyTo(AnalysisTask.java:39)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager$AnalysisTaskWrapper.run(AutoAnalysisManager.java:688)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:788)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:667)
at ghidra.app.plugin.core.analysis.AutoAnalysisManager.startAnalysis(AutoAnalysisManager.java:632)
at ghidra.app.plugin.core.analysis.AnalysisBackgroundCommand.applyTo(AnalysisBackgroundCommand.java:58)
at ghidra.framework.plugintool.mgr.BackgroundCommandTask.run(BackgroundCommandTask.java:102)
at ghidra.framework.plugintool.mgr.ToolTaskManager.run(ToolTaskManager.java:319)
at java.base/java.lang.Thread.run(Thread.java:829)
The strange thing is...the data in the plugin is there but in a different path!
The correct path is data/psyq/430 with zero! I got this error in other projects as well, seems somehow the last digit is missing, if I symlink the path 43->430 it works but is just a workaround.
I tried a couple of times to delete ghidra and start over, but still the problem is there.
I am using ghidra on fedora linux with Java 11
as always thank you for this amazing plugin!
Vagrant Story passes 0x800401ac to InitHeap
, but makes no use of system memory management and has its own separate heap.
Unfortunately 0x800401ac is right in the middle of the main exe, which occupies 0x80010000 - 0x80061fff, and due to the way psx_ldr sets up the segments the region from 0x800401a8 - 0x80061fff is configured as uninitialized when it actually contains code and data.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.