5 Commits

8 changed files with 61 additions and 20 deletions

View File

@ -32,7 +32,7 @@ include $(DEVKITPRO)/libnx/switch_rules
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
APP_TITLE := Lockpick APP_TITLE := Lockpick
APP_AUTHOR := shchmue APP_AUTHOR := shchmue
APP_VERSION := 1.2.3 APP_VERSION := 1.2.6
TARGET := $(subst $e ,_,$(notdir $(APP_TITLE))) TARGET := $(subst $e ,_,$(notdir $(APP_TITLE)))
BUILD := build BUILD := build

View File

@ -36,7 +36,7 @@ Notes
Building Building
= =
Release built with [libnx commit d2e2c15](https://github.com/switchbrew/libnx/tree/d2e2c159374f18c22350846019f2a615cb35b523). Release built with [libnx release v2.4.0](https://github.com/switchbrew/libnx).
Uses `freetype` which comes with `switch-portlibs` via `devkitPro pacman`: Uses `freetype` which comes with `switch-portlibs` via `devkitPro pacman`:
``` ```

View File

@ -1,4 +1,16 @@
# Changelog # Changelog
## Version 1.2.6
* Fix bis key generation on newer hardware
## Version 1.2.5
* Support Hekate v5 fuse dump format
* Make names consistent with libnx v2.2.0
* Adjust text alignment and coloring in Lockpick_RCM note
## Version 1.2.4
* Support new emunand FS memory layout
* No longer save header_key if empty
## Version 1.2.3 ## Version 1.2.3
* Remove mbedtls dependency in favor of new libnx crypto library * Remove mbedtls dependency in favor of new libnx crypto library
* Remove libnx 1.6.0 support since crypto requires later commit * Remove libnx 1.6.0 support since crypto requires later commit

View File

@ -125,8 +125,10 @@ namespace Common {
framebufferEnd(&fb); framebufferEnd(&fb);
draw_text(0x010, 0x020, YELLOW, "Lockpick! by shchmue"); draw_text(0x010, 0x020, YELLOW, "Lockpick! by shchmue");
draw_text(0x190, 0x020, YELLOW, "Note: This can only dump keys 00-05 (or 00-06 on 6.2.0)"); draw_text(0x190, 0x020, YELLOW, "Note:");
draw_text(0x190, 0x040, YELLOW, "Use Lockpick_RCM for newer keys on firmware 7.0.0+!"); draw_text(0x1e0, 0x020, YELLOW, "Lockpick can only dump keys 00-05 (or 00-06 on 6.2.0)");
draw_text(0x1e0, 0x040, CYAN, "Lockpick_RCM");
draw_text(0x2a0, 0x040, YELLOW, "can get newer keys on firmware 7.0.0+!");
draw_set_rect(814, 452 + 42 * 0, 450, 42, FLAG_RED); draw_set_rect(814, 452 + 42 * 0, 450, 42, FLAG_RED);
draw_set_rect(814, 452 + 42 * 1, 450, 42, FLAG_ORANGE); draw_set_rect(814, 452 + 42 * 1, 450, 42, FLAG_ORANGE);
@ -159,8 +161,9 @@ namespace Common {
if (std::filesystem::exists("/backup")) { if (std::filesystem::exists("/backup")) {
for (auto &p : std::filesystem::recursive_directory_iterator("/backup")) { for (auto &p : std::filesystem::recursive_directory_iterator("/backup")) {
if (p.is_regular_file()) { if (p.is_regular_file()) {
if (!sbk.found() && (p.file_size() == 0x2fc) && if (!sbk.found() && (p.file_size() == 0x2fc || p.file_size() == 0x300) &&
(std::string("fuse").compare(std::string(p.path().filename()).substr(0, 4)) == 0)) ((p.path().filename().string().substr(0, 5).compare("fuses") == 0) ||
(p.path().filename().string().substr(0, 11).compare("fuse_cached") == 0)))
{ {
FILE *fuse_file = fopen(p.path().c_str(), "rb"); FILE *fuse_file = fopen(p.path().c_str(), "rb");
if (!fuse_file) continue; if (!fuse_file) continue;
@ -171,7 +174,7 @@ namespace Common {
fclose(fuse_file); fclose(fuse_file);
} }
else if (!tsec.found() && (p.file_size() == 0x20 || p.file_size() == 0x30) && else if (!tsec.found() && (p.file_size() == 0x20 || p.file_size() == 0x30) &&
(std::string("tsec").compare(std::string(p.path().filename()).substr(0, 4)) == 0)) (p.path().filename().string().substr(0, 4).compare("tsec") == 0))
{ {
FILE *tsec_file = fopen(p.path().c_str(), "rb"); FILE *tsec_file = fopen(p.path().c_str(), "rb");
if (!tsec_file) continue; if (!tsec_file) continue;

View File

@ -392,7 +392,6 @@ void KeyCollection::get_memory_keys() {
} }
void KeyCollection::derive_keys() { void KeyCollection::derive_keys() {
header_key = {"header_key", 0x20, {}};
if (header_kek_source.found() && header_key_source.found()) { if (header_kek_source.found() && header_key_source.found()) {
u8 tempheaderkek[0x10], tempheaderkey[0x20]; u8 tempheaderkek[0x10], tempheaderkey[0x20];
splCryptoInitialize(); splCryptoInitialize();
@ -403,16 +402,28 @@ void KeyCollection::derive_keys() {
splCryptoExit(); splCryptoExit();
} }
if (bis_key_source_00.found() && bis_key_source_01.found() && bis_key_source_02.found()) { u64 key_generation = 0;
SetSysFirmwareVersion ver;
setsysInitialize();
setsysGetFirmwareVersion(&ver);
setsysExit();
Result rc = 0;
if (ver.major >= 5) {
rc = splGetConfig(SplConfigItem_NewKeyGeneration, &key_generation);
}
if (R_SUCCEEDED(rc) && bis_key_source_00.found() && bis_key_source_01.found() && bis_key_source_02.found()) {
u8 tempbiskek[0x10], tempbiskey[0x20]; u8 tempbiskek[0x10], tempbiskey[0x20];
splFsInitialize(); splFsInitialize();
splFsGenerateSpecificAesKey(bis_key_source_00.key.data() + 0x00, 0, 0, tempbiskey + 0x00); splFsGenerateSpecificAesKey(bis_key_source_00.key.data() + 0x00, key_generation, 0, tempbiskey + 0x00);
splFsGenerateSpecificAesKey(bis_key_source_00.key.data() + 0x10, 0, 0, tempbiskey + 0x10); splFsGenerateSpecificAesKey(bis_key_source_00.key.data() + 0x10, key_generation, 0, tempbiskey + 0x10);
bis_key.push_back(Key {"bis_key_00", 0x20, byte_vector(tempbiskey, tempbiskey + 0x20)}); bis_key.push_back(Key {"bis_key_00", 0x20, byte_vector(tempbiskey, tempbiskey + 0x20)});
splFsExit(); splFsExit();
splCryptoInitialize(); splCryptoInitialize();
splCryptoGenerateAesKek(bis_kek_source.key.data(), 0, 1, tempbiskek); splCryptoGenerateAesKek(bis_kek_source.key.data(), key_generation, 1, tempbiskek);
splCryptoGenerateAesKey(tempbiskek, bis_key_source_01.key.data() + 0x00, tempbiskey + 0x00); splCryptoGenerateAesKey(tempbiskek, bis_key_source_01.key.data() + 0x00, tempbiskey + 0x00);
splCryptoGenerateAesKey(tempbiskek, bis_key_source_01.key.data() + 0x10, tempbiskey + 0x10); splCryptoGenerateAesKey(tempbiskek, bis_key_source_01.key.data() + 0x10, tempbiskey + 0x10);
bis_key.push_back(Key {"bis_key_01", 0x20, byte_vector(tempbiskey, tempbiskey + 0x20)}); bis_key.push_back(Key {"bis_key_01", 0x20, byte_vector(tempbiskey, tempbiskey + 0x20)});
@ -475,7 +486,7 @@ void KeyCollection::derive_keys() {
FRESULT fr; FRESULT fr;
FIL save_file; FIL save_file;
fsOpenBisStorage(&storage, 31); fsOpenBisStorage(&storage, FsBisStorageId_System);
if (f_mount(&fs, "", 1) || if (f_mount(&fs, "", 1) ||
f_chdir("/save") || f_chdir("/save") ||
f_open(&save_file, "8000000000000043", FA_READ | FA_OPEN_EXISTING)) f_open(&save_file, "8000000000000043", FA_READ | FA_OPEN_EXISTING))
@ -581,7 +592,7 @@ void KeyCollection::get_titlekeys() {
esInitialize(); esInitialize();
esCountCommonTicket(&common_count); esCountCommonTicket(&common_count);
esCountPersonalizedTicket(&personalized_count); esCountPersonalizedTicket(&personalized_count);
NcmRightsId common_rights_ids[common_count], personalized_rights_ids[personalized_count]; NcmNcaId common_rights_ids[common_count], personalized_rights_ids[personalized_count];
esListCommonTicket(&ids_written, common_rights_ids, sizeof(common_rights_ids)); esListCommonTicket(&ids_written, common_rights_ids, sizeof(common_rights_ids));
esListPersonalizedTicket(&ids_written, personalized_rights_ids, sizeof(personalized_rights_ids)); esListPersonalizedTicket(&ids_written, personalized_rights_ids, sizeof(personalized_rights_ids));
esExit(); esExit();
@ -635,7 +646,7 @@ void KeyCollection::get_titlekeys() {
// map of all found rights ids and corresponding titlekeys // map of all found rights ids and corresponding titlekeys
std::unordered_map<std::string, std::string> titlekeys; std::unordered_map<std::string, std::string> titlekeys;
fsOpenBisStorage(&storage, 31); fsOpenBisStorage(&storage, FsBisStorageId_System);
if (f_mount(&fs, "", 1) || f_chdir("/save")) return; if (f_mount(&fs, "", 1) || f_chdir("/save")) return;
if (f_open(&save_file, "80000000000000e1", FA_READ | FA_OPEN_EXISTING)) return; if (f_open(&save_file, "80000000000000e1", FA_READ | FA_OPEN_EXISTING)) return;
while ((common_count != 0) && (titlekeys_dumped < common_count)) { while ((common_count != 0) && (titlekeys_dumped < common_count)) {

View File

@ -62,7 +62,22 @@ void KeyLocation::get_from_memory(u64 tid, u8 seg_mask) {
u32 page_info; u32 page_info;
u64 addr = 0; u64 addr = 0;
u64 last_text_addr = 0;
// locate "real" .text segment as Atmosphere emuNAND has two
for (;;) {
svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr);
if ((mem_info.perm & Perm_X) &&
((mem_info.type & 0xff) >= MemType_CodeStatic) &&
((mem_info.type & 0xff) < MemType_Heap))
{
last_text_addr = mem_info.addr;
}
addr = mem_info.addr + mem_info.size;
if (addr == 0) break;
}
addr = last_text_addr;
for (u8 segment = 1; segment < BIT(3); ) for (u8 segment = 1; segment < BIT(3); )
{ {
svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr); svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr);
@ -86,7 +101,7 @@ void KeyLocation::get_from_memory(u64 tid, u8 seg_mask) {
void KeyLocation::get_keyblobs() { void KeyLocation::get_keyblobs() {
FsStorage boot0; FsStorage boot0;
fsOpenBisStorage(&boot0, 0); fsOpenBisStorage(&boot0, FsBisStorageId_Boot0);
data.resize(0x200 * KNOWN_KEYBLOBS); data.resize(0x200 * KNOWN_KEYBLOBS);
fsStorageRead(&boot0, KEYBLOB_OFFSET, data.data(), data.size()); fsStorageRead(&boot0, KEYBLOB_OFFSET, data.data(), data.size());
fsStorageClose(&boot0); fsStorageClose(&boot0);

View File

@ -97,7 +97,7 @@ Result esCountPersonalizedTicket(u32 *num_tickets)
return rc; return rc;
} }
Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize) { Result esListCommonTicket(u32 *numRightsIdsWritten, NcmNcaId *outBuf, size_t bufSize) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal); ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
@ -133,7 +133,7 @@ Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t
return rc; return rc;
} }
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize) { Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmNcaId *outBuf, size_t bufSize) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal); ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);

View File

@ -8,5 +8,5 @@ void esExit();
Result esCountCommonTicket(u32 *num_tickets); //9 Result esCountCommonTicket(u32 *num_tickets); //9
Result esCountPersonalizedTicket(u32 *num_tickets); // 10 Result esCountPersonalizedTicket(u32 *num_tickets); // 10
Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize); Result esListCommonTicket(u32 *numRightsIdsWritten, NcmNcaId *outBuf, size_t bufSize);
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize); Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmNcaId *outBuf, size_t bufSize);