diff --git a/Makefile b/Makefile index 46b230b4..38f8ade9 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ FixPath = $(subst /,,$1) N64CRC = $(TOOLS_DIR)/n64crc TEXBUILDER = $(TOOLS_DIR)/dkr_texbuilder COMPRESS = $(TOOLS_DIR)/dkr_decompressor -c -ENCRYPT = $(TOOLS_DIR)/dkr_encryptor +CHEAT_ENCRYPTOR = $(TOOLS_DIR)/dkr_cheats_encryptor ASM_DIRS := asm asm/boot asm/assets SRC_DIRS := src @@ -125,8 +125,8 @@ UCODE_BUILT := $(patsubst $(UCODE_IN_DIR)/%.bin,$(UCODE_OUT_DIR)/%.bin,$(UCODE)) CHEATS_IN_DIR = $(ASSETS_DIR)/cheats CHEATS_OUT_DIR = $(BUILD_DIR)/cheats -CHEATS = $(wildcard $(CHEATS_IN_DIR)/*.ebin) -CHEATS_BUILT := $(patsubst $(CHEATS_IN_DIR)/%.ebin,$(CHEATS_OUT_DIR)/%.ebin,$(CHEATS)) +CHEATS = $(wildcard $(CHEATS_IN_DIR)/*.cheats) +CHEATS_BUILT := $(patsubst %.cheats,%.bin,$(patsubst $(CHEATS_IN_DIR)/%.cheats,$(CHEATS_OUT_DIR)/%.cheats,$(CHEATS))) ALL_ASSETS_BUILT := $(ANIMATIONS_BUILT) $(BINS_BUILT) $(CHEATS_BUILT) $(LEVELS_BUILT) $(OBJECTS_BUILT) $(TEXTURES_BUILT) $(TEXTURES_BIN_BUILT) $(TEXT_BUILT) $(UCODE_BUILT) @@ -160,8 +160,8 @@ $(ANIMATIONS_OUT_DIR)/%.cbin: $(ANIMATIONS_IN_DIR)/%.cbin $(BINS_OUT_DIR)/%.bin: $(BINS_IN_DIR)/%.bin $(ASSETS_OBJCOPY) $^ $@ -$(CHEATS_OUT_DIR)/%.ebin: $(CHEATS_IN_DIR)/%.ebin - $(ENCRYPT) $^ $@ +$(CHEATS_OUT_DIR)/%.bin: $(CHEATS_IN_DIR)/%.cheats + $(CHEAT_ENCRYPTOR) $^ $@ $(LEVELS_OUT_DIR)/%.bin: $(LEVELS_IN_DIR)/%.bin $(ASSETS_OBJCOPY) $^ $@ diff --git a/asm/assets/assets.s b/asm/assets/assets.s index 91b80c8a..f0af08ab 100644 --- a/asm/assets/assets.s +++ b/asm/assets/assets.s @@ -4631,7 +4631,7 @@ .incbin "./build/text/menu_text_french.37ed10.bin" .incbin "./build/text/menu_text_german.37fb30.bin" .incbin "./build/bin/unknown.380bb0.bin" -.incbin "./build/cheats/magic_codes.3833a0.ebin" +.incbin "./build/cheats/magic_codes.3833a0.bin" .incbin "./build/bin/unknown.383760.bin" .balign 16 .incbin "./build/levels/level_object_maps_lut.383aa0.bin" diff --git a/extract-ver/dkr-us-1.0.extract-config b/extract-ver/dkr-us-1.0.extract-config index 96110688..453a6f04 100644 --- a/extract-ver/dkr-us-1.0.extract-config +++ b/extract-ver/dkr-us-1.0.extract-config @@ -100,7 +100,7 @@ include: "extract-textures/textures_2-us-1.0.extract-config" [0x27F0]: "Binary", "unknown", "bin" # [0x3833A0, 0x383760] = Unknown -[0x3C0]: "Encrypted", "magic_codes", "cheats" +[0x3C0]: "Cheats", "magic_codes", "cheats" # [0x383760, 0x383AA0] = Unknown [0x340]: "Binary", "unknown", "bin" diff --git a/tools/.gitignore b/tools/.gitignore index 7d2392ff..0fccf7e6 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1,5 +1,5 @@ /n64crc /dkr_decompressor -/dkr_encryptor +/dkr_cheats_encryptor /dkr_extractor /dkr_texbuilder \ No newline at end of file diff --git a/tools/Makefile b/tools/Makefile index c039ef7d..7e3a9a2b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -3,17 +3,17 @@ CXX := g++ CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -O2 -s LDFLAGS := -lm PROGRAMS := n64crc -CXX_PROGRAMS := dkr_decompressor dkr_encryptor dkr_extractor dkr_texbuilder +CXX_PROGRAMS := dkr_cheats_encryptor dkr_decompressor dkr_extractor dkr_texbuilder default: all n64crc_SOURCES := n64crc.c +dkr_cheats_encryptor_SOURCES := dkr_cheats_encryptor.cpp + dkr_decompressor_SOURCES := dkr_decompressor.cpp $(wildcard dkr_decompressor_src/*.cpp dkr_decompressor_src/*.c) dkr_decompressor_CXXFLAGS := -lstdc++fs -lcrypto -lssl -dkr_encryptor_SOURCES := dkr_encryptor.cpp - dkr_extractor_SOURCES := dkr_extractor.cpp $(wildcard dkr_decompressor_src/*.cpp dkr_decompressor_src/*.c dkr_extractor_classes/*.cpp n64graphics/*.c) dkr_extractor_CXXFLAGS := -lstdc++fs -lcrypto -lssl diff --git a/tools/dkr_cheats_encryptor.cpp b/tools/dkr_cheats_encryptor.cpp new file mode 100644 index 00000000..71b04caf --- /dev/null +++ b/tools/dkr_cheats_encryptor.cpp @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include +#include + +void show_help() { + std::cout << "Usage: ./dkr_encryptor " << std::endl; +} + +void encrypt_data(std::vector& data) { + int numWords = data.size() / 4; + int a, b, c, d, sp0, sp1, sp2, sp3; + for(int i = 0; i < numWords; i++) { + a = (data[(i * 4) + 3] & 0xC0) >> 6; + b = (data[(i * 4) + 0] & 0xC0); + c = (data[(i * 4) + 1] & 0xC0) >> 2; + d = (data[(i * 4) + 2] & 0xC0) >> 4; + sp0 = a | b | c | d; + a = (data[(i * 4) + 3] & 0x30) >> 4; + b = (data[(i * 4) + 0] & 0x30) << 2; + c = (data[(i * 4) + 1] & 0x30); + d = (data[(i * 4) + 2] & 0x30) >> 2; + sp1 = a | b | c | d; + a = (data[(i * 4) + 3] & 0x0C) >> 2; + b = (data[(i * 4) + 0] & 0x0C) << 4; + c = (data[(i * 4) + 1] & 0x0C) << 2; + d = (data[(i * 4) + 2] & 0x0C); + sp2 = a | b | c | d; + a = (data[(i * 4) + 3] & 0x03); + b = (data[(i * 4) + 0] ) << 6; + c = (data[(i * 4) + 1] & 0x03) << 4; + d = (data[(i * 4) + 2] & 0x03) << 2; + sp3 = a | b | c | d; + a = (sp0 & 0xAA) >> 1; + b = (sp0 & 0x55) << 1; + data[(i * 4) + 0] = a | b; + a = (sp1 & 0xAA) >> 1; + b = (sp1 & 0x55) << 1; + data[(i * 4) + 1] = a | b; + a = (sp2 & 0xAA) >> 1; + b = (sp2 & 0x55) << 1; + data[(i * 4) + 2] = a | b; + a = (sp3 & 0xAA) >> 1; + b = (sp3 & 0x55) << 1; + data[(i * 4) + 3] = a | b; + } +} + +std::string read_text_file(std::string& filename) { + std::ifstream t(filename); + t.seekg(0, std::ios::end); + size_t size = t.tellg(); + std::string buffer(size, ' '); + t.seekg(0); + t.read(&buffer[0], size); + return buffer; +} + +void write_binary_file(std::vector& data, std::string& filename) { + std::ofstream wf(filename.c_str(), std::ios::out | std::ios::binary); + for(int i = 0; i < data.size(); i++) + wf.write((char *)&data[i], 1); + wf.close(); +} + +std::string trim(std::string input) { + size_t b = input.find_first_not_of(' '); + if (b == std::string::npos) b = 0; + return input.substr(b, input.find_last_not_of(' ') + 1 - b); +} + +std::vector split_string(std::string s, char delim) { + std::stringstream ss(s); + std::string item; + std::vector elems; + while (std::getline(ss, item, delim)) { + if(item.length() > 0) { + elems.push_back(trim(item)); + } + } + return elems; +} + +#define push_back_u16(data, offset, value) \ + data.push_back((value >> 8) & 0xFF); \ + data.push_back(value & 0xFF) + +int main(int argc, char* argv[]) { + + if(argc != 3) { + show_help(); + return 1; + } + + std::string inputFile = argv[1]; + std::string outputFile = argv[2]; + + std::vector lines = split_string(read_text_file(inputFile), '\n'); + + int numCheats = lines.size(); + + std::vector data; + + push_back_u16(data, 0, numCheats); + + std::regex regex_cheat("^[\"]([^\"]+)[\"]\\s*[,]\\s*[\"]([^\"]+)[\"]$"); + std::smatch match; + + // Create look-up table + uint16_t offset = 2 + (numCheats * 4); + for(auto& line : lines) { + if (std::regex_search(line, match, regex_cheat)) { + push_back_u16(data, 0, offset); + offset += match[1].length() + 1; // +1 for the null terminator + push_back_u16(data, 0, offset); + offset += match[2].length() + 1; + } else { + std::cout << "Invalid line: " << line << std::endl; + throw 1; + } + } + + // Now insert the strings + for(auto& line : lines) { + if (std::regex_search(line, match, regex_cheat)) { + std::string codeWord = match[1]; + std::string codeDescription = match[2]; + for(int ch = 0; ch < codeWord.length(); ch++) { + data.push_back(codeWord[ch]); + } + data.push_back(0); + for(int ch = 0; ch < codeDescription.length(); ch++) { + data.push_back(codeDescription[ch]); + } + data.push_back(0); + } else { + std::cout << "Invalid line: " << line << std::endl; + throw 1; + } + } + + // Make sure the data is 16-byte aligned. + while(data.size() % 16 != 0) { + data.push_back(0); + } + + encrypt_data(data); + write_binary_file(data, outputFile); + + return 0; +} + + diff --git a/tools/dkr_encryptor.cpp b/tools/dkr_encryptor.cpp deleted file mode 100644 index f5976ff3..00000000 --- a/tools/dkr_encryptor.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include - -void show_help() { - std::cout << "Usage: ./dkr_encryptor " << std::endl; -} - -void encrypt_data(std::vector& data) { - int numWords = data.size() / 4; - int a, b, c, d, sp0, sp1, sp2, sp3; - for(int i = 0; i < numWords; i++) { - a = (data[(i * 4) + 3] & 0xC0) >> 6; - b = (data[(i * 4) + 0] & 0xC0); - c = (data[(i * 4) + 1] & 0xC0) >> 2; - d = (data[(i * 4) + 2] & 0xC0) >> 4; - sp0 = a | b | c | d; - a = (data[(i * 4) + 3] & 0x30) >> 4; - b = (data[(i * 4) + 0] & 0x30) << 2; - c = (data[(i * 4) + 1] & 0x30); - d = (data[(i * 4) + 2] & 0x30) >> 2; - sp1 = a | b | c | d; - a = (data[(i * 4) + 3] & 0x0C) >> 2; - b = (data[(i * 4) + 0] & 0x0C) << 4; - c = (data[(i * 4) + 1] & 0x0C) << 2; - d = (data[(i * 4) + 2] & 0x0C); - sp2 = a | b | c | d; - a = (data[(i * 4) + 3] & 0x03); - b = (data[(i * 4) + 0] ) << 6; - c = (data[(i * 4) + 1] & 0x03) << 4; - d = (data[(i * 4) + 2] & 0x03) << 2; - sp3 = a | b | c | d; - a = (sp0 & 0xAA) >> 1; - b = (sp0 & 0x55) << 1; - data[(i * 4) + 0] = a | b; - a = (sp1 & 0xAA) >> 1; - b = (sp1 & 0x55) << 1; - data[(i * 4) + 1] = a | b; - a = (sp2 & 0xAA) >> 1; - b = (sp2 & 0x55) << 1; - data[(i * 4) + 2] = a | b; - a = (sp3 & 0xAA) >> 1; - b = (sp3 & 0x55) << 1; - data[(i * 4) + 3] = a | b; - } -} - -void read_binary_file(std::vector& data, std::string filename) { - std::ifstream is; - is.open(filename.c_str(), std::ios::binary); - is.seekg(0, std::ios::end); - size_t filesize = is.tellg(); - is.seekg(0, std::ios::beg); - data.resize(filesize); - is.read((char *)data.data(), filesize); - is.close(); -} - -void write_binary_file(std::vector& data, std::string& filename) { - std::ofstream wf(filename.c_str(), std::ios::out | std::ios::binary); - for(int i = 0; i < data.size(); i++) - wf.write((char *)&data[i], 1); - wf.close(); -} - -int main(int argc, char* argv[]) { - - if(argc != 3) { - show_help(); - return 1; - } - - std::string inputFile = argv[1]; - std::string outputFile = argv[2]; - std::vector data; - - read_binary_file(data, inputFile); - encrypt_data(data); - write_binary_file(data, outputFile); - - return 0; -} - - diff --git a/tools/dkr_extractor.cpp b/tools/dkr_extractor.cpp index 793684bc..2cb0bae5 100644 --- a/tools/dkr_extractor.cpp +++ b/tools/dkr_extractor.cpp @@ -70,15 +70,21 @@ void write_binary_file(std::vector& data, std::string& filename) { wf.close(); } -void extract_binary(std::vector& data, int startOffset, int endOffset, std::string& name, const char* extension, std::string& subfolder, std::string& outFolder) { - // std::cout << "Extracting Binary! " << startHex << std::endl; +void write_text_file(std::string& text, std::string& filename) { + std::ofstream myfile; + myfile.open(filename); + myfile << text; + myfile.close(); +} + +void get_filename(std::string& rangeHex, std::string& startHex, std::string& filename, int startOffset, int endOffset, std::string& name, const char* extension, std::string& subfolder, std::string& outFolder) { std::stringstream hexStream, rangeStream, filenameStream; hexStream << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << startOffset; - std::string startHex = hexStream.str(); + startHex = hexStream.str(); rangeStream << startHex << "-" << std::setfill('0') << std::setw(6) << std::hex << std::uppercase << endOffset; - std::string rangeHex = rangeStream.str(); + rangeHex = rangeStream.str(); to_lowercase(startHex); @@ -88,15 +94,13 @@ void extract_binary(std::vector& data, int startOffset, int endOffset, } filenameStream << outputDirectory << "/" << name << "." << startHex << extension; - std::string filename = filenameStream.str(); - - // Make sure the file is 16-byte aligned. - /* - while(data.size() % 16 != 0) { - data.push_back(0); - } - */ + filename = filenameStream.str(); +} + +void extract_binary(std::vector& data, int startOffset, int endOffset, std::string& name, const char* extension, std::string& subfolder, std::string& outFolder) { + std::string rangeHex, startHex, filename; + get_filename(rangeHex, startHex, filename, startOffset, endOffset, name, extension, subfolder, outFolder); write_binary_file(data, filename); std::cout << "Extracted " << rangeHex << " as /" << outFolder << "/" << name << "." << startHex << ".bin" << std::endl; @@ -154,9 +158,31 @@ void decrypt_data(std::vector& data) { } } -void extract_encrypted(std::vector& data, int startOffset, int endOffset, std::string& name, std::string& subfolder, std::string& outFolder) { +#define get_u16(data, offset) (uint16_t)((data[offset] << 8) | data[offset + 1]) + +void extract_cheats(std::vector& data, int startOffset, int endOffset, std::string& name, std::string& subfolder, std::string& outFolder) { decrypt_data(data); - extract_binary(data, startOffset, endOffset, name, ".ebin", subfolder, outFolder); + + std::string rangeHex, startHex, filename; + + get_filename(rangeHex, startHex, filename, startOffset, endOffset, name, ".cheats", subfolder, outFolder); + + std::stringstream outFile; + + uint16_t numOfCheats = get_u16(data, 0); + + for(int i = 0; i < numOfCheats; i++) { + uint16_t codeWordOffset = get_u16(data, 2 + (i * 4)); + uint16_t codeDescriptionOffset = get_u16(data, 2 + (i * 4) + 2); + char* codeWord = (char*)&data[codeWordOffset]; + char* codeDescription = (char*)&data[codeDescriptionOffset]; + outFile << "\"" << codeWord << "\", \"" << codeDescription << "\"" << std::endl; + } + + std::string outText = outFile.str(); + + write_text_file(outText, filename); + std::cout << "Extracted " << rangeHex << " as /" << outFolder << "/" << name << "." << startHex << ".cheats" << std::endl; } int get_texture_size(int width, int height, int textureFormat) { @@ -424,10 +450,10 @@ void extract_range(std::string subfolder, ConfigRange& range, ROM& rom) { numberOfFilesExtracted++; break; } - case ConfigRangeType::ENCRYPTED: + case ConfigRangeType::CHEATS: { std::vector data = rom.get_bytes_from_range(startOffset, range.get_size()); - extract_encrypted(data, startOffset, endOffset, name, subfolder, outFolder); + extract_cheats(data, startOffset, endOffset, name, subfolder, outFolder); numberOfFilesExtracted++; break; } diff --git a/tools/dkr_extractor_classes/extract_config.cpp b/tools/dkr_extractor_classes/extract_config.cpp index 5e7435a6..4b097c8a 100644 --- a/tools/dkr_extractor_classes/extract_config.cpp +++ b/tools/dkr_extractor_classes/extract_config.cpp @@ -137,7 +137,7 @@ ConfigRangeType Config::get_range_type(std::string typeString) { if(type == "binary") return ConfigRangeType::BINARY; if(type == "noextract") return ConfigRangeType::NOEXTRACT; if(type == "compressed") return ConfigRangeType::COMPRESSED; - if(type == "encrypted") return ConfigRangeType::ENCRYPTED; + if(type == "cheats") return ConfigRangeType::CHEATS; if(type == "texture") return ConfigRangeType::TEXTURE; std::cout << "Unknown extraction type: " << type << std::endl; diff --git a/tools/dkr_extractor_classes/extract_config.h b/tools/dkr_extractor_classes/extract_config.h index 27f96b86..7dadcceb 100644 --- a/tools/dkr_extractor_classes/extract_config.h +++ b/tools/dkr_extractor_classes/extract_config.h @@ -16,7 +16,7 @@ enum ConfigRangeType { BINARY, NOEXTRACT, COMPRESSED, - ENCRYPTED, + CHEATS, TEXTURE };