mirror of
https://github.com/shchmue/Lockpick.git
synced 2025-02-09 22:33:06 +01:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b150d20957 | ||
|
d91923accc | ||
|
9bbef1cc69 | ||
|
b85a2e6631 | ||
|
09f9e4242c | ||
|
b2ca9c881d | ||
|
0c6bb239f0 | ||
|
b65668144f | ||
|
31a882496f |
2
Makefile
2
Makefile
@ -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
|
||||||
|
@ -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`:
|
||||||
```
|
```
|
||||||
|
12
changelog.md
12
changelog.md
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "nx/es.h"
|
#include "nx/es.h"
|
||||||
#include "nx/set_ext.h"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TITLEKEY_BUFFER_SIZE 0x40000
|
#define TITLEKEY_BUFFER_SIZE 0x40000
|
||||||
@ -392,7 +391,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 +401,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 +485,7 @@ void KeyCollection::derive_keys() {
|
|||||||
FRESULT fr;
|
FRESULT fr;
|
||||||
FIL save_file;
|
FIL save_file;
|
||||||
|
|
||||||
fsOpenBisStorage(&storage, 31);
|
fsOpenBisStorage(&storage, FsBisPartitionId_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 +591,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];
|
RightsId 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();
|
||||||
@ -609,15 +619,15 @@ void KeyCollection::get_titlekeys() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get extended eticket RSA key from PRODINFO
|
// get extended eticket RSA key from PRODINFO
|
||||||
u8 eticket_data[0x244] = {};
|
SetCalRsa2048DeviceKey eticket_data = {};
|
||||||
|
|
||||||
setcalInitialize();
|
setcalInitialize();
|
||||||
setcalGetEticketDeviceKey(eticket_data);
|
setcalGetEticketDeviceKey(&eticket_data);
|
||||||
setcalExit();
|
setcalExit();
|
||||||
|
|
||||||
byte_vector dec_keypair = eticket_rsa_kek.aes_decrypt_ctr(
|
byte_vector dec_keypair = eticket_rsa_kek.aes_decrypt_ctr(
|
||||||
byte_vector(eticket_data + 0x14, eticket_data + 0x244),
|
byte_vector(eticket_data.key + 0x10, eticket_data.key + 0x240),
|
||||||
byte_vector(eticket_data + 4, eticket_data + 0x14)
|
byte_vector(eticket_data.key, eticket_data.key + 0x10)
|
||||||
);
|
);
|
||||||
|
|
||||||
// public exponent must be 65537 == 0x10001 (big endian)
|
// public exponent must be 65537 == 0x10001 (big endian)
|
||||||
@ -635,7 +645,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, FsBisPartitionId_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)) {
|
||||||
|
@ -30,7 +30,7 @@ void KeyLocation::get_from_memory(u64 tid, u8 seg_mask) {
|
|||||||
// if not a kernel process, get pid from pm:dmnt
|
// if not a kernel process, get pid from pm:dmnt
|
||||||
if ((tid > 0x0100000000000005) && (tid != 0x0100000000000028)) {
|
if ((tid > 0x0100000000000005) && (tid != 0x0100000000000028)) {
|
||||||
u64 pid;
|
u64 pid;
|
||||||
pmdmntGetTitlePid(&pid, tid);
|
pmdmntGetProcessId(&pid, tid);
|
||||||
|
|
||||||
if (R_FAILED(svcDebugActiveProcess(&debug_handle, pid)) ||
|
if (R_FAILED(svcDebugActiveProcess(&debug_handle, pid)) ||
|
||||||
R_FAILED(svcGetDebugEvent(reinterpret_cast<u8 *>(&d), debug_handle)))
|
R_FAILED(svcGetDebugEvent(reinterpret_cast<u8 *>(&d), debug_handle)))
|
||||||
@ -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, FsBisPartitionId_BootPartition1Root);
|
||||||
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);
|
||||||
|
156
source/nx/es.c
156
source/nx/es.c
@ -1,170 +1,64 @@
|
|||||||
#include "es.h"
|
#include "es.h"
|
||||||
|
|
||||||
#include <switch/arm/atomics.h>
|
#include "../service_guard.h"
|
||||||
|
|
||||||
#include <switch/kernel/ipc.h>
|
#include <switch/kernel/ipc.h>
|
||||||
#include <switch/services/sm.h>
|
#include <switch/services/sm.h>
|
||||||
|
|
||||||
static Service g_esSrv;
|
static Service g_esSrv;
|
||||||
static u64 g_esRefCnt;
|
|
||||||
|
|
||||||
Result esInitialize() {
|
NX_GENERATE_SERVICE_GUARD(es);
|
||||||
atomicIncrement64(&g_esRefCnt);
|
|
||||||
|
|
||||||
if (serviceIsActive(&g_esSrv))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
Result _esInitialize() {
|
||||||
return smGetService(&g_esSrv, "es");
|
return smGetService(&g_esSrv, "es");
|
||||||
}
|
}
|
||||||
|
|
||||||
void esExit()
|
void _esCleanup() {
|
||||||
{
|
|
||||||
if (atomicDecrement64(&g_esRefCnt) == 0) {
|
|
||||||
serviceClose(&g_esSrv);
|
serviceClose(&g_esSrv);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esCountCommonTicket(u32 *num_tickets)
|
Result esCountCommonTicket(u32 *out_count)
|
||||||
{
|
{
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 9;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 num_tickets;
|
u32 num_tickets;
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
Result rc = serviceDispatchOut(&g_esSrv, 9, num_tickets);
|
||||||
|
if (R_SUCCEEDED(rc) && out_count) *out_count = num_tickets;
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
*num_tickets = resp->num_tickets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esCountPersonalizedTicket(u32 *num_tickets)
|
Result esCountPersonalizedTicket(u32 *out_count)
|
||||||
{
|
{
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 10;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 num_tickets;
|
u32 num_tickets;
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
Result rc = serviceDispatchOut(&g_esSrv, 10, num_tickets);
|
||||||
|
if (R_SUCCEEDED(rc) && out_count) *out_count = num_tickets;
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
*num_tickets = resp->num_tickets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize) {
|
Result esListCommonTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize)
|
||||||
IpcCommand c;
|
{
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 11;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 num_rights_ids_written;
|
u32 num_rights_ids_written;
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
Result rc = serviceDispatchOut(&g_esSrv, 11, num_rights_ids_written,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||||
if (R_SUCCEEDED(rc)) {
|
.buffers = { { outBuf, bufSize } },
|
||||||
if (numRightsIdsWritten) *numRightsIdsWritten = resp->num_rights_ids_written;
|
);
|
||||||
}
|
if (R_SUCCEEDED(rc) && numRightsIdsWritten) *numRightsIdsWritten = num_rights_ids_written;
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize) {
|
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize)
|
||||||
IpcCommand c;
|
{
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 12;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 num_rights_ids_written;
|
u32 num_rights_ids_written;
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
Result rc = serviceDispatchOut(&g_esSrv, 12, num_rights_ids_written,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||||
if (R_SUCCEEDED(rc)) {
|
.buffers = { { outBuf, bufSize } },
|
||||||
if (numRightsIdsWritten) *numRightsIdsWritten = resp->num_rights_ids_written;
|
);
|
||||||
}
|
if (R_SUCCEEDED(rc) && numRightsIdsWritten) *numRightsIdsWritten = num_rights_ids_written;
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
@ -3,10 +3,14 @@
|
|||||||
#include <switch/types.h>
|
#include <switch/types.h>
|
||||||
#include <switch/services/ncm.h>
|
#include <switch/services/ncm.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 c[0x10];
|
||||||
|
} RightsId;
|
||||||
|
|
||||||
Result esInitialize();
|
Result esInitialize();
|
||||||
void esExit();
|
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, RightsId *outBuf, size_t bufSize);
|
||||||
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize);
|
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize);
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
#include "set_ext.h"
|
|
||||||
|
|
||||||
#include <switch/arm/atomics.h>
|
|
||||||
#include <switch/services/sm.h>
|
|
||||||
#include <switch/types.h>
|
|
||||||
|
|
||||||
static Service g_setcalSrv;
|
|
||||||
static u64 g_refCntCal;
|
|
||||||
|
|
||||||
Result setcalInitialize(void) {
|
|
||||||
atomicIncrement64(&g_refCntCal);
|
|
||||||
|
|
||||||
if (serviceIsActive(&g_setcalSrv))
|
|
||||||
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
|
||||||
|
|
||||||
return smGetService(&g_setcalSrv, "set:cal");
|
|
||||||
}
|
|
||||||
|
|
||||||
void setcalExit(void) {
|
|
||||||
if (atomicDecrement64(&g_refCntCal) == 0) {
|
|
||||||
serviceClose(&g_setcalSrv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result setcalGetEticketDeviceKey(void *key) {
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddRecvBuffer(&c, key, 0x244, 0);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 21;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_setcalSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <switch/result.h>
|
|
||||||
|
|
||||||
Result setcalInitialize(void);
|
|
||||||
void setcalExit(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets the extended ETicket RSA-2048 Key from CAL0
|
|
||||||
* @param key Pointer to 0x244-byte output buffer.
|
|
||||||
*/
|
|
||||||
Result setcalGetEticketDeviceKey(void *key);
|
|
56
source/service_guard.h
Normal file
56
source/service_guard.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <switch/types.h>
|
||||||
|
#include <switch/result.h>
|
||||||
|
#include <switch/kernel/mutex.h>
|
||||||
|
#include <switch/sf/service.h>
|
||||||
|
#include <switch/services/sm.h>
|
||||||
|
|
||||||
|
typedef struct ServiceGuard {
|
||||||
|
Mutex mutex;
|
||||||
|
u32 refCount;
|
||||||
|
} ServiceGuard;
|
||||||
|
|
||||||
|
NX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)
|
||||||
|
{
|
||||||
|
mutexLock(&g->mutex);
|
||||||
|
return (g->refCount++) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))
|
||||||
|
{
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
cleanupFunc();
|
||||||
|
--g->refCount;
|
||||||
|
}
|
||||||
|
mutexUnlock(&g->mutex);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))
|
||||||
|
{
|
||||||
|
mutexLock(&g->mutex);
|
||||||
|
if (g->refCount && (--g->refCount) == 0)
|
||||||
|
cleanupFunc();
|
||||||
|
mutexUnlock(&g->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \
|
||||||
|
\
|
||||||
|
static ServiceGuard g_##name##Guard; \
|
||||||
|
NX_INLINE Result _##name##Initialize _paramdecl; \
|
||||||
|
static void _##name##Cleanup(void); \
|
||||||
|
\
|
||||||
|
Result name##Initialize _paramdecl \
|
||||||
|
{ \
|
||||||
|
Result rc = 0; \
|
||||||
|
if (serviceGuardBeginInit(&g_##name##Guard)) \
|
||||||
|
rc = _##name##Initialize _parampass; \
|
||||||
|
return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void name##Exit(void) \
|
||||||
|
{ \
|
||||||
|
serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())
|
Loading…
x
Reference in New Issue
Block a user