refactor: make code work with mingw
This commit is contained in:
parent
929acfab04
commit
f364acaec3
@ -4,7 +4,11 @@
|
|||||||
#include <endian_helper.h>
|
#include <endian_helper.h>
|
||||||
#include <md5.h>
|
#include <md5.h>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Infra {
|
namespace Infra {
|
||||||
|
|
||||||
@ -18,15 +22,15 @@ inline bool is_valid_page_1_header(const uint8_t* page1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void derive_page_key(uint8_t* aes_key, uint8_t* aes_iv, const uint8_t* p_master_key, const uint32_t page_no) {
|
void derive_page_key(uint8_t* aes_key, uint8_t* aes_iv, const uint8_t* p_master_key, const uint32_t page_no) {
|
||||||
uint8_t buffer[0x18];
|
std::array<uint8_t, 0x18> buffer{};
|
||||||
|
|
||||||
// Setup buffer
|
// Setup buffer
|
||||||
memcpy(buffer, p_master_key, 0x10);
|
std::copy_n(p_master_key, 0x10, buffer.begin());
|
||||||
Endian::le_write(&buffer[0x10], page_no);
|
Endian::le_write(&buffer[0x10], page_no);
|
||||||
Endian::le_write(&buffer[0x14], 0x546C4173);
|
Endian::le_write(&buffer[0x14], 0x546C4173);
|
||||||
|
|
||||||
// Derive Key
|
// Derive Key
|
||||||
md5(aes_key, buffer, 24);
|
md5(aes_key, buffer.data(), buffer.size());
|
||||||
|
|
||||||
// Derive IV
|
// Derive IV
|
||||||
for (uint32_t ebx{page_no + 1}, i = 0; i < 16; i += 4) {
|
for (uint32_t ebx{page_no + 1}, i = 0; i < 16; i += 4) {
|
||||||
@ -38,10 +42,10 @@ void derive_page_key(uint8_t* aes_key, uint8_t* aes_iv, const uint8_t* p_master_
|
|||||||
ebx = ecx;
|
ebx = ecx;
|
||||||
Endian::le_write(&buffer[i], ebx);
|
Endian::le_write(&buffer[i], ebx);
|
||||||
}
|
}
|
||||||
md5(aes_iv, buffer, 16);
|
md5(aes_iv, buffer.data(), 0x10);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
memset(buffer, 0xCC, sizeof(buffer));
|
std::ranges::fill(buffer, 0xcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t kDefaultMasterKey[0x10] = {
|
static const uint8_t kDefaultMasterKey[0x10] = {
|
||||||
@ -49,8 +53,8 @@ static const uint8_t kDefaultMasterKey[0x10] = {
|
|||||||
0x3d, 0x18, 0x96, 0x72, 0x14, 0x4f, 0xe4, 0xbf, //
|
0x3d, 0x18, 0x96, 0x72, 0x14, 0x4f, 0xe4, 0xbf, //
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr uint8_t kSQLiteDatabaseHeader[0x10] = {'S', 'Q', 'L', 'i', 't', 'e', ' ', 'f',
|
static constexpr std::array<uint8_t, 0x10> kSQLiteDatabaseHeader = { //
|
||||||
'o', 'r', 'm', 'a', 't', ' ', '3', 0};
|
'S', 'Q', 'L', 'i', 't', 'e', ' ', 'f', 'o', 'r', 'm', 'a', 't', ' ', '3', 0};
|
||||||
|
|
||||||
int load_db(std::vector<uint8_t>& db_data, const std::filesystem::path& db_path) {
|
int load_db(std::vector<uint8_t>& db_data, const std::filesystem::path& db_path) {
|
||||||
using namespace AES;
|
using namespace AES;
|
||||||
@ -87,25 +91,25 @@ int load_db(std::vector<uint8_t>& db_data, const std::filesystem::path& db_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (page_no == 1) [[unlikely]] {
|
if (page_no == 1) [[unlikely]] {
|
||||||
if (memcmp(p_page, kSQLiteDatabaseHeader, 0x10) == 0) {
|
if (std::equal(kSQLiteDatabaseHeader.cbegin(), kSQLiteDatabaseHeader.cend(), p_page)) {
|
||||||
ifs_db.read(reinterpret_cast<char*>(p_page + kPageSize),
|
ifs_db.read(reinterpret_cast<char*>(p_page + kPageSize),
|
||||||
static_cast<std::streamsize>(db_size - kPageSize));
|
static_cast<std::streamsize>(db_size - kPageSize));
|
||||||
return SQLITE_OK; // no encryption
|
return SQLITE_OK; // no encryption
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_valid_page_1_header(p_page)) [[unlikely]] {
|
if (!is_valid_page_1_header(p_page)) {
|
||||||
db_data.clear();
|
db_data.clear();
|
||||||
return SQLITE_CORRUPT; // header validation failed
|
return SQLITE_CORRUPT; // header validation failed
|
||||||
}
|
}
|
||||||
uint8_t backup[0x08]; // backup magic numbers
|
std::array<uint8_t, 8> backup{}; // backup magic numbers
|
||||||
memcpy(&backup, &p_page[0x10], 0x08);
|
std::copy_n(&p_page[0x10], 0x08, backup.begin());
|
||||||
memcpy(&p_page[0x10], &p_page[0x08], 0x08);
|
std::copy_n(&p_page[0x08], 0x08, &p_page[0x10]);
|
||||||
AES_CBC_decrypt_buffer(&ctx_aes, p_page + 0x10, kPageSize - 0x10);
|
AES_CBC_decrypt_buffer(&ctx_aes, p_page + 0x10, kPageSize - 0x10);
|
||||||
if (memcmp(backup, &p_page[0x10], 0x08) != 0) {
|
if (!std::equal(backup.cbegin(), backup.cend(), &p_page[0x10])) {
|
||||||
db_data.clear();
|
db_data.clear();
|
||||||
return SQLITE_CORRUPT; // header validation failed
|
return SQLITE_CORRUPT; // header validation failed
|
||||||
}
|
}
|
||||||
memcpy(p_page, kSQLiteDatabaseHeader, 0x10);
|
std::ranges::copy(kSQLiteDatabaseHeader, p_page);
|
||||||
} else {
|
} else {
|
||||||
AES_CBC_decrypt_buffer(&ctx_aes, p_page, kPageSize);
|
AES_CBC_decrypt_buffer(&ctx_aes, p_page, kPageSize);
|
||||||
}
|
}
|
||||||
|
26
src/jobs.hpp
26
src/jobs.hpp
@ -1,31 +1,35 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <windows.h>
|
#include "qmc2/qmc2.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <condition_variable>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "qmc2/qmc2.h"
|
|
||||||
|
|
||||||
class KggTask {
|
class KggTask {
|
||||||
public:
|
public:
|
||||||
explicit KggTask(std::filesystem::path kgg_path, std::filesystem::path out_dir)
|
explicit KggTask(std::filesystem::path kgg_path, std::filesystem::path out_dir)
|
||||||
: kgg_path_(std::move(kgg_path)), out_dir_(std::move(out_dir)) {}
|
: kgg_path_(std::move(kgg_path)), out_dir_(std::move(out_dir)) {}
|
||||||
|
|
||||||
void warning(const wchar_t* msg) const { fwprintf(stderr, L"[WARN] %s (%s)\n", msg, kgg_path_.filename().c_str()); }
|
static void log(const std::wstring& msg) { fputws(msg.c_str(), stderr); }
|
||||||
void warning(const std::wstring& msg) const { warning(msg.c_str()); }
|
void warning(const std::wstring& msg) const {
|
||||||
|
log(std::format(L"[WARN] {} ({})\n", msg, kgg_path_.filename().wstring()));
|
||||||
void error(const wchar_t* msg) const { fwprintf(stderr, L"[ERR ] %s (%s)\n", msg, kgg_path_.filename().c_str()); }
|
}
|
||||||
void error(const std::wstring& msg) const { error(msg.c_str()); }
|
void error(const std::wstring& msg) const {
|
||||||
|
log(std::format(L"[ERR ] {} ({})\n", msg, kgg_path_.filename().wstring()));
|
||||||
void info(const wchar_t* msg) const { fwprintf(stderr, L"[INFO] %s (%s)\n", msg, kgg_path_.filename().c_str()); }
|
}
|
||||||
void info(const std::wstring& msg) const { info(msg.c_str()); }
|
void info(const std::wstring& msg) const {
|
||||||
|
log(std::format(L"[INFO] {} ({})\n", msg, kgg_path_.filename().wstring()));
|
||||||
|
}
|
||||||
|
|
||||||
void Execute(const Infra::kgm_ekey_db_t& ekey_db, const std::wstring_view suffix) const {
|
void Execute(const Infra::kgm_ekey_db_t& ekey_db, const std::wstring_view suffix) const {
|
||||||
constexpr static std::array<uint8_t, 16> kMagicHeader{0x7C, 0xD5, 0x32, 0xEB, 0x86, 0x02, 0x7F, 0x4B,
|
constexpr static std::array<uint8_t, 16> kMagicHeader{0x7C, 0xD5, 0x32, 0xEB, 0x86, 0x02, 0x7F, 0x4B,
|
||||||
|
@ -29,7 +29,7 @@ void WalkFileOrDir(KggTaskQueue& queue, const std::filesystem::path& input_path,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fwprintf(stderr, L"[WARN] invalid path: %s\n", target_path.c_str());
|
fputws(std::format(L"[WARN] invalid path: {}\n", target_path.wstring()).c_str(), stderr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user