mirror of
https://github.com/pret/pokeheartgold.git
synced 2024-12-16 09:27:49 +00:00
Merge pull request #22 from PikalaxALT/mod123_decry
This commit is contained in:
commit
9207816fb5
File diff suppressed because it is too large
Load Diff
@ -126,7 +126,7 @@ basefile=${MYDIR}/.bins/${baserom}${basestem}.sbin
|
||||
[[ -f $basefile ]] || {
|
||||
dd if="$baserom" of="$basefile" bs=1 skip="$fileoff" count="$size" 2>/dev/null
|
||||
[[ $proc == armv5te ]] && {
|
||||
_start_ModuleParams=$(python $MYDIR/find_module_params.py ${basefile})
|
||||
_start_ModuleParams=$(getword "$baserom" $((fileoff+size+4)))
|
||||
compstatend=$(getword "$basefile" $((_start_ModuleParams+20)))
|
||||
[[ $compstatend != "0" ]] && {
|
||||
$MYDIR/ntruncompbw $basefile $vma $compstatend || { rm -f $basefile; exit 1; }
|
||||
|
63
tools/mod123encry/CryptoRc4.cpp
Normal file
63
tools/mod123encry/CryptoRc4.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "CryptoRc4.h"
|
||||
|
||||
u8 CryptoRC4Context::GetEncodedByte() {
|
||||
i = (++i) & 0xFF;
|
||||
u8 x = s[i];
|
||||
j = (j + x) & 0xFF;
|
||||
u8 y = s[j];
|
||||
s[j] = x;
|
||||
s[i] = y;
|
||||
return s[(x + y) & 0xFF];
|
||||
}
|
||||
|
||||
void CryptoRC4Context::Decrypt(u32 *start, u32 *end) {
|
||||
// assert (!(size & 3));
|
||||
u8 buffer[256];
|
||||
for (int _i = 0; _i < 256; _i++) {
|
||||
buffer[_i] = _i ^ 1;
|
||||
}
|
||||
for (; start < end; start++) {
|
||||
u32 &word = *start;
|
||||
switch (GetInsnType(word)) {
|
||||
case 1:
|
||||
case 2:
|
||||
word = (((word & ~0xFF000000) - 0x1300) & ~0xFF000000) | ((word & 0xFF000000) ^ 0x01000000);
|
||||
break;
|
||||
case 3:
|
||||
word = (((word & ~0xFF000000) - 0x4C2) & ~0xFF000000) | ((word & 0xFF000000) ^ 0x01000000);
|
||||
break;
|
||||
default:
|
||||
u8 *bytes = (u8 *)&word;
|
||||
bytes[0] ^= GetEncodedByte();
|
||||
bytes[1] ^= GetEncodedByte();
|
||||
bytes[2] = buffer[bytes[2]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoRC4Context::Encrypt(u32 *start, u32 *end) {
|
||||
// assert (!(size & 3));
|
||||
u8 buffer[256];
|
||||
for (int _i = 0; _i < 256; _i++) {
|
||||
buffer[_i] = _i ^ 1;
|
||||
}
|
||||
for (; start < end; start++) {
|
||||
u32 &word = *start;
|
||||
switch (GetInsnType(word)) {
|
||||
case 1:
|
||||
case 2:
|
||||
word = (((word & ~0xFF000000) + 0x4C2) & ~0xFF000000) | ((word & 0xFF000000) ^ 0x01000000);
|
||||
break;
|
||||
case 3:
|
||||
word = (((word & ~0xFF000000) + 0x1300) & ~0xFF000000) | ((word & 0xFF000000) ^ 0x01000000);
|
||||
break;
|
||||
default:
|
||||
u8 *bytes = (u8 *)&word;
|
||||
bytes[0] ^= GetEncodedByte();
|
||||
bytes[1] ^= GetEncodedByte();
|
||||
bytes[2] = buffer[bytes[2]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
52
tools/mod123encry/CryptoRc4.h
Normal file
52
tools/mod123encry/CryptoRc4.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef GUARD_CRYPTORC4_H
|
||||
#define GUARD_CRYPTORC4_H
|
||||
|
||||
#include "ntrtypes.h"
|
||||
|
||||
static inline int GetInsnType(u32 value) {
|
||||
u8 highByte = (value >> 24) & 0xFF;
|
||||
if ((highByte & 0xE) == 0xA) {
|
||||
if ((highByte & 0xF0) == 0xF0)
|
||||
return 1;
|
||||
else if (highByte & 1)
|
||||
return 2;
|
||||
else
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
class CryptoRC4Context {
|
||||
u32 i;
|
||||
u32 j;
|
||||
u8 s[256];
|
||||
|
||||
u8 GetEncodedByte();
|
||||
|
||||
public:
|
||||
CryptoRC4Context() {
|
||||
i = 0;
|
||||
j = 0;
|
||||
for (int _i = 0; _i < 256; _i++) {
|
||||
s[_i] = _i;
|
||||
}
|
||||
}
|
||||
CryptoRC4Context(const u8 *keys) : CryptoRC4Context() {
|
||||
int key_i = 0;
|
||||
int s_i = 0;
|
||||
for (int s_j = 255; s_j >= 0; s_j--) {
|
||||
u8 s_k = s[s_j];
|
||||
s_i = (s_i + keys[key_i++] + s_k) & 0xFF;
|
||||
u8 s_l = s[s_i];
|
||||
if (key_i >= 16)
|
||||
key_i = 0;
|
||||
s[s_i] = s_k;
|
||||
s[s_j] = s_l;
|
||||
}
|
||||
}
|
||||
void Decrypt(u32 *start, u32 *end);
|
||||
void Encrypt(u32 *start, u32 *end);
|
||||
};
|
||||
|
||||
|
||||
#endif //GUARD_CRYPTORC4_H
|
126
tools/mod123encry/Decrypt.cpp
Normal file
126
tools/mod123encry/Decrypt.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include <cstring>
|
||||
#include "Decrypt.h"
|
||||
#include "CryptoRc4.h"
|
||||
|
||||
u32 Decryptor::FindDecryLvl2(u32 offset) {
|
||||
offset = (offset + 3) & ~3; // round up
|
||||
static const u8 pattern1[] = {
|
||||
0xf0, 0x00, 0x2d, 0xe9, 0x0f, 0x00, 0x2d, 0xe9, 0xf0, 0x00, 0xbd, 0xe8, 0x60, 0x10, 0x9f, 0xe5,
|
||||
0x50, 0x30, 0x8f, 0xe2, 0x00, 0xe0, 0x83, 0xe5, 0x4c, 0x20, 0x9f, 0xe5, 0x4c, 0x00, 0x9f, 0xe5,
|
||||
}; // size=32
|
||||
static const u8 pattern2[] = {
|
||||
0x00, 0xc0, 0xa0, 0xe1, 0xf0, 0x00, 0x2d, 0xe9, 0x0f, 0x00, 0xbd, 0xe8,
|
||||
0xf0, 0x00, 0xbd, 0xe8, 0x3c, 0xff, 0x2f, 0xe1, 0x10, 0x00, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1,
|
||||
0x2c, 0x10, 0x9f, 0xe5, 0x20, 0x20, 0x9f, 0xe5, 0x20, 0x00, 0x9f, 0xe5,
|
||||
}; // size=40
|
||||
static const u8 pattern3[] = {
|
||||
0x18, 0x00, 0x8f, 0xe5, 0x04, 0x00, 0xa0, 0xe1, 0x10, 0x00, 0xbd, 0xe8, 0x04, 0xe0, 0x9f, 0xe5,
|
||||
0x00, 0xf0, 0x8f, 0xe5, 0x1e, 0xff, 0x2f, 0xe1
|
||||
}; // size=24
|
||||
|
||||
for (int i = offset; i < data.size() - sizeof(pattern1) - sizeof(pattern2) - sizeof(pattern3) - 8; i += 4) {
|
||||
if (memcmp(&data[i], pattern1, sizeof(pattern1)) == 0
|
||||
&& memcmp(&data[i + sizeof(pattern1) + 4], pattern2, sizeof(pattern2)) == 0
|
||||
&& memcmp(&data[i + sizeof(pattern1) + sizeof(pattern2) + 8], pattern3, sizeof(pattern3)) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return data.size();
|
||||
}
|
||||
|
||||
u32 Decryptor::DoDecryptLvl2(u32 tableOffset) {
|
||||
u32 *pool = (u32 *)&data[tableOffset + 104];
|
||||
pool[1] -= info.start + info.size + 0x1300;
|
||||
pool[2] -= info.start + info.size + 0x1300;
|
||||
pool[3] -= 0x1300;
|
||||
u32 param = pool[2];
|
||||
u32 start = pool[3];
|
||||
u32 size = pool[1];
|
||||
u32 keys[4] = {
|
||||
size ^ param,
|
||||
size ^ ((param << 8) | (param >> 24)),
|
||||
size ^ ((param << 16) | (param >> 16)),
|
||||
size ^ ((param << 24) | (param >> 8)),
|
||||
};
|
||||
CryptoRC4Context buffer((const u8 *)keys);
|
||||
buffer.Decrypt((u32 *) &data[start - info.start], (u32 *) &data[start + size - info.start]);
|
||||
return tableOffset + 120;
|
||||
}
|
||||
|
||||
void Decryptor::DecryptLvl2() {
|
||||
u32 i = 0;
|
||||
while ((i = FindDecryLvl2(i)) != data.size()) {
|
||||
i = DoDecryptLvl2(i);
|
||||
}
|
||||
}
|
||||
|
||||
u32 Decryptor::DoDecryptLvl1(u32 tableOffset) {
|
||||
FATEntry *table;
|
||||
FATEntry *table_start = (FATEntry *)(&data[tableOffset]);
|
||||
for (table = table_start; table->start != 0 && table->end != 0; table++) {
|
||||
table->start -= 0x1300;
|
||||
table->end -= info.start + info.size + 0x1300;
|
||||
u32 start_offs = table->start - info.start;
|
||||
u32 size = table->end & ~3;
|
||||
for (int i = start_offs; i < start_offs + size; i += 4) {
|
||||
u32 & word = (u32 &)data[i];
|
||||
switch (GetInsnType(word)) {
|
||||
case 1:
|
||||
case 2:
|
||||
word = (((word & ~0xFF000000) - 0x1300) & ~0xFF000000) | ((word & 0xFF000000) ^ 0x01000000);
|
||||
break;
|
||||
case 3:
|
||||
word = (((word & ~0xFF000000) - 0x4C2) & ~0xFF000000) | ((word & 0xFF000000) ^ 0x01000000);
|
||||
break;
|
||||
default:
|
||||
u8 *ptr = (u8 *)&word;
|
||||
word = ((ptr[0] ^ 0x56) << 0) | ((ptr[1] ^ 0x65) << 8) | ((ptr[2] ^ 0x56) << 16) | ((ptr[3] ^ 0xF0) << 24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (u8 *)table - (u8 *)table_start + tableOffset + sizeof(*table);
|
||||
}
|
||||
|
||||
void Decryptor::DecryptLvl1() {
|
||||
for (int i = info.sinit_start; i != info.sinit_end; i += 4) {
|
||||
if (*(u32 *)&data[i - info.start] != 0) {
|
||||
(void)DoDecryptLvl1(*(u32 *)&data[i - info.start] - info.start + 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Decryptor::Decrypt() {
|
||||
DecryptLvl1();
|
||||
DecryptLvl2();
|
||||
}
|
||||
|
||||
void Decryptor::Write(std::ofstream &outfile) {
|
||||
outfile.write((char *)data.data(), data.size());
|
||||
}
|
||||
|
||||
DecryptOptions::DecryptOptions(int argc, char ** argv) : Options(argc, argv) {
|
||||
if (argc < 5) {
|
||||
throw std::invalid_argument("missing required argument: " +
|
||||
((std::string[]) {"", "mode", "baserom", "outfile", "ovy_id"})[argc]);
|
||||
}
|
||||
baserom = new NtrRom(argv[2], std::ios::binary);
|
||||
outfile = std::ofstream(argv[3], std::ios::binary);
|
||||
if (!outfile.good()) {
|
||||
throw std::runtime_error(std::string("unable to open file '") + argv[3] + "' for reading");
|
||||
}
|
||||
|
||||
// Translate module number
|
||||
ovy_id = std::strtoul(argv[4], nullptr, 10);
|
||||
}
|
||||
|
||||
DecryptOptions::~DecryptOptions() {
|
||||
delete baserom;
|
||||
}
|
||||
|
||||
int DecryptOptions::main() {
|
||||
Decryptor decryptor(baserom, ovy_id);
|
||||
decryptor.Decrypt();
|
||||
decryptor.Write(outfile);
|
||||
return 0;
|
||||
}
|
66
tools/mod123encry/Decrypt.h
Normal file
66
tools/mod123encry/Decrypt.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef GUARD_DECRYPT_H
|
||||
#define GUARD_DECRYPT_H
|
||||
|
||||
#include "NtrRom.h"
|
||||
#include "Options.h"
|
||||
|
||||
struct DecryptPart2 {
|
||||
u32 i;
|
||||
u32 j;
|
||||
u8 s[256];
|
||||
const u8 *keys = nullptr;
|
||||
|
||||
DecryptPart2() {
|
||||
i = 0;
|
||||
j = 0;
|
||||
for (int _i = 0; _i < 256; _i++) {
|
||||
s[_i] = _i;
|
||||
}
|
||||
}
|
||||
DecryptPart2(const u8 *_keys) : DecryptPart2() {
|
||||
keys = _keys;
|
||||
int r6 = 0;
|
||||
int r7 = 0;
|
||||
for (int _i = 255; _i >= 0; _i--) {
|
||||
u8 r4 = s[_i];
|
||||
r7 = (r7 + keys[r6++] + r4) & 0xFF;
|
||||
u8 ip = s[r7];
|
||||
if (r6 >= 16)
|
||||
r6 = 0;
|
||||
s[r7] = r4;
|
||||
s[_i] = ip;
|
||||
}
|
||||
}
|
||||
u8 GetEncodedByte();
|
||||
void DoDecrypt(u32 *start, u32 *end);
|
||||
};
|
||||
|
||||
class Decryptor : public NtrOverlay {
|
||||
protected:
|
||||
u32 FindDecryLvl2(u32 offset);
|
||||
u32 DoDecryptLvl1(u32 tableOffset);
|
||||
u32 DoDecryptLvl2(u32 tableOffset);
|
||||
void DecryptLvl1();
|
||||
void DecryptLvl2();
|
||||
public:
|
||||
Decryptor() = default;
|
||||
Decryptor(FSOverlayInfo &_info, std::vector<u8> &_data) : NtrOverlay(_info, _data) {}
|
||||
Decryptor(NtrOverlay &_overlay) : NtrOverlay(_overlay) {}
|
||||
Decryptor(NtrRom *baserom, u32 ovy_id) : NtrOverlay(baserom, ovy_id) {}
|
||||
void Decrypt();
|
||||
void Write(std::ofstream &outfile);
|
||||
};
|
||||
|
||||
struct DecryptOptions: public Options {
|
||||
NtrRom *baserom;
|
||||
std::ofstream outfile;
|
||||
std::uint32_t ovy_id;
|
||||
|
||||
DecryptOptions(int argc, char ** argv);
|
||||
~DecryptOptions();
|
||||
int main();
|
||||
};
|
||||
|
||||
int decrypt_main(DecryptOptions &options);
|
||||
|
||||
#endif //GUARD_DECRYPT_H
|
124
tools/mod123encry/Encrypt.cpp
Normal file
124
tools/mod123encry/Encrypt.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include <iostream>
|
||||
#include "Encrypt.h"
|
||||
#include "CryptoRc4.h"
|
||||
|
||||
Encryptor::Encryptor(std::string &buildname, u32 ovy_id) {
|
||||
std::filesystem::path table_path(buildname + "_table.sbin");
|
||||
std::ifstream table(table_path, std::ios::binary);
|
||||
if (!table.good()) {
|
||||
throw std::runtime_error("unable to open " + buildname + "_table.sbin for reading");
|
||||
}
|
||||
table.seekg(ovy_id * sizeof(FSOverlayInfo));
|
||||
table.read((char *)&info, sizeof(info));
|
||||
|
||||
std::ifstream defs(buildname + "_defs.sbin", std::ios::binary);
|
||||
if (!defs.good()) {
|
||||
throw std::runtime_error("unable to open " + buildname + "_defs.sbin for reading");
|
||||
}
|
||||
defs.seekg(16);
|
||||
std::string filename;
|
||||
for (int i = 0; i < ovy_id; i++) {
|
||||
std::getline(defs, filename, '\0');
|
||||
}
|
||||
std::getline(defs, filename, '\0');
|
||||
|
||||
std::filesystem::path ovyfname = table_path.replace_filename(filename);
|
||||
std::ifstream ovyfile(ovyfname, std::ios::binary | std::ios::ate);
|
||||
if (!ovyfile.good()) {
|
||||
throw std::runtime_error("unable to open " + ovyfname.string() + " for reading");
|
||||
}
|
||||
u32 size = ovyfile.tellg();
|
||||
data.resize(size);
|
||||
ovyfile.seekg(0);
|
||||
ovyfile.read((char *)data.data(), size);
|
||||
}
|
||||
|
||||
u32 Encryptor::DoEncryptLvl2(u32 tableOffset) {
|
||||
u32 *pool = (u32 *)&data[tableOffset + 104];
|
||||
u32 param = pool[2];
|
||||
u32 start = pool[3];
|
||||
u32 size = pool[1];
|
||||
pool[1] += info.start + info.size + 0x1300;
|
||||
pool[2] += info.start + info.size + 0x1300;
|
||||
pool[3] += 0x1300;
|
||||
u32 keys[4] = {
|
||||
size ^ param,
|
||||
size ^ ((param << 8) | (param >> 24)),
|
||||
size ^ ((param << 16) | (param >> 16)),
|
||||
size ^ ((param << 24) | (param >> 8)),
|
||||
};
|
||||
CryptoRC4Context buffer((const u8 *)keys);
|
||||
buffer.Encrypt((u32 *) &data[start - info.start], (u32 *) &data[start + size - info.start]);
|
||||
return tableOffset + 120;
|
||||
}
|
||||
|
||||
void Encryptor::EncryptLvl2() {
|
||||
u32 i = 0;
|
||||
while ((i = FindDecryLvl2(i)) != data.size()) {
|
||||
i = DoEncryptLvl2(i);
|
||||
}
|
||||
}
|
||||
|
||||
u32 Encryptor::DoEncryptLvl1(u32 tableOffset) {
|
||||
FATEntry *table;
|
||||
FATEntry *table_start = (FATEntry *)(&data[tableOffset]);
|
||||
for (table = table_start; table->start != 0 && table->end != 0; table++) {
|
||||
u32 start_offs = table->start - info.start;
|
||||
u32 size = table->end & ~3;
|
||||
table->start += 0x1300;
|
||||
table->end += info.start + info.size + 0x1300;
|
||||
for (int i = start_offs; i < start_offs + size; i += 4) {
|
||||
u32 & word = (u32 &)data[i];
|
||||
switch (GetInsnType(word)) {
|
||||
case 1:
|
||||
case 2:
|
||||
word = (((word & ~0xFF000000) + 0x1300) & ~0xFF000000) | ((word & 0xFF000000) ^ 0x01000000);
|
||||
break;
|
||||
case 3:
|
||||
word = (((word & ~0xFF000000) + 0x4C2) & ~0xFF000000) | ((word & 0xFF000000) ^ 0x01000000);
|
||||
break;
|
||||
default:
|
||||
u8 *ptr = (u8 *)&word;
|
||||
word = ((ptr[0] ^ 0x56) << 0) | ((ptr[1] ^ 0x65) << 8) | ((ptr[2] ^ 0x56) << 16) | ((ptr[3] ^ 0xF0) << 24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (u8 *)table - (u8 *)table_start + tableOffset + sizeof(*table);
|
||||
}
|
||||
|
||||
void Encryptor::EncryptLvl1() {
|
||||
for (int i = info.sinit_start; i != info.sinit_end; i += 4) {
|
||||
if (*(u32 *)&data[i - info.start] != 0) {
|
||||
(void)DoEncryptLvl1(*(u32 *)&data[i - info.start] - info.start + 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Encryptor::Encrypt() {
|
||||
EncryptLvl2();
|
||||
EncryptLvl1();
|
||||
}
|
||||
|
||||
EncryptOptions::EncryptOptions(int argc, char ** argv) : Options(argc, argv) {
|
||||
if (argc < 5) {
|
||||
throw std::invalid_argument("missing required argument: " +
|
||||
((std::string[]) {"", "mode", "buildname", "outfile", "ovy_id"})[argc]);
|
||||
}
|
||||
|
||||
buildname = argv[2];
|
||||
outfile = std::ofstream(argv[3], std::ios::binary);
|
||||
if (!outfile.good()) {
|
||||
throw std::runtime_error(std::string("unable to open file '") + argv[3] + "' for reading");
|
||||
}
|
||||
|
||||
// Translate module number
|
||||
ovy_id = std::strtoul(argv[4], nullptr, 10);
|
||||
}
|
||||
|
||||
int EncryptOptions::main() {
|
||||
Encryptor encryptor(buildname, ovy_id);
|
||||
encryptor.Encrypt();
|
||||
encryptor.Write(outfile);
|
||||
return 0;
|
||||
}
|
33
tools/mod123encry/Encrypt.h
Normal file
33
tools/mod123encry/Encrypt.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef GUARD_ENCRYPT_H
|
||||
#define GUARD_ENCRYPT_H
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include "ntrtypes.h"
|
||||
#include "Decrypt.h"
|
||||
|
||||
class Encryptor : public Decryptor {
|
||||
u32 FindEncryLvl2(u32 offset) { return FindDecryLvl2(offset); }
|
||||
u32 DoEncryptLvl1(u32 tableOffset);
|
||||
u32 DoEncryptLvl2(u32 tableOffset);
|
||||
void EncryptLvl1();
|
||||
void EncryptLvl2();
|
||||
public:
|
||||
Encryptor(std::string &buildname, u32 ovy_id);
|
||||
Encryptor(FSOverlayInfo &_info, std::vector<u8> &_data) : Decryptor(_info, _data) {}
|
||||
void Encrypt();
|
||||
};
|
||||
|
||||
struct EncryptOptions : public Options {
|
||||
std::string buildname;
|
||||
std::ofstream outfile;
|
||||
u32 ovy_id;
|
||||
|
||||
EncryptOptions(int argc, char ** argv);
|
||||
~EncryptOptions() = default;
|
||||
int main(void);
|
||||
};
|
||||
|
||||
|
||||
#endif //GUARD_ENCRYPT_H
|
49
tools/mod123encry/Makefile
Normal file
49
tools/mod123encry/Makefile
Normal file
@ -0,0 +1,49 @@
|
||||
DEBUG ?= 1
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
ifneq ($(DEBUG),1)
|
||||
OPTFLAGS += -O3
|
||||
DEFINES += -DNDEBUG
|
||||
endif
|
||||
CFLAGS := $(OPTFLAGS) $(DEFINES) -g
|
||||
CXXFLAGS := $(OPTFLAGS) $(DEFINES) -g -std=c++17
|
||||
LDFLAGS :=
|
||||
|
||||
DEPDIR := .deps
|
||||
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d
|
||||
|
||||
PROGRAM := mod123encry
|
||||
CXXSRCS := mod123encry.cpp NtrRom.cpp Decrypt.cpp Encrypt.cpp CryptoRc4.cpp Overlay.cpp
|
||||
CXXOBJS := $(CXXSRCS:%.cpp=%.o)
|
||||
CSRCS := ntruncompbw.c
|
||||
COBJS := $(CSRCS:%.c=%.o)
|
||||
SRCS := $(CXXSRCS) $(CSRCS)
|
||||
OBJS := $(CXXOBJS) $(COBJS)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(PROGRAM)
|
||||
@:
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
$(CXX) $(LDFLAGS) -o $@ $^
|
||||
|
||||
clean:
|
||||
$(RM) $(PROGRAM) $(OBJS)
|
||||
$(RM) -r $(DEPDIR)
|
||||
|
||||
%.o: %.cpp
|
||||
%.o: %.cpp $(DEPDIR)/%.d | $(DEPDIR)
|
||||
$(CXX) $(CXXFLAGS) $(DEPFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
%.o: %.c $(DEPDIR)/%.d | $(DEPDIR)
|
||||
$(CC) $(CFLAGS) $(DEPFLAGS) -c -o $@ $<
|
||||
|
||||
$(DEPDIR): ; @mkdir -p $@
|
||||
|
||||
DEPFILES := $(CXXSRCS:%.cpp=$(DEPDIR)/%.d) $(CSRCS:%.c=$(DEPDIR)/%.d)
|
||||
$(DEPFILES):
|
||||
|
||||
include $(wildcard $(DEPFILES))
|
82
tools/mod123encry/NtrRom.cpp
Normal file
82
tools/mod123encry/NtrRom.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include "NtrRom.h"
|
||||
#include "ntruncompbw.h"
|
||||
|
||||
NtrRom::NtrRom(const char *filename, std::ios::openmode mode) : handle(filename, mode | std::ios::ate) {
|
||||
size_t romsize = handle.tellg();
|
||||
raw = new u8[romsize];
|
||||
handle.seekg(0);
|
||||
handle.read((char *)raw, romsize);
|
||||
|
||||
const RomHeader *header = getHeader();
|
||||
arm9_static = raw + header->main_rom_offset;
|
||||
arm7_static = raw + header->sub_rom_offset;
|
||||
|
||||
// ARM9 might be compressed
|
||||
u32 *_start_ModuleParams = (u32 *)(arm9_static + *(u32 *)(arm9_static + header->main_size + 4));
|
||||
if (_start_ModuleParams[5] != 0) {
|
||||
arm9_static = new u8[header->main_size];
|
||||
memcpy(arm9_static, raw + header->main_rom_offset, header->main_size);
|
||||
arm9_static_uncomp_size = MIi_UncompressBackwards((u8 **)&arm9_static, header->main_size);
|
||||
}
|
||||
// ARM7 static is never compressed
|
||||
|
||||
// Set FAT
|
||||
AssignRomVector(fat, header->fat.offset, header->fat.length);
|
||||
|
||||
// Set FNT
|
||||
fnt.raw = raw + header->fnt.offset;
|
||||
AssignRomVector(fnt.directories, header->fnt.offset, sizeof(FNTHeader));
|
||||
AssignRomVector(fnt.directories, header->fnt.offset, fnt.directories[0].parent * sizeof(FNTHeader));
|
||||
fnt.paths = (char *)&*fnt.directories.cend();
|
||||
|
||||
// Set overlay tables
|
||||
AssignRomVector(arm9_ovt, header->main_ovt.offset, header->main_ovt.length);
|
||||
arm9_ovy = new u8*[arm9_ovt.size()];
|
||||
for (int i = 0; i < arm9_ovt.size(); i++) {
|
||||
if (arm9_ovt[i].flag & 1) {
|
||||
arm9_ovy[i] = new u8[arm9_ovt[i].compsize];
|
||||
memcpy(arm9_ovy[i], raw + fat[arm9_ovt[i].file_id].start, arm9_ovt[i].compsize);
|
||||
MIi_UncompressBackwards((u8 **)&arm9_ovy[i], arm9_ovt[i].compsize);
|
||||
} else {
|
||||
arm9_ovy[i] = raw + fat[arm9_ovt[i].file_id].start;
|
||||
}
|
||||
}
|
||||
AssignRomVector(arm7_ovt, header->main_ovt.offset, header->main_ovt.length);
|
||||
arm7_ovy = new u8*[arm7_ovt.size()];
|
||||
for (int i = 0; i < arm7_ovt.size(); i++) {
|
||||
if (arm7_ovt[i].flag & 1) {
|
||||
arm7_ovy[i] = new u8[arm7_ovt[i].compsize];
|
||||
memcpy(arm7_ovy[i], raw + fat[arm7_ovt[i].file_id].start, arm7_ovt[i].compsize);
|
||||
MIi_UncompressBackwards((u8 **)&arm7_ovy[i], arm7_ovt[i].compsize);
|
||||
} else {
|
||||
arm7_ovy[i] = raw + fat[arm7_ovt[i].file_id].start;
|
||||
}
|
||||
}
|
||||
|
||||
banner = (NtrBanner *)(raw + header->banner_offset);
|
||||
}
|
||||
|
||||
NtrRom::~NtrRom() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < arm9_ovt.size(); i++) {
|
||||
if (arm9_ovt[i].flag & 1) {
|
||||
delete[] arm9_ovy[i];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < arm7_ovt.size(); i++) {
|
||||
if (arm7_ovt[i].flag & 1) {
|
||||
delete[] arm7_ovy[i];
|
||||
}
|
||||
}
|
||||
delete[] arm9_ovy;
|
||||
delete[] arm7_ovy;
|
||||
// explicit delete for static only if uncomped
|
||||
if (arm9_static_uncomp_size != 0) {
|
||||
delete[] arm9_static;
|
||||
}
|
||||
delete[] raw;
|
||||
}
|
119
tools/mod123encry/NtrRom.h
Normal file
119
tools/mod123encry/NtrRom.h
Normal file
@ -0,0 +1,119 @@
|
||||
#ifndef GUARD_NTRROM_H
|
||||
#define GUARD_NTRROM_H
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include "ntrtypes.h"
|
||||
#include "Overlay.h"
|
||||
|
||||
struct CARDRomRegion {
|
||||
u32 offset;
|
||||
u32 length;
|
||||
};
|
||||
|
||||
struct RomHeader {
|
||||
char game_name[12];
|
||||
u32 game_code;
|
||||
u16 maker_code;
|
||||
u8 product_id;
|
||||
u8 device_type;
|
||||
u8 device_size;
|
||||
u8 reserved_A[9];
|
||||
u8 game_version;
|
||||
u8 property;
|
||||
u32 main_rom_offset;
|
||||
u32 main_entry_address;
|
||||
u32 main_ram_address;
|
||||
u32 main_size;
|
||||
u32 sub_rom_offset;
|
||||
u32 sub_entry_address;
|
||||
u32 sub_ram_address;
|
||||
u32 sub_size;
|
||||
CARDRomRegion fnt;
|
||||
CARDRomRegion fat;
|
||||
CARDRomRegion main_ovt;
|
||||
CARDRomRegion sub_ovt;
|
||||
u8 rom_param_A[8];
|
||||
u32 banner_offset;
|
||||
u16 secure_crc;
|
||||
u8 rom_param_B[2];
|
||||
u32 main_autoload_done;
|
||||
u32 sub_autoload_done;
|
||||
u8 rom_param_C[8];
|
||||
u32 rom_size;
|
||||
u32 header_size;
|
||||
u8 reserved_B[0x38];
|
||||
u8 logo_data[0x9C];
|
||||
u16 logo_crc;
|
||||
u16 header_crc;
|
||||
};
|
||||
|
||||
struct NtrBanner {
|
||||
u16 reserved[16];
|
||||
u16 pixels[0x100];
|
||||
u16 palette[16];
|
||||
char16_t titles[6][128];
|
||||
};
|
||||
|
||||
struct FATEntry {
|
||||
u32 start;
|
||||
u32 end;
|
||||
};
|
||||
|
||||
struct FNTHeader {
|
||||
u32 start;
|
||||
u16 index;
|
||||
u16 parent;
|
||||
};
|
||||
|
||||
struct FNT {
|
||||
u8 *raw;
|
||||
std::vector<FNTHeader> directories;
|
||||
char *paths;
|
||||
};
|
||||
|
||||
class NtrRom {
|
||||
std::ifstream handle;
|
||||
u8 * raw;
|
||||
u8 * arm9_static;
|
||||
u8 * arm7_static;
|
||||
u32 arm9_static_uncomp_size = 0;
|
||||
std::vector<FSOverlayInfo> arm9_ovt;
|
||||
std::vector<FSOverlayInfo> arm7_ovt;
|
||||
std::vector<FATEntry> fat;
|
||||
FNT fnt;
|
||||
u8 ** arm9_ovy;
|
||||
u8 ** arm7_ovy;
|
||||
NtrBanner *banner;
|
||||
|
||||
template <typename T> void AssignRomVector(std::vector<T> &dest, u32 address, u32 size) {
|
||||
if (size % sizeof(T) != 0) {
|
||||
throw std::runtime_error("requested size not a multiple of type size");
|
||||
}
|
||||
dest.assign((T *)(raw + address), (T *)(raw + address + size));
|
||||
}
|
||||
|
||||
public:
|
||||
NtrRom(const char * filename, std::ios::openmode mode = std::ios::in);
|
||||
~NtrRom();
|
||||
const RomHeader * getHeader() { return (const RomHeader *)(raw + 0); }
|
||||
FSOverlayInfo &getOverlayInfo(u32 proc, u32 ovy_id) {
|
||||
std::vector<FSOverlayInfo> &ovyi = (proc == 0) ? arm9_ovt : arm7_ovt;
|
||||
return ovyi[ovy_id];
|
||||
}
|
||||
std::vector<u8> getOverlayData(u32 proc, u32 ovy_id) {
|
||||
u8 *& data_raw = ((proc == 0) ? arm9_ovy : arm7_ovy)[ovy_id];
|
||||
FSOverlayInfo &info = getOverlayInfo(proc, ovy_id);
|
||||
return std::vector<u8>(data_raw, data_raw + info.size);
|
||||
}
|
||||
NtrOverlay getOverlay(u32 proc, u32 ovy_id) {
|
||||
std::vector<FSOverlayInfo> &ovyi = (proc == 0) ? arm9_ovt : arm7_ovt;
|
||||
u8 *& data_raw = ((proc == 0) ? arm9_ovy : arm7_ovy)[ovy_id];
|
||||
FSOverlayInfo &info = ovyi[ovy_id];
|
||||
std::vector<u8> data(data_raw, data_raw + info.size);
|
||||
return {info, data};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif //GUARD_NTRROM_H
|
30
tools/mod123encry/Options.h
Normal file
30
tools/mod123encry/Options.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef GUARD_OPTIONS_H
|
||||
#define GUARD_OPTIONS_H
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include "NtrRom.h"
|
||||
|
||||
enum ExecMode {
|
||||
EXEC_DECRY = 0,
|
||||
EXEC_ENCRY = 1,
|
||||
};
|
||||
|
||||
struct Options {
|
||||
Options(int argc, char ** argv) {};
|
||||
virtual ~Options() = default;
|
||||
virtual int main() = 0;
|
||||
static ExecMode TranslateExecMode(const char * value) {
|
||||
ExecMode mode;
|
||||
if (strcmp(value, "decry") == 0) {
|
||||
mode = EXEC_DECRY;
|
||||
} else if (strcmp(value, "encry") == 0) {
|
||||
mode = EXEC_ENCRY;
|
||||
} else {
|
||||
throw std::invalid_argument(std::string("invalid ExecMode value: expected 'encry' or 'decry'; got ") + value);
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //GUARD_OPTIONS_H
|
7
tools/mod123encry/Overlay.cpp
Normal file
7
tools/mod123encry/Overlay.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "Overlay.h"
|
||||
#include "NtrRom.h"
|
||||
|
||||
NtrOverlay::NtrOverlay(NtrRom *baserom, u32 ovy_id) {
|
||||
info = baserom->getOverlayInfo(0, ovy_id);
|
||||
data = baserom->getOverlayData(0, ovy_id);
|
||||
}
|
32
tools/mod123encry/Overlay.h
Normal file
32
tools/mod123encry/Overlay.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef GUARD_OVERLAY_H
|
||||
#define GUARD_OVERLAY_H
|
||||
|
||||
#include <vector>
|
||||
#include "ntrtypes.h"
|
||||
|
||||
class NtrRom;
|
||||
|
||||
struct FSOverlayInfo {
|
||||
u32 ovy_id;
|
||||
u32 start;
|
||||
u32 size;
|
||||
u32 bssize;
|
||||
u32 sinit_start;
|
||||
u32 sinit_end;
|
||||
u32 file_id;
|
||||
u32 compsize : 24;
|
||||
u32 flag : 8;
|
||||
};
|
||||
|
||||
class NtrOverlay {
|
||||
protected:
|
||||
FSOverlayInfo info;
|
||||
std::vector<u8> data;
|
||||
public:
|
||||
NtrOverlay() = default;
|
||||
NtrOverlay(FSOverlayInfo &_info, std::vector<u8> &_data) : info(_info), data(_data) {}
|
||||
NtrOverlay(NtrRom *baserom, u32 ovy_id);
|
||||
};
|
||||
|
||||
|
||||
#endif //GUARD_OVERLAY_H
|
31
tools/mod123encry/mod123encry.cpp
Normal file
31
tools/mod123encry/mod123encry.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "Decrypt.h"
|
||||
#include "Encrypt.h"
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
// Usage:
|
||||
// mod123encry decry BASEROM OUTFILE OVY_ID
|
||||
// mod123encry encry BUILDNAME OUTFILE OVY_ID
|
||||
try {
|
||||
if (argc < 2) {
|
||||
throw std::invalid_argument("missing required argument: mode");
|
||||
}
|
||||
Options *options;
|
||||
switch (Options::TranslateExecMode(argv[1])) {
|
||||
case EXEC_DECRY:
|
||||
options = new DecryptOptions(argc, argv);
|
||||
break;
|
||||
case EXEC_ENCRY:
|
||||
options = new EncryptOptions(argc, argv);
|
||||
break;
|
||||
}
|
||||
|
||||
int ret = options->main();
|
||||
delete options;
|
||||
return ret;
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "An exception has occurred: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
24
tools/mod123encry/ntrtypes.h
Normal file
24
tools/mod123encry/ntrtypes.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef GUARD_NTRTYPES_H
|
||||
#define GUARD_NTRTYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
typedef s32 BOOL;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //GUARD_NTRTYPES_H
|
51
tools/mod123encry/ntruncompbw.c
Normal file
51
tools/mod123encry/ntruncompbw.c
Normal file
@ -0,0 +1,51 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "ntruncompbw.h"
|
||||
|
||||
static inline uint32_t READ32(const unsigned char * ptr)
|
||||
{
|
||||
return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
|
||||
}
|
||||
|
||||
uint32_t MIi_UncompressBackwards(unsigned char ** out_p, size_t compsize)
|
||||
{
|
||||
unsigned char * out = *out_p;
|
||||
|
||||
// Read the pointer to the end of the compressed image
|
||||
uint8_t * endptr = out + compsize - 8;
|
||||
uint32_t size = READ32(endptr);
|
||||
uint32_t offset = READ32(endptr + 4);
|
||||
out = realloc(out, compsize + offset);
|
||||
if (out == NULL)
|
||||
return -1u;
|
||||
endptr = out + compsize;
|
||||
uint8_t * dest_p = endptr + offset;
|
||||
uint8_t * end = endptr - ((uint8_t)(size >> 24));
|
||||
uint8_t * start = endptr - (size & ~0xFF000000);
|
||||
while (dest_p > end && end > start) {
|
||||
uint8_t r5 = *--end;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if ((r5 & 0x80) == 0)
|
||||
*--dest_p = *--end;
|
||||
else {
|
||||
int ip = *--end;
|
||||
int r7 = *--end;
|
||||
|
||||
|
||||
r7 = ((r7 | (ip << 8)) & ~0xF000) + 2;
|
||||
ip += 0x20;
|
||||
while (ip >= 0) {
|
||||
dest_p[-1] = dest_p[r7];
|
||||
dest_p--;
|
||||
ip -= 0x10;
|
||||
}
|
||||
}
|
||||
if (end <= start)
|
||||
break;
|
||||
r5 <<= 1;
|
||||
}
|
||||
}
|
||||
*out_p = out;
|
||||
return compsize + offset;
|
||||
}
|
14
tools/mod123encry/ntruncompbw.h
Normal file
14
tools/mod123encry/ntruncompbw.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef GUARD_NTRUNCOMPBW_H
|
||||
#define GUARD_NTRUNCOMPBW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint32_t MIi_UncompressBackwards(unsigned char ** out_p, size_t compsize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //GUARD_NTRUNCOMPBW_H
|
@ -33,6 +33,19 @@ NM=arm-none-eabi-nm
|
||||
OBJCOPY=arm-none-eabi-objcopy
|
||||
STEM="$1"
|
||||
|
||||
[[ -z "$STEM" ]] && { echo "usage: $0 [-h] STEM"; exit 1; }
|
||||
[[ $STEM == "-h" ]] && {
|
||||
echo "usage: $0 [-h] STEM"
|
||||
echo ""
|
||||
echo "STEM Prefix to the output static sbin (from running"
|
||||
echo " mwldarm in a nitro build). For example, if you"
|
||||
echo " output build/diamond.us/main.sbin, STEM would"
|
||||
echo " be \"build/diamond.us/main\"."
|
||||
echo ""
|
||||
echo "-h Print this message and exit"
|
||||
exit 0
|
||||
}
|
||||
|
||||
assertFile $STEM.sbin
|
||||
assertFile $STEM.nef
|
||||
assertFile ${STEM}_defs.sbin
|
||||
@ -62,9 +75,10 @@ autoload_start=$(($(getword ${STEM}.sbin $((ptr+8)))-static_load))
|
||||
|
||||
# Truncate the static module and dump
|
||||
static_size=$autoload_start
|
||||
dd if=${STEM}.sbin of=$(basename $STEM).sbin bs=1 count=${static_size} 2>/dev/null
|
||||
flags="$flags --update-section $(basename $STEM)=$(basename $STEM).sbin"
|
||||
to_clean=$(basename $STEM)
|
||||
static_sbin=$(mktemp --suffix=sbin)
|
||||
dd if=${STEM}.sbin of=$static_sbin bs=1 count=${static_size} 2>/dev/null
|
||||
flags="$flags --update-section $(basename $STEM)=$static_sbin"
|
||||
to_clean=$static_sbin
|
||||
|
||||
# Dump autoloads
|
||||
# The output of `NM -n $STEM.nef` is assumed to be sorted in the order in
|
||||
@ -72,11 +86,12 @@ to_clean=$(basename $STEM)
|
||||
# Autoload table is struct { u32 load; u32 size; u32 bsssize; } table[];
|
||||
while read -r name; do
|
||||
aload_text_size=$(getword ${STEM}.sbin $((autoload_table_start+4)))
|
||||
dd if=${STEM}.sbin of=$name.sbin bs=1 skip=$autoload_start count=$aload_text_size 2>/dev/null
|
||||
aload_sbin=$(mktemp --suffix=sbin)
|
||||
dd if=${STEM}.sbin of=$aload_sbin bs=1 skip=$autoload_start count=$aload_text_size 2>/dev/null
|
||||
((autoload_start+=aload_text_size))
|
||||
((autoload_table_start+=12))
|
||||
flags="$flags --update-section $name=$name.sbin"
|
||||
to_clean="$to_clean $name.sbin"
|
||||
flags="$flags --update-section $name=$aload_sbin"
|
||||
to_clean="$to_clean $aload_sbin"
|
||||
done < <($NM -n $STEM.nef | grep -E "SDK_AUTOLOAD_\w+_START" | grep -vE "_(TEXT|BSS|DATA|ARENA|SINIT|ETABLE)_" | cut -d' ' -f3 | cut -d'_' -f3- | sed 's/_START//g')
|
||||
|
||||
# Compile the elf
|
||||
|
Loading…
Reference in New Issue
Block a user