Skip to content

Instantly share code, notes, and snippets.

@safiire
Last active May 21, 2023 09:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save safiire/9acb5ec8c34d7f8690e5 to your computer and use it in GitHub Desktop.
Save safiire/9acb5ec8c34d7f8690e5 to your computer and use it in GitHub Desktop.
This is a C program to decrypt pokémon files
#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