OK, so turns out porting to different regions/languages is just a matter of finding new jump target, which isn't too difficult.

Prefer using jump targets which aren't part of the language data, so that exploit is compatible with all languages. I might go back and redo 3.10 for this reason.

Porting to different versions, means finding all the function addresses again, which is the time consuming bit.



porting to 3.11J (English language)

make memory dump for EE (PCSX2 save state, rename to zip extract, eeMemory.bin)
search DVDVIDEO-VMG = 0x014331c8
memory write breakpoint to find sb instruction at 0x00258BC8
decompile that in Ghidra, you'll see getDiscData is 0x258b98, and getDiscByte is 0x258ac8
inside getDiscByte, we can see that currentDiscBytePointer is 0x143b3e4 and endDiscBytePointer is 0x143b3e8
xref getDiscData, 20 locations, go through them till you find the buffer overflow described in my post which copies with size (a + b + c) * 8, it's the call at 0x257564
note destination of copy, which is 0x14351cc
so we control range 0x14351cc - 0x15B51B4 (0x14351cc + 3 * 0xffff * 8)
go to destination + roughly 0x6A76 and search for fpIndex (xrefs will be functions looking like setFpIndex and the OOB call as shown in my post)
fpIndex is at 0x143bc4a
OOB call is at 0x25ab44 (actually there are more than 1, but this one is executed first - set memory read breakpoint on fpIndex to find it)
note the base of the function pointer array, in this case 0x003b3050
dump the memory from base till 0x003b3050 + 4 * 0xffff = 0x3F304C, group into 4 bytes and search for jump targets that fit within overflow range
eg: searching for "14352... " I see some results
must also be 4 byte aligned
3.11 is actually pretty good, there are quite a few results that should work, if not you can try switching languages and there will be different jump targets to check
0x01522944 looks pretty good, it's at 0x3E4A74, so index would be (0x3E4A74-0x003b3050)/4 = 0xC689
ok, we have everything we need - let's make the IFO exploit file
the copy size should be at the same offset since that's part of the spec, so no need to change that
now run and break at the copy (0x257564), v1 is 0xffff so we're triggering the bug :)
set a memory write breakpoint for the byte just before currentDiscBytePointer (0x143b3e4 - 1), wait till its set by the sb instruction in getDiscData
now note down currentDiscBytePointer's value, it's 0x0143a94c (so will be +1 by the time we are writing currentDiscBytePointer)
goto that in the memory viewer to see where we're copying from
we can see the "ABOVE 3" note I wrote to myself just below it (just an arbitrary marker point), so we can work out that this corresponds to offset 0x000277c in the IFO
we write currentDiscBytePointer's same value, and then 0xffffff for endDiscBytePointer next to it
run again and make sure it overwrites the same value it already has (easy to get off-by-one here)
that's probably the hardest part done now, we are now overwriting fpIndex and payload space with controlled contents
break at writing fpIndex (0x143bc4a), and see it's corrupted by getDiscData
note down currentDiscBytePointer value, it's 0x0143b1b3
goto that in memory view and look what it's near to, we see that the 7e e0 fpIndex for 3.10 is just above
so we can count our offset will be at offset 0x2fe2 in the IFO
we wanted to corrupt that to 89 c6, which should lead to jumping to 0x01522944
run again and now break at the OOB call (0x25ab44)
sure enough we can trace it and see jump v0 which is 0x01522944 (we got lucky and already corrupted the thing that stops resetting fpIndex)
now we just need to run again to the copy, and break at writing 0x01522944 to find where to start our initial payload in the IFO
currentDiscBytePointer value is 0x01521ead, which is just above where we put payload for 3.10, at offset 0x2ba4
BOOM! We have arbitrary code execution.
for now, I haven't reimplemented everything needed by the loader, so we need to find a few functions to use in our loader - this will be improved in future
you need getBufferInternal (getBuffer is called inside getDiscByteInternal, 0x295518 in our case, and then getBufferInternal is called inside that, 0x2952f0 for us)
getDiscData (we already have it, 0x258b98)
pointToIFO (search for call to getDiscData, and it'll be near those calls - called like pointToIFO(param_1,0,0x80) and calls getDiscByteInternal inside) in our case 0x258a28
SifIopReset (0x20e7d8), SifInitRpc (0x208d80), SifExitRpc (0x208f20) - for these, find SifIopReboot first, which is easy because of "rom0:UDNL " string (see https://github.com/ps2dev/ps2sdk/blob/8b7579979db87ace4b0aa5693a8a560d15224a96/ee/kernel/src/iopcontrol.c#L82) and look at the calls inside that match
SifIopSync (0x20e958) - look for a call to SifIopReset and looping call just after
edit build.sh to place correct loading address and offsets, and recompile!
Insert fullpayload.bin into VIDEO_TS.IFO at offset 0x2ba4
test, and see ule boot successfully in pcsx2!


3.11 all (English language)
getDiscData and getDiscByte seem the same as in 3.11J
overflow call is also at 0x257564
fpIndex also 0x143bc4a
oob jump also at 0x0025A618
it's just the jump targets that are different
dump 0x3b3050 to 0x3b3050 + 0xffff * 4 = 0x3F304C
we have a nice one! 01500014 will work - same as we used for 3.10EU lol :)
that's at 0x3EA438, so index (0x3EA438-0x3b3050)/4 = 0xDCFA
so patch the IFO, same offset as for 3.11J (0x2fe2) to fa dc
now break at writing payload (0x1500014)
currentDiscBytePointer points to 0x014ff57d
nearest landmark is "ABOVE 3" string at 0x14ff41b
so payload goes at ABOVE 3 location in IFO + (0x014ff57d - 0x14ff41b) - 1 = 0x2954



hybrid 3.10 + 3.11
so starting with a 3.11 base VIDEO_TS.IFO
currentDiscBytePointer offset for 3.10 is 00002744
for 3.11 is 0000277c
copy 3.10 currentDiscBytePointer and endDiscBytePointer corruption to its offset (8 bytes at 00002744)
fpIndex for 3.10 is offset 00002faa, so copy those 2 bytes over
payload needs to be modified to load stage 2 differently, I just moved it from 0x3000 to 0x38000
payload for 3.10 is at 0x2bb4 copy that over




3.04 (M tested only so far, but probably all regions work)
getDiscData - 0x23e138
getDiscByte - 0x23e068
currentDiscBytePointer - 0x16ceee4
endDiscBytePointer - 0x16ceee8

0x23cb04 is the copy we want, but I actually decided to look at different buffer overflows in case it is useful for hybrid-ing, here they all are:

Location 	Destination 	Max Size 	End
0x23bd4c 	0x16c6d60 	0xffff * 0xc 	0x1786D54
0x23c48c 	0x16c79d8 	0xffff * 4 	0x17079D4
0x23cb04 	0x16c8cd4 	0xffff * 3 * 8 	0x1848CBC 	
0x23cc74 	0x16c8cd4 	0xffff * 4 	0x1708CD0

writing currentDiscBytePointer, it's value is 0x016ce444
offset in IFO is 0x2744 - uh on we have collision with 3.10, might not be possible to make hybrid disc with both of those
will need more crazy tricks to do that... we'll see
in mean time, doing 3.04 only disc

OOB call is at 0x23faac
fpIndex at 0x16cf74a
function pointer array - 0x95ace8
select 0x95ace8 to 0x95ace8 + 0xffff * 4 = 0x99ACE4
looking for jump targets, we have some starting with 0x018...
01800180 at 0x95CF40, so index (0x95CF40-0x95ace8)/4 = 0x0896
fpIndex offset in IFO is 0x2faa
payload offset in IFO is 0x2d00

getBufferInternal - 0x261548
pointToIFO - 0x23dfc8
getDiscData - 0x23e138
SifIopReboot - 0x291528
SifInitRpc - 0x208260
SifExitRpc - 0x208400
SifIopReset - 0x291358
SifIopSync - 0x2914d8
