Last active
July 12, 2024 23:43
-
-
Save safiire/9acb5ec8c34d7f8690e5 to your computer and use it in GitHub Desktop.
This is a C program to decrypt pokémon files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#define NICKNAMED(x) ((x & 0x80000000) >> 31) | |
#define IS_EGG(x) ((x & 0x40000000) >> 30) | |
#define SP_DEF_IV(x) ((x & 0x3e000000) >> 25) | |
#define SP_ATT_IV(x) ((x & 0x01f00000) >> 20) | |
#define SPE_IV(x) ((x & 0x000f8000) >> 15) | |
#define DEF_IV(x) ((x & 0x00007c00) >> 10) | |
#define ATT_IV(x) ((x & 0x000003e0) >> 5) | |
#define HP_IV(x) (x & 0x0000001f) | |
//// Global state of the prng | |
uint32_t prng_state = 0; | |
//// Set the seed of the prng | |
void seed_prng(uint32_t seed){ | |
prng_state = seed; | |
} | |
//// Get the next psuedo random value | |
uint16_t prng(void){ | |
prng_state = (0x41C64E6D * prng_state + 0x6073); | |
return prng_state >> 16; | |
} | |
///// Encrypted PC Box Pokemon Data Structure | |
typedef struct pkm_encrypted_t { | |
uint32_t pid; | |
uint16_t unused; | |
uint16_t checksum; | |
uint16_t encrypted[64]; | |
} pkm_encrypted_t; | |
//// Unencrypted PC Box Pokemon Block Shuffled | |
typedef struct pkm_block_shuffled_t { | |
uint32_t pid; | |
uint16_t unused; | |
uint16_t checksum; | |
unsigned char shuffled[4][32]; | |
} pkm_block_shuffled_t; | |
//// Unencrypted PC Pokemon Data Structure | |
typedef struct pkm_t { | |
uint32_t pid; | |
uint16_t unused; | |
uint16_t checksum; | |
/* Block A */ | |
uint16_t national_pokedex; | |
uint16_t held_item; | |
uint16_t ot_id; | |
uint16_t ot_secret_id; | |
uint32_t experience; | |
unsigned char friendship; | |
unsigned char ability; | |
unsigned char markings; | |
unsigned char original_language; | |
unsigned char hp_ev; | |
unsigned char attack_ev; | |
unsigned char defense_ev; | |
unsigned char speed_ev; | |
unsigned char sp_attack_ev; | |
unsigned char sp_defense_ev; | |
unsigned char cool_contest; | |
unsigned char beauty_contest; | |
unsigned char cute_contest; | |
unsigned char smart_contest; | |
unsigned char tough_contest; | |
unsigned char sheen_contest; | |
uint16_t sinnoh_ribbon_set1; | |
uint16_t sinnoh_ribbon_set2; | |
/* Block B */ | |
uint16_t move1; | |
uint16_t move2; | |
uint16_t move3; | |
uint16_t move4; | |
unsigned char move1_pp; | |
unsigned char move2_pp; | |
unsigned char move3_pp; | |
unsigned char move4_pp; | |
uint32_t move_pp_ups; | |
uint32_t ivs_and_stuff; | |
uint16_t hoenn_ribbon_set1; | |
uint16_t hoenn_ribbon_set2; | |
unsigned char some_flags1; | |
unsigned char some_flags2; | |
uint16_t unused1; | |
uint16_t egg_location_platinum; | |
uint16_t met_at_location_platinum; | |
/* Block C */ | |
unsigned char nickname[22]; | |
unsigned char unused2; | |
unsigned char hometown; | |
uint16_t sinnoh_ribbon_set3; | |
uint16_t sinnoh_ribbon_set4; | |
unsigned char unused3; | |
/* Block D */ | |
unsigned char ot_name[16]; | |
unsigned char date_egg_recieved[3]; | |
unsigned char date_met[3]; | |
uint16_t egg_location_diamond_perl; | |
uint16_t met_location_diamond_perl; | |
unsigned char pokerus; | |
unsigned char pokeball; | |
unsigned char met_at_level_ot_gender; | |
unsigned char encounter_type; | |
unsigned char hgss_pokeball; | |
unsigned char unused4; | |
} pkm_t; | |
//// Block shuffling table | |
typedef enum Block{A, B, C, D} Block; | |
Block block_shifts[][2][4] = { | |
/* Block Order, Inverse */ | |
{ {A, B, C, D}, {A, B, C, D} }, | |
{ {A, B, D, C}, {A, B, D, C} }, | |
{ {A, C, B, D}, {A, C, B, D} }, | |
{ {A, C, D, B}, {A, D, B, C} }, | |
{ {A, D, B, C}, {A, C, D, B} }, | |
{ {A, D, C, B}, {A, D, C, B} }, | |
{ {B, A, C, D}, {B, A, C, D} }, | |
{ {B, A, D, C}, {B, A, D, C} }, | |
{ {B, C, A, D}, {C, A, B, D} }, | |
{ {B, C, D, A}, {D, A, B, C} }, | |
{ {B, D, A, C}, {C, A, D, B} }, | |
{ {B, D, C, A}, {D, A, C, B} }, | |
{ {C, A, B, D}, {B, C, A, D} }, | |
{ {C, A, D, B}, {B, D, A, C} }, | |
{ {C, B, A, D}, {C, B, A, D} }, | |
{ {C, B, D, A}, {D, B, A, C} }, | |
{ {C, D, A, B}, {C, D, A, B} }, | |
{ {C, D, B, A}, {D, C, A, B} }, | |
{ {D, A, B, C}, {B, C, D, A} }, | |
{ {D, A, C, B}, {B, D, C, A} }, | |
{ {D, B, A, C}, {C, B, D, A} }, | |
{ {D, B, C, A}, {D, B, C, A} }, | |
{ {D, C, A, B}, {C, D, B, A} }, | |
{ {D, C, B, A}, {D, C, B, A} } | |
}; | |
//// Read an encrypted pkm file from disk | |
void read_pkm(char *filename, pkm_encrypted_t *pkm){ | |
FILE *fp = fopen(filename, "rb"); | |
int read = fread(pkm, sizeof(pkm_encrypted_t), 1, fp); | |
fclose(fp); | |
} | |
//// Decrypt pkm into unencrypted but block shuffled | |
pkm_block_shuffled_t *decrypt_pkm(pkm_encrypted_t *pkm){ | |
int i; | |
seed_prng(pkm->checksum); | |
for(i = 0; i < 64; i++){ | |
pkm->encrypted[i] ^= prng(); | |
} | |
return (pkm_block_shuffled_t *) pkm; | |
} | |
//// Unshuffle blocks | |
pkm_t *unshuffle_blocks(pkm_block_shuffled_t *shuffled){ | |
int i; | |
unsigned char temp[4][32]; | |
int shift_value = ((shuffled->pid & 0x3E000) >> 0xD) % 24; | |
Block *order = block_shifts[shift_value][0]; | |
for(i = 0; i < 4; i++){ | |
memcpy(temp[order[i]], shuffled->shuffled[i], 32); | |
} | |
memcpy(shuffled->shuffled, temp, 32 * 4); | |
return (pkm_t *) shuffled; | |
} | |
//// Is checksum valid? | |
bool is_valid_checksum(pkm_t *pokemon){ | |
int i; | |
uint32_t sum = 0; | |
uint16_t *data = (uint16_t *)pokemon; | |
data += 4; | |
for(i = 0; i < 64; i++){ | |
sum += data[i]; | |
} | |
sum &= 0xffff; | |
return sum == pokemon->checksum; | |
} | |
void print_pokemon_bytes(pkm_t *pokemon){ | |
int i; | |
unsigned char *bytes = (unsigned char *)pokemon; | |
for(i = 0; i < 136; i++){ | |
printf("%.2x ", bytes[i]); | |
} | |
} | |
//// Print out the pokemon | |
void print_pokemon(pkm_t *pokemon){ | |
printf("Printing Pokemon\n"); | |
printf("===============\n"); | |
printf("National Pokedex: #%u\n", pokemon->national_pokedex); | |
printf("PID: %u\n", pokemon->pid); | |
printf("Held Item: %u\n", pokemon->held_item); | |
printf("OT ID: %u\n", pokemon->ot_id); | |
printf("OT SID: %u\n", pokemon->ot_secret_id); | |
printf("Exp: %u\n", pokemon->experience); | |
printf("Friendship: %u\n", pokemon->friendship); | |
printf("EVs:\n\tHP: %u\n\tATT: %u\n\tDEF: %u\n\tSP-ATT %u\n\tSP-DEF: %u\n\tSPE: %u\n", | |
pokemon->hp_ev, pokemon->attack_ev, pokemon->defense_ev, pokemon->sp_attack_ev, pokemon->sp_defense_ev, pokemon->speed_ev); | |
printf("IVs:\n\tHP: %u\n\tATT: %u\n\tDEF: %u\n\tSP-ATT %u\n\tSP-DEF: %u\n\tSPE: %u\n", | |
HP_IV(pokemon->ivs_and_stuff), ATT_IV(pokemon->ivs_and_stuff), DEF_IV(pokemon->ivs_and_stuff), SP_ATT_IV(pokemon->ivs_and_stuff), | |
SP_DEF_IV(pokemon->ivs_and_stuff), SPE_IV(pokemon->ivs_and_stuff)); | |
printf("===============\n"); | |
} | |
int main(int argc, char **argv){ | |
char *filename = "squirtwig.pkm"; | |
printf("----------------------------------------------\n"); | |
pkm_encrypted_t *pkm_encrypted; | |
pkm_block_shuffled_t *pkm_block_shuffled; | |
pkm_t *pokemon; | |
pkm_encrypted = (pkm_encrypted_t *)malloc(sizeof(pkm_encrypted_t)); | |
read_pkm(filename, pkm_encrypted); | |
pkm_block_shuffled = decrypt_pkm(pkm_encrypted); | |
pokemon = unshuffle_blocks(pkm_block_shuffled); | |
printf("Pokemon is%s valid.\n", is_valid_checksum(pokemon) ? "" : " not"); | |
print_pokemon(pokemon); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment