PS3 Apollo save tool (development thread)

I have just realized about a big obvious thing that I completely missed... :sco hmmthink: the internal PS3 load/save functions available for save-games can already encrypt and decrypt file contents (and sign the saves too)... Doh! hahahah

I ported flatz tools but now I think that this whole approach was a bit "overkill"... :cower: probably a bit too late to change, but for HDD saves I'm pretty sure that everything could have been done without the external PFD/SFO tools.

For saves on USB, that's not possible so signing/patching/resigning wouldn't be available... but for HDD saves it would simplify the code a lot... as long as you have the file encryption keys, the rest is just "load" or "save".

Note to self: think before you code
 
Last edited:
How are you doing the save btw ?
1) You create the save from inside apollo (without exiting) ?
2) When you create the save it appears the official (black) screen with the dialogs related to create the save ?
3) Incase the answer to 2 is affirmative... there is some way to create the save in a "stealth" mode ? (without dialogs), with the goal of generating/importing a lot of saves in a "hands free" mode ?

I dont remember other homebrews that creates saves
 
How are you doing the save btw ?
1) You create the save from inside apollo (without exiting) ?
2) When you create the save it appears the official (black) screen with the dialogs related to create the save ?
3) Incase the answer to 2 is affirmative... there is some way to create the save in a "stealth" mode ? (without dialogs), with the goal of generating/importing a lot of saves in a "hands free" mode ?

I dont remember other homebrews that creates saves

1/ yes, the save is created in Apollo, using the internal PS3 functions (in PSL1GHT, see /ppu/include/sysutil/save.h )

2/ yes, you can make the official "black" save screen to show up when saving.

3/ I'm actually using the internal "auto-save" function so I don't show that annoying black saving screen :) , I just run a "saving" thread in the background when the settings have changed in the app. ;)

yes, I think that most homebrews I've seen are saving settings manually in a file, but not creating actual PS3 saves.
 
Last edited:
Nice, then i really think what we was discussing here is going to work, as you mentioned, "not tried yet, theory only", but yeah it smells good :encouragement:
https://www.psx-place.com/threads/apollo-save-tool-v0-6-5-released.28124/page-3#post-229040
https://www.psx-place.com/threads/apollo-save-tool-v0-6-5-released.28124/page-3#post-229049

well, I might have to try my theory after all, so I can dodge a nasty bullet:

I was doing tests yesterday applying Bruteforce data patches to save-games, and I found a critical issue. After 2 or 3 times the app do "decrypt -> patch -> encrypt -> resigns" some saves using the PFD tools, the application freezes and dies. I assume there's a memory leak somewhere in the encrypt/decrypt part of PFD tools, and debugging that would take a long time. :( the code is doing a lot of stuff there, not nice to start messing with it. :sang banghead:

So, instead of going heads-on with the bug, I'll try the Buddha trick (there's no spoon, there's no bug) and check my theory using the internal PS3 save functions. If I can get the ps3 to load and decrypt a save file from HDD (other than my Apollo settings) then I'll go that way. There won't be cheat patches available when browsing USB, but still is better than getting a dead app after 2 clicks.

note: I hope that the PS3 doesn't have any security check like "hey why are you trying to access a save-file from another TITLE_ID?!" ... I recall Yakuza games detecting Yakuza saves from older games and giving you prizes for that, so hopefully there's no security check on that. (Only the "protected file ID", but that's a key that we already have from BSD database).
 
Last edited:
There are some unknown fields inside the attribute named PARAMS of PARAM.SFO btw
https://www.psdevwiki.com/ps3/PARAM.SFO#PARAMS

When i made that table and i was researching about all that i could identify some weird stuff that seems to be used for protection purposes (probably involved with the encryption used in the bruteforce process), also some counters for different stuff, and yeah the yakuza games uses some of that extended features (other games doesnt)
Actually... if i remember right there is a counter (or some value) related with the import/export to USB... if i remember right at the time you import/export to USB the PARAM.SFO is updated because one of the counters increases or/and changes his value (and consequently the PFD is updated too)
I tryed to explain all my findings in that psdevwiki page (and in the talk page too, there is a more extended explaination... partially speculative)

At that time i was not using any code to process the data from my guinea pigs experiments, so it was very time consuming and i only had a very limited amount of samples
But now that you are managing saves massivelly with apollo maybe you are going to find something... i suggest you to keep an eye at all that values stored inside PARAMS because im sure some/all of them are related with "extended" save features
 
Last edited:
thanks for all the info @sandungas , great resource! :encouragement:

btw, I can confirm that my theory works!!! :D

I was able to load a save-game (Asura's Wrath) from within Apollo using the internal PS3 save-game handling functions (and the correct protected file key). I've got the decrypted PAYLOAD data file served directly by the ps3 :cool:
Then I injected the data back to the Asuras Wrath savegame, and everything was saved, updated, encrypted, and signed internally. Just to confirm, I went to the game, and the save-game was loaded correctly with no issues.

Next step is to clean-up the code for this new method to decrypt/inject/encrypt files so I can use it with the game genie patches.

Everything looking good ahead, I'm back on track (thanks to the fact that they didn't went berserk with the security... no check on who's loading/saving what)
 
After I cleaned up the code, everything is working nicely and the patches are applied properly (thanks to the internal ps3 save/load functions).
Only drawback with this new solution is that cheats can only be applied and signed to saves on the HDD. Saves on usb will only show options to unlock, remove account/console id, export to zip, and copy.

Regarding cheat patches, right now only Game Genie cheat codes are applied, so cheats that need a checksum hash (crc, md5, etc) shouldn't be used or you'll end up with an invalid save.

Next steps: release this new version, get feedback about issues or bugs, and add support to the Bruteforce data patch format.
 
Now that v0.9 is out I got back working on the BSD script format patches. :)
I've implemented the 'search' and 'write' commands. I need to implement many others before I can release a new version.

To prioritize work, I did some grep & count, to find which commands are the "must have" and which ones can be left for later.
(for example, 'insert' is only used in 2 games, and 'copy' is never used)

Also to speed up things, I checked how many hash commands I'd need to include (number is how many games use it):
// crc32 (494)
// md5 (75)
// sha1 (95)
// crc_X (34)
// adler32 (23)
// hmac_sha1 (8)
// sha256 (8)
// md2 (3)
// eacheck (2)
// crc16 (0)
// adler16 (0)
// md4 (0)
// sha384 (0)
// sha512 (0)

I'll probably release a version with the most widely-used stuff (crc, md5, sha1) and then add the remaining exotic cases later.

btw, here's some more info about BSD's script format:
https://github.com/bucanero/apollo-ps3/blob/master/docs/_EXAMPLE.ps3savepatch
 
Last edited:
Now that v0.9 is out I got back working on the BSD script format patches. :)
I've implemented the 'search' and 'write' commands. I need to implement many others before I can release a new version.

To prioritize work, I did some grep & count, to find which commands are the "must have" and which ones can be left for later.
(for example, 'insert' is only used in 2 games, and 'copy' is never used)

similar, to speed up things, I checked how many hash commands I'd need to include (number is how many games use it):


I'll probably release a version with the most widely-used stuff (crc, md5, sha1) and then add the remaining exotic cases later.

btw, here's some more info about BSD script format:
https://github.com/bucanero/apollo-ps3/blob/master/docs/_EXAMPLE.ps3savepatch

The following site has a lot of useful info.... I suggest you to contact @chaoszage
https://bruteforcesavedata.forumms.net/

I like your approach of apply the law of vital few (Pareto Principle). That principle is one of the basis of Rapid Application Development methodology ;)
 
I like your approach of apply the law of vital few (Pareto Principle). That principle is one of the basis of Rapid Application Development methodology ;)

I had no idea about the Pareto principle, I was mostly trying to optimize time and results. :D

To be honest, when I saw the source code for the BSD patching funcs I was a bit afraid, ~5000 lines of VB code that I would have to understand and re-write in C. So I had to choose between running away :-p or taking it slow and work by chunks of functionality that I could implement and test in increments. (Also smaller increments are easier to release.)

Hopefully at some point I'll be able to implement 100% of BSD script language, but meanwhile having something like 95 ~ 98% is good too. :)
 
the BSD script implementation is moving forward, I've added some more commands and hash algos :)

commands:
+ set
+ range

hashes:
+ crc32
+ crc32big
+ crc16
+ custom crc(16/32)
+ adler32

pending stuff to complete for a first release:
- md5 / md5_xor / sha1
- add() / wadd() / dwadd()

I've been using (and abusing :-p ) BSD to test and compare my results with aldo's app. So far so good, my code is giving the same output as the original Bruteforce data app for the implemented commands/hashes.

Some debugging example:
Code:
set pointer:eof+1
set range:0x13FEF,pointer
set [hash]:CRC32big
set [hash]:CRC32
write at 0x13F00:[hash]
set [hash]:CRC16
set crc_bandwidth:16
set crc_polynomial:0x1021
set crc_initial_value:0xFFFF
set crc_output_xor:0
set crc_reflection_input:0
set crc_reflection_output:0
set [hash]:CRC
set crc_bandwidth:32
set crc_polynomial:0xEDB88320
set crc_initial_value:0
set crc_output_xor:0
set crc_reflection_input:1
set crc_reflection_output:0
set [hash]:CRC

Applying [Hash crc check] to './PAYLOAD'...POINTER = 81920 (0x14000)
RANGE = 81903 (0x13FEF) - 81920 (0x14000)
Var name = hash
len 17 CRC32Big HASH = 34C2BC7F
Var name = hash
len 17 CRC32 HASH = E3148DC3
Getting value for [hash]
Wrote 4 bytes ([hash]) to 0x13F00
Var name = hash
len 17 CRC16 HASH = 6EBF
Var name = hash
ref.in 0 ref.out 0
len 17 Custom CRC16 HASH = A953
Var name = hash
ref.in 1 ref.out 0
len 17 Custom CRC32 HASH = 6F78280

once I complete the first batch of commands+hashes I'll start testing and see if Apollo can truly beat the savegame protections or not. :D
 
@aldostools , I was trying to implement the HMAC_SHA1 algo , and I'm missing the "TLOU_HMAC_KEY"
(I assume is for "The Last of Us" games)

could you share it?, as I couldn't find it in the source
thanks! :encouragement:
 
@aldostools , I was trying to implement the HMAC_SHA1 algo , and I'm missing the "TLOU_HMAC_KEY"
(I assume is for "The Last of Us" games)

could you share it?, as I couldn't find it in the source
thanks! :encouragement:

Public Const TLOU_HMAC_KEY As String = "xM;6X%/p^L/:}-5QoA+K8:F*M!~sb(WK<E%6sW_un0a[7Gm6,()kHoXY+yI/s;Ba"

or in C:

uint8_t TLOU_HMAC_KEY[64] = {0x78, 0x4D, 0x3B, 0x36, 0x58, 0x25, 0x2F, 0x70, 0x5E, 0x4C, 0x2F, 0x3A, 0x7D, 0x2D, 0x35, 0x51, 0x6F, 0x41, 0x2B, 0x4B, 0x38, 0x3A, 0x46, 0x2A, 0x4D, 0x21, 0x7E, 0x73, 0x62, 0x28, 0x57, 0x4B, 0x3C, 0x45, 0x25, 0x36, 0x73, 0x57, 0x5F, 0x75, 0x6E, 0x30, 0x61, 0x5B, 0x37, 0x47, 0x6D, 0x36, 0x2C, 0x28, 0x29, 0x6B, 0x48, 0x6F, 0x58, 0x59, 0x2B, 0x79, 0x49, 0x2F, 0x73, 0x3B, 0x42, 0x61};
 
Last edited:
Public Const TLOU_HMAC_KEY As String = "xM;6X%/p^L/:}-5QoA+K8:F*M!~sb(WK<E%6sW_un0a[7Gm6,()kHoXY+yI/s;Ba"

thanks! :encouragement: I didn't had time to test, so I hope I did it properly :D

almost all BSD commands and hashes have been implemented in v1.0.0 , except the compress/decompress feature.

Hash-wise, I think the only missing one that is actually used is crc64_ecma . I tried a few crc64 algos I found online but I couldn't make it match the results from Bruteforce data. I even tried changing reflection in/out settings but I always got different results. Perhaps we can check later which crc64 is the right one for BSD so I can implement it on the next release.
 
thanks! :encouragement: I didn't had time to test, so I hope I did it properly :D

almost all BSD commands and hashes have been implemented in v1.0.0 , except the compress/decompress feature.

Hash-wise, I think the only missing one that is actually used is crc64_ecma . I tried a few crc64 algos I found online but I couldn't make it match the results from Bruteforce data. I even tried changing reflection in/out settings but I always got different results. Perhaps we can check later which crc64 is the right one for BSD so I can implement it on the next release.

CRC64_ECMA and CRC64_ISO tables of 64bit, while CRC32 algorithms use table values of 32bit.

CRC64_ECMA uses a CRC table generated with the polynomial 0xC96C5795D7870F42
CRC64_ISO uses a CRC table generated with the polynomial 0xD800000000000000

The CRC table is generated with something like:
Code:
uint64_t CRC64_Table[0x100];

void GenerateTable64(uint64_t Poly64)
{
  for(int i = 0; i < 256; i++)
  {
    uint64_t CRC64 = i;
    for(int j = 0; j < 8; j++)
    {
      if(CRC64 & 1)
        CRC64 = (CRC64>>1) ^ Poly64;
      else
        CRC64 = (CRC64>>1);
    }
    CRC64_Table[i] = CRC64;
  }
}

The standard CRC32 tables use different tables depending of the endianness.
The CRC32 table for little endian use the polynomial 0xEDB88320
The CRC32 table for big endian use the polynomial 0x04C11DB7 (same as above but with the bits reversed)

Here are the tables with the generated values already precalculated. BTW your "MC02_table" is a CRC32 table big endian.
Private Function InitializeCRC32_little_endian()
Dim vararray As Variant, i As Integer
'polynomial: 0xEDB88320
On Local Error Resume Next
vararray = Array(&H0, &H77073096, &HEE0E612C, &H990951BA, &H76DC419, &H706AF48F, &HE963A535, &H9E6495A3, &HEDB8832, &H79DCB8A4, &HE0D5E91E, &H97D2D988, _
&H9B64C2B, &H7EB17CBD, &HE7B82D07, &H90BF1D91, &H1DB71064, &H6AB020F2, &HF3B97148, &H84BE41DE, &H1ADAD47D, &H6DDDE4EB, &HF4D4B551, &H83D385C7, _
&H136C9856, &H646BA8C0, &HFD62F97A, &H8A65C9EC, &H14015C4F, &H63066CD9, &HFA0F3D63, &H8D080DF5, &H3B6E20C8, &H4C69105E, &HD56041E4, &HA2677172, _
&H3C03E4D1, &H4B04D447, &HD20D85FD, &HA50AB56B, &H35B5A8FA, &H42B2986C, &HDBBBC9D6, &HACBCF940, &H32D86CE3, &H45DF5C75, &HDCD60DCF, &HABD13D59, _
&H26D930AC, &H51DE003A, &HC8D75180, &HBFD06116, &H21B4F4B5, &H56B3C423, &HCFBA9599, &HB8BDA50F, &H2802B89E, &H5F058808, &HC60CD9B2, &HB10BE924, _
&H2F6F7C87, &H58684C11, &HC1611DAB, &HB6662D3D, &H76DC4190, &H1DB7106, &H98D220BC, &HEFD5102A, &H71B18589, &H6B6B51F, &H9FBFE4A5, &HE8B8D433, _
&H7807C9A2, &HF00F934, &H9609A88E, &HE10E9818, &H7F6A0DBB, &H86D3D2D, &H91646C97, &HE6635C01, &H6B6B51F4, &H1C6C6162, &H856530D8, &HF262004E, _
&H6C0695ED, &H1B01A57B, &H8208F4C1, &HF50FC457, &H65B0D9C6, &H12B7E950, &H8BBEB8EA, &HFCB9887C, &H62DD1DDF, &H15DA2D49, &H8CD37CF3, &HFBD44C65, _
&H4DB26158, &H3AB551CE, &HA3BC0074, &HD4BB30E2, &H4ADFA541, &H3DD895D7, &HA4D1C46D, &HD3D6F4FB, &H4369E96A, &H346ED9FC, &HAD678846, &HDA60B8D0, _
&H44042D73, &H33031DE5, &HAA0A4C5F, &HDD0D7CC9, &H5005713C, &H270241AA, &HBE0B1010, &HC90C2086, &H5768B525, &H206F85B3, &HB966D409, &HCE61E49F, _
&H5EDEF90E, &H29D9C998, &HB0D09822, &HC7D7A8B4, &H59B33D17, &H2EB40D81, &HB7BD5C3B, &HC0BA6CAD, &HEDB88320, &H9ABFB3B6, &H3B6E20C, &H74B1D29A, _
&HEAD54739, &H9DD277AF, &H4DB2615, &H73DC1683, &HE3630B12, &H94643B84, &HD6D6A3E, &H7A6A5AA8, &HE40ECF0B, &H9309FF9D, &HA00AE27, &H7D079EB1, _
&HF00F9344, &H8708A3D2, &H1E01F268, &H6906C2FE, &HF762575D, &H806567CB, &H196C3671, &H6E6B06E7, &HFED41B76, &H89D32BE0, &H10DA7A5A, &H67DD4ACC, _
&HF9B9DF6F, &H8EBEEFF9, &H17B7BE43, &H60B08ED5, &HD6D6A3E8, &HA1D1937E, &H38D8C2C4, &H4FDFF252, &HD1BB67F1, &HA6BC5767, &H3FB506DD, &H48B2364B, _
&HD80D2BDA, &HAF0A1B4C, &H36034AF6, &H41047A60, &HDF60EFC3, &HA867DF55, &H316E8EEF, &H4669BE79, &HCB61B38C, &HBC66831A, &H256FD2A0, &H5268E236, _
&HCC0C7795, &HBB0B4703, &H220216B9, &H5505262F, &HC5BA3BBE, &HB2BD0B28, &H2BB45A92, &H5CB36A04, &HC2D7FFA7, &HB5D0CF31, &H2CD99E8B, &H5BDEAE1D, _
&H9B64C2B0, &HEC63F226, &H756AA39C, &H26D930A, &H9C0906A9, &HEB0E363F, &H72076785, &H5005713, &H95BF4A82, &HE2B87A14, &H7BB12BAE, &HCB61B38, _
&H92D28E9B, &HE5D5BE0D, &H7CDCEFB7, &HBDBDF21, &H86D3D2D4, &HF1D4E242, &H68DDB3F8, &H1FDA836E, &H81BE16CD, &HF6B9265B, &H6FB077E1, &H18B74777, _
&H88085AE6, &HFF0F6A70, &H66063BCA, &H11010B5C, &H8F659EFF, &HF862AE69, &H616BFFD3, &H166CCF45, &HA00AE278, &HD70DD2EE, &H4E048354, &H3903B3C2, _
&HA7672661, &HD06016F7, &H4969474D, &H3E6E77DB, &HAED16A4A, &HD9D65ADC, &H40DF0B66, &H37D83BF0, &HA9BCAE53, &HDEBB9EC5, &H47B2CF7F, &H30B5FFE9, _
&HBDBDF21C, &HCABAC28A, &H53B39330, &H24B4A3A6, &HBAD03605, &HCDD70693, &H54DE5729, &H23D967BF, &HB3667A2E, &HC4614AB8, &H5D681B02, &H2A6F2B94, _
&HB40BBE37, &HC30C8EA1, &H5A05DF1B, &H2D02EF8D)
For i = 0 To 255
crc32table(i) = vararray(i)
Next
End Function

Private Sub InitializeCRC32_big_endian()
Dim vararray As Variant, i As Integer
'polynomial: 0x04C11DB7
On Local Error Resume Next
vararray = Array(&H0, &H4C11DB7, &H9823B6E, &HD4326D9, &H130476DC, &H17C56B6B, &H1A864DB2, &H1E475005, &H2608EDB8, &H22C9F00F, &H2F8AD6D6, _
&H2B4BCB61, &H350C9B64, &H31CD86D3, &H3C8EA00A, &H384FBDBD, &H4C11DB70, &H48D0C6C7, &H4593E01E, &H4152FDA9, &H5F15ADAC, &H5BD4B01B, &H569796C2, &H52568B75, &H6A1936C8, &H6ED82B7F, &H639B0DA6, &H675A1011, &H791D4014, &H7DDC5DA3, &H709F7B7A, _
&H745E66CD, &H9823B6E0, &H9CE2AB57, &H91A18D8E, &H95609039, &H8B27C03C, &H8FE6DD8B, &H82A5FB52, &H8664E6E5, &HBE2B5B58, &HBAEA46EF, &HB7A96036, &HB3687D81, &HAD2F2D84, &HA9EE3033, &HA4AD16EA, &HA06C0B5D, &HD4326D90, &HD0F37027, &HDDB056FE, _
&HD9714B49, &HC7361B4C, &HC3F706FB, &HCEB42022, &HCA753D95, &HF23A8028, &HF6FB9D9F, &HFBB8BB46, &HFF79A6F1, &HE13EF6F4, &HE5FFEB43, &HE8BCCD9A, &HEC7DD02D, &H34867077, &H30476DC0, &H3D044B19, &H39C556AE, &H278206AB, &H23431B1C, &H2E003DC5, _
&H2AC12072, &H128E9DCF, &H164F8078, &H1B0CA6A1, &H1FCDBB16, &H18AEB13, &H54BF6A4, &H808D07D, &HCC9CDCA, &H7897AB07, &H7C56B6B0, &H71159069, &H75D48DDE, &H6B93DDDB, &H6F52C06C, &H6211E6B5, &H66D0FB02, &H5E9F46BF, &H5A5E5B08, &H571D7DD1, _
&H53DC6066, &H4D9B3063, &H495A2DD4, &H44190B0D, &H40D816BA, &HACA5C697, &HA864DB20, &HA527FDF9, &HA1E6E04E, &HBFA1B04B, &HBB60ADFC, &HB6238B25, &HB2E29692, &H8AAD2B2F, &H8E6C3698, &H832F1041, &H87EE0DF6, &H99A95DF3, &H9D684044, &H902B669D, _
&H94EA7B2A, &HE0B41DE7, &HE4750050, &HE9362689, &HEDF73B3E, &HF3B06B3B, &HF771768C, &HFA325055, &HFEF34DE2, &HC6BCF05F, &HC27DEDE8, &HCF3ECB31, &HCBFFD686, &HD5B88683, &HD1799B34, &HDC3ABDED, &HD8FBA05A, &H690CE0EE, &H6DCDFD59, &H608EDB80, _
&H644FC637, &H7A089632, &H7EC98B85, &H738AAD5C, &H774BB0EB, &H4F040D56, &H4BC510E1, &H46863638, &H42472B8F, &H5C007B8A, &H58C1663D, &H558240E4, &H51435D53, &H251D3B9E, &H21DC2629, &H2C9F00F0, &H285E1D47, &H36194D42, &H32D850F5, &H3F9B762C, _
&H3B5A6B9B, &H315D626, &H7D4CB91, &HA97ED48, &HE56F0FF, &H1011A0FA, &H14D0BD4D, &H19939B94, &H1D528623, &HF12F560E, &HF5EE4BB9, &HF8AD6D60, &HFC6C70D7, &HE22B20D2, &HE6EA3D65, &HEBA91BBC, &HEF68060B, &HD727BBB6, &HD3E6A601, &HDEA580D8, _
&HDA649D6F, &HC423CD6A, &HC0E2D0DD, &HCDA1F604, &HC960EBB3, &HBD3E8D7E, &HB9FF90C9, &HB4BCB610, &HB07DABA7, &HAE3AFBA2, &HAAFBE615, &HA7B8C0CC, &HA379DD7B, &H9B3660C6, &H9FF77D71, &H92B45BA8, &H9675461F, &H8832161A, &H8CF30BAD, &H81B02D74, _
&H857130C3, &H5D8A9099, &H594B8D2E, &H5408ABF7, &H50C9B640, &H4E8EE645, &H4A4FFBF2, &H470CDD2B, &H43CDC09C, &H7B827D21, &H7F436096, &H7200464F, &H76C15BF8, &H68860BFD, &H6C47164A, &H61043093, &H65C52D24, &H119B4BE9, &H155A565E, &H18197087, _
&H1CD86D30, &H29F3D35, &H65E2082, &HB1D065B, &HFDC1BEC, &H3793A651, &H3352BBE6, &H3E119D3F, &H3AD08088, &H2497D08D, &H2056CD3A, &H2D15EBE3, &H29D4F654, &HC5A92679, &HC1683BCE, &HCC2B1D17, &HC8EA00A0, &HD6AD50A5, &HD26C4D12, &HDF2F6BCB, _
&HDBEE767C, &HE3A1CBC1, &HE760D676, &HEA23F0AF, &HEEE2ED18, &HF0A5BD1D, &HF464A0AA, &HF9278673, &HFDE69BC4, &H89B8FD09, &H8D79E0BE, &H803AC667, &H84FBDBD0, &H9ABC8BD5, &H9E7D9662, &H933EB0BB, &H97FFAD0C, &HAFB010B1, &HAB710D06, &HA6322BDF, _
&HA2F33668, &HBCB4666D, &HB8757BDA, &HB5365D03, &HB1F740B4)
For i = 0 To 255
crc32table(i) = vararray(i)
Next
End Sub

0x04C11DB7 is the official polynomial used in the big endian CRC32 of PKZip, WinZip and Ethernet.
 
Last edited:
Some notes about the "Game Genie" patch codes for future reference:

Here is an updated list of codes... it includes the available info for codes 0,1,2,3,5,6,7,8,9,A,C (Code 6 is very hard to understand)
Code:
___________________________________________________
Standard Code types 0/1/2: Write Code
0TXXXXXX 000000YY
1TXXXXXX 0000YYYY
2TXXXXXX YYYYYYYY
  XXXXXX = Address / Offset to write to
               YY = 8-Bit value to write
             YYYY = 16-Bit value to write
         YYYYYYYY = 32-Bit value to write
 T = Offset Type
     0 = From start of the data
     8 = From found from a search
___________________________________________________
Code Type 3: Increase / Decrease Code
3TXXXXXX YYYYYYYY
 XXXXXX  = Address
         YYYYYYYY = Bytes to Add/Sub
 T = Byte Value & Offset Type
     0 = Add 1 Byte  000000YY
     1 = Add 2 Bytes 0000YYYY
     2 = Add 4 Bytes YYYYYYYY
     4 = Sub 1 Byte  000000YY
     5 = Sub 2 Bytes 0000YYYY
     6 = Sub 4 Bytes YYYYYYYY
     8 = Offset from Pointer; Add 1 Byte  000000YY
     9 = Offset from Pointer; Add 2 Bytes 0000YYYY
     A = Offset from Pointer; Add 4 Bytes YYYYYYYY
     C = Offset from Pointer; Sub 1 Byte  000000YY
     D = Offset from Pointer; Sub 2 Bytes 0000YYYY
     E = Offset from Pointer; Sub 4 Bytes YYYYYYYY
___________________________________________________
Code Type 4: Multi Write/Value
4TXXXXXX YYYYYYYY
4NNNWWWW VVVVVVVV
  XXXXXX = Address / Offset from Pointer
         YYYYYYYY = Bytes to Write / 8/16/32-Bit value
 NNN = Number of times to repeat Write
    WWWW = Increases address by (in bytes)
         VVVVVVVV = Increases value by
 T = Bit Size of YYYYYYYY
     0 =  8-Bit Address / Start of the data
     1 = 16-Bit Address / Start of the data
     2 = 32-Bit Address / Start of the data
     8 =  8-Bit Pointer / Offset from a search; 1 Byte  (Writes 000000YY)
     9 = 16-Bit Pointer / Offset from a search; 2 Bytes (Writes 0000YYYY)
     A = 32-Bit Pointer / Offset from a search; 4 Bytes (Writes YYYYYYYY)
___________________________________________________
Code Type 5: Copy/Paste Bytes
5TXXXXXX ZZZZZZZZ
5TYYYYYY 00000000
  XXXXXX = Offset to copy from
  YYYYYY = Offset to copy to / Paste bytes
         ZZZZZZZZ = Number of bytes to copy
 T = Offset Type
     0 = Address / Start of the data
     8 = Pointer / Offset from a search
___________________________________________________
Code Type 6: Pointer codes
6TWX0Y0Z VVVVVVVV
 T = Data size of VVVVVVVV
     0 =  8-Bit Address / Start of the data
     1 = 16-Bit Address / Start of the data
     2 = 32-Bit Address / Start of the data
     8 =  8-Bit Pointer / Offset from a search; 1 Byte  (Writes 000000YY)
     9 = 16-Bit Pointer / Offset from a search; 2 Bytes (Writes 0000YYYY)
     A = 32-Bit Pointer / Offset from a search; 4 Bytes (Writes YYYYYYYY)
  W = operator:
      0  = Read "address" from file
      1X = Move pointer from obtained address ?? (X = 0:add, 1:substract, 2:multiply)
      2X = Move pointer ?? (X = 0:add, 1:substract, 2:multiply)
      4X = Write value: X=0 at read address, X=1 at pointer address
     Y = flag relative to read add (very tricky to understand)
       Z = flag relative to current pointer (very tricky to understand)
         VVVVVVVV = Data
___________________________________________________
Code Type 7: Add Write
7TXXXXXX YYYYYYYY = Add Write (T: 0=1byte/1=2byte/2=4byte)
 T = Bit Size
     0 = 8 bit (1 byte)
     1 = 16 bit (2 bytes)
     2 = 32 bit (4 bytes)
  XXXXXX = Address
         YYYYYYYY = Value to add
___________________________________________________
Code Type 8: Search / Pointer Command (Use Bytes to Search with)
8TFFGGGG HHHHHHHH
 T = Offset Type
     0 = Normal
     8 = Offset from Pointer (Can essentially stack pointers)
  FF = Amount of Times to Find until Write
    GGGG = Size of data to be found
         HHHHHHHH = Raw data to search for, use Multiple Lines if Needed
This command is followed by another pointer command (08*, 18*, 28*, 58*, 48*, 49*, 4A*, 9*, A8*, etc)
Example 1:
80030002 FFFF0000 - Searches for 2 bytes FFFF Three Times Until Writes
18000000 00007FFF - After the Searched Value is Found, Replaces FFFF with 7FFF
Example 2:
80040006 FFFF0000 - Searches for 6 bytes FFFF0000FFFF Four Times Until Writes
FFFF0000 00000000 - Search Code Extended
4A000000 7F7F7F7F - After the Searched Value is Found, Writes 4 bytes 7F7F7F7F two times
40020008 00000000 - Multi Code 2nd line - repeat 2 times, increase address by 8, increase value by 0
___________________________________________________
Code Type 9: Pointer Manipulator
9Y000000 XXXXXXXX
 Y = Operator
     0 = Move pointer to offset in address XXXXXXXXX
     2 = Step forward
     3 = Step backward
     4 = Step back from end of file
         XXXXXXXX = Amount to Offset
Put this after the Pointer Commands (8*, C*) and it will offset from the Pointer.
___________________________________________________
Code Type A: Mass Byte Write
ATXXXXXX YYYYYYYY
ZZZZZZZZ ZZZZZZZZ
 T = Offset Type
     0 = Address
     8 = Offset from Pointer
  XXXXXX = Writes to this Address
         YYYYYYYY = Amount of Bytes to Write
  Z = Bytes to Write (GOES FROM LEFT TO RIGHT, Does Not Flip the Values)
Example:
A0004510 0000000F - Write 15 bytes to address 4510
11223344 55667788 - First 8 bytes to Write
99AABBCC DDEEFF00 - Remaining 7 bytes to Write
___________________________________________________
Code Type C: Search / Pointer Command 2: (Use Bytes from Offset to Search with)
CTFFGGGG HHHHHHHH
 T = Offset Type
     0 = Search Forwards from Address Given
     4 = Search Backwards from Address Given
     8 = Offset from Pointer; Search Forwards from Address Given
     C = Offset from Pointer; Search Backwards from Address Given
  FF = Amount of Times to Find until Write
    GGGG = Amount of Bytes to Search
         HHHHHHHH = Bytes to Search, use Multiple Lines if Needed
This command is followed by another pointer command (08*, 18*, 28*, 58*, 48*, 49*, 4A*, 9*, A8*, etc)
 
Last edited:
Here is an updated list of codes... it includes the available info for codes 0,1,2,3,5,6,7,8,9,A,C (Code 6 is very hard to understand)

thanks @aldostools , I've updated the docs in the Apollo project to keep this information available:
https://github.com/bucanero/apollo-ps3/blob/master/docs/gamegenie.txt

btw: a few Game genie code types are still missing from Apollo, but as with BSD commands, I prioritized the most used ones :)

Right now I want to try adding the compress/decompress feature so most of the "critical abilities" from Bruteforce Data are supported by Apollo. Also, I went back to the custom encrypt/decrypt by pfdtools, so I'll re-add the possibility to patch cheats on USB saves in the next release.
 

Similar threads

Back
Top