From 9735cb2cf501cfd3c8a9e753eab983597a7938ee Mon Sep 17 00:00:00 2001 From: Eren <66168591+Elpisdev@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:24:16 +0300 Subject: [PATCH] Delete unsegareborn directory --- unsegareborn/bootid.c | 7 - unsegareborn/bootid.h | 74 -- unsegareborn/common.h | 11 - unsegareborn/crypto.c | 344 --------- unsegareborn/crypto.h | 44 -- unsegareborn/exfat.c | 268 ------- unsegareborn/exfat.h | 103 --- unsegareborn/main.c | 517 ------------- unsegareborn/ntfs.c | 837 ---------------------- unsegareborn/ntfs.h | 224 ------ unsegareborn/unsegareborn.vcxproj | 150 ---- unsegareborn/unsegareborn.vcxproj.filters | 48 -- unsegareborn/unsegareborn.vcxproj.user | 4 - 13 files changed, 2631 deletions(-) delete mode 100644 unsegareborn/bootid.c delete mode 100644 unsegareborn/bootid.h delete mode 100644 unsegareborn/common.h delete mode 100644 unsegareborn/crypto.c delete mode 100644 unsegareborn/crypto.h delete mode 100644 unsegareborn/exfat.c delete mode 100644 unsegareborn/exfat.h delete mode 100644 unsegareborn/main.c delete mode 100644 unsegareborn/ntfs.c delete mode 100644 unsegareborn/ntfs.h delete mode 100644 unsegareborn/unsegareborn.vcxproj delete mode 100644 unsegareborn/unsegareborn.vcxproj.filters delete mode 100644 unsegareborn/unsegareborn.vcxproj.user diff --git a/unsegareborn/bootid.c b/unsegareborn/bootid.c deleted file mode 100644 index 0abec04..0000000 --- a/unsegareborn/bootid.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "bootid.h" -#include - -void format_timestamp(const Timestamp* ts, char* buffer, size_t buffer_size) { - snprintf(buffer, buffer_size, "%04d%02d%02d%02d%02d%02d", - ts->year, ts->month, ts->day, ts->hour, ts->minute, ts->second); -} \ No newline at end of file diff --git a/unsegareborn/bootid.h b/unsegareborn/bootid.h deleted file mode 100644 index 5bd875f..0000000 --- a/unsegareborn/bootid.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef BOOTID_H -#define BOOTID_H - -#include -#include - -static const uint8_t BOOTID_KEY[16] = { - 0x09, 0xCA, 0x5E, 0xFD, 0x30, 0xC9, 0xAA, 0xEF, - 0x38, 0x04, 0xD0, 0xA7, 0xE3, 0xFA, 0x71, 0x20 -}; - -static const uint8_t BOOTID_IV[16] = { - 0xB1, 0x55, 0xC2, 0x2C, 0x2E, 0x7F, 0x04, 0x91, - 0xFA, 0x7F, 0x0F, 0xDC, 0x21, 0x7A, 0xFF, 0x90 -}; - -enum ContainerType { - CONTAINER_TYPE_OS = 0x00, - CONTAINER_TYPE_APP = 0x01, - CONTAINER_TYPE_OPTION = 0x02 -}; - -#pragma pack(push, 1) - -typedef struct { - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t unk1; -} Timestamp; - -typedef struct { - uint8_t release; - uint8_t minor; - uint16_t major; -} Version; - -typedef union { - Version version; - uint8_t option[4]; -} GameVersion; - -typedef struct { - uint32_t crc32; - uint32_t length; - uint8_t signature[4]; - uint8_t unk1; - uint8_t container_type; - uint8_t sequence_number; - bool use_custom_iv; - uint8_t game_id[4]; - Timestamp target_timestamp; - GameVersion target_version; - uint64_t block_count; - uint64_t block_size; - uint64_t header_block_count; - uint64_t unk2; - uint8_t os_id[3]; - uint8_t os_generation; - Timestamp source_timestamp; - Version source_version; - Version os_version; - uint8_t padding[8]; - uint8_t extra_padding[4]; -} BootId; - -#pragma pack(pop) - -void format_timestamp(const Timestamp* ts, char* buffer, size_t buffer_size); - -#endif // BOOTID_H \ No newline at end of file diff --git a/unsegareborn/common.h b/unsegareborn/common.h deleted file mode 100644 index 853780f..0000000 --- a/unsegareborn/common.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef COMMON_H - -#include - -#define PATH_SEPARATOR "\\" -#define MAX_PATH_LENGTH 256 -#define MAX_FILENAME_LENGTH 256 -#define MKDIR(path) _mkdir(path) - -#endif // !COMMON_H - diff --git a/unsegareborn/crypto.c b/unsegareborn/crypto.c deleted file mode 100644 index 63abc58..0000000 --- a/unsegareborn/crypto.c +++ /dev/null @@ -1,344 +0,0 @@ -#include "crypto.h" -#include -#include -#include -#include -#include - -void calculate_page_iv(uint64_t file_offset, const uint8_t* file_iv, uint8_t* page_iv) { - for (int i = 0; i < 16; i++) { - page_iv[i] = file_iv[i] ^ ((file_offset >> (8 * (i % 8))) & 0xFF); - } -} - -bool calculate_file_iv( - const uint8_t key[16], - const uint8_t expected_header[16], - const uint8_t* first_page, - uint8_t out_iv[16] -) { - uint8_t iv[16]; - uint8_t header[16]; - memcpy(header, first_page, 16); - - calculate_page_iv(0, expected_header, iv); - - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - if (!ctx) - return false; - - int len; - int plaintext_len; - - if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)) { - EVP_CIPHER_CTX_free(ctx); - return false; - } - - EVP_CIPHER_CTX_set_padding(ctx, 0); - - uint8_t decrypted[16]; - - if (1 != EVP_DecryptUpdate(ctx, decrypted, &len, header, 16)) { - EVP_CIPHER_CTX_free(ctx); - return false; - } - plaintext_len = len; - - if (1 != EVP_DecryptFinal_ex(ctx, decrypted + len, &len)) { - EVP_CIPHER_CTX_free(ctx); - return false; - } - plaintext_len += len; - - EVP_CIPHER_CTX_free(ctx); - - if (plaintext_len != 16) - return false; - - memcpy(out_iv, decrypted, 16); - - return true; -} - -typedef struct { - const char* game_id; - uint8_t key[16]; - uint8_t iv[16]; - bool has_iv; -} GameKeyEntry; - -// game keys array -static const GameKeyEntry game_keys[] = { - // Nu Firmware / Hardware Test - {"SBZS", {0x2e, 0xcb, 0xcf, 0xf6, 0x5c, 0xe0, 0xab, 0xec, 0xc1, 0x05, 0x47, 0xf8, 0xac, 0x83, 0x51, 0xd8}, {0xf2, 0xac, 0x6c, 0x28, 0x17, 0xd0, 0x57, 0x4b, 0xba, 0x11, 0x3d, 0x49, 0x7e, 0x31, 0x9f, 0x3e}, true}, - - // KEY CHIP NU FACTORY / KEY CHIP NUSX FACTORY - {"SBZT", {0x9a, 0xb9, 0xce, 0x55, 0xed, 0x9c, 0x19, 0x4a, 0x71, 0x5a, 0x73, 0xa7, 0x69, 0x9f, 0x79, 0x5b}, {0x85, 0x52, 0xde, 0x88, 0xfe, 0xdd, 0xa6, 0xe8, 0x59, 0x36, 0x9f, 0xb0, 0x00, 0xf4, 0x4d, 0x5b}, true}, - - // Nu Firmware / Hardware Test - {"SBZU", {0xeb, 0x12, 0x28, 0x25, 0x4c, 0xdd, 0x30, 0x77, 0xeb, 0x3e, 0x44, 0x1c, 0x02, 0x27, 0xbf, 0x40}, {0x3f, 0x9b, 0x46, 0x76, 0x11, 0x8c, 0xee, 0x12, 0x9f, 0xe2, 0xf1, 0xcb, 0x27, 0x47, 0xbc, 0xa5}, true}, - - // Project DIVA Arcade Future Tone - {"SBZV", {0x32, 0x74, 0xa3, 0x99, 0x59, 0x4d, 0x84, 0x77, 0x96, 0x25, 0x94, 0x0b, 0x69, 0xc0, 0x2d, 0x3f}, {0x67, 0x5b, 0xa6, 0x6d, 0x29, 0xc8, 0x79, 0x23, 0xf5, 0xf1, 0x54, 0xc4, 0x06, 0xaf, 0xee, 0x42}, true}, - - // Wonderland Wars - {"SDAP", {0x41, 0xb5, 0x02, 0x7c, 0x5e, 0x99, 0xd9, 0x4a, 0xa9, 0x33, 0x5d, 0x6d, 0x71, 0x83, 0x8e, 0xcf}, {0x41, 0xb5, 0x02, 0x7c, 0x5e, 0x99, 0xd9, 0x4a, 0xa9, 0x33, 0x5d, 0x6d, 0x71, 0x83, 0x8e, 0xcf}, true}, - - // Herobank Arcade - {"SDAQ", {0xc2, 0x8f, 0x22, 0xbc, 0x1b, 0x33, 0x9a, 0xe6, 0x41, 0x80, 0x73, 0x98, 0x86, 0xdc, 0x83, 0xd6}, {0x0a, 0x29, 0xfd, 0x14, 0x5d, 0x72, 0xbf, 0x8d, 0xed, 0xd4, 0x36, 0x02, 0x5d, 0xf0, 0xa9, 0xfc}, true}, - - // Uranai Collection: Torotte - {"SDAV", {0xee, 0xd9, 0x55, 0x13, 0x26, 0x6a, 0x49, 0x9a, 0x55, 0xe2, 0x65, 0xb0, 0x49, 0x16, 0x9c, 0x44}, {0x84, 0xc0, 0xe5, 0x93, 0x1d, 0x91, 0xa6, 0xa4, 0x77, 0xd6, 0x2c, 0x27, 0x15, 0x46, 0x05, 0x6e}, true}, - - // Shin Kouchuu Ouja Mushiking - {"SDBE", {0x70, 0x53, 0xfb, 0x94, 0x45, 0x72, 0xe5, 0xb6, 0x31, 0xa6, 0x65, 0xce, 0xf4, 0xb5, 0xbc, 0xdd}, {0xae, 0x4d, 0x7e, 0x88, 0x40, 0x02, 0xc7, 0x9e, 0xb3, 0x57, 0x11, 0x55, 0x4d, 0x61, 0x30, 0x57}, true}, - - // E-DEL Sand - {"SDBN", {0xc1, 0xf1, 0x4a, 0xe2, 0xe8, 0x5b, 0x09, 0x5e, 0x31, 0x3c, 0x8b, 0xae, 0xc1, 0x25, 0x80, 0x5e}, {0x3c, 0x53, 0x8e, 0xea, 0x66, 0x25, 0x1a, 0xcd, 0x54, 0x04, 0xb9, 0x3f, 0x89, 0x76, 0xa7, 0xf7}, true}, - - // CHUNITHM - {"SDBT", {0xa6, 0xa8, 0x70, 0x67, 0x1f, 0xd4, 0x32, 0xec, 0x63, 0x7a, 0xdf, 0x7a, 0x82, 0x2f, 0x97, 0xda}, {0x2c, 0x27, 0x7f, 0x31, 0xcd, 0x55, 0x0c, 0xfa, 0x2c, 0x99, 0x3b, 0x4d, 0xd5, 0x6b, 0x85, 0xae}, true}, - - // Sonic Dash Extreme - {"SDBX", {0x3d, 0xc1, 0x9c, 0x2d, 0x0c, 0x20, 0xac, 0x19, 0x9d, 0x5f, 0xa4, 0x6e, 0x7f, 0x63, 0x35, 0xa6}, {0xd8, 0xf0, 0x29, 0xec, 0x90, 0xfe, 0x55, 0xbe, 0x67, 0x58, 0x4f, 0x74, 0x2c, 0x55, 0xef, 0x8b}, true}, - - // Kancolle Arcade - {"SDBZ", {0x52, 0x1b, 0xde, 0x44, 0x60, 0xf4, 0x18, 0x4e, 0xdd, 0x87, 0x91, 0x36, 0xad, 0xee, 0xa5, 0xee}, {0x1b, 0x83, 0x24, 0x03, 0x2d, 0xb6, 0x9d, 0x7b, 0x09, 0x54, 0x79, 0x4a, 0xa2, 0x29, 0xfe, 0x68}, true}, - - // crossbeats REV. - {"SDCA", {0x16, 0x49, 0x49, 0x0a, 0x03, 0xd6, 0xc2, 0xae, 0xc1, 0xc4, 0x96, 0x98, 0x2c, 0xb0, 0x40, 0x5c}, {0x46, 0x80, 0x71, 0x1c, 0x7e, 0x67, 0xa2, 0x6f, 0x92, 0x30, 0xd5, 0xaf, 0x74, 0xb5, 0xdc, 0xfb}, true}, - - // nailpuri - {"SDCD", {0x43, 0xb3, 0x85, 0x02, 0xd8, 0xf6, 0xd3, 0xc7, 0xb0, 0x2b, 0x95, 0xfc, 0x28, 0xdb, 0x53, 0x08}, {0x6d, 0xfc, 0xb9, 0x4b, 0xf7, 0x4f, 0x15, 0x2b, 0x55, 0xf3, 0xe0, 0xc7, 0xf3, 0x5b, 0x44, 0xb5}, true}, - - // Luigi's Mansion Arcade - {"SDCF", {0xdf, 0x98, 0x68, 0x83, 0xda, 0x83, 0x75, 0x38, 0xe3, 0x7b, 0x95, 0x9a, 0x3e, 0x41, 0x17, 0xcd}, {0xda, 0xbf, 0x53, 0x97, 0x38, 0x85, 0x2f, 0x17, 0x71, 0x48, 0x11, 0xaf, 0x70, 0x43, 0x5a, 0x83}, true}, - - // Mario & Sonic at Rio Olympic Games - {"SDCH", {0xe2, 0xda, 0x76, 0x9e, 0x94, 0xf1, 0xd3, 0xac, 0xa1, 0x93, 0x0c, 0xdb, 0xe0, 0x70, 0x8c, 0x9f}, {0xc7, 0xdc, 0xce, 0x20, 0x3c, 0x84, 0xab, 0x04, 0x77, 0x23, 0x6d, 0x69, 0x75, 0x70, 0xda, 0xdc}, true}, - - // KEY CHIP NUSX EDB SOC - {"SDCR", {0x49, 0x61, 0xa5, 0x1f, 0xd3, 0x6f, 0x14, 0xe7, 0x26, 0x64, 0xf5, 0x23, 0x73, 0x05, 0x21, 0x60}, {0x25, 0xd7, 0xd1, 0x34, 0x1a, 0x28, 0x2c, 0x5e, 0x0a, 0x34, 0xc6, 0x45, 0x62, 0xc0, 0x23, 0xec}, true}, - - // Celevie - {"SDCT", {0xd6, 0xae, 0x51, 0xf1, 0x0e, 0xc7, 0x6d, 0xa9, 0x3c, 0x98, 0x18, 0x00, 0xfc, 0x3a, 0xd3, 0xcb}, {0xfb, 0x8e, 0x43, 0xe2, 0x80, 0xd3, 0x30, 0xd0, 0x65, 0x81, 0x73, 0x2f, 0x2e, 0x11, 0xa6, 0xdc}, true}, - - // CYTUS Ω - {"SDCX", {0x79, 0x50, 0x4c, 0xcc, 0x50, 0x9b, 0x67, 0xd1, 0xf7, 0xa3, 0xf5, 0x93, 0xe6, 0xf9, 0xd9, 0xd6}, {0x15, 0x51, 0xea, 0x89, 0x26, 0xf2, 0xae, 0xe2, 0x33, 0xee, 0xc3, 0x09, 0xde, 0x3e, 0x5f, 0x3c}, true}, - - // KEY CHIP NUSX1.1 TDW - {"SDDB", {0x87, 0x56, 0x79, 0xb2, 0xcd, 0x16, 0x37, 0x96, 0x2b, 0x0d, 0xb2, 0x5c, 0x51, 0xfb, 0x21, 0xa6}, {0x8e, 0xf4, 0x47, 0x22, 0xa0, 0x56, 0x6e, 0x8f, 0x57, 0x23, 0x56, 0x24, 0x56, 0x87, 0xfb, 0xe5}, true}, - - // Sangokushi Taisen - {"SDDD", {0x56, 0x4e, 0x96, 0x78, 0x73, 0xde, 0x6c, 0xbc, 0xd2, 0x2e, 0xfe, 0xca, 0x69, 0x52, 0xe9, 0xdc}, {0x4e, 0x3d, 0xd4, 0x65, 0xcf, 0x09, 0xcd, 0x82, 0xb2, 0x59, 0xf7, 0xbe, 0xd5, 0xfc, 0x2d, 0x6d}, true}, - - // Initial D Arcade Stage Zero - {"SDDF", {0x65, 0x05, 0x85, 0x73, 0xa0, 0xcb, 0x81, 0x74, 0x9e, 0x69, 0x4a, 0xe1, 0x64, 0xc6, 0x1b, 0x04}, {0x98, 0x1c, 0x4f, 0x45, 0xe3, 0xc6, 0x95, 0x8f, 0x05, 0x4e, 0x5d, 0x00, 0x91, 0x6b, 0xdf, 0x2b}, true}, - - // KEY CHIP NU1.1 ESC - {"SDDJ", {0x63, 0x0f, 0xe5, 0x22, 0x76, 0x53, 0x7b, 0xd7, 0xfb, 0x26, 0x7a, 0xdf, 0x17, 0x5f, 0x4e, 0x99}, {0xdc, 0x57, 0x55, 0xbe, 0x57, 0xde, 0xd2, 0xcd, 0xb3, 0x44, 0x33, 0xbb, 0xba, 0x22, 0x04, 0xff}, true}, - - // APM3 Sample Program 2 - {"SDDL", {0x99, 0x24, 0x58, 0x29, 0x5f, 0xd0, 0x6d, 0x6a, 0x8a, 0xf0, 0xdf, 0xb3, 0xf6, 0x85, 0x4c, 0x19}, {0x84, 0x84, 0x90, 0x6d, 0x4c, 0xd5, 0xfd, 0x22, 0x5e, 0x03, 0x28, 0x43, 0xed, 0x37, 0x49, 0x5d}, true}, - - // ALLS MX Factory Dummy - {"SDDM", {0x01, 0x27, 0x95, 0x82, 0x10, 0xf6, 0xae, 0x9b, 0xde, 0xb8, 0x97, 0x50, 0x18, 0xb5, 0xaf, 0x24}, {0x18, 0x17, 0x16, 0xba, 0xdc, 0xcf, 0xf4, 0xbc, 0x2b, 0x1e, 0x29, 0xae, 0x02, 0xa1, 0xbb, 0xbb}, true}, - - // Demo ID - {"SDDN", {0x41, 0xdd, 0x8e, 0x66, 0x29, 0x01, 0x17, 0xac, 0x67, 0xd3, 0x11, 0xa2, 0xf0, 0xa6, 0x41, 0x6e}, {0x73, 0xe1, 0x8e, 0x84, 0x18, 0xf6, 0xce, 0xef, 0xb1, 0x1e, 0x27, 0x67, 0xfd, 0xea, 0x19, 0x0c}, true}, - - // Soul Reverse - {"SDDP", {0xcf, 0x6d, 0x64, 0x42, 0x7e, 0xec, 0xa4, 0x76, 0x74, 0xe1, 0x7b, 0xcd, 0x46, 0xd1, 0xea, 0x8c}, {0xce, 0x51, 0x74, 0x09, 0x3d, 0x26, 0xca, 0x2a, 0x31, 0xb5, 0x85, 0x41, 0xe8, 0x5a, 0xc2, 0x76}, true}, - - // SEGA World Driver Championship - {"SDDS", {0x16, 0x1b, 0xec, 0x6d, 0x90, 0x98, 0x9d, 0x0e, 0x26, 0xd7, 0x91, 0x17, 0x06, 0x07, 0xa4, 0x40}, {0x81, 0xdc, 0x26, 0xa2, 0x70, 0x28, 0xe2, 0x09, 0x23, 0x32, 0x03, 0x8a, 0xa1, 0xbf, 0xfc, 0x47}, true}, - - // O.N.G.E.K.I. - {"SDDT", {0x3f, 0x76, 0x58, 0x72, 0x8b, 0x95, 0x17, 0xd3, 0x31, 0x4e, 0x68, 0x4f, 0xa2, 0xe2, 0xa0, 0x45}, {0x41, 0x57, 0x88, 0x33, 0xc5, 0x47, 0xaa, 0xff, 0x04, 0xdb, 0x59, 0x7a, 0x6e, 0x9e, 0xb7, 0x84}, true}, - - // Let's dzuri GO! - {"SDDU", {0x64, 0x9a, 0xe9, 0x98, 0x26, 0x25, 0xf9, 0x0c, 0x55, 0xaf, 0x86, 0x71, 0x3c, 0x55, 0xd3, 0xfd}, {0x18, 0x71, 0x16, 0xfc, 0x46, 0x47, 0xa7, 0xd3, 0xb6, 0xf2, 0x30, 0x3a, 0x34, 0xf0, 0xa2, 0xfe}, true}, - - // ALLS X / X2 Research & Development - {"SDDW", {0x11, 0x85, 0x65, 0xd3, 0x44, 0xf3, 0xe1, 0x4c, 0xa6, 0x92, 0x99, 0xee, 0xac, 0x04, 0x9b, 0xb9}, {0x9d, 0x6d, 0x39, 0x2e, 0xc3, 0x5e, 0xd9, 0x4e, 0xf9, 0xfe, 0x0a, 0x5b, 0xe0, 0x57, 0x39, 0x81}, true}, - - // KEY CHIP ALLS X FACTORY - {"SDDX", {0x42, 0x8b, 0xff, 0x0f, 0x9e, 0x7a, 0xaf, 0xc1, 0x69, 0xa7, 0xa7, 0x57, 0x51, 0xff, 0xda, 0x98}, {0xf8, 0x25, 0x05, 0x94, 0xf4, 0x25, 0x33, 0x2c, 0x6d, 0x34, 0x9d, 0x7e, 0xa0, 0xe8, 0x66, 0x69}, true}, - - // Shin Kouchuu Ouja Mushiking TWN - {"SDEA", {0x9f, 0x9c, 0xf1, 0x48, 0xac, 0x3c, 0x50, 0xaa, 0xf9, 0x25, 0xaf, 0x1d, 0xfb, 0x27, 0xf5, 0x8b}, {0x4d, 0x8e, 0xbb, 0xd9, 0x71, 0x89, 0x6b, 0x8a, 0x4a, 0x3d, 0xd8, 0x4a, 0x23, 0xb3, 0x29, 0xfc}, true}, - - // WCCF FOOTISTA - {"SDEB", {0xd5, 0x11, 0xed, 0x69, 0x04, 0x15, 0xf6, 0x35, 0x98, 0x43, 0xa1, 0x34, 0xfd, 0x47, 0x83, 0x6a}, {0xac, 0x13, 0x9b, 0x38, 0x2a, 0xcd, 0xd1, 0x12, 0xe3, 0x15, 0x64, 0xea, 0x7f, 0x38, 0x18, 0x6c}, true}, - - // Chrono Regalia - {"SDEC", {0xf2, 0x72, 0xe5, 0x01, 0x68, 0x63, 0xaf, 0x2b, 0xa0, 0x33, 0x7f, 0x50, 0xde, 0x68, 0x6f, 0x6e}, {0x53, 0x27, 0xe1, 0x32, 0x63, 0x1e, 0x7f, 0x71, 0xb6, 0x1b, 0xe7, 0xcc, 0x0d, 0xf3, 0x82, 0xce}, true}, - - // CARD MAKER - {"SDED", {0x21, 0xfc, 0xec, 0x77, 0x9a, 0x16, 0x76, 0x9f, 0x52, 0x77, 0xa3, 0x6f, 0xb5, 0x42, 0x99, 0x2c}, {0x22, 0xb5, 0x02, 0x39, 0xf1, 0xb4, 0x0c, 0xcc, 0x3e, 0x55, 0xa2, 0xd6, 0x9c, 0x69, 0xb1, 0x60}, true}, - - // House of the Dead: Scarlet Dawn - {"SDEE", {0x19, 0x1e, 0xb7, 0x44, 0x06, 0x72, 0xda, 0xb0, 0x8d, 0xdb, 0xb7, 0x19, 0x5e, 0xfb, 0x35, 0x6f}, {0xc2, 0x78, 0xb5, 0x38, 0x6d, 0xc3, 0x8b, 0xd7, 0x6d, 0x71, 0xdb, 0xcd, 0x82, 0x69, 0x54, 0xcf}, true}, - - // FiZ - { "SDEG", {0x72, 0x18, 0x53, 0xdb, 0xe2, 0xd3, 0x0b, 0xaf, 0xe2, 0x4f, 0x0e, 0xdb, 0xd2, 0x10, 0xde, 0xeb}, {0x4d, 0xfb, 0x0b, 0xce, 0xc8, 0x61, 0x59, 0xaa, 0xb2, 0x97, 0x16, 0x6b, 0xcd, 0x50, 0x9e, 0x6f}, true }, - - // Fate/Grand Order Arcade - { "SDEJ", {0x9d, 0xe1, 0xea, 0x6a, 0xe3, 0x8d, 0x90, 0x11, 0xf5, 0x5d, 0x8e, 0xe8, 0x64, 0x39, 0x5d, 0x24}, {0xf6, 0x0c, 0xde, 0x21, 0x98, 0x28, 0x76, 0xd1, 0x2d, 0x17, 0x66, 0x2a, 0x48, 0xd9, 0x08, 0x36}, true }, - - // ALL.Net P.ras multi Ver.3 - { "SDEM", {0x70, 0x06, 0x17, 0xf2, 0x93, 0x69, 0x6c, 0x07, 0xfb, 0x9f, 0x35, 0x6d, 0x3b, 0x99, 0x24, 0x0d}, {0x66, 0x7d, 0x02, 0x6d, 0x6c, 0xdf, 0x32, 0x9f, 0xf3, 0x51, 0xdb, 0xaf, 0x70, 0x98, 0xe8, 0x1d}, true }, - - // StarHorse4 (Server) / MESTA Medal Station - { "SDEP", {0xfa, 0x2b, 0x7c, 0xa5, 0x3a, 0x82, 0x3c, 0x15, 0x2d, 0x94, 0x09, 0x72, 0xcb, 0xf5, 0x32, 0xf5}, {0xf4, 0xaf, 0x35, 0x12, 0x0c, 0x48, 0x61, 0x77, 0x04, 0xbb, 0x5b, 0x84, 0x71, 0x79, 0x7a, 0x62}, true }, - - // Initial D Arcade Stage Zero (CHN) - { "SDER", {0x7d, 0x73, 0x36, 0x7e, 0xbb, 0x21, 0x8e, 0xc8, 0x29, 0x30, 0xd5, 0x8d, 0xc6, 0xd7, 0x95, 0x0b}, {0x97, 0x88, 0xc3, 0xec, 0xa2, 0xdb, 0x6b, 0xa9, 0x2b, 0xac, 0x4f, 0x6f, 0x7b, 0x70, 0x63, 0x08}, true }, - - // House of the Dead: Scarlet Dawn (EXP) - { "SDET", {0x46, 0x43, 0xe7, 0xb2, 0xc3, 0x00, 0x6e, 0x02, 0x64, 0x16, 0x3e, 0xdc, 0x85, 0x45, 0xfb, 0x72}, {0x61, 0x2b, 0xca, 0x81, 0xea, 0x29, 0x58, 0xff, 0xba, 0xc3, 0x6f, 0x78, 0x0f, 0x1e, 0xd6, 0x88}, true }, - - // KEY CHIP ALLS X HDZ - { "SDEU", {0x23, 0xb3, 0xe9, 0xbb, 0x47, 0xe3, 0xac, 0x99, 0x98, 0xf6, 0xe6, 0xc1, 0xad, 0xc4, 0xae, 0x33}, {0xa9, 0x64, 0x71, 0x4c, 0xea, 0x60, 0x68, 0x84, 0x07, 0xbf, 0x55, 0x4b, 0xd1, 0xc2, 0x7e, 0xc2}, true }, - - // House of the Dead: Scarlet Dawn (CHN) - { "SDEV", {0x3c, 0x1f, 0x01, 0x8d, 0x88, 0x92, 0x6d, 0x98, 0x16, 0x3b, 0x07, 0xa1, 0x56, 0x3a, 0x48, 0x18}, {0xca, 0x73, 0x73, 0xc9, 0xc7, 0xdf, 0xeb, 0xac, 0x0f, 0xc2, 0x42, 0x54, 0xc0, 0x30, 0xe4, 0xad}, true }, - - // maimai DX - { "SDEZ", {0xd1, 0x36, 0xeb, 0xa0, 0x5d, 0x40, 0xe8, 0x26, 0x82, 0xe6, 0xaa, 0xd8, 0xd9, 0xe8, 0x68, 0x8c}, {0xc4, 0x84, 0xde, 0xea, 0xa0, 0x24, 0x9e, 0xf4, 0x66, 0x95, 0xf6, 0x36, 0x94, 0xb7, 0x37, 0x2f}, true }, - - // KEY CHIP ALLS X REC - { "SDFA", {0x8e, 0x81, 0x6b, 0x43, 0x62, 0xdb, 0x24, 0xa2, 0x30, 0x87, 0x78, 0x85, 0x86, 0x4d, 0x20, 0x6d}, {0x8e, 0x5a, 0x0b, 0xa6, 0xa0, 0xa1, 0x15, 0x0d, 0x47, 0xd1, 0x2b, 0xdb, 0x64, 0xde, 0xbb, 0xa7}, true }, - - // WACCA - { "SDFE", {0xf6, 0x17, 0x19, 0xc3, 0x71, 0xe5, 0xbc, 0xa6, 0x78, 0x8c, 0x13, 0x9a, 0x53, 0x09, 0x16, 0x17}, {0x67, 0xd4, 0x31, 0x73, 0xe3, 0x43, 0x81, 0x3f, 0xa2, 0x09, 0x7f, 0xd3, 0x29, 0x92, 0xa8, 0xe2}, true }, - - // SANDRA - { "SDFG", {0x33, 0x98, 0xfb, 0x86, 0xbf, 0xe6, 0x30, 0xa1, 0x49, 0x79, 0x41, 0x18, 0x79, 0x86, 0x1a, 0xc7}, {0xa7, 0x94, 0xc4, 0x9c, 0x2c, 0x76, 0x39, 0xcd, 0x80, 0x57, 0x18, 0x07, 0xc1, 0x72, 0x46, 0xff}, true }, - - // Kemono Friends 3: Planet Tours - { "SDFL", {0x24, 0x49, 0xb4, 0x80, 0x67, 0xb9, 0x17, 0x6a, 0x6e, 0x0f, 0x95, 0x63, 0x48, 0x1e, 0x97, 0xf4}, {0x61, 0x6f, 0x87, 0x10, 0x45, 0x46, 0x32, 0xeb, 0x4f, 0xb1, 0xd8, 0x9d, 0x8c, 0x19, 0xc1, 0x9a}, true }, - - // KEY CHIP ALLS X CASJ - { "SDFN", {0x29, 0xf6, 0x2e, 0x22, 0xc6, 0xa9, 0xfd, 0x8b, 0xe3, 0x27, 0x63, 0x1c, 0x68, 0x54, 0x64, 0x05}, {0x2a, 0x86, 0x09, 0x76, 0xe6, 0xd9, 0x85, 0x13, 0x82, 0x5f, 0x29, 0x1e, 0x56, 0xcf, 0xb5, 0xee}, true }, - - // KEY CHIP NUSX FUTURE - { "SDFP", {0x57, 0x0b, 0x87, 0x26, 0x3a, 0x7c, 0xa0, 0xaa, 0x4c, 0x13, 0x88, 0xe2, 0x04, 0xee, 0x6d, 0x4b}, {0x76, 0x40, 0x88, 0x60, 0x11, 0xa2, 0x30, 0x0a, 0x91, 0xfa, 0xd9, 0xf3, 0x6a, 0x8c, 0x47, 0x75}, true }, - - // StarHorse4 - { "SDFT", {0x92, 0xa2, 0x5f, 0x38, 0x8c, 0x50, 0x73, 0x7e, 0x39, 0xc3, 0xc2, 0xf0, 0x06, 0x64, 0x5f, 0x31}, {0xa9, 0x7e, 0x72, 0xf9, 0x90, 0x41, 0x74, 0x88, 0xcb, 0x4c, 0x67, 0xf8, 0xf0, 0xc3, 0xfb, 0x25}, true }, - - // Mario & Sonic at TOKYO Olympic - { "SDFV", {0xfe, 0x82, 0xdb, 0x9a, 0x60, 0x29, 0x5d, 0x82, 0x9b, 0x95, 0xf0, 0x3c, 0x22, 0x76, 0x01, 0x8b}, {0x34, 0xd8, 0x27, 0x72, 0xae, 0x18, 0x17, 0x4f, 0x0a, 0x18, 0x1d, 0xc5, 0x33, 0x99, 0xea, 0x9c}, true }, - - // maimai DX (EXP) - { "SDGA", {0x0a, 0x66, 0x10, 0xa6, 0x2e, 0xf6, 0x70, 0xc6, 0x5b, 0x7e, 0x7b, 0x17, 0x50, 0xff, 0xb7, 0xa1}, {0x17, 0xa2, 0xa2, 0x29, 0x15, 0xf8, 0x1c, 0x58, 0x96, 0xed, 0xbb, 0xa4, 0xc4, 0x12, 0x58, 0x5e}, true }, - - // maimai DX (CHN) - { "SDGB", {0x7c, 0xa4, 0xe6, 0xb6, 0xf3, 0xd6, 0xe8, 0xb2, 0x64, 0x72, 0x97, 0x38, 0x87, 0xd7, 0xfa, 0x3a}, {0x53, 0xfe, 0x71, 0x35, 0x76, 0x2d, 0xe3, 0xf9, 0x7e, 0x7f, 0xe7, 0x6b, 0x0f, 0xef, 0x3f, 0x27}, true }, - - // Puyo Puyo e-Sports Arcade - { "SDGH", {0xb3, 0xe3, 0x0e, 0x7e, 0xab, 0xac, 0x37, 0x67, 0xad, 0xe1, 0x3c, 0x69, 0xc9, 0xb2, 0xf2, 0x2b}, {0x03, 0xde, 0xae, 0xa3, 0x74, 0x2d, 0x69, 0x67, 0x5b, 0x36, 0xcd, 0xdc, 0x8b, 0x15, 0xac, 0x91}, true }, - - // WCCF FOOTISTA (EXP) - { "SDGK", {0x9d, 0xc4, 0xa1, 0x7f, 0xc3, 0x9f, 0xca, 0x5a, 0x8a, 0x35, 0x89, 0x84, 0x80, 0x1c, 0xaa, 0xa7}, {0xe0, 0x44, 0x5b, 0x11, 0xdc, 0xfa, 0x0d, 0xae, 0x56, 0xc8, 0x5e, 0x87, 0x87, 0xe1, 0x1d, 0x9b}, true }, - - // KEY CHIP ALLS X HDZ CASJ - { "SDGP", {0xc8, 0x7a, 0xb3, 0x12, 0x47, 0xe7, 0xb6, 0xff, 0x95, 0xfd, 0xd7, 0x9f, 0xb9, 0x1f, 0x9f, 0x37}, {0x24, 0x67, 0xab, 0x3c, 0x03, 0x1e, 0x3d, 0xc0, 0x56, 0x8b, 0x70, 0x77, 0xef, 0xd2, 0x7c, 0x36}, true }, - - // ROKUMEN - { "SDGQ", {0xc5, 0x35, 0x6d, 0xae, 0x7b, 0x06, 0x6b, 0xce, 0x88, 0x98, 0x4a, 0xec, 0x36, 0xde, 0xb6, 0x2d}, {0x4e, 0x9f, 0x29, 0x82, 0x46, 0x0e, 0x2f, 0xd9, 0x07, 0xbd, 0xe1, 0x57, 0x09, 0xed, 0xfb, 0xa7}, true }, - - // CHUNITHM (EXP) - { "SDGS", {0xa5, 0x15, 0x0c, 0xc5, 0x06, 0x5d, 0x2c, 0x59, 0xee, 0x2f, 0x8f, 0x33, 0x2c, 0xbd, 0x29, 0xd5}, {0x84, 0x01, 0x4d, 0x26, 0x69, 0x6f, 0x29, 0x0a, 0xd7, 0xea, 0xd7, 0x0c, 0x75, 0x49, 0xbd, 0x81}, true }, - - // Initial D THE ARCADE - { "SDGT", {0x9d, 0x0b, 0xba, 0x20, 0xd1, 0xe8, 0x4f, 0x24, 0x59, 0x39, 0x9f, 0x53, 0x83, 0xbe, 0xee, 0x72}, {0x5d, 0x34, 0x00, 0x13, 0xfd, 0xfb, 0x24, 0x64, 0xd2, 0x53, 0x09, 0x36, 0x02, 0xfe, 0x4b, 0x64}, true }, - - // Pokemon COROGARENA - { "SDGV", {0x57, 0x3f, 0x5c, 0x8c, 0xc4, 0x4f, 0x10, 0xf3, 0x1e, 0xc7, 0x49, 0xb6, 0x95, 0xeb, 0xe8, 0x86}, {0x6b, 0xfc, 0xa8, 0x6f, 0x9d, 0x20, 0x8a, 0x79, 0x44, 0xcd, 0xfc, 0x25, 0xea, 0x3c, 0xd2, 0x20}, true }, - - // Eiketsu Taisen: Sanzensekai no Hadou - { "SDGY", {0xc0, 0x4b, 0x66, 0x3a, 0x59, 0x05, 0x5a, 0xcb, 0xdf, 0xeb, 0xc6, 0xd3, 0xdf, 0x0e, 0x6a, 0x04}, {0x76, 0xfc, 0x5f, 0x1d, 0x88, 0x60, 0x51, 0x07, 0x94, 0x7d, 0x0c, 0x1f, 0xf3, 0x47, 0x02, 0x2d}, true }, - - // Hori a Tale - { "SDGZ", {0x9a, 0xd7, 0x4e, 0xfb, 0x20, 0x8d, 0x6e, 0xe4, 0xfe, 0x5e, 0xe7, 0x70, 0x33, 0x17, 0x12, 0xcf}, {0x45, 0xf6, 0xe5, 0x3f, 0x0e, 0xb8, 0xfa, 0xe6, 0x66, 0x5b, 0x45, 0x44, 0x4a, 0x61, 0xe2, 0x66}, true }, - - // CHUNITHM NEW!! - { "SDHD", {0x3a, 0xbd, 0x00, 0xd7, 0xa8, 0x20, 0xce, 0x86, 0x2e, 0xaf, 0x47, 0x4b, 0xf6, 0xc8, 0xf3, 0x3e}, {0x0f, 0x1e, 0x7e, 0xea, 0x78, 0xda, 0x7e, 0x03, 0x7e, 0x05, 0x52, 0xc2, 0x84, 0x3e, 0x1b, 0x6a}, true }, - - // Gutsdzuri GO! - { "SDHH", {0xfc, 0x6f, 0x88, 0x7f, 0x37, 0x17, 0xc5, 0xd6, 0x71, 0x31, 0x13, 0xb9, 0x2f, 0xa3, 0xfb, 0x27}, {0xad, 0x76, 0x60, 0x64, 0x60, 0xdb, 0xe1, 0xe9, 0x1e, 0x41, 0xbe, 0xf7, 0xab, 0x0c, 0x15, 0x35}, true }, - - // CHUNITHM (CHN) - { "SDHJ", {0x98, 0x5e, 0xa6, 0x6e, 0xcb, 0x5b, 0x1f, 0x20, 0x8c, 0x90, 0xe2, 0xb8, 0x98, 0xf0, 0xb0, 0x73}, {0x16, 0x4a, 0x65, 0x42, 0x2e, 0x7f, 0x01, 0xb7, 0xf1, 0xb0, 0x84, 0x9f, 0xc7, 0x73, 0x7c, 0xdb}, true }, - - // UFO CATCHER LINK STATION - { "SDHK", {0xbc, 0x92, 0xd6, 0x3c, 0x2a, 0x09, 0x9c, 0xa2, 0x31, 0x5a, 0x48, 0x3c, 0x30, 0x41, 0xfd, 0xd7}, {0xb1, 0x4d, 0x84, 0x49, 0xb6, 0xd4, 0x32, 0x5d, 0x83, 0xa2, 0x77, 0x4b, 0x13, 0xdd, 0x21, 0xff}, true }, - - // WACCA (CHN) - { "SDHN", {0x89, 0x21, 0x23, 0xa2, 0x6d, 0x7c, 0x03, 0xd4, 0x9e, 0xdd, 0x12, 0xa8, 0x0e, 0xe0, 0xc5, 0x8f}, {0x76, 0xaa, 0x15, 0xa6, 0x86, 0x8b, 0x8d, 0xbd, 0xf7, 0x20, 0x79, 0x06, 0x35, 0x4d, 0x51, 0x69}, true }, - - // meityromantic - { "SDHR", {0x1f, 0xb8, 0x97, 0xca, 0xb9, 0x7c, 0x81, 0x70, 0xa6, 0xac, 0x0a, 0x21, 0x68, 0x5c, 0x58, 0xd9}, {0xf9, 0xb6, 0x0f, 0x65, 0xb0, 0x1e, 0x8e, 0x83, 0x6a, 0x4b, 0xc2, 0x0f, 0x7d, 0x39, 0xfa, 0xf5}, true }, - - // ALLS System - { "ACA", {0xe4, 0x28, 0x1b, 0xcf, 0x48, 0xc4, 0xd2, 0x8e, 0xb0, 0x57, 0x72, 0xce, 0x6f, 0x98, 0x58, 0x7a}, {0x6c, 0xee, 0x7f, 0x5a, 0x2c, 0x4b, 0x5f, 0x1e, 0x93, 0xc5, 0x94, 0x91, 0x14, 0xff, 0x0b, 0x74}, true }, - - // Read from {game_id}.bin for unknown keys. - { NULL, {0}, {0}, false } -}; - -bool get_game_keys(const char* game_id, GameKeys* out_keys) { - const GameKeyEntry* entry = game_keys; - while (entry->game_id != NULL) { - if (strcmp(entry->game_id, game_id) == 0) { - memcpy(out_keys->key, entry->key, 16); - if (entry->has_iv) { - memcpy(out_keys->iv, entry->iv, 16); - out_keys->has_iv = true; - } - else { - memset(out_keys->iv, 0, 16); - out_keys->has_iv = false; - } - return true; - } - entry++; - } - - char filename[256]; - sprintf(filename, "%s.bin", game_id); - - FILE* file = fopen(filename, "rb"); - if (!file) { - return false; - } - - uint8_t buffer[32]; - size_t read_size = fread(buffer, 1, sizeof(buffer), file); - fclose(file); - - if (read_size == 16) { - memcpy(out_keys->key, buffer, 16); - memset(out_keys->iv, 0, 16); - out_keys->has_iv = false; - return true; - } - else if (read_size == 32) { - memcpy(out_keys->key, buffer, 16); - memcpy(out_keys->iv, buffer + 16, 16); - - if (memcmp(out_keys->iv, NTFS_HEADER, 16) == 0 || memcmp(out_keys->iv, EXFAT_HEADER, 16) == 0) { - out_keys->has_iv = false; - } - else { - out_keys->has_iv = true; - } - return true; - } - else { - return false; - } -} \ No newline at end of file diff --git a/unsegareborn/crypto.h b/unsegareborn/crypto.h deleted file mode 100644 index ec4aa04..0000000 --- a/unsegareborn/crypto.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef CRYPTO_H -#define CRYPTO_H - -#include -#include - -static const uint8_t NTFS_HEADER[16] = { - 0xeb, 0x52, 0x90, 0x4e, 0x54, 0x46, 0x53, 0x20, - 0x20, 0x20, 0x20, 0x00, 0x10, 0x01, 0x00, 0x00 -}; - -static const uint8_t EXFAT_HEADER[16] = { - 0xeb, 0x76, 0x90, 0x45, 0x58, 0x46, 0x41, 0x54, - 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const uint8_t OPTION_KEY[16] = { - 0x5c, 0x84, 0xa9, 0xe7, 0x26, 0xea, 0xa5, 0xdd, - 0x35, 0x1f, 0x2b, 0x07, 0x50, 0xc2, 0x36, 0x97 -}; - -static const uint8_t OPTION_IV[16] = { - 0xc0, 0x63, 0xbf, 0x6f, 0x56, 0x2d, 0x08, 0x4d, - 0x79, 0x63, 0xc9, 0x87, 0xf5, 0x28, 0x17, 0x61 -}; - -typedef struct { - uint8_t key[16]; - uint8_t iv[16]; - bool has_iv; -} GameKeys; - -void calculate_page_iv(uint64_t file_offset, const uint8_t* file_iv, uint8_t* page_iv); - -bool calculate_file_iv( - const uint8_t key[16], - const uint8_t expected_header[16], - const uint8_t* first_page, - uint8_t out_iv[16] -); - -bool get_game_keys(const char* game_id, GameKeys* out_keys); - -#endif // CRYPTO_H \ No newline at end of file diff --git a/unsegareborn/exfat.c b/unsegareborn/exfat.c deleted file mode 100644 index 7554727..0000000 --- a/unsegareborn/exfat.c +++ /dev/null @@ -1,268 +0,0 @@ -#include "exfat.h" -#include -#include -#include -#include -#include - -static bool create_directories(const char* path) { - char temp[MAX_PATH_LENGTH]; - char* p = NULL; - size_t len; - bool result = true; - - strncpy(temp, path, MAX_PATH_LENGTH - 1); - temp[MAX_PATH_LENGTH - 1] = '\0'; - len = strlen(temp); - - if (len > 0 && (temp[len - 1] == '/' || temp[len - 1] == '\\')) { - temp[len - 1] = '\0'; - } - - for (p = temp + 1; *p; p++) { - if (*p == '/' || *p == '\\') { - *p = '\0'; - if (MKDIR(temp) != 0 && errno != EEXIST) { - result = false; - break; - } - *p = PATH_SEPARATOR[0]; - } - } - - if (result && MKDIR(temp) != 0 && errno != EEXIST) { - result = false; - } - - return result; -} - -static uint32_t get_cluster_offset(ExfatContext* ctx, uint32_t cluster) { - return ctx->cluster_heap_offset_bytes + ((cluster - 2) * ctx->bytes_per_cluster); -} - -static bool read_cluster(ExfatContext* ctx, uint32_t cluster, void* buffer) { - uint32_t offset = get_cluster_offset(ctx, cluster); - if (fseek(ctx->fp, offset, SEEK_SET) != 0) { - return false; - } - return fread(buffer, 1, ctx->bytes_per_cluster, ctx->fp) == ctx->bytes_per_cluster; -} - -static uint32_t get_next_cluster(ExfatContext* ctx, uint32_t cluster) { - uint32_t next = ctx->fat[cluster]; - if (next >= 0xFFFFFFF8) { - return 0; // end-of-chain - } - if (next == 0) - { - return cluster + 1; // if cluster in FAT is 0, it means the cluster heap is continous (exfat only) - } - return next; -} - -static void combine_path(char* dest, size_t dest_size, const char* dir, const char* name) { - size_t dir_len = strlen(dir); - size_t name_len = strlen(name); - - if (dir_len + name_len + 2 > dest_size) { - dest[0] = '\0'; - return; - } - - strcpy(dest, dir); - if (dir_len > 0 && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\') { - strcat(dest, PATH_SEPARATOR); - } - strcat(dest, name); -} - -static bool extract_file(ExfatContext* ctx, ExfatFileInfo* file, const char* output_path) { - FILE* out = fopen(output_path, "wb"); - if (!out) { - return false; - } - - uint32_t current_cluster = file->first_cluster; - uint64_t remaining = file->data_length; - uint8_t* buffer = malloc(ctx->bytes_per_cluster); - if (!buffer) { - fclose(out); - return false; - } - - bool success = true; - while (remaining > 0 && current_cluster != 0 && success) { - if (!read_cluster(ctx, current_cluster, buffer)) { - success = false; - break; - } - - size_t write_size = (remaining > ctx->bytes_per_cluster) ? ctx->bytes_per_cluster : (size_t)remaining; - if (fwrite(buffer, 1, write_size, out) != write_size) { - success = false; - break; - } - - remaining -= write_size; - current_cluster = get_next_cluster(ctx, current_cluster); - } - - free(buffer); - fclose(out); - return success; -} - -static bool process_directory(ExfatContext* ctx, uint32_t start_cluster, const char* output_dir) { - uint8_t* cluster_buffer = malloc(ctx->bytes_per_cluster); - if (!cluster_buffer) { - return false; - } - - uint32_t current_cluster = start_cluster; - bool finished = false; - - while (!finished && current_cluster != 0) { - if (!read_cluster(ctx, current_cluster, cluster_buffer)) { - free(cluster_buffer); - return false; - } - - uint32_t entries_per_cluster = ctx->bytes_per_cluster / EXFAT_ENTRY_SIZE; - uint8_t* entry_ptr = cluster_buffer; - for (uint32_t i = 0; i < entries_per_cluster; ) { - uint8_t entry_type = *entry_ptr; - if (entry_type == EXFAT_ENTRY_EOD) { - finished = true; - break; - } - - if (entry_type == EXFAT_ENTRY_FILE) { - ExfatFileEntry* file_entry = (ExfatFileEntry*)entry_ptr; - ExfatStreamEntry* stream_entry = (ExfatStreamEntry*)(entry_ptr + EXFAT_ENTRY_SIZE); - if (stream_entry->entry_type != EXFAT_ENTRY_STREAM) { - i++; - entry_ptr += EXFAT_ENTRY_SIZE; - continue; - } - int total_name_chars = stream_entry->name_length; - int num_name_entries = (total_name_chars + 14) / 15; - - char full_name[MAX_FILENAME_LENGTH]; - wchar_t full_name_unicode[MAX_FILENAME_LENGTH]; - int pos = 0; - uint8_t* name_entry_ptr = entry_ptr + EXFAT_ENTRY_SIZE * 2; - for (int k = 0; k < num_name_entries; k++) { - ExfatFileNameEntry* name_entry = (ExfatFileNameEntry*)(name_entry_ptr + k * EXFAT_ENTRY_SIZE); - int chars_in_this_entry = (total_name_chars - k * 15 < 15) ? (total_name_chars - k * 15) : 15; - for (int j = 0; j < chars_in_this_entry; j++) { - if (pos < MAX_FILENAME_LENGTH - 1) { - // you shouldn't cut of the wide char - full_name_unicode[pos++] = (wchar_t)name_entry->file_name[j]; - } - } - } - full_name_unicode[pos] = L'\0'; - - // just convert it - _locale_t locale = _create_locale(LC_ALL, ""); - _wcstombs_l(full_name, full_name_unicode, MAX_FILENAME_LENGTH, locale); - - ExfatFileInfo file_info; - memset(&file_info, 0, sizeof(file_info)); - strncpy(file_info.name, full_name, MAX_PATH_LENGTH - 1); - file_info.name[MAX_PATH_LENGTH - 1] = '\0'; - file_info.first_cluster = stream_entry->first_cluster; - file_info.data_length = stream_entry->data_length; - file_info.is_directory = ((file_entry->file_attributes & 0x10) != 0); - - char full_path[MAX_PATH_LENGTH]; - combine_path(full_path, sizeof(full_path), output_dir, file_info.name); - - if (file_info.is_directory) { - if (create_directories(full_path)) { - process_directory(ctx, file_info.first_cluster, full_path); - } - } - else { - extract_file(ctx, &file_info, full_path); - } - - int total_entries = 2 + num_name_entries; - i += total_entries; - entry_ptr += EXFAT_ENTRY_SIZE * total_entries; - continue; - } - else { - i++; - entry_ptr += EXFAT_ENTRY_SIZE; - } - } - - if (!finished) { - current_cluster = get_next_cluster(ctx, current_cluster); - } - } - - free(cluster_buffer); - return true; -} - -bool exfat_init(ExfatContext* ctx, const char* filename) { - memset(ctx, 0, sizeof(ExfatContext)); - - ctx->fp = fopen(filename, "rb"); - if (!ctx->fp) { - return false; - } - - if (fread(&ctx->boot_sector, sizeof(ExfatBootSector), 1, ctx->fp) != 1) { - fclose(ctx->fp); - return false; - } - - ctx->bytes_per_sector = (1 << ctx->boot_sector.bytes_per_sector_shift); - ctx->bytes_per_cluster = ctx->bytes_per_sector * (1 << ctx->boot_sector.sectors_per_cluster_shift); - ctx->cluster_heap_offset_bytes = ctx->boot_sector.cluster_heap_offset * ctx->bytes_per_sector; - - ctx->fat_offset_bytes = ctx->boot_sector.fat_offset * ctx->bytes_per_sector; - ctx->fat_length_bytes = ctx->boot_sector.fat_length * ctx->bytes_per_sector; - - ctx->fat = malloc(ctx->fat_length_bytes); - if (!ctx->fat) { - fclose(ctx->fp); - return false; - } - - if (fseek(ctx->fp, ctx->fat_offset_bytes, SEEK_SET) != 0) { - free(ctx->fat); - fclose(ctx->fp); - return false; - } - - if (fread(ctx->fat, 1, ctx->fat_length_bytes, ctx->fp) != ctx->fat_length_bytes) { - free(ctx->fat); - fclose(ctx->fp); - return false; - } - - return true; -} - -bool exfat_extract_all(ExfatContext* ctx, const char* output_dir) { - if (!create_directories(output_dir)) { - return false; - } - return process_directory(ctx, ctx->boot_sector.first_cluster_of_root_dir, output_dir); -} - -void exfat_close(ExfatContext* ctx) { - if (ctx->fp) { - fclose(ctx->fp); - ctx->fp = NULL; - } - if (ctx->fat) { - free(ctx->fat); - ctx->fat = NULL; - } -} diff --git a/unsegareborn/exfat.h b/unsegareborn/exfat.h deleted file mode 100644 index 2cd25f8..0000000 --- a/unsegareborn/exfat.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef EXFAT_H -#define EXFAT_H - -#include -#include -#include -#include "common.h" - -#define EXFAT_ENTRY_SIZE 32 - -#define EXFAT_ENTRY_EOD 0x00 -#define EXFAT_ENTRY_BITMAP 0x81 -#define EXFAT_ENTRY_FILE 0x85 -#define EXFAT_ENTRY_STREAM 0xC0 -#define EXFAT_ENTRY_FILENAME 0xC1 - -#pragma pack(push, 1) - -typedef struct { - uint8_t jump_boot[3]; - uint8_t fs_name[8]; - uint8_t must_be_zero[53]; - uint64_t partition_offset; - uint64_t volume_length; - uint32_t fat_offset; - uint32_t fat_length; - uint32_t cluster_heap_offset; - uint32_t cluster_count; - uint32_t first_cluster_of_root_dir; - uint32_t volume_serial_number; - uint16_t fs_revision; - uint16_t volume_flags; - uint8_t bytes_per_sector_shift; - uint8_t sectors_per_cluster_shift; - uint8_t number_of_fats; - uint8_t drive_select; - uint8_t percent_in_use; - uint8_t reserved[7]; - uint8_t boot_code[390]; - uint16_t boot_signature; -} ExfatBootSector; - -typedef struct { - uint8_t entry_type; - uint8_t secondary_count; - uint16_t set_checksum; - uint16_t file_attributes; - uint16_t reserved1; - uint32_t create_timestamp; - uint32_t last_modified_timestamp; - uint32_t last_access_timestamp; - uint8_t create_10ms; - uint8_t last_modified_10ms; - uint8_t create_utc_offset; - uint8_t last_modified_utc_offset; - uint8_t last_access_utc_offset; - uint8_t reserved2[7]; -} ExfatFileEntry; - -typedef struct { - uint8_t entry_type; - uint8_t flags; - uint8_t reserved1; - uint8_t name_length; - uint16_t name_hash; - uint16_t reserved2; - uint64_t valid_data_length; - uint32_t reserved3; - uint32_t first_cluster; - uint64_t data_length; -} ExfatStreamEntry; - -typedef struct { - uint8_t entry_type; - uint8_t flags; - uint16_t file_name[15]; // please work -} ExfatFileNameEntry; - -#pragma pack(pop) - -typedef struct { - char name[MAX_PATH_LENGTH]; - uint32_t first_cluster; - uint64_t data_length; - bool is_directory; -} ExfatFileInfo; - -typedef struct { - FILE* fp; - ExfatBootSector boot_sector; - uint32_t bytes_per_sector; - uint32_t bytes_per_cluster; - uint32_t cluster_heap_offset_bytes; - uint32_t fat_offset_bytes; - uint32_t fat_length_bytes; - uint32_t* fat; -} ExfatContext; - -bool exfat_init(ExfatContext* ctx, const char* filename); -bool exfat_extract_all(ExfatContext* ctx, const char* output_dir); -void exfat_close(ExfatContext* ctx); - -#endif // EXFAT_H diff --git a/unsegareborn/main.c b/unsegareborn/main.c deleted file mode 100644 index bf30d9f..0000000 --- a/unsegareborn/main.c +++ /dev/null @@ -1,517 +0,0 @@ -#include -#include -#include -#include -#include -#include "bootid.h" -#include "crypto.h" -#include "exfat.h" -#include "ntfs.h" -#include -#include - -#define PAGE_SIZE 4096 -#define BUFFER_SIZE (PAGE_SIZE * 256) -#define MAX_PATH_LENGTH 256 - -char* g_output_filename = NULL; - -int process_file(const char* path, bool extract_fs) { - uint8_t* bootid_bytes = malloc(96); - uint8_t* read_buffer = malloc(BUFFER_SIZE); - uint8_t* write_buffer = malloc(BUFFER_SIZE); - uint8_t* decrypted_buffer = malloc(BUFFER_SIZE); - uint8_t iv[16]; - uint8_t page_iv[16]; - uint8_t key[16]; - - if (!bootid_bytes || !read_buffer || !write_buffer || !decrypted_buffer) { - printf("Memory allocation failed\n"); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - FILE* file = fopen(path, "rb"); - if (!file) { - printf("Could not open file %s\n", path); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - if (fread(bootid_bytes, 1, 96, file) != 96) { - printf("Could not read BootId from %s\n", path); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - uint8_t decrypted_bootid_bytes[96]; - int out_len = 0; - - EVP_CIPHER_CTX* bootid_ctx = EVP_CIPHER_CTX_new(); - if (!bootid_ctx) { - printf("Could not create cipher context\n"); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - EVP_DecryptInit_ex(bootid_ctx, EVP_aes_128_cbc(), NULL, BOOTID_KEY, BOOTID_IV); - EVP_CIPHER_CTX_set_padding(bootid_ctx, 0); - - if (!EVP_DecryptUpdate(bootid_ctx, decrypted_bootid_bytes, &out_len, bootid_bytes, 96)) { - printf("Could not decrypt BootId in %s\n", path); - EVP_CIPHER_CTX_free(bootid_ctx); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - int final_len = 0; - if (!EVP_DecryptFinal_ex(bootid_ctx, decrypted_bootid_bytes + out_len, &final_len)) { - printf("Could not finalize decryption\n"); - EVP_CIPHER_CTX_free(bootid_ctx); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - EVP_CIPHER_CTX_free(bootid_ctx); - - BootId bootid; - memcpy(&bootid, decrypted_bootid_bytes, sizeof(BootId)); - - if (bootid.container_type != CONTAINER_TYPE_OS && - bootid.container_type != CONTAINER_TYPE_APP && - bootid.container_type != CONTAINER_TYPE_OPTION) { - printf("Unknown container type %d\n", bootid.container_type); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - char target_timestamp_str[20]; - format_timestamp(&bootid.target_timestamp, target_timestamp_str, sizeof(target_timestamp_str)); - - char os_id[4]; - char game_id[5]; - memcpy(os_id, bootid.os_id, 3); - os_id[3] = '\0'; - memcpy(game_id, bootid.game_id, 4); - game_id[4] = '\0'; - - const char* id = (bootid.container_type == CONTAINER_TYPE_OS) ? os_id : game_id; - - GameKeys keys; - bool got_keys = false; - if (bootid.container_type == CONTAINER_TYPE_OS || bootid.container_type == CONTAINER_TYPE_APP) { - got_keys = get_game_keys(id, &keys); - } - else { - memcpy(keys.key, OPTION_KEY, 16); - memcpy(keys.iv, OPTION_IV, 16); - keys.has_iv = true; - got_keys = true; - } - - if (!got_keys) { - printf("Decryption key invalid or not found.\n"); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - uint64_t data_offset = bootid.header_block_count * bootid.block_size; - - bool has_iv = false; - memcpy(key, keys.key, 16); - - if (bootid.use_custom_iv) { - has_iv = false; - } - else { - has_iv = keys.has_iv; - if (has_iv) { - memcpy(iv, keys.iv, 16); - } - } - - if (!has_iv) { - if (fseek(file, data_offset, SEEK_SET) != 0) { - printf("Could not seek to data offset\n"); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - size_t read_size = fread(read_buffer, 1, PAGE_SIZE, file); - if (read_size != PAGE_SIZE) { - printf("Could not read data page\n"); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - if (bootid.container_type == CONTAINER_TYPE_OPTION) { - if (!calculate_file_iv(key, EXFAT_HEADER, read_buffer, iv)) { - printf("Could not calculate file IV\n"); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - } - else { - if (!calculate_file_iv(key, NTFS_HEADER, read_buffer, iv)) { - printf("Could not calculate file IV\n"); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - } - has_iv = true; - } - - char* output_filename = malloc(MAX_PATH_LENGTH); - if (!output_filename) { - printf("Memory allocation failed\n"); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - if (bootid.container_type == CONTAINER_TYPE_OS) { - snprintf(output_filename, MAX_PATH_LENGTH, "%s_%04d%02d%02d_%s_%d.ntfs", - os_id, - bootid.os_version.major, - bootid.os_version.minor, - bootid.os_version.release, - target_timestamp_str, - bootid.sequence_number); - } - else if (bootid.container_type == CONTAINER_TYPE_APP) { - if (bootid.sequence_number > 0) { - snprintf(output_filename, MAX_PATH_LENGTH, "%s_%d%02d%02d_%s_%d_%d%02d%02d.ntfs", - game_id, - bootid.target_version.version.major, - bootid.target_version.version.minor, - bootid.target_version.version.release, - target_timestamp_str, - bootid.sequence_number, - bootid.source_version.major, - bootid.source_version.minor, - bootid.source_version.release); - } - else { - snprintf(output_filename, MAX_PATH_LENGTH, "%s_%d%02d%02d_%s_%d.ntfs", - game_id, - bootid.target_version.version.major, - bootid.target_version.version.minor, - bootid.target_version.version.release, - target_timestamp_str, - bootid.sequence_number); - } - } - else if (bootid.container_type == CONTAINER_TYPE_OPTION) { - char option_str[5]; - memcpy(option_str, bootid.target_version.option, 4); - option_str[4] = '\0'; - snprintf(output_filename, MAX_PATH_LENGTH, "%s_%s_%s_%d.exfat", - game_id, - option_str, - target_timestamp_str, - bootid.sequence_number); - } - - FILE* output_file = fopen(output_filename, "wb"); - if (!output_file) { - printf("Could not create output file %s\n", output_filename); - free(output_filename); - fclose(file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - uint64_t output_size = (bootid.block_count - bootid.header_block_count) * bootid.block_size; - - if (fseek(file, data_offset, SEEK_SET) != 0) { - printf("Could not seek to data offset\n"); - fclose(file); - fclose(output_file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - - EVP_CIPHER_CTX* page_ctx = EVP_CIPHER_CTX_new(); - if (!page_ctx) { - printf("Could not create cipher context\n"); - fclose(file); - fclose(output_file); - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - return 1; - } - EVP_DecryptInit_ex(page_ctx, EVP_aes_128_cbc(), NULL, key, NULL); - EVP_CIPHER_CTX_set_padding(page_ctx, 0); - - printf("\nDecrypting file...\n"); - time_t last_update_time = time(NULL); - int last_percentage = -1; - - uint64_t total_bytes_read = 0; - uint64_t bytes_remaining = output_size; - - while (bytes_remaining > 0) { - size_t chunk_size = (bytes_remaining > BUFFER_SIZE) ? BUFFER_SIZE : (size_t)bytes_remaining; - - size_t read_size = fread(read_buffer, 1, chunk_size, file); - if (read_size != chunk_size) { - printf("\nCould not read data\n"); - break; - } - - size_t offset = 0; - while (offset < read_size) { - size_t block_size = (read_size - offset > PAGE_SIZE) ? PAGE_SIZE : (read_size - offset); - - uint64_t file_offset = data_offset + total_bytes_read + offset - data_offset; - calculate_page_iv(file_offset, iv, page_iv); - - EVP_DecryptInit_ex(page_ctx, NULL, NULL, NULL, page_iv); - - int out_len1 = 0, out_len2 = 0; - if (!EVP_DecryptUpdate(page_ctx, decrypted_buffer + offset, &out_len1, read_buffer + offset, block_size)) { - printf("\nCould not decrypt data\n"); - break; - } - if (!EVP_DecryptFinal_ex(page_ctx, decrypted_buffer + offset + out_len1, &out_len2)) { - printf("\nCould not finalize decryption\n"); - break; - } - if (out_len1 + out_len2 != (int)block_size) { - printf("\nDecrypted data size mismatch\n"); - break; - } - offset += block_size; - } - - if (fwrite(decrypted_buffer, 1, read_size, output_file) != read_size) { - printf("\nCould not write to output file\n"); - break; - } - - total_bytes_read += read_size; - bytes_remaining -= read_size; - - time_t current_time = time(NULL); - if (current_time != last_update_time) { - int percentage = (int)((total_bytes_read * 100) / output_size); - if (percentage != last_percentage) { - printf("\rProgress: %d%%", percentage); - fflush(stdout); - last_percentage = percentage; - } - last_update_time = current_time; - } - } - - printf("\rProgress: 100%%\n"); - - EVP_CIPHER_CTX_free(page_ctx); - - fclose(file); - fclose(output_file); - - memset(read_buffer, 0, BUFFER_SIZE); - memset(decrypted_buffer, 0, BUFFER_SIZE); - memset(page_iv, 0, sizeof(page_iv)); - memset(bootid_bytes, 0, 96); - memset(iv, 0, sizeof(iv)); - - printf("Decryption finalized: %s\n", output_filename); - - if (extract_fs) { - if (g_output_filename) { - free(g_output_filename); - } - g_output_filename = output_filename; - } - else { - free(output_filename); - } - - free(bootid_bytes); - free(read_buffer); - free(write_buffer); - free(decrypted_buffer); - - return 0; -} - -int main(int argc, char* argv[]) { - bool extract_fs = true; - int start_index = 1; - - if (argc < 2) { - printf("usage: unsegaREBORN [-no] [ ...]\n"); - printf(" -no Do not extract filesystem archives after decryption\n"); - return 0; - } - - if (strcmp(argv[1], "-no") == 0) { - extract_fs = false; - start_index = 2; - - if (argc < 3) { - printf("No input files specified\n"); - return 1; - } - } - - for (int i = start_index; i < argc; ++i) { - const char* file_path = argv[i]; - printf("Processing file: %s\n", file_path); - - if (process_file(file_path, extract_fs) == 0) { - if (extract_fs && g_output_filename) { - char output_dir[MAX_PATH_LENGTH]; - strncpy(output_dir, g_output_filename, sizeof(output_dir) - 1); - output_dir[sizeof(output_dir) - 1] = '\0'; - - char* ext = strrchr(output_dir, '.'); - if (ext) *ext = '\0'; - - if (strstr(g_output_filename, ".exfat") != NULL) { - ExfatContext ctx; - if (exfat_init(&ctx, g_output_filename)) { - if (exfat_extract_all(&ctx, output_dir)) { - printf("\nExFAT extraction completed successfully\n"); - } - else { - printf("\nFailed to extract ExFAT archive\n"); - } - exfat_close(&ctx); - } - else { - printf("\nFailed to initialize ExFAT context\n"); - } - } - else if (strstr(g_output_filename, ".ntfs") != NULL) { - NTFSContext ctx = { 0 }; - if (ntfs_init(&ctx, g_output_filename, output_dir)) { - printf("\nExtracting NTFS archive...\n"); - - if (ntfs_extract_all(&ctx)) { - printf("\nNTFS extraction completed successfully\n"); - - char vhd_path[MAX_PATH_LENGTH]; - bool found_child = false; - - for (int vhd_num = 0; vhd_num < 10; vhd_num++) { - snprintf(vhd_path, sizeof(vhd_path), "%s%sinternal_%d.vhd", - output_dir, PATH_SEPARATOR, vhd_num); - - FILE* test = fopen(vhd_path, "rb"); - if (!test) continue; - fclose(test); - - if (vhd_num > 0) { - printf("\nChild internal VHD identified, finalizing process.\n"); - found_child = true; - break; - } - - char vhd_output_dir[MAX_PATH_LENGTH]; - snprintf(vhd_output_dir, sizeof(vhd_output_dir), "%s%scontents", - output_dir, PATH_SEPARATOR); - - NTFSContext vhd_ctx = { 0 }; - if (ntfs_init(&vhd_ctx, vhd_path, vhd_output_dir)) { - printf("\nExtracting from internal VHD...\n"); - if (ntfs_extract_all(&vhd_ctx)) { - printf("\nInternal VHD extraction completed successfully\n"); - } - else { - printf("\nFailed to extract VHD contents\n"); - } - ntfs_close(&vhd_ctx); - } - else { - printf("\nFailed to open internal VHD\n"); - } - break; - } - } - else { - printf("\nFailed to extract NTFS archive\n"); - } - ntfs_close(&ctx); - } - else { - printf("\nFailed to initialize NTFS context\n"); - } - } - else { - printf("\nUnknown filesystem type for file %s\n", g_output_filename); - } - - free(g_output_filename); - g_output_filename = NULL; - } - } - else { - printf("Failed to process %s\n", file_path); - } - } - - if (g_output_filename) { - free(g_output_filename); - } - - return 0; -} \ No newline at end of file diff --git a/unsegareborn/ntfs.c b/unsegareborn/ntfs.c deleted file mode 100644 index ab32c61..0000000 --- a/unsegareborn/ntfs.c +++ /dev/null @@ -1,837 +0,0 @@ -#include "ntfs.h" -#include -#include -#define BUFFER_SIZE 65536 - -static uint16_t swap16(uint16_t value) { - return ((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8); -} - -static uint32_t swap32(uint32_t value) { - return ((value & 0xFF000000) >> 24) | - ((value & 0x00FF0000) >> 8) | - ((value & 0x0000FF00) << 8) | - ((value & 0x000000FF) << 24); -} - -static uint64_t swap64(uint64_t value) { - return ((value & 0xFF00000000000000ULL) >> 56) | - ((value & 0x00FF000000000000ULL) >> 40) | - ((value & 0x0000FF0000000000ULL) >> 24) | - ((value & 0x000000FF00000000ULL) >> 8) | - ((value & 0x00000000FF000000ULL) << 8) | - ((value & 0x0000000000FF0000ULL) << 24) | - ((value & 0x000000000000FF00ULL) << 40) | - ((value & 0x00000000000000FFULL) << 56); -} - -static bool create_directories(const char* path) { - char* tmp = _strdup(path); - if (!tmp) return false; - - bool success = true; - char* p = tmp; - - if (strlen(p) > 2) { - if (p[1] == ':') p += 2; - if (*p == '\\' || *p == '/') p++; - } - - while ((p = strchr(p, PATH_SEPARATOR[0])) != NULL) { - *p = '\0'; - if (strlen(tmp) > 0) { - if (MKDIR(tmp) != 0 && errno != EEXIST) { - success = false; - break; - } - } - *p = PATH_SEPARATOR[0]; - p++; - } - - if (success && strlen(tmp) > 0) { - if (MKDIR(tmp) != 0 && errno != EEXIST) { - success = false; - } - } - - free(tmp); - return success; -} - -static void convert_name_to_ascii(const uint16_t* utf16_name, int name_length, char* ascii_name) { - // just convert it - _locale_t locale = _create_locale(LC_ALL, ""); - int real_name_length = min(name_length, MAX_FILENAME_LENGTH - 1); - _wcstombs_l(ascii_name, utf16_name, real_name_length, locale); - ascii_name[real_name_length] = '\0'; -} - -static bool ntfs_read(NTFSContext* ctx, void* buffer, uint64_t offset, size_t size) { - if (ctx->is_vhd) { - return vhd_read(&ctx->vhd, buffer, offset, size); - } - if (fseeko(ctx->raw.fp, offset, SEEK_SET) != 0) { - return false; - } - return fread(buffer, 1, size, ctx->raw.fp) == size; -} - -static bool read_file_info(NTFSContext* ctx, uint64_t ref_number, FileInfo* info) { - memset(info, 0, sizeof(FileInfo)); - - uint64_t mft_offset = ctx->mft_offset + (ref_number * ctx->mft_record_size); - uint8_t* record_buffer = malloc(ctx->mft_record_size); - if (!record_buffer) { - return false; - } - - bool success = false; - if (ntfs_read(ctx, record_buffer, mft_offset, ctx->mft_record_size)) { - const MFTRecordHeader* record = (const MFTRecordHeader*)record_buffer; - - if (memcmp(record->magic, "FILE", 4) == 0 && (record->flags & MFT_RECORD_IN_USE)) { - info->is_directory = (record->flags & MFT_RECORD_IS_DIRECTORY) != 0; - - const uint8_t* attr = (const uint8_t*)record + record->attrs_offset; - while (attr < (const uint8_t*)record + record->bytes_used) { - const AttributeHeader* header = (const AttributeHeader*)attr; - - if (header->type == 0xFFFFFFFF || header->length == 0) { - break; - } - - if (header->type == FILE_NAME_ATTR && !header->non_resident) { - const FileNameAttribute* fname = - (const FileNameAttribute*)(attr + header->data.resident.value_offset); - - if (fname->namespace != 2) { - convert_name_to_ascii(fname->name, fname->name_length, info->name); - info->parent_ref = fname->parent_directory & 0xFFFFFFFFFFFF; - info->valid = true; - success = true; - break; - } - } - - attr += header->length; - } - } - } - - free(record_buffer); - return success; -} - -static bool init_directory_cache(DirectoryCache* cache) { - cache->capacity = 1024; - cache->count = 0; - cache->directories = malloc(cache->capacity * sizeof(DirectoryInfo)); - if (!cache->directories) return false; - - cache->directories[0].ref_number = 5; - cache->directories[0].path[0] = '\0'; - cache->count = 1; - return true; -} - -static void free_directory_cache(DirectoryCache* cache) { - free(cache->directories); - cache->directories = NULL; - cache->capacity = 0; - cache->count = 0; -} - -static bool add_directory_to_cache(DirectoryCache* cache, uint64_t ref_number, const char* path) { - for (size_t i = 0; i < cache->count; i++) { - if (cache->directories[i].ref_number == ref_number) { - strncpy(cache->directories[i].path, path, MAX_PATH_LENGTH - 1); - cache->directories[i].path[MAX_PATH_LENGTH - 1] = '\0'; - return true; - } - } - - if (cache->count >= cache->capacity) { - size_t new_capacity = cache->capacity * 2; - DirectoryInfo* new_dirs = realloc(cache->directories, - new_capacity * sizeof(DirectoryInfo)); - if (!new_dirs) return false; - cache->directories = new_dirs; - cache->capacity = new_capacity; - } - - if (cache->count < cache->capacity) { - cache->directories[cache->count].ref_number = ref_number; - strncpy(cache->directories[cache->count].path, path, MAX_PATH_LENGTH - 1); - cache->directories[cache->count].path[MAX_PATH_LENGTH - 1] = '\0'; - cache->count++; - return true; - } - - return false; -} - -static const char* get_cached_path(DirectoryCache* cache, uint64_t ref_number) { - for (size_t i = 0; i < cache->count; i++) { - if (cache->directories[i].ref_number == ref_number) { - return cache->directories[i].path; - } - } - return NULL; -} - -static bool build_path_recursively(NTFSContext* ctx, uint64_t ref_number, char* buffer, size_t buffer_size) { - if (ref_number == 5) { - buffer[0] = '\0'; - return true; - } - - const char* cached_path = get_cached_path(&ctx->dir_cache, ref_number); - if (cached_path) { - strncpy(buffer, cached_path, buffer_size - 1); - buffer[buffer_size - 1] = '\0'; - return true; - } - - FileInfo info; - if (!read_file_info(ctx, ref_number, &info) || !info.valid) { - return false; - } - - if (info.name[0] == '$') { - return false; - } - - char parent_path[MAX_PATH_LENGTH]; - if (!build_path_recursively(ctx, info.parent_ref, parent_path, sizeof(parent_path))) { - return false; - } - - if (parent_path[0] == '\0') { - strncpy(buffer, info.name, buffer_size - 1); - } - else { - snprintf(buffer, buffer_size, "%s%s%s", parent_path, PATH_SEPARATOR, info.name); - } - buffer[buffer_size - 1] = '\0'; - - if (info.is_directory) { - add_directory_to_cache(&ctx->dir_cache, ref_number, buffer); - } - - return true; -} - -static void get_full_path(const NTFSContext* ctx, uint64_t parent_ref, const char* name, - char* out_path, size_t out_size) { - char parent_path[MAX_PATH_LENGTH]; - - if (!build_path_recursively(ctx, parent_ref, parent_path, sizeof(parent_path))) { - snprintf(out_path, out_size, "%s%s%s", - ctx->base_path, - PATH_SEPARATOR, - name); - return; - } - - if (parent_path[0] == '\0') { - snprintf(out_path, out_size, "%s%s%s", - ctx->base_path, - PATH_SEPARATOR, - name); - } - else { - snprintf(out_path, out_size, "%s%s%s%s%s", - ctx->base_path, - PATH_SEPARATOR, - parent_path, - PATH_SEPARATOR, - name); - } -} - -static bool extract_data_from_runs(NTFSContext* ctx, const DataRun* runs, int run_count, - uint64_t data_size, FILE* out_file) { - uint8_t* temp_buffer = malloc(BUFFER_SIZE); - if (!temp_buffer) return false; - - uint64_t total_written = 0; - bool success = true; - - for (int i = 0; i < run_count && total_written < data_size; i++) { - uint64_t cluster_offset = ctx->data_start_offset + - (runs[i].offset * ctx->bytes_per_cluster); - uint64_t length = runs[i].length * ctx->bytes_per_cluster; - - if (length > data_size - total_written) { - length = data_size - total_written; - } - - uint64_t remaining = length; - while (remaining > 0 && success) { - size_t to_read = (remaining > BUFFER_SIZE) ? BUFFER_SIZE : (size_t)remaining; - - if (!ntfs_read(ctx, temp_buffer, cluster_offset, to_read)) { - success = false; - break; - } - - if (fwrite(temp_buffer, 1, to_read, out_file) != to_read) { - success = false; - break; - } - - cluster_offset += to_read; - remaining -= to_read; - total_written += to_read; - } - } - - free(temp_buffer); - return success; -} - -static int parse_data_runs(const uint8_t* run_list, DataRun* runs, int max_runs) { - int count = 0; - uint64_t offset_base = 0; - const uint8_t* p = run_list; - - while (*p != 0 && count < max_runs) { - uint8_t header = *p++; - int length_size = header & 0xF; - int offset_size = header >> 4; - - if (length_size == 0) break; - - uint64_t length = 0; - for (int i = 0; i < length_size; i++) { - length |= ((uint64_t)*p++) << (i * 8); - } - - int64_t offset = 0; - if (offset_size > 0) { - for (int i = 0; i < offset_size; i++) { - offset |= ((uint64_t)*p++) << (i * 8); - } - if (offset & ((uint64_t)1 << ((offset_size * 8) - 1))) { - offset |= ~((uint64_t)(1ULL << (offset_size * 8)) - 1); - } - } - - offset_base += offset; - runs[count].offset = offset_base; - runs[count].length = length; - count++; - } - - return count; -} - -static bool extract_file(NTFSContext* ctx, const MFTRecordHeader* record, - const char* full_path) { - char parent_path[MAX_PATH_LENGTH]; - strncpy(parent_path, full_path, sizeof(parent_path) - 1); - parent_path[sizeof(parent_path) - 1] = '\0'; - - char* last_separator = strrchr(parent_path, PATH_SEPARATOR[0]); - if (last_separator) { - *last_separator = '\0'; - create_directories(parent_path); - } - - FILE* out_file = fopen(full_path, "wb"); - if (!out_file) { - printf("Failed to create file: %s\n", full_path); - return false; - } - - bool success = false; - const uint8_t* attr = (const uint8_t*)record + record->attrs_offset; - - while (attr < (const uint8_t*)record + record->bytes_used) { - const AttributeHeader* header = (const AttributeHeader*)attr; - - if (header->type == 0xFFFFFFFF || header->length == 0) { - break; - } - - if (header->type == DATA_ATTR && header->name_length == 0) { - if (header->non_resident) { - DataRun runs[256]; - const uint8_t* run_list = attr + header->data.non_resident.mapping_pairs_offset; - int run_count = parse_data_runs(run_list, runs, 256); - - success = extract_data_from_runs(ctx, runs, run_count, - header->data.non_resident.data_size, - out_file); - } - else { - const uint8_t* data = attr + header->data.resident.value_offset; - success = (fwrite(data, 1, header->data.resident.value_length, out_file) == - header->data.resident.value_length); - } - break; - } - - attr += header->length; - } - - fclose(out_file); - if (!success) { - remove(full_path); - } - return success; -} - -static bool process_mft_record(NTFSContext* ctx, const uint8_t* record_data) { - const MFTRecordHeader* record = (const MFTRecordHeader*)record_data; - - if (memcmp(record->magic, "FILE", 4) != 0 || !(record->flags & MFT_RECORD_IN_USE)) { - return true; - } - - char filename[MAX_FILENAME_LENGTH]; - uint64_t parent_ref = 0; - bool got_filename = false; - bool is_directory = (record->flags & MFT_RECORD_IS_DIRECTORY) != 0; - uint64_t record_num = record->record_number & 0xFFFFFFFFFFFF; - - const uint8_t* attr = (const uint8_t*)record + record->attrs_offset; - while (attr < (const uint8_t*)record + record->bytes_used) { - const AttributeHeader* header = (const AttributeHeader*)attr; - - if (header->type == 0xFFFFFFFF || header->length == 0) { - break; - } - - if (header->type == FILE_NAME_ATTR && !header->non_resident) { - const FileNameAttribute* fname = - (const FileNameAttribute*)(attr + header->data.resident.value_offset); - - if (fname->namespace != 2) { - convert_name_to_ascii(fname->name, fname->name_length, filename); - parent_ref = fname->parent_directory & 0xFFFFFFFFFFFF; - got_filename = true; - break; - } - } - - attr += header->length; - } - - if (!got_filename || filename[0] == '$') { - return true; - } - - char full_path[MAX_PATH_LENGTH]; - get_full_path(ctx, parent_ref, filename, full_path, sizeof(full_path)); - - if (is_directory) { - if (!create_directories(full_path)) { - printf("Failed to create directory: %s\n", full_path); - return false; - } - - const char* relative_path = full_path + strlen(ctx->base_path); - while (*relative_path == PATH_SEPARATOR[0]) relative_path++; - - if (!add_directory_to_cache(&ctx->dir_cache, record_num, relative_path)) { - printf("Failed to cache directory: %s\n", filename); - return false; - } - return true; - } - - return extract_file(ctx, record, full_path); -} - -static bool vhd_read(VHDContext* ctx, void* buffer, uint64_t offset, size_t size) { - if (ctx->footer.disk_type == VHD_TYPE_FIXED) { - if (fseeko(ctx->fp, offset, SEEK_SET) != 0) { - return false; - } - return fread(buffer, 1, size, ctx->fp) == size; - } - else if (ctx->footer.disk_type == VHD_TYPE_DYNAMIC) { - uint8_t* buf = (uint8_t*)buffer; - uint64_t block_size = ctx->dyn_header.block_size; - - while (size > 0) { - uint32_t block_idx = (uint32_t)(offset / block_size); - uint32_t block_offset = (uint32_t)(offset % block_size); - - if (block_idx >= ctx->dyn_header.max_bat_entries) { - return false; - } - - uint32_t bat_entry = ctx->bat[block_idx]; - if (bat_entry == VHD_BAT_ENTRY_RESERVED) { - size_t chunk = (size < (block_size - block_offset)) ? - size : (size_t)(block_size - block_offset); - memset(buf, 0, chunk); - buf += chunk; - offset += chunk; - size -= chunk; - } - else { - uint64_t sector_offset = ((uint64_t)bat_entry) * VHD_SECTOR_SIZE; - - if (fseeko(ctx->fp, sector_offset, SEEK_SET) != 0) { - return false; - } - - if (fread(ctx->sector_bitmap, 1, ctx->sector_bitmap_size, ctx->fp) - != ctx->sector_bitmap_size) { - return false; - } - - if (fread(ctx->block_buffer, 1, block_size, ctx->fp) != block_size) { - return false; - } - - size_t chunk = (size < (block_size - block_offset)) ? - size : (size_t)(block_size - block_offset); - memcpy(buf, ctx->block_buffer + block_offset, chunk); - buf += chunk; - offset += chunk; - size -= chunk; - } - } - return true; - } - return false; -} - -static bool vhd_init(VHDContext* ctx, const char* filename) { - memset(ctx, 0, sizeof(VHDContext)); - - ctx->fp = fopen(filename, "rb"); - if (!ctx->fp) { - printf("Failed to open file: %s\n", filename); - return false; - } - - if (fseeko(ctx->fp, -((int64_t)VHD_FOOTER_SIZE), SEEK_END) != 0) { - printf("Failed to seek to VHD footer\n"); - fclose(ctx->fp); - return false; - } - - if (fread(&ctx->footer, 1, sizeof(VHDFooter), ctx->fp) != sizeof(VHDFooter)) { - printf("Failed to read VHD footer\n"); - fclose(ctx->fp); - return false; - } - - if (memcmp(ctx->footer.cookie, VHD_COOKIE, strlen(VHD_COOKIE)) != 0) { - printf("Invalid VHD signature\n"); - fclose(ctx->fp); - return false; - } - - ctx->footer.features = swap32(ctx->footer.features); - ctx->footer.version = swap32(ctx->footer.version); - ctx->footer.data_offset = swap64(ctx->footer.data_offset); - ctx->footer.timestamp = swap32(ctx->footer.timestamp); - ctx->footer.creator_app = swap32(ctx->footer.creator_app); - ctx->footer.creator_ver = swap32(ctx->footer.creator_ver); - ctx->footer.creator_os = swap32(ctx->footer.creator_os); - ctx->footer.original_size = swap64(ctx->footer.original_size); - ctx->footer.current_size = swap64(ctx->footer.current_size); - ctx->footer.cylinder = swap16(ctx->footer.cylinder); - ctx->footer.disk_type = swap32(ctx->footer.disk_type); - ctx->footer.checksum = swap32(ctx->footer.checksum); - - if (ctx->footer.disk_type == VHD_TYPE_DYNAMIC) { - if (fseeko(ctx->fp, ctx->footer.data_offset, SEEK_SET) != 0) { - printf("Failed to seek to dynamic header\n"); - fclose(ctx->fp); - return false; - } - - if (fread(&ctx->dyn_header, 1, sizeof(VHDDynamicHeader), ctx->fp) != sizeof(VHDDynamicHeader)) { - printf("Failed to read dynamic header\n"); - fclose(ctx->fp); - return false; - } - - if (memcmp(ctx->dyn_header.cookie, VHD_DYNAMIC_COOKIE, strlen(VHD_DYNAMIC_COOKIE)) != 0) { - printf("Invalid dynamic disk header signature\n"); - fclose(ctx->fp); - return false; - } - - ctx->dyn_header.data_offset = swap64(ctx->dyn_header.data_offset); - ctx->dyn_header.bat_offset = swap64(ctx->dyn_header.bat_offset); - ctx->dyn_header.head_vers = swap32(ctx->dyn_header.head_vers); - ctx->dyn_header.max_bat_entries = swap32(ctx->dyn_header.max_bat_entries); - ctx->dyn_header.block_size = swap32(ctx->dyn_header.block_size); - - size_t bat_size = (size_t)ctx->dyn_header.max_bat_entries * sizeof(uint32_t); - - if (bat_size == 0 || bat_size > (1ULL << 30)) { - printf("Invalid BAT size\n"); - fclose(ctx->fp); - return false; - } - - ctx->bat = malloc(bat_size); - if (!ctx->bat) { - printf("Failed to allocate BAT memory\n"); - fclose(ctx->fp); - return false; - } - - if (fseeko(ctx->fp, ctx->dyn_header.bat_offset, SEEK_SET) != 0) { - printf("Failed to seek to BAT\n"); - free(ctx->bat); - fclose(ctx->fp); - return false; - } - - if (fread(ctx->bat, 1, bat_size, ctx->fp) != bat_size) { - printf("Failed to read BAT\n"); - free(ctx->bat); - fclose(ctx->fp); - return false; - } - - for (uint32_t i = 0; i < ctx->dyn_header.max_bat_entries; i++) { - ctx->bat[i] = swap32(ctx->bat[i]); - } - - ctx->sector_bitmap_size = (ctx->dyn_header.block_size / VHD_SECTOR_SIZE + 7) / 8; - ctx->sector_bitmap = malloc(ctx->sector_bitmap_size); - ctx->block_buffer = malloc(ctx->dyn_header.block_size); - - if (!ctx->sector_bitmap || !ctx->block_buffer) { - printf("Failed to allocate dynamic disk buffers\n"); - free(ctx->bat); - free(ctx->sector_bitmap); - free(ctx->block_buffer); - fclose(ctx->fp); - return false; - } - } - - return true; -} - -bool ntfs_init(NTFSContext* ctx, const char* path, const char* extract_path) { - memset(ctx, 0, sizeof(NTFSContext)); - strncpy(ctx->base_path, extract_path, sizeof(ctx->base_path) - 1); - - if (!init_directory_cache(&ctx->dir_cache)) { - return false; - } - - FILE* fp = fopen(path, "rb"); - if (!fp) return false; - - if (fseeko(fp, -512, SEEK_END) == 0) { - char signature[9] = { 0 }; - if (fread(signature, 1, 8, fp) == 8 && memcmp(signature, VHD_COOKIE, 8) == 0) { - fclose(fp); - ctx->is_vhd = true; - if (!vhd_init(&ctx->vhd, path)) { - free_directory_cache(&ctx->dir_cache); - return false; - } - } - else { - rewind(fp); - ctx->is_vhd = false; - ctx->raw.fp = fp; - } - } - - uint64_t ntfs_offset = 0; - bool found_ntfs = false; - - if (ctx->is_vhd) { - uint8_t sector[VHD_SECTOR_SIZE]; - if (ntfs_read(ctx, sector, 0, VHD_SECTOR_SIZE)) { - if (sector[0x1FE] == 0x55 && sector[0x1FF] == 0xAA) { - for (int i = 0; i < 4; i++) { - const uint8_t* part = sector + 0x1BE + (i * 16); - if (part[4] == NTFS_PARTITION_TYPE) { - uint32_t start_sector = - (uint32_t)part[8] | - ((uint32_t)part[9] << 8) | - ((uint32_t)part[10] << 16) | - ((uint32_t)part[11] << 24); - ntfs_offset = (uint64_t)start_sector * VHD_SECTOR_SIZE; - - if (ntfs_read(ctx, sector, ntfs_offset, VHD_SECTOR_SIZE) && - memcmp(sector + 3, NTFS_SIGNATURE, 8) == 0) { - found_ntfs = true; - break; - } - } - } - } - } - - if (!found_ntfs) { - const uint64_t offsets[] = { 0, 0x100000, 0x200000, 0x400000, 0x800000, 0 }; - for (int i = 0; offsets[i]; i++) { - if (ntfs_read(ctx, sector, offsets[i], VHD_SECTOR_SIZE) && - memcmp(sector + 3, NTFS_SIGNATURE, 8) == 0) { - ntfs_offset = offsets[i]; - found_ntfs = true; - break; - } - } - } - } - else { - uint8_t boot[512]; - if (ntfs_read(ctx, boot, 0, sizeof(boot)) && - boot[0] == 0xEB && boot[1] == 0x52 && boot[2] == 0x90 && - memcmp(boot + 3, NTFS_SIGNATURE, 8) == 0) { - found_ntfs = true; - } - } - - if (!found_ntfs) { - printf("No NTFS filesystem found\n"); - ntfs_close(ctx); - return false; - } - - ctx->data_start_offset = ntfs_offset; - - if (!ntfs_read(ctx, &ctx->boot, ntfs_offset, sizeof(NTFSBootSector))) { - printf("Failed to read NTFS boot sector\n"); - ntfs_close(ctx); - return false; - } - - ctx->bytes_per_cluster = (uint32_t)ctx->boot.bytes_per_sector * ctx->boot.sectors_per_cluster; - ctx->mft_offset = ntfs_offset + (ctx->boot.mft_cluster_number * ctx->bytes_per_cluster); - - if (ctx->boot.clusters_per_mft_record > 0) { - ctx->mft_record_size = ctx->boot.clusters_per_mft_record * ctx->bytes_per_cluster; - } - else { - ctx->mft_record_size = 1U << (-ctx->boot.clusters_per_mft_record); - } - - uint8_t* mft_record = malloc(ctx->mft_record_size); - if (!mft_record) { - printf("Failed to allocate memory for MFT record\n"); - ntfs_close(ctx); - return false; - } - - if (!ntfs_read(ctx, mft_record, ctx->mft_offset, ctx->mft_record_size)) { - printf("Failed to read MFT record 0\n"); - free(mft_record); - ntfs_close(ctx); - return false; - } - - const MFTRecordHeader* record = (const MFTRecordHeader*)mft_record; - if (memcmp(record->magic, "FILE", 4) != 0) { - printf("Invalid MFT record signature\n"); - free(mft_record); - ntfs_close(ctx); - return false; - } - - const uint8_t* attr = mft_record + record->attrs_offset; - while (attr < mft_record + record->bytes_used) { - const AttributeHeader* header = (const AttributeHeader*)attr; - if (header->type == 0xFFFFFFFF || header->length == 0) break; - - if (header->type == DATA_ATTR && header->name_length == 0) { - if (header->non_resident) { - uint64_t mft_data_size = header->data.non_resident.data_size; - ctx->mft_data_size = mft_data_size; - ctx->total_mft_records = mft_data_size / ctx->mft_record_size; - } - break; - } - attr += header->length; - } - - free(mft_record); - return true; -} - -bool ntfs_extract_all(NTFSContext* ctx) { - if (!create_directories(ctx->base_path)) { - printf("Failed to create output directory\n"); - return false; - } - - uint8_t* record_buffer = malloc(ctx->mft_record_size); - if (!record_buffer) { - printf("Failed to allocate MFT record buffer\n"); - return false; - } - - printf("Extraction in progress...\n"); - uint64_t current_offset = ctx->mft_offset; - uint64_t total_records = ctx->total_mft_records; - uint64_t processed_records = 0; - uint64_t extracted_records = 0; - - time_t last_update_time = time(NULL); - int last_percentage = -1; - - // Process MFT records - for (uint64_t i = 0; i < total_records; i++) { - if (!ntfs_read(ctx, record_buffer, current_offset, ctx->mft_record_size)) { - printf("Failed to read MFT record at offset 0x%llX\n", - (unsigned long long)current_offset); - break; - } - - const MFTRecordHeader* record = (const MFTRecordHeader*)record_buffer; - if (memcmp(record->magic, "FILE", 4) == 0) { - processed_records++; - if (process_mft_record(ctx, record_buffer)) { - extracted_records++; - } - } - - current_offset += ctx->mft_record_size; - - time_t current_time = time(NULL); - if (current_time != last_update_time) { - int percentage = (int)((i + 1) * 100 / total_records); - if (percentage != last_percentage) { - printf("\rProgress: %d%%", percentage); - fflush(stdout); - last_percentage = percentage; - } - last_update_time = current_time; - } - } - - printf("\rProgress: 100%%\n"); - - printf("Extraction completed.\n"); - - free(record_buffer); - return true; -} - -void ntfs_close(NTFSContext* ctx) { - if (ctx->is_vhd) { - if (ctx->vhd.fp) { - fclose(ctx->vhd.fp); - free(ctx->vhd.bat); - free(ctx->vhd.sector_bitmap); - free(ctx->vhd.block_buffer); - } - } - else { - if (ctx->raw.fp) { - fclose(ctx->raw.fp); - } - } - free_directory_cache(&ctx->dir_cache); - memset(ctx, 0, sizeof(NTFSContext)); -} \ No newline at end of file diff --git a/unsegareborn/ntfs.h b/unsegareborn/ntfs.h deleted file mode 100644 index 6293791..0000000 --- a/unsegareborn/ntfs.h +++ /dev/null @@ -1,224 +0,0 @@ -#ifndef NTFS_H -#define NTFS_H - -#include -#include -#include -#include -#include -#include -#include "common.h" - -#define fseeko _fseeki64 -#define ftello _ftelli64 - -#define VHD_FOOTER_SIZE 512 -#define VHD_SECTOR_SIZE 512 -#define VHD_BAT_ENTRY_RESERVED 0xFFFFFFFF -#define NTFS_RECORD_SIZE 1024 -#define MFT_RECORD_MAGIC "FILE" -#define VHD_COOKIE "conectix" -#define VHD_DYNAMIC_COOKIE "cxsparse" -#define VHD_TYPE_FIXED 2 -#define VHD_TYPE_DYNAMIC 3 -#define FILE_NAME_ATTR 0x30 -#define DATA_ATTR 0x80 -#define INDEX_ROOT_ATTR 0x90 -#define INDEX_ALLOCATION_ATTR 0xA0 -#define NTFS_SIGNATURE "NTFS " -#define NTFS_PARTITION_TYPE 0x07 -#define MFT_RECORD_IN_USE 0x0001 -#define MFT_RECORD_IS_DIRECTORY 0x0002 - -typedef struct { - uint64_t ref_number; - char path[MAX_PATH_LENGTH]; -} DirectoryInfo; - -typedef struct { - DirectoryInfo* directories; - size_t capacity; - size_t count; -} DirectoryCache; - -#pragma pack(push, 1) - -typedef struct { - char cookie[8]; - uint32_t features; - uint32_t version; - uint64_t data_offset; - uint32_t timestamp; - uint32_t creator_app; - uint32_t creator_ver; - uint32_t creator_os; - uint64_t original_size; - uint64_t current_size; - uint16_t cylinder; - uint8_t heads; - uint8_t sectors; - uint32_t disk_type; - uint32_t checksum; - uint8_t unique_id[16]; - uint8_t saved_state; - uint8_t reserved[427]; -} VHDFooter; - -typedef struct { - char cookie[8]; - uint64_t data_offset; - uint64_t bat_offset; - uint32_t head_vers; - uint32_t max_bat_entries; - uint32_t block_size; - uint32_t checksum; - uint8_t parent_id[16]; - uint32_t parent_timestamp; - uint32_t reserved1; - uint16_t parent_name[256]; - uint8_t parent_loc[8][512]; - uint8_t reserved2[256]; -} VHDDynamicHeader; - -typedef struct { - uint8_t jump[3]; - uint8_t signature[8]; - uint16_t bytes_per_sector; - uint8_t sectors_per_cluster; - uint16_t reserved_sectors; - uint8_t always_zero1[3]; - uint16_t not_used1; - uint8_t media_descriptor; - uint16_t always_zero2; - uint16_t sectors_per_track; - uint16_t number_of_heads; - uint32_t hidden_sectors; - uint32_t not_used2; - uint32_t not_used3; - uint64_t total_sectors; - uint64_t mft_cluster_number; - uint64_t mft_mirror_cluster_number; - int8_t clusters_per_mft_record; - uint8_t not_used4[3]; - int8_t clusters_per_index_record; - uint8_t not_used5[3]; - uint64_t volume_serial_number; - uint32_t checksum; -} NTFSBootSector; - -typedef struct { - char magic[4]; - uint16_t usa_offset; - uint16_t usa_count; - uint64_t lsn; - uint16_t sequence_number; - uint16_t link_count; - uint16_t attrs_offset; - uint16_t flags; - uint32_t bytes_used; - uint32_t bytes_allocated; - uint64_t base_ref; - uint16_t next_attr_id; - uint16_t record_number; - uint16_t usa_value; -} MFTRecordHeader; - -typedef struct { - uint32_t type; - uint32_t length; - uint8_t non_resident; - uint8_t name_length; - uint16_t name_offset; - uint16_t flags; - uint16_t attribute_id; - union { - struct { - uint32_t value_length; - uint16_t value_offset; - uint16_t flags; - } resident; - struct { - uint64_t lowest_vcn; - uint64_t highest_vcn; - uint16_t mapping_pairs_offset; - uint16_t compression_unit; - uint32_t padding; - uint64_t allocated_size; - uint64_t data_size; - uint64_t initialized_size; - uint64_t compressed_size; - } non_resident; - } data; -} AttributeHeader; - -typedef struct { - uint64_t parent_directory; - uint64_t creation_time; - uint64_t modification_time; - uint64_t mft_modification_time; - uint64_t access_time; - uint64_t allocated_size; - uint64_t real_size; - uint32_t flags; - uint32_t reparse_value; - uint8_t name_length; - uint8_t namespace; - uint16_t name[256]; -} FileNameAttribute; - -typedef struct { - uint64_t offset; - uint64_t length; -} DataRun; - -#pragma pack(pop) - -typedef struct { - FILE* fp; - VHDFooter footer; - VHDDynamicHeader dyn_header; - uint32_t* bat; - uint32_t sector_bitmap_size; - uint8_t* sector_bitmap; - uint8_t* block_buffer; -} VHDContext; - -typedef struct { - char name[MAX_FILENAME_LENGTH]; - uint64_t parent_ref; - bool is_directory; - bool valid; -} FileInfo; - -typedef struct { - FILE* fp; -} RawNTFSContext; - -typedef struct { - union { - VHDContext vhd; - RawNTFSContext raw; - }; - bool is_vhd; - NTFSBootSector boot; - uint32_t bytes_per_cluster; - uint64_t mft_offset; - uint32_t mft_record_size; - uint64_t mft_data_size; - uint64_t total_mft_records; - char base_path[MAX_PATH_LENGTH]; - DirectoryCache dir_cache; - uint64_t data_start_offset; -} NTFSContext; - -bool ntfs_init(NTFSContext* ctx, const char* vhd_path, const char* extract_path); -bool ntfs_extract_all(NTFSContext* ctx); -void ntfs_close(NTFSContext* ctx); -static bool vhd_read(VHDContext* ctx, void* buffer, uint64_t offset, size_t size); -static bool create_directories(const char* path); -static void convert_name_to_ascii(const uint16_t* utf16_name, int name_length, char* ascii_name); -static bool add_directory_to_cache(DirectoryCache* cache, uint64_t ref_number, const char* path); -static bool vhd_init(VHDContext* ctx, const char* filename); -static bool ntfs_read(NTFSContext* ctx, void* buffer, uint64_t offset, size_t size); - -#endif // NTFS_H \ No newline at end of file diff --git a/unsegareborn/unsegareborn.vcxproj b/unsegareborn/unsegareborn.vcxproj deleted file mode 100644 index c3cdfbe..0000000 --- a/unsegareborn/unsegareborn.vcxproj +++ /dev/null @@ -1,150 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {4b2c8a0e-0be1-4ed1-8108-6124c58f3a46} - unsegareturn - 10.0 - unsegareborn - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - - - Console - true - "D:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64\WS2_32.Lib";"D:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64\User32.Lib";"D:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64\Crypt32.Lib";"C:\Users\User\vcpkg\buildtrees\openssl\x64-windows-rel\libssl_static.lib";"C:\Users\User\vcpkg\buildtrees\openssl\x64-windows-rel\libcrypto_static.lib";%(AdditionalDependencies) - - - - - Level3 - true - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - - - Console - true - true - true - "D:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64\WS2_32.Lib";"D:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64\User32.Lib";"D:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64\Crypt32.Lib";"C:\Users\User\vcpkg\buildtrees\openssl\x64-windows-rel\libssl_static.lib";"C:\Users\User\vcpkg\buildtrees\openssl\x64-windows-rel\libcrypto_static.lib";%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/unsegareborn/unsegareborn.vcxproj.filters b/unsegareborn/unsegareborn.vcxproj.filters deleted file mode 100644 index 009fe1f..0000000 --- a/unsegareborn/unsegareborn.vcxproj.filters +++ /dev/null @@ -1,48 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/unsegareborn/unsegareborn.vcxproj.user b/unsegareborn/unsegareborn.vcxproj.user deleted file mode 100644 index 0f14913..0000000 --- a/unsegareborn/unsegareborn.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file