/* * Copyright (c) 2018 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KeyLocation.hpp" #include "xxhash64.h" #include #include #include void KeyLocation::get_from_memory(u64 tid, u8 seg_mask) { Handle debug_handle = INVALID_HANDLE; u64 d[8]; // if not a kernel process, get pid from pm:dmnt if ((tid > 0x0100000000000005) && (tid != 0x0100000000000028)) { u64 pid; pmdmntGetProcessId(&pid, tid); if (R_FAILED(svcDebugActiveProcess(&debug_handle, pid)) || R_FAILED(svcGetDebugEvent(reinterpret_cast(&d), debug_handle))) { return; } } else { // otherwise query svc for the process list u64 pids[300]; u32 num_processes; svcGetProcessList(&num_processes, pids, 300); u32 i; for (i = 0; i < num_processes - 1; i++) { if (R_SUCCEEDED(svcDebugActiveProcess(&debug_handle, pids[i])) && R_SUCCEEDED(svcGetDebugEvent(reinterpret_cast(&d), debug_handle)) && (d[2] == tid)) { break; } if (debug_handle) svcCloseHandle(debug_handle); } if (i == num_processes - 1) { if (debug_handle) svcCloseHandle(debug_handle); return; } } MemoryInfo mem_info = {}; u32 page_info; 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); ) { svcQueryDebugProcessMemory(&mem_info, &page_info, debug_handle, addr); // weird code to allow for bitmasking segments if ((mem_info.perm & Perm_R) && ((mem_info.type & 0xff) >= MemType_CodeStatic) && ((mem_info.type & 0xff) < MemType_Heap) && ((segment <<= 1) >> 1 & seg_mask) > 0) { data.resize(data.size() + mem_info.size); if(R_FAILED(svcReadDebugProcessMemory(data.data() + data.size() - mem_info.size, debug_handle, mem_info.addr, mem_info.size))) { if (debug_handle) svcCloseHandle(debug_handle); return; } } addr = mem_info.addr + mem_info.size; if (addr == 0) break; } svcCloseHandle(debug_handle); } void KeyLocation::get_keyblobs() { FsStorage boot0; fsOpenBisStorage(&boot0, FsBisPartitionId_BootPartition1Root); data.resize(0x200 * KNOWN_KEYBLOBS); fsStorageRead(&boot0, KEYBLOB_OFFSET, data.data(), data.size()); fsStorageClose(&boot0); } void KeyLocation::find_keys(std::vector &keys) { if (data.size() == 0) return; u8 temp_hash[0x20]; size_t key_indices_left = keys.size(); u64 hash = 0; std::unordered_map hash_index; for (size_t i = 0; i < keys.size(); i++) hash_index[keys[i]->xx_hash] = i; // hash every length-sized byte chunk in data until it matches a key hash for (size_t i = 0; i < data.size() - 0x10; i++) { hash = XXHash64::hash(data.data() + i, 0x10, 0); auto search = hash_index.find(hash); if (search == hash_index.end()) { continue; } size_t key_index = hash_index[hash]; u8 key_length = keys[key_index]->length; // double-check sha256 since xxhash64 isn't as collision-safe sha256CalculateHash(temp_hash, data.data() + i, key_length); if (!std::equal(keys[key_index]->hash.begin(), keys[key_index]->hash.end(), temp_hash)) continue; std::copy(data.begin() + i, data.begin() + i + key_length, std::back_inserter(keys[key_index]->key)); keys[key_index]->is_found = true; key_indices_left--; if (key_indices_left == 0) return; hash_index.erase(hash); i += key_length - 1; } }