Alex

Lib Enigma - A PlayStation 1/2 CD Image C Library For Patching And Identification (Spiritual Successor To PPF)

by Alex Free

Enigma: a person or thing that is mysterious, puzzling, or difficult to understand. Paradox: a seemingly absurd or self-contradictory statement or proposition that when investigated or explained may prove to be well founded or true.

This is a C library that can be used in your program to:

Examples

Note: these are also compiled for multiple operating systems on the releases page under assets.

Homepage GitHub PSX Place Thread

Table Of Contents

Downloads

Get the latest as a submodule for your project:

git add submodule https://github.com/alex-free/lib-enigma.

v1.0.2 (4/22/2026)

Changes:


Previous versions.

Usage

From lib-enigma.h

// Structure of sector: sector_sync_header_len + sector_user_data_len + sector_edc_ecc_len.
#define SECTOR_SYNC_HEADER_LEN 0x18
#define SECTOR_USER_DATA_LEN 0x800
#define SECTOR_EDC_LEN 0x04
#define SECTOR_ECC_LEN 0x114
#define SECTOR_RAW_LEN 0x930
#define PREGAP 150

// Sector Read Funcs
int read_sector_raw(FILE *bin, unsigned int sector_number, unsigned char * sector_buf); // Read an entire 2352 byte sector into sector_buf. If requested sector does not exist (i.e. not enough sectors in disc image for sector requested), it returns 2. If it successfully reads the sector, it returns 1. If it fails to read the sector but the sector exists, it returns 0.

int read_sector_user_data(FILE *bin, unsigned int sector_number, unsigned char * sector_buf); // Read only the user data (real data) into sector_buf. This excludes sync header, EDC, or ECC. If requested sector does not exist (i.e. not enough sectors in disc image for sector requested), it returns 2. If it successfully reads the sector, it returns 1. If it fails to read the sector but the sector exists, it returns 0.

int read_sector_edc(FILE *bin, unsigned int sector_number, unsigned char * sector_buf); // Read only the edc data (checksum of the sector used by ECC during disc error repair attempts) into sector_buf. This excludes sync header, user data, or ECC. If requested sector does not exist (i.e. not enough sectors in disc image for sector requested), it returns 2. If it successfully reads the sector, it returns 1. If it fails to read the sector but the sector exists, it returns 0.

int read_sector_ecc(FILE *bin, unsigned int sector_number, unsigned char * sector_buf); // Read only the ecc data (repair data used during disc error repair attempts when EDC verification mismatches) into sector_buf. This excludes sync header, user data, or EDC. If requested sector does not exist (i.e. not enough sectors in disc image for sector requested), it returns 2. If it successfully reads the sector, it returns 1. If it fails to read the sector but the sector exists, it returns 0.

// Identification functions.
const char * get_psx_exe_gameid(FILE *bin, char *volume_creation_timestamp);
int is_ps_cd(FILE *bin); // returns 1 if `bin` is a PlayStation 1 or 2 CD image in MODE2/2352 format. Returns 0 if it is not. Should be called before any of the functions below.

void get_volume_creation_timestamp(FILE *bin, char *volume_creation_timestamp); // sets volume_creation_timestamp with value from bin file. Useful for identifying PSX.EXE boot file games that are not yet in the library's database and are not automatically identified using get_boot_file_name(). If get_boot_file_name() returns `PSX.EXE`, you can use this to identify it uniquely, as many discs are sharing that boot file name.

int get_boot_file_name(FILE *bin, char *bootfile); // Returns boot file name in `bin` as `char *boot_file`. Supports most if not all PSX.EXE games as well as all SYSTEM.CNF games. Returns 1 on success. Returns 0 on failure. Returns 2 if a PSX.EXE game was unable to be verified by the internal database.

int id_rev(FILE *bin, const unsigned int difference_offset, const unsigned char old_byte, const unsigned char new_byte); // Returns 0 if `bin` has `old_byte` at `difference_offset`. Returns 1 if `bin` has `new_byte` at `difference_offset`. Returns 2 if neither are found at `different_offset`.

// Size functions.

int cdr_minimum_requirement(FILE *bin); // Returns 0 if the bin file will fit on a 71 minute CD-R. Returns 1 if at least a 74 minute CD-R is required. Returns 2 if an 80 minute CD-R is required.

unsigned int number_of_sectors(FILE *bin); // Returns the number of sectors in a disc image.

// Patching functions.
void bin_patch(FILE *bin,
               const unsigned char *pattern,
               int pattern_len,

               bool contains_unmatchable_bytes,
               
               const unsigned char *unmatchable_byte_offsets,
               int unmatchable_byte_offsets_len,
               
               const unsigned char *patch,
               int patch_len,

               const unsigned char *unpatchable_byte_offsets,
               int unpatchable_byte_offsets_len); // Custom 'Lossy' Patching by myself. Applies lossy patch (no hardcoded offsets). Unmatchable bytes is optional, please see example 3 for implementation details: https://github.com/alex-free/lib-enigma/tree/master/example-3-piracy-patcher

void apply_ppf(const unsigned char ppf[], unsigned int ppf_len, FILE *bin); // Apply PlayStation Patch File patch from unsigned char array.

void undo_ppf(const unsigned char ppf[], unsigned int ppf_len, FILE *bin); // Apply PlayStation Patch File patch from unsigned char array.

History

I have developed quite a few patchers for the PlayStation:

I grew very, very tired of rewriting the same functions for each of these. And then, when I fixed bugs/made improvements to one, all of the other patchers if using similar functions would need to be rewritten with the same improvements. This kept making less and less sense until I ended up making 2 different libraries (both now obsoleted by Lib-Enigma, PLEASE don’t use these):

The first was lib-ps-cd-id, which identifies the boot file of a PSX cd image bin file and if it is valid. This had many issues due to being the first library I ever wrote, and lack of understanding of the CD bin MODE2/2352 format. If the boot file of a bin file:

Then lib-ps-cd-id failed to identify it. There were also problems due to myself being inexpierenced with building libraries on how the syntax/return values should be handled, making it just akward/less flexible to implement (requiring specific names for your variables, etc.). I’ve fixed EVERYTHING mentioned with lib-enigma.

The second library I wrote was lib-ppf. YEARS ago, the almighty PARADOX group famous for PSX/Dreamcast during the turn of the century (Sega bribed them with stock in return of leaving the poor Dreamcast alone, totally happened trust me bro) created one of if not THE best patching formats ever. Incredibly, it is still popular with random unrelated things like Super Mario 64 hacking. But it always originally was PlaystationPatchFile (PPF). There were 3 different versions. The last including support to do things like fancy descriptions during the patch, as well as optionally including data to undo the patch and restore your bin file back to how it was originally. It also had 4GB+ file (so DVD-DL is fine) support.

Anyways, I saw this problem. Patching LibCrypt protection for PSX games sucked in early 2023. You needed to do so much stuff manually. You needed to find the PPF patch for your LibCrypt game, hopefully it was the correct revesion too since this format is very hard-coded. Hopefully the patch didn’t have a cracktro (or did if your into that). Sometimes you needed DOSBOX to run some exotic patch tool. And then you needed to specify the bin file your patching. Why?? PARADOX released the source code to the PPF patcher/creator in like 2001. So I thought, why does this have to suck? Can’t we just identify what the bin file is, what boot file and revision, and then apply the correct patch? And why do we even need external patch files? Can’t all of this be in one single .exe?

Well, yes. I took the patcher for linux source code that was released by PARADOX way back when. And I had one goal. I didn’t want to modify anything really, except for one single goal. I wanted to turn the patcher into a library. I wanted to be able to call a function, and give it an unsigned char array. Said unsigned char array was just a PPF patch file’s bytes. This meant we could just make sense. You give a program a PSX bin file. The program detects what the bin file is (magic) and then figures out exactly what patch will defeat this protection. It loads the patch from the executable data itself and applies it. One single file to modify your game to remove this protection. And it’s not just LibCrypt, anything really. English translations are in PPF format too. Super Mario 64 ROM hacks as well. You can use PPF to do anything with a file, if it’s a hardcoded patch.

And before you tell me I stole the code, please read what PARADOX put in the source code:

 *     ApplyPPF3.c (Linux Version)
 *     written by Icarus/Paradox
 *
 *     Big Endian support by Hu Kares.
 *
 *     Applies PPF1.0, PPF2.0 & PPF3.0 Patches (including PPF3.0 Undo support)
 *     Feel free to use this source in and for your own
 *     programms.

This was the early 2000s. If they were OK with it being used in even closed source programs, then I think the 3-BSD license is more then acceptable. Also, at the point that I’ve modified it, it doesn’t even do the same thing nor is it designed too. Using memory/RAM/executable data is very different then reading a patch file and using it as a reference like the original PARADOX patcher. It’s actually kinda sad no one else but me saw the potentional in this. And again, much code is rewritten for memory data vs reading a patch file. I’d like to think the original PARADOX team would be proud.

I have much respect for the PPF format, and have so far seen no need to modify it. If I ever did, I would declare it as PPF v4.0, but PPF v3.0 again supports even DVD-DL, fancy descriptions, undoing the patch previously applied, etc. They maxxed out the hard-coded patcher format in the early 2000s and always will be legends. Their ‘loosley open source declared format’ is still relevent today as discussed due to how well it does what it was designed to do…

Okay enough PARADOX praising… But yes, it makes sense to make this a library. You can still make a very much sub 1MB portable executable self-containing a PPF patch, and have the user just drag the file to be patched into the executable on i.e. Windows and have it 100% automatic. And I just want to make it clear, we all start from somewhere. My first C program was written horribly in 2020, and even in 2023 this was really hard to figure out some random 90s C code and how it worked. But I did thank god, and it has always matched 1 to 1 with using the official patcher vs this library from what I’ve tested (including advanced things like undo support and fancy descriptions). So surprisingly I’ve never had to fix any bugs with this lib-ppf technology I’ve created from thier original work, since I stuck strickly to the philosphy of (if it does this with a file, it would do this with RAM/memory/executable data that is self-contained).

So really, it only makes sense to combine this work with the very much improved boot file detection/bin file validator functions I was already working on in the original lib-ps-cd-id. Hence, lib-enigma was born.

I also saw fit that some other functions be added. I added one to detect if the CD image is too large to fit on certain CD-R capacities (int cdr_minimum_requirement(FILE *bin)). The PSX80MP patcher adds enough dummy data to an existing PSX bin file to make it work with 80 minute CD-Rs correctly, so this may be important to know by a patcher so the user doesn’t waste a rare 71 minute or 74 minute CD-R.

Another thing is the volume creation timestamp. What this does is figure out WHEN the original file was generated. In 1994 and early 1995, Sony specified all game executables should be named PSX.EXE and located in the root directory. The PSX BIOS looks for either a PSX.EXE executable file in the root directory, or it looks for a SYSTEM.CNF text file to find a custom named file. In early 1995, Sony specified newer games should start using the serial number on the CD case as the executable name, and therefore use a SYSTEM.CNF file to specify it. This led to a problem no one really saw a need to solve for a long time. How do you identify WHAT a PSX.EXE game is? The first real neccesity was when the MemCardPro/GameID devices became prevalent. While other soft-mods just ignored the uniqueness of the PSX.EXE executables and sent that as GameID. I took a further look. The first idea was to do some kind of checksum on the executable. This idea died quite quickly due to a few things. For one, most PSX.EXE games are early Japanese, so english translations are pretty common like for King’s Feild. Once patched, the checksum doesn’t match. Another issue with checksums is hacks, or even just revision differences. While Lib-Enigma can detect what revision a game is with additional checking functions, you shouldn’t have to if you don’t care what the revision is and just want to figure out if it’s the same game in the end.

The last issue was about modifying CD images. There is a volume modification timestamp as well. But that can change if the image is edited. Which is finally why the volume creation timestamp is the only one which makes sense. It always stays the same, it is 16 unique bytes, and so far not a single collision. This was implemented for Tonyhax International, where it allowed a soft-mod for the first time to detect what the PSX.EXE game is.