code:
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com

#ifdef _disable_me_self_decrypt
#include "SelfDecrypt.hpp"

#include <Utils/SysWrappers.hpp>
#include <Utils/Logger.hpp>
#include <Utils/Kernel.hpp>
#include <Utils/Kdlsym.hpp>

#include <Mira.hpp>
#include <OrbisOS/ThreadManager.hpp>

extern "C"
{
    #include <sys/fcntl.h>
    #include <sys/unistd.h>
};

#ifdef ALIGN
#undef ALIGN
#define ALIGN(size, alignment) \
    (((size) + ((alignment) - 1)) & ~((alignment) - 1))
#endif

#define ALIGN_PAGE(size) \
    ALIGN(size, PAGE_SIZE)

#define sceSblServiceMailbox_locked(ret, id, iptr, optr) do { \
    _sx_xlock(s_sm_sxlock, 0); \
    ret = sceSblServiceMailbox((id), (iptr), (optr)); \
    _sx_xunlock(s_sm_sxlock); \
} while (0)

using namespace Mira::OrbisOS;

SelfDecrypt::SelfDecrypt(const char* p_FilePath) :
    m_Self { 0 }
{
    // Before we do anything assign a invalid fd
    m_Self.fd = -1;
    m_Self.svc_id = -1;

    auto s_ThreadManager = Mira::Framework::GetFramework()->GetThreadManager();
    if (s_ThreadManager == nullptr)
    {
        WriteLog(LL_Error, "could not get thread manager");
        return;
    }

    auto s_FileThread = s_ThreadManager->GetIoThread();
    if (s_FileThread == nullptr)
    {
        WriteLog(LL_Error,"could not get the file io thread");
        return;
    }

    // Open the descriptor
    auto s_Descriptor = kopen_t(p_FilePath, O_RDONLY, 0, s_FileThread);
    if (s_Descriptor < 0)
    {
        WriteLog(LL_Error, "could not open (%s): (%d).", p_FilePath, s_Descriptor);
        return;
    }

    // Seek to the end of the file to get the size
    auto s_FileSize = klseek_t(s_Descriptor, 0, SEEK_END, s_FileThread);
    if (s_FileSize < 0)
    {
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "could not seek (%d) (%lld).", s_Descriptor, s_FileSize);
        return;
    }

    // Reset back to the beginning
    if (klseek_t(s_Descriptor, 0, SEEK_SET, s_FileThread) < 0)
    {
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "could not seek back to start");
        return;
    }

    // Read out the self header
    auto s_BytesRead = kread_t(s_Descriptor, &m_Self.header, sizeof(m_Self.header), s_FileThread);
    if (s_BytesRead != sizeof(m_Self.header))
    {
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "did not read the correct amount of data (%lld) != (%lld).", s_BytesRead, sizeof(m_Self.header));
        return;
    }

    // Validate the self magic
    if (m_Self.header.magic != SELF_MAGIC)
    {
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "invalid self magic");
        return;
    }

    // Validate self version
    if (m_Self.header.version != SELF_VERSION)
    {
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "invalid self version");
        return;
    }

    if (m_Self.header.mode != SELF_MODE)
    {
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "invalid self mode");
        return;
    }

    if (m_Self.header.endian != SELF_ENDIANNESS)
    {
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "invalid self endianness");
        return;
    }

    if (m_Self.header.file_size != s_FileSize)
    {
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "invalid self file size");
        return;
    }

    // Allocate new self entries
    auto s_EntriesSize = m_Self.header.num_entries * sizeof(self_entry_t);
    auto s_Entries = new self_entry_t[m_Self.header.num_entries];
    if (s_Entries == nullptr)
    {
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "could not allocate self entries cnt: (%d).", m_Self.header.num_entries);
        return;
    }
    memset(s_Entries, 0, s_EntriesSize);

    // Read out all of the self entries
    s_BytesRead = kread_t(s_Descriptor, s_Entries, s_EntriesSize, s_FileThread);
    if (s_BytesRead != s_EntriesSize)
    {
        delete [] s_Entries;
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "bytes read (%lld) != size (%lld).", s_BytesRead, s_EntriesSize);
        return;
    }

    // Copy the contents
    auto s_Contents = new uint8_t[s_FileSize];
    if (s_Contents == nullptr)
    {
        delete [] s_Entries;
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "could not allocate file size (%llx).", s_FileSize);
        return;
    }

    if (klseek_t(s_Descriptor, 0, SEEK_SET, s_FileThread) < 0)
    {
        delete [] s_Contents;
        delete [] s_Entries;
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "could not allocate file size (%llx).", s_FileSize);
        return;
    }

    s_BytesRead = kread_t(s_Descriptor, s_Contents, s_FileSize, s_FileThread);
    if (s_BytesRead != s_FileSize)
    {
        delete[] s_Contents;
        delete [] s_Entries;
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "bytes read (%lld) != size (%lld).", s_BytesRead, s_FileSize);
        return;
    }

    auto s_FileNameLength = strlen(p_FilePath);
    if (s_FileNameLength <= 0 || s_FileNameLength > 260)
    {
        delete [] s_Contents;
        delete [] s_Entries;
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "invalid file path size (%d).", s_FileNameLength);
        return;
    }

    char* s_FileName = new char[s_FileNameLength];
    if (s_FileName == nullptr)
    {
        delete [] s_Contents;
        delete [] s_Entries;
        memset(&m_Self.header, 0, sizeof(m_Self.header));
        kclose_t(s_Descriptor, s_FileThread);
        WriteLog(LL_Error, "could not allocate file path size (%d).", s_FileNameLength);
        return;
    }
    memset(s_FileName, 0, s_FileNameLength);
    memcpy(s_FileName, p_FilePath, s_FileNameLength);

    // Update all of the self information
    m_Self.fd = s_Descriptor;
    m_Self.file_size = s_FileSize;
    m_Self.entries_size = s_EntriesSize;
    m_Self.entries = s_Entries;
    m_Self.data = s_Contents;
    m_Self.file_path = s_FileName;
    m_Self.ctx_id = -1;
}

bool SelfDecrypt::VerifyHeader()
{
    if (m_Self.fd <= 0)
        return false;

    auto ctxStatus = static_cast<uint32_t*>(kdlsym(ctxStatus));
    auto _sceSblAuthMgrSmFinalize = (int(*)(void* ctx))kdlsym(_sceSblAuthMgrSmFinalize);
    auto ctxTable = (struct self_context_t*)kdlsym(ctxTable);
    auto sceSblDriverMapPages = (int(*)(uint64_t *gpu_paddr, void *cpu_vaddr, uint32_t npages, uint64_t flags, uint64_t unk, uint64_t *gpu_desc))kdlsym(sceSblDriverMapPages);
    auto sceSblDriverUnmapPages = (int(*)(uint64_t gpu_desc))kdlsym(sceSblDriverUnmapPages);
    auto sceSblServiceMailbox = (int(*)(uint32_t p_ServiceId, void* p_Request, void* p_Response))kdlsym(sceSblServiceMailbox);
    auto s_sm_sxlock = (struct sx*)kdlsym(s_sm_sxlock);
    auto _sx_xlock = (int (*)(struct sx *sx, int opts))kdlsym(_sx_xlock);
    auto _sx_xunlock = (int (*)(struct sx *sx))kdlsym(_sx_xunlock);

    int s_ContextId = -1;

    if (m_Self.ctx_id == -1)
    {
        m_Self.ctx_id = 0;
        while (ctxStatus[s_ContextId] != 3)
            s_ContextId = (s_ContextId + 1) % SELF_MAX_CONTEXTS;

        WriteLog(LL_Debug, "found available context id: (%d).", s_ContextId);
        ctxStatus[s_ContextId] = 1;
        m_Self.ctx_id = s_ContextId;
    }

    if (m_Self.svc_id == -1)
        m_Self.svc_id = *static_cast<int*>(kdlsym(s_taskId));

    if (m_Self.ctx_id < 0 || m_Self.ctx_id > 3)
    {
        ReleaseContext();

        WriteLog(LL_Error, "invalid self context id (%d).", m_Self.ctx_id);
        return false;
    }

    m_Self.ctx = &ctxTable[m_Self.ctx_id];
    _sceSblAuthMgrSmFinalize(m_Self.ctx);

    size_t s_HeaderDataSize = ALIGN_PAGE(m_Self.header.header_size + m_Self.header.meta_size);
    uint8_t* s_HeaderData = new uint8_t[s_HeaderDataSize];
    if (s_HeaderData == nullptr)
    {
        ReleaseContext();

        WriteLog(LL_Error, "could not allocate header data (%lld).", s_HeaderDataSize);
        return false;
    }

    memset(s_HeaderData, 0, s_HeaderDataSize);
    memcpy(s_HeaderData, m_Self.data, MIN(m_Self.file_size, s_HeaderDataSize));

    uint64_t s_HeaderDataMapped = 0;
    uint64_t s_HeaderDataMapDesc = 0;
    auto s_Ret = sceSblDriverMapPages(&s_HeaderDataMapped, s_HeaderData, 1, 0x61, 0, &s_HeaderDataMapDesc);
    if (s_Ret != 0)
    {
        delete [] s_HeaderData;

        ReleaseContext();

        WriteLog(LL_Error, "could not map driver pages (%d).", s_Ret);
        return false;
    }

    size_t s_AuthInfoSize = ALIGN_PAGE(SELF_AUTH_INFO_SIZE);
    auto s_AuthInfo = new uint8_t[s_AuthInfoSize];
    if (s_AuthInfo == nullptr)
    {
        s_Ret = sceSblDriverUnmapPages(s_HeaderDataMapDesc);
        if (s_Ret != 0)
            WriteLog(LL_Error, "could not unmap header driver pages (%d).", s_Ret);

        delete [] s_HeaderData;

        ReleaseContext();

        WriteLog(LL_Error, "could not allocate auth info");
        return false;
    }
    memset(s_AuthInfo, 0, s_AuthInfoSize);

    uint64_t s_AuthInfoMapped = 0;
    uint64_t s_AuthInfoMapDesc = 0;
    s_Ret = sceSblDriverMapPages(&s_AuthInfoMapped, s_AuthInfo, 1, 0x61, 0, &s_AuthInfoMapDesc);
    if (s_Ret != 0)
    {
        s_Ret = sceSblDriverUnmapPages(s_AuthInfoMapDesc);
        if (s_Ret != 0)
            WriteLog(LL_Error, "could not unmap auth driver pages (%d).", s_Ret);
        s_Ret = sceSblDriverUnmapPages(s_HeaderDataMapDesc);
        if (s_Ret != 0)
            WriteLog(LL_Error, "could not unmap header driver pages (%d).", s_Ret);

        delete [] s_AuthInfo;
        delete [] s_HeaderData;

        ReleaseContext();

        WriteLog(LL_Error, "could not map auth info driver pages (%d).", s_Ret);
        return false;
    }

    // Send command
    uint8_t s_Payload[0x80] = { 0 };
    auto s_Args = reinterpret_cast<sbl_authmgr_verify_header_t*>(&s_Payload[0]);
    memset(s_Payload, 0, sizeof(s_Payload));

    s_Args->function = AUTHMGR_CMD_VERIFY_HEADER;
    s_Args->status = 0;
    s_Args->header_addr = s_HeaderDataMapped;
    s_Args->header_size = m_Self.header.header_size + m_Self.header.meta_size;
    s_Args->context_id = m_Self.ctx_id;
    s_Args->auth_info_addr = s_AuthInfoMapped;
    s_Args->key_id = 0;
    memset(&s_Args->key, 0, SELF_KEY_SIZE);

    WriteLog(LL_Info, "Sending AUTHMGR_CMD_VERIFY_HEADER...");
    sceSblServiceMailbox_locked(s_Ret, m_Self.svc_id, &s_Payload, &s_Payload);
    if (s_Ret != 0 || s_Args->status != 0)
    {
        s_Ret = sceSblDriverUnmapPages(s_AuthInfoMapDesc);
        if (s_Ret != 0)
            WriteLog(LL_Error, "could not unmap auth driver pages (%d).", s_Ret);
        s_Ret = sceSblDriverUnmapPages(s_HeaderDataMapDesc);
        if (s_Ret != 0)
            WriteLog(LL_Error, "could not unmap header driver pages (%d).", s_Ret);

        delete [] s_AuthInfo;
        delete [] s_HeaderData;

        ReleaseContext();

        WriteLog(LL_Error, "sceSblServiceMailbox returned (%d) status: (%d) func: (%d)", s_Ret, s_Args->status, s_Args->function);
        return false;
    }

    WriteLog(LL_Debug, "confirmed context id: (%d).", m_Self.ctx_id);
    m_Self.auth_ctx_id = s_Args->context_id;
    memcpy(&m_Self.auth_info, s_AuthInfo, sizeof(m_Self.auth_info));
    m_Self.verified = true;

    if (s_AuthInfoMapped != 0)
    {
        s_Ret = sceSblDriverUnmapPages(s_AuthInfoMapDesc);
        if (s_Ret != 0)
        {
            WriteLog(LL_Error, "could not unmap driver pages (%d).", s_Ret);
            return false;
        }
    }

    if (s_HeaderDataMapped != 0)
    {
        s_Ret = sceSblDriverUnmapPages(s_HeaderDataMapDesc);
        if (s_Ret != 0)
        {
            WriteLog(LL_Error, "could not unmap header data driver pages (%d).", s_Ret);
            return false;
        }
    }

    return true;
}

void SelfDecrypt::Close()
{
    auto s_ThreadManager = Mira::Framework::GetFramework()->GetThreadManager();
    if (s_ThreadManager == nullptr)
    {
        WriteLog(LL_Error, "could not get thread manager");
        return;
    }

    auto s_IoThread = s_ThreadManager->GetIoThread();
    if (s_IoThread == nullptr)
    {
        WriteLog(LL_Error, "could not get the io thread");
        return;
    }

    struct blob_t* s_Blob = m_Self.blobs;
    struct blob_t* s_Next = nullptr;
    if (s_Blob == nullptr)
        return;

    while (s_Blob != nullptr)
    {
        s_Next = s_Blob->next;

        delete [] s_Blob->data;
        delete s_Blob;

        s_Blob = s_Next;
    }

    // Close the file
    if (m_Self.fd > -1)
    {
        kclose_t(m_Self.fd, s_IoThread);
        m_Self.fd = -1;
    }
}

bool SelfDecrypt::ReleaseContext()
{
    auto ctxStatus = static_cast<uint32_t*>(kdlsym(ctxStatus));
    int32_t s_ContextId = m_Self.ctx_id;
    if (0 <= s_ContextId && s_ContextId <= 3)
    {
        ctxStatus[s_ContextId] = 3;
        m_Self.ctx_id = -1;
    }

    return true;
}

bool SelfDecrypt::DecryptSegment(uint8_t* p_InputData, size_t p_InputDataLength, uint64_t p_SegmentIndex, bool p_IsBlockTable, uint8_t* p_OutputData, uint64_t* p_InOutOutputSize)
{
    //auto sceSblDriverMapPages = (int(*)(uint64_t *gpu_paddr, void *cpu_vaddr, uint32_t npages, uint64_t flags, uint64_t unk, uint64_t *gpu_desc))kdlsym(sceSblDriverMapPages);
    auto sceSblDriverUnmapPages = (int(*)(uint64_t gpu_desc))kdlsym(sceSblDriverUnmapPages);
    auto sceSblServiceMailbox = (int(*)(uint32_t p_ServiceId, void* p_Request, void* p_Response))kdlsym(sceSblServiceMailbox);
    auto make_chunk_table_system = (int(*)(uint64_t *segment_info_gpu_paddr, uint64_t *segment_info_gpu_desc, void *segment_info_cpu_vaddr, size_t segment_info_size, void *chunk_table_cpu_vaddr, size_t chunk_table_size, int type))kdlsym(make_chunk_table_system);
    auto map_chunk_table = (int(*)(uint64_t *gpu_paddr, uint64_t *gpu_desc, void *cpu_vaddr))kdlsym(map_chunk_table);
    auto s_sm_sxlock = (struct sx*)kdlsym(s_sm_sxlock);
    auto _sx_xlock = (int (*)(struct sx *sx, int opts))kdlsym(_sx_xlock);
    auto _sx_xunlock = (int (*)(struct sx *sx))kdlsym(_sx_xunlock);

    bool s_Success = false;
    uint64_t s_SegmentDataGpuPAddr = 0;
    uint64_t s_SegmentDataGpuDesc = 0;
    uint8_t* s_SegmentData = nullptr;
    uint64_t s_SegmentDataSize = 0;
    uint64_t s_ChunkTableGpuPAddr = 0;
    uint64_t s_ChunkTableGpuDesc = 0;
    uint8_t* s_ChunkTable = nullptr;
    //uint64_t s_InputMapped = 0;
    //uint64_t s_InputMapDesc = 0;
    int32_t s_Ret = 0;
    const size_t c_ChunkTableSize = 0x4000;
    uint8_t s_Payload[0x80] = { 0 };

    // This is assigned to payload, don't attempt to free
    sbl_authmgr_load_self_segment_t* s_Command = nullptr;

    if (p_OutputData == nullptr)
    {
        WriteLog(LL_Error, "no output data provided.");
        goto cleanup;
    }

    if (p_InOutOutputSize == nullptr)
    {
        WriteLog(LL_Error, "no input/output size provided");
        goto cleanup;
    }

    // Create the segment data and copy it over
    s_SegmentDataSize = ALIGN_PAGE(p_InputDataLength);
    s_SegmentData = new uint8_t[s_SegmentDataSize];
    if (s_SegmentData == nullptr)
    {
        WriteLog(LL_Error, "could not allocate segment data");
        goto cleanup;
    }
    memset(s_SegmentData, 0, s_SegmentDataSize);
    memcpy(s_SegmentData, p_InputData, p_InputDataLength);

    // Create a new chunk table buffer

    s_ChunkTable = new uint8_t[c_ChunkTableSize];
    if (s_ChunkTable == nullptr)
    {
        WriteLog(LL_Error, "could not allocate chunk table");
        goto cleanup;
    }
    memset(s_ChunkTable, 0, c_ChunkTableSize);

    // Create the chunk table system
    s_Ret = make_chunk_table_system(
        &s_SegmentDataGpuPAddr,
        &s_SegmentDataGpuDesc,
        s_SegmentData,
        s_SegmentDataSize,
        s_ChunkTable,
        c_ChunkTableSize,
        1);
    if (s_Ret != 0)
    {
        WriteLog(LL_Error, "make_chunk_table_system returned: (%d).", s_Ret);
        goto cleanup;
    }

    // Validate our returned arguments
    if (s_SegmentDataGpuPAddr == 0 || s_SegmentDataGpuDesc == 0)
    {
        WriteLog(LL_Error, "cinvalid segment data paddr (%llx) or segment data gpu desc (%llx)", s_SegmentDataGpuPAddr, s_SegmentDataGpuDesc);
        goto cleanup;
    }

    // Map the chunk table
    s_Ret = map_chunk_table(
        &s_ChunkTableGpuPAddr,
        &s_ChunkTableGpuDesc,
        s_ChunkTable);
    if (s_Ret != 0)
    {
        WriteLog(LL_Error, "map_chunk_table returned: (%d).", s_Ret);
        goto cleanup;
    }

    // Decrypt the segment
    s_Command = reinterpret_cast<sbl_authmgr_load_self_segment_t*>(&s_Payload[0]);
    memset(s_Command, 0, sizeof(s_Payload));

    s_Command->function = AUTHMGR_CMD_LOAD_SELF_SEGMENT;
    s_Command->status = 0;
    s_Command->chunk_table_addr = s_ChunkTableGpuPAddr;
    s_Command->segment_index = p_SegmentIndex;
    s_Command->is_block_table = p_IsBlockTable;
    s_Command->context_id = m_Self.auth_ctx_id;

    WriteLog(LL_Debug, "Sending load self segment");
    sceSblServiceMailbox_locked(s_Ret, m_Self.svc_id, &s_Payload, &s_Payload);

    if (s_Ret != 0)
    {
        WriteLog(LL_Error, "sceSblServiceMailbox_locked returned: (%d).", s_Ret);
        goto cleanup;
    }

    if (s_Command->status != 0)
    {
        WriteLog(LL_Error, "command status returned: (%d).", s_Command->status);
        goto cleanup;
    }

    if (s_Command->function != AUTHMGR_CMD_LOAD_SELF_SEGMENT)
    {
        WriteLog(LL_Error, "invalid function");
        goto cleanup;
    }

    // Bounds check the output size
    if (*p_InOutOutputSize < p_InputDataLength)
    {
        WriteLog(LL_Error, "not enough output space: (%lld) < (%lld) bytes.", *p_InOutOutputSize, p_InputDataLength);
        goto cleanup;
    }

    // Copy out the data
    memcpy(p_OutputData, s_SegmentData, p_InputDataLength);

    // Set our success
    s_Success = true;

cleanup:
    // Free up all of the resources
    if (s_ChunkTableGpuPAddr)
    {
        if ((s_Ret = sceSblDriverUnmapPages(s_ChunkTableGpuDesc)) != 0)
            WriteLog(LL_Error, "could not unmap pages: (%d).", s_Ret);
    }

    if (s_SegmentDataGpuPAddr)
    {
        if ((s_Ret = sceSblDriverUnmapPages(s_SegmentDataGpuDesc)) != 0)
            WriteLog(LL_Error, "could not unmap pages: (%d).", s_Ret);
    }

    if (s_ChunkTable)
        delete [] s_ChunkTable;

    if (s_SegmentData)
        delete [] s_SegmentData;

    return s_Success;
}

bool SelfDecrypt::DecryptBlock(uint8_t* p_BlobData, uint64_t p_BlobSize, self_block_info_t* p_Block, int p_SegmentIndex, int p_ContextId)
{
    auto sceSblDriverMapPages = (int(*)(uint64_t *gpu_paddr, void *cpu_vaddr, uint32_t npages, uint64_t flags, uint64_t unk, uint64_t *gpu_desc))kdlsym(sceSblDriverMapPages);
    /*auto sceSblDriverUnmapPages = (int(*)(uint64_t gpu_desc))kdlsym(sceSblDriverUnmapPages);
    auto sceSblServiceMailbox = (int(*)(uint32_t p_ServiceId, void* p_Request, void* p_Response))kdlsym(sceSblServiceMailbox);
    auto make_chunk_table_system = (int(*)(uint64_t *segment_info_gpu_paddr, uint64_t *segment_info_gpu_desc, void *segment_info_cpu_vaddr, size_t segment_info_size, void *chunk_table_cpu_vaddr, size_t chunk_table_size, int type))kdlsym(make_chunk_table_system);
    auto map_chunk_table = (int(*)(uint64_t *gpu_paddr, uint64_t *gpu_desc, void *cpu_vaddr))kdlsym(map_chunk_table);
    auto s_sm_sxlock = (struct sx*)kdlsym(s_sm_sxlock);
    auto _sx_xlock = (int (*)(struct sx *sx, int opts))kdlsym(_sx_xlock);
    auto _sx_xunlock = (int (*)(struct sx *sx))kdlsym(_sx_xunlock);*/

    uint8_t* s_InputData = nullptr;
    uint64_t s_InputSize = 0;
    uint64_t s_InputMapped = 0;
    uint64_t s_InputMapDesc = 0;

    uint8_t* s_OutputData = nullptr;

    uint64_t s_OutputSize = 0;
    uint64_t s_OutputMapped = 0;
    uint64_t s_OutputMapDesc = 0;

    uint8_t s_Payload[0x80] = { 0 };

    // Not allocated do not free
    sbl_authmgr_load_self_block_t* s_Command = nullptr;

    bool s_Success = false;

    int32_t s_Ret = 0;

    // Get the input data size and allocate new buffers
    s_InputSize = ALIGN_PAGE(p_BlobSize);
    s_InputData = new uint8_t[s_InputSize];
    if (s_InputData == nullptr)
    {
        WriteLog(LL_Error, "could not allocate input data of size (%llx).", s_InputSize);
        goto cleanup;
    }
    memset(s_InputData, 0, s_InputSize);
    memcpy(s_InputData, p_BlobData, p_BlobSize);

    if ((s_Ret = sceSblDriverMapPages(&s_InputMapped, s_InputData, 1, 0x61, 0, &s_InputMapDesc)) != 0)
    {
        WriteLog(LL_Error, "could not map driver pages: (%d).", s_Ret);
        goto cleanup;
    }

    s_OutputSize = ALIGN_PAGE(p_BlobSize);
    s_OutputData = new uint8_t[s_OutputSize];
    if (s_OutputData == nullptr)
    {
        WriteLog(LL_Error, "could not allocate output data of size (%llx).", s_OutputData);
        goto cleanup;
    }
    memset(s_OutputData, 0, s_OutputSize);

    if ((s_Ret = sceSblDriverMapPages(&s_OutputMapped, s_OutputData, 1, 0x61, 0, &s_OutputMapDesc)) != 0)
    {
        WriteLog(LL_Error, "could not map driver pages: (%d).", s_Ret);
        goto cleanup;
    }

    // Decrypt block
    s_Command = reinterpret_cast<sbl_authmgr_load_self_block_t*>(&s_Payload[0]);
    memset(s_Payload, 0, sizeof(s_Payload));

    memcpy(&s_Command->digest, &p_Block->digest, sizeof(p_Block->digest));
    memcpy(&s_Command->extent, &p_Block->extent, sizeof(p_Block->extent));

    s_Command->function = AUTHMGR_CMD_LOAD_SELF_BLOCK;
    s_Command->status = 0;
    s_Command->pages_addr = s_OutputMapped;
    s_Command->segment_index = p_SegmentIndex;
    s_Command->context_id = p_ContextId;
    s_Command->block_index = p_Block->index;

cleanup:
    return s_Success;
}
#endif


code:
/*
    Port of self-decryption

    Credits: https://github.com/AlexAltea/orbital/
    AlexAltea, fail0verflow, flatz
*/
#ifdef _disable_me_self_decrypt
#pragma once
#include <Utils/Types.hpp>

namespace Mira
{
    namespace OrbisOS
    {
        class SelfDecrypt
        {
        protected:
            enum
            {
                SELF_MAGIC = 0x1D3D154F,
                SELF_VERSION = 0x0,
                SELF_MODE = 0x1,
                SELF_ENDIANNESS = 0x1,

                SELF_AUTH_INFO_SIZE = 0x88,
                SELF_KEY_SIZE = 0x10,
                SELF_DIGEST_SIZE = 0x20,
                SELF_SEGMENT_BLOCK_ALIGNMENT = 0x10,

                SELF_MAX_CONTEXTS = 0x4,

                AUTHMGR_CMD_VERIFY_HEADER = 0x01,
                AUTHMGR_CMD_LOAD_SELF_SEGMENT = 0x02,
                AUTHMGR_CMD_LOAD_SELF_BLOCK  = 0x06,
            };

        public:
            // Format
            typedef struct blob_t
            {
                struct blob_t *next;
                char *path;
                size_t size;
                uint8_t *data;
            } blob_t;

            typedef struct self_entry_t
            {
                uint32_t props;
                uint32_t reserved;
                uint64_t offset;
                uint64_t filesz;
                uint64_t memsz;
            } self_entry_t;

            typedef struct self_header_t
            {
                uint32_t magic;
                uint8_t version;
                uint8_t mode;
                uint8_t endian;
                uint8_t attr;
                uint32_t key_type;
                uint16_t header_size;
                uint16_t meta_size;
                uint64_t file_size;
                uint16_t num_entries;
                uint16_t flags;
                uint32_t reserved;
                self_entry_t entries[0];
            } self_header_t;

            // Context
            struct self_auth_info_t
            {
                uint8_t buf[0x88];
            };

            typedef struct self_context_t
            {
                uint32_t format;
                uint32_t elf_auth_type;
                uint32_t total_header_size;
                uint32_t unk_0C;
                void *segment;
                uint32_t unk_18;
                uint32_t ctx_id;
                uint64_t svc_id;
                uint64_t unk_28;
                uint32_t buf_id;
                uint32_t unk_34;
                struct self_header_t *header;
                uint8_t mtx_struct[0x20];
            } self_context_t;

            typedef struct self_t {
                int fd;
                char *file_path;
                size_t file_size;
                size_t entries_size;
                size_t data_offset;
                size_t data_size;
                /* contents */
                struct self_header_t header;
                struct self_entry_t *entries;
                uint8_t *data;
                /* kernel */
                struct self_auth_info_t auth_info;
                struct self_context_t *ctx;
                int auth_ctx_id;
                int ctx_id;
                int svc_id;
                int verified;
                /* blobs */
                struct blob_t *blobs;
            } self_t;

            typedef struct self_block_extent_t {
                uint32_t offset;
                uint32_t size;
            } self_block_extent_t;

            typedef struct self_block_info_t {
                uint32_t size;
                uint16_t index;
                struct self_block_extent_t extent;
                uint8_t digest[SELF_DIGEST_SIZE];
            } self_block_info_t;

            typedef struct sbl_authmgr_verify_header_t
            {
                uint32_t function;
                uint32_t status;
                uint64_t header_addr;
                uint32_t header_size;
                uint32_t zero_0C;
                uint32_t zero_10;
                uint32_t context_id;
                uint64_t auth_info_addr;
                uint32_t unk_20;
                uint32_t key_id;
                uint8_t key[0x10];
            } sbl_authmgr_verify_header_t;

            typedef struct sbl_authmgr_load_self_segment_t
            {
                uint32_t function;
                uint32_t status;
                uint64_t chunk_table_addr;
                uint32_t segment_index;
                uint32_t is_block_table;
                uint64_t zero_10;
                uint64_t zero_18;
                uint32_t zero_20;
                uint32_t zero_24;
                uint32_t context_id;
            } sbl_authmgr_load_self_segment_t;

            typedef struct sbl_authmgr_load_self_block_t
            {
                uint32_t function;
                uint32_t status;
                uint64_t pages_addr;
                uint32_t segment_index;
                uint32_t context_id;
                uint8_t digest[0x20];
                uint8_t extent[0x8];
                uint32_t block_index;
                uint32_t data_offset;
                uint32_t data_size;
                uint64_t data_start_addr;
                uint64_t data_end_addr;
                uint32_t zero;
            } sbl_authmgr_load_self_block_t;

        protected:
            self_t m_Self;

        public:
            SelfDecrypt(const char* p_FilePath);
            ~SelfDecrypt();

            bool VerifyHeader();
            bool LoadSegments();
            void Close();
            bool ReleaseContext();

            bool DecryptSegment(uint8_t* p_InputData, size_t p_InputDataLength, uint64_t p_SegmentIndex, bool p_IsBlockTable, uint8_t* p_OutputData, uint64_t* p_InOutOutputSize);
            bool DecryptBlock(uint8_t* p_BlobData, uint64_t p_BlobSize, self_block_info_t* p_Block, int p_SegmentIndex, int p_ContextId);
        };
    }
}
#endif

repo_name: veiledmerc/mira

license: mit


code:
#pragma once
#include <Utils/Types.hpp>
#include <Utils/Kernel.hpp>

struct proc;
struct thread;

struct posixldr_header {
    uint32_t magic;
    uint64_t entrypoint;
    uint32_t ldrdone;
    uint64_t stubentry;
    uint64_t scePthreadAttrInit;
    uint64_t scePthreadAttrSetstacksize;
    uint64_t scePthreadCreate;
    uint64_t thr_initial;
} __attribute__((packed));

struct prxldr_header {
    uint32_t magic;
    uint64_t entrypoint;
    uint32_t prxdone;
    uint64_t prx_path;
    uint64_t sceKernelLoadStartModule;
} __attribute__((packed));

namespace Mira
{
    namespace OrbisOS
    {
        class Utilities
        {
        private:
            static Utilities* m_Instance;

            Utilities();

        protected:

        public:
            static Utilities* GetInstance();

            static void HookFunctionCall(uint8_t* p_HookTrampoline, void* p_Function, void* p_Address);
            static uint64_t PtraceIO(int32_t p_ProcessId, int32_t p_Operation, void* p_DestAddress, void* p_ToReadWriteAddress, size_t p_ToReadWriteSize);
            static struct ::proc* FindProcessByName(const char* name);
            static int ExecutableWriteProtection(struct proc* p, bool write_allowed);
            static int ProcessReadWriteMemory(struct ::proc* p_Process, void* p_DestAddress, size_t p_Size, void* p_ToReadWriteAddress, size_t* p_ReadWriteSize, bool p_Write);
            static int GetProcessVmMap(struct ::proc* p_Process, ProcVmMapEntry** p_Entries, size_t* p_NumEntries);
            static int MountNullFS(char* where, char* what, int flags);
            static int CreatePOSIXThread(struct proc* p, void* entrypoint);
            static int LoadPRXModule(struct proc* p, const char* prx_path);
            static int KillProcess(struct proc* p);
            static void GetEapKeys(uint8_t* data, uint8_t* tweak);
            static int DumpEapKeys(const char* path);
        };
    }
}


code:
; entrypoint_trigger.s
; Mira - OpenOrbis Team
; Detect the end of preload module and execute action
; Use NASM for compile and edit Substitute

BITS 64
DEFAULT REL

magic: db 'MIRA'
entrypoint: dq preload_prx_hook
epdone: dd 0
sceSysmodulePreloadModuleForLibkernel: dq 0
fakeReturnAddress: dq 0

doSubstitute: db 'doSubstituteLoadPRX', 0

preload_prx_hook:
	; Save R9
	push r9

	; Call the preload module function
	mov r9, qword [sceSysmodulePreloadModuleForLibkernel]
	call r9

	; Restore R9
	pop r9

	; Save register
	push rdi
	push rsi
	push rdx
	push rax

	; Call dynlib_dlsym with custom name
	mov rdi, 0
	lea rsi, [doSubstitute]
	lea rdx, [fakeReturnAddress]
	mov rax, 591
	syscall

	; restore register
	pop rax
	pop rdx
	pop rsi
	pop rdi
	ret


code:
; prx.s
; Mira
; Use NASM for compile and edit Utilities

BITS 64
DEFAULT REL

magic: db 'MIRA'
entrypoint: dq loadprx
prxdone: dd 0
prx_path: dq 0
sceKernelLoadStartModule: dq 0

str_rpcstub: db 'prxstub', 0

loadprx:
	;load prx
	mov rdi, qword [prx_path]
	xor rsi, rsi
	xor rdx, rdx
	xor rcx, rcx
	xor r8, r8
	xor r9, r9
	mov r12, qword [sceKernelLoadStartModule]
	call r12
	mov dword [prxdone], 1
	xor eax, eax
	ret


code:
; rpcldr.s
; From golden a.k.a jogolden
; Edited for Mira
; Use NASM for compile and edit Utilities

BITS 64
DEFAULT REL

magic: db 'MIRA'
entrypoint: dq rpcldr
ldrdone: dd 0
stubentry: dq 0
scePthreadAttrInit: dq 0
scePthreadAttrSetstacksize: dq 0
scePthreadCreate: dq 0
thr_initial: dq 0

hthread: dq 0
scePthreadAttr: dq 0
str_rpcstub: db 'rpcstub', 0

rpcldr:
	; load pthread data into fs
	mov rdi, qword [thr_initial]
	mov rsi, qword [rdi]
	mov rdi, qword [rsi + 0x1E0]
	call amd64_set_fsbase

	; create attr
	lea rdi, [scePthreadAttr]
	mov r12, qword [scePthreadAttrInit]
	call r12

	; set stack size
	mov rsi, 0x80000 ; 512 kb
	lea rdi, [scePthreadAttr]
	mov r12, qword [scePthreadAttrSetstacksize]
	call r12

	; create thread
	lea r8, [str_rpcstub]
	mov rcx, 0
	mov rdx, qword [stubentry]
	lea rsi, [scePthreadAttr]
	lea rdi, [hthread]
	mov r12, qword [scePthreadCreate]
	call r12

	mov dword [ldrdone], 1

	mov rdi, 0
	call sys_thr_exit
	retn

sys_thr_exit:
	mov rax, 431
	mov r10, rcx
	syscall
	retn

sys_sysarch:
	mov rax, 165
	mov r10, rcx
	syscall
	retn

amd64_set_fsbase:
	push rbp
	mov rbp, rsp
	push rbx
	sub rsp, 0x18

	mov [rbp - 0x18], rdi

	lea rsi, [rbp - 0x18]
	mov edi, 129
	call sys_sysarch

	add rsp, 0x18
	pop rbx
	pop rbp
	retn


code:
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com

#include "BrowserActivator.hpp"
#include <Utils/Kdlsym.hpp>
#include <Utils/Logger.hpp>

using namespace Mira::Plugins;

BrowserActivator::BrowserActivator()
{

}

BrowserActivator::~BrowserActivator()
{

}

bool BrowserActivator::OnLoad()
{
	auto sceRegMgrGetInt = (uint32_t(*)(uint32_t p_Id, int32_t* p_OutValue))kdlsym(sceRegMgrGetInt);
	auto sceRegMgrSetInt = (uint32_t(*)(uint32_t p_Id, int32_t p_Value))kdlsym(sceRegMgrSetInt);

	int32_t rtv;

	auto s_Ret = sceRegMgrGetInt(0x3C040000, &rtv);

	if (s_Ret != 0)
	{
		WriteLog(LL_Error, "could not get browser activation status");
		return false;
	} else if (rtv == 0) {
		WriteLog(LL_Info, "web browser already activated");
		return true;
	}

	WriteLog(LL_Warn, "activating web browser");

	s_Ret = sceRegMgrSetInt(0x3C040000, 0);

	if (s_Ret != 0)
	{
		WriteLog(LL_Error, "could not activate browser");
		return false;
	}

	WriteLog(LL_Info, "activated web browser");
	return true;
}

bool BrowserActivator::OnUnload()
{
		return true;
}

bool BrowserActivator::OnSuspend()
{
		return true;
}

bool BrowserActivator::OnResume()
{
		return true;
}


code:
#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Types.hpp>

namespace Mira
{
		namespace Plugins
		{
				class BrowserActivator : public Mira::Utils::IModule
				{
				public:
						BrowserActivator();
						virtual ~BrowserActivator();

						virtual const char* GetName() override { return "BrowserActivator"; }
						virtual bool OnLoad() override;
						virtual bool OnUnload() override;
						virtual bool OnSuspend() override;
						virtual bool OnResume() override;
				};
		}
}


code:
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com

#include "Debugger2.hpp"
#include <Utils/Kdlsym.hpp>

using namespace Mira::Plugins;

const char Debugger2::hexchars[] = "0123456789abcdef";

Debugger2::Debugger2(uint16_t p_Port) :
    m_TrapFatalHook(nullptr),
    m_ServerAddress { 0 },
    m_Socket(-1),
    m_Port(p_Port),
    m_OnProcessExitTag(nullptr),
    m_AttachedPid(-1)
{
    // auto mtx_init = (void(*)(struct mtx *m, const char *name, const char *type, int opts))kdlsym(mtx_init);
    //auto eventhandler_register = (eventhandler_tag(*)(struct eventhandler_list *list, const char *name, void *func, void *arg, int priority))kdlsym(eventhandler_register);

    // mtx_init(&m_Mutex, "DbgLock", nullptr, MTX_SPIN);

    // Registers process exiting
    //m_OnProcessExitTag = EVENTHANDLER_REGISTER(process_exit, reinterpret_cast<void*>(OnProcessExit), this, EVENTHANDLER_PRI_FIRST);
}

Debugger2::~Debugger2()
{
    auto eventhandler_deregister = (void(*)(struct eventhandler_list* a, struct eventhandler_entry* b))kdlsym(eventhandler_deregister);
	auto eventhandler_find_list = (struct eventhandler_list * (*)(const char *name))kdlsym(eventhandler_find_list);

    if (m_OnProcessExitTag != nullptr)
    {
        EVENTHANDLER_DEREGISTER(process_exit, m_OnProcessExitTag);
        m_OnProcessExitTag = nullptr;
    }
}

bool Debugger2::OnLoad()
{
#if MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_500
	// Create the trap fatal hook
    WriteLog(LL_Info, "creating trap_fatal hook");
    m_TrapFatalHook = new Utils::Hook(kdlsym(trap_fatal), reinterpret_cast<void*>(OnTrapFatal));

    if (m_TrapFatalHook != nullptr)
    {
        WriteLog(LL_Info, "enabling trap_fatal hook");
        m_TrapFatalHook->Enable();
    }
#endif
    return true;
}

bool Debugger2::OnUnload()
{
#if MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_500
    WriteLog(LL_Info, "deleting trap fatal hook");
	if (m_TrapFatalHook != nullptr)
    {
        if (m_TrapFatalHook->IsEnabled())
            m_TrapFatalHook->Disable();

        delete m_TrapFatalHook;
        m_TrapFatalHook = nullptr;
    }
#endif

    return true;
}

bool Debugger2::OnSuspend()
{
    return OnUnload();
}

bool Debugger2::OnResume()
{
    return OnLoad();
}


code:
#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Hook.hpp>
#include <Utils/Kernel.hpp>
#include <Utils/Logger.hpp>
#include <Utils/Kdlsym.hpp>
#include <Utils/SysWrappers.hpp>

#include <Messaging/Rpc/Connection.hpp>
#include <Messaging/Rpc/Connection.hpp>
#include <Messaging/MessageManager.hpp>
#include <Plugins/PluginManager.hpp>

#include <OrbisOS/Utilities.hpp>

#include <Mira.hpp>

extern "C"
{
    #include <Messaging/Rpc/rpc.pb-c.h>

    #include <sys/uio.h>
	#include <sys/proc.h>
	#include <sys/ioccom.h>
    #include <sys/ptrace.h>
    #include <sys/mman.h>
    #include <sys/sx.h>
    #include <sys/errno.h>
    #include <sys/wait.h>
    #include <sys/socket.h>

    #include <vm/vm.h>
	#include <vm/pmap.h>

    #include <machine/reg.h>
    #include <machine/param.h>
    #include <machine/frame.h>
	#include <machine/psl.h>
	#include <machine/pmap.h>
	#include <machine/segments.h>

	#include <sys/eventhandler.h>
};

#define BREAKPOINT() asm("   int $3");

namespace Mira
{
    namespace Plugins
    {
        /**
         * @brief Debugger Plugin
         *
         * This thing memory leaks like a mf
         * go back and fix it at a later date, maybe tomorow?
         */
        class Debugger2 : public Utils::IModule
        {
        private:
            enum
            {
                GdbDefaultPort = 9997
            };

            typedef enum _Commands
            {
                DbgCmd_None = 0x7AB56E31,
                DbgCmd_ReadMem = 0xF25FEE19,
                DbgCmd_WriteMem = 0x78B3A60C,
                DbgCmd_ProtectMem = 0x73FA541B,
                DbgCmd_ScanMem = 0xEDCCE6D4,
                DbgCmd_GetProcInfo = 0xF3B7D3F1,
                DbgCmd_AllocateProcMem = 0x16FE60FC,
                DbgCmd_FreeProcMem = 0x93E0CC76,
                DbgCmd_GetProcMap = 0x758DC819,
                DbgCmd_Attach = 0xFEFCF9C8,
                DbgCmd_Detach = 0xF3B1D649,
                DbgCmd_Breakpoint = 0xD60E69E4,
                DbgCmd_Watchpoint = 0x23DE0FCE,
                DbgCmd_GetProcThreads = 0x1F5290F2,
                DbgCmd_SignalProc = 0xA2E2610F,
                DbgCmd_GetRegs = 0x449EAA46,
                DbgCmd_SetRegs = 0xD70F129B,
                DbgCmd_GetThreadInfo = 0x51B931C2,
                DbgCmd_ThreadSinglestep = 0x080B3752,
                DbgCmd_ReadKernelMem = 0x844AE491,
                DbgCmd_WriteKernelMem = 0xCFD904E7,
                DbgCmd_GetProcList = 0x7CF61ABE
            } Commands;

            Utils::Hook* m_TrapFatalHook;

            // Remote GDB extension
            // https://www.embecosm.com/appnotes/ean4/embecosm-howto-rsp-server-ean4-issue-2.html
            struct sockaddr m_ServerAddress;
            int32_t m_Socket;
            uint16_t m_Port;

            // struct sx m_Mutex;
            eventhandler_tag m_OnProcessExitTag;

            // Local target information

            // Attached process id
            int32_t m_AttachedPid;

        public:
            Debugger2(uint16_t p_Port = -1);
            virtual ~Debugger2();

            virtual const char* GetName() override { return "Debugger"; }
            virtual const char* GetDescription() override { return "GDB compatible debugger with ReClass abilties."; }

            // Module callbacks
            virtual bool OnLoad() override;
            virtual bool OnUnload() override;
            virtual bool OnSuspend() override;
            virtual bool OnResume() override;

        protected:
            static void OnTrapFatal(struct trapframe* p_Frame, vm_offset_t p_Eva);
            static bool IsStackSpace(void* p_Address);

            void putDebugChar(char p_Char);
            unsigned char getDebugChar();

            enum
            {
                BufMax = PAGE_SIZE * 4,
                NumRegs = 14,
                NumRegBytes = (NumRegs * sizeof(void*))
            };
            enum amd64_regnum
            {
                AMD64_RAX_REGNUM,
                AMD64_RBX_REGNUM,
                AMD64_RCX_REGNUM,
                AMD64_RDX_REGNUM,
                AMD64_RSI_REGNUM,
                AMD64_RDI_REGNUM,
                AMD64_RBP_REGNUM,
                AMD64_RSP_REGNUM,
                AMD64_R8_REGNUM,
                AMD64_R9_REGNUM,
                AMD64_R10_REGNUM,
                AMD64_R11_REGNUM,
                AMD64_R12_REGNUM,
                AMD64_R13_REGNUM,
                AMD64_R14_REGNUM,
                AMD64_R15_REGNUM,
                AMD64_RIP_REGNUM,
                AMD64_EFLAGS_REGNUM,
                AMD64_CS_REGNUM,
                AMD64_SS_REGNUM,
                AMD64_DS_REGNUM,
                AMD64_ES_REGNUM,
                AMD64_FS_REGNUM,
                AMD64_GS_REGNUM,
                AMD64_ST0_REGNUM = 24,
                AMD64_ST1_REGNUM,
                AMD64_FCTRL_REGNUM = AMD64_ST0_REGNUM + 8,
                AMD64_FSTAT_REGNUM = AMD64_ST0_REGNUM + 9,
                AMD64_FTAG_REGNUM = AMD64_ST0_REGNUM + 10,
                AMD64_XMM0_REGNUM = 40,
                AMD64_XMM1_REGNUM,
                AMD64_MXCSR_REGNUM = AMD64_XMM0_REGNUM + 16,
                AMD64_YMM0H_REGNUM,
                AMD64_YMM15H_REGNUM = AMD64_YMM0H_REGNUM + 15,
                AMD64_BND0R_REGNUM = AMD64_YMM15H_REGNUM + 1,
                AMD64_BND3R_REGNUM = AMD64_BND0R_REGNUM + 3,
                AMD64_BNDCFGU_REGNUM,
                AMD64_BNDSTATUS_REGNUM,
                AMD64_XMM16_REGNUM,
                AMD64_XMM31_REGNUM = AMD64_XMM16_REGNUM + 15,
                AMD64_YMM16H_REGNUM,
                AMD64_YMM31H_REGNUM = AMD64_YMM16H_REGNUM + 15,
                AMD64_K0_REGNUM,
                AMD64_K7_REGNUM = AMD64_K0_REGNUM + 7,
                AMD64_ZMM0H_REGNUM,
                AMD64_ZMM31H_REGNUM = AMD64_ZMM0H_REGNUM + 31,
                AMD64_PKRU_REGNUM,
                AMD64_FSBASE_REGNUM,
                AMD64_GSBASE_REGNUM
            };

            static const char hexchars[];

            int hex (char ch);
        public:
        };
    }
}


code:
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com

#include "Debugger2.hpp"
#include <Utils/Kdlsym.hpp>
#include <Mira.hpp>

extern "C"
{
	#include <sys/lock.h>
	#include <sys/uio.h>
	#include <sys/proc.h>
	#include <sys/ioccom.h>
	#include <sys/fcntl.h>

	#include <vm/vm.h>
	#include <vm/pmap.h>

	#include <machine/psl.h>
	#include <machine/pmap.h>
	#include <machine/segments.h>
	#include <machine/trap.h>
};

struct amd64_frame
{
	struct amd64_frame      *f_frame;
	long                    f_retaddr;
	long                    f_arg0;
};

using namespace Mira::Plugins;

void sdtossd(struct user_segment_descriptor *sd, struct soft_segment_descriptor *ssd)
{
	ssd->ssd_base  = (sd->sd_hibase << 24) | sd->sd_lobase;
	ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit;
	ssd->ssd_type  = sd->sd_type;
	ssd->ssd_dpl   = sd->sd_dpl;
	ssd->ssd_p     = sd->sd_p;
	ssd->ssd_long  = sd->sd_long;
	ssd->ssd_def32 = sd->sd_def32;
	ssd->ssd_gran  = sd->sd_gran;
}

bool Debugger2::IsStackSpace(void* p_Address)
{
	return ((reinterpret_cast<uint64_t>(p_Address) & 0xFFFFFFFF00000000) == 0xFFFFFF8000000000);
}

void Debugger2::OnTrapFatal(struct trapframe* frame, vm_offset_t eva)
{
	int code, ss;
	u_int type;
	long esp;
	struct soft_segment_descriptor softseg;
	const char *msg;

	// Needed for writing to klog
	auto printf = (void(*)(const char *format, ...))kdlsym(printf);

	// Global descriptor tables
	auto gdt = (struct user_segment_descriptor*)kdlsym(gdt);

	// Page faults have to be disabled while getting stack frame information
	auto vm_fault_disable_pagefaults = (int(*)(void))kdlsym(vm_fault_disable_pagefaults);
	auto vm_fault_enable_pagefaults = (void(*)(int))kdlsym(vm_fault_enable_pagefaults);

	// Get the trap message based on the trap code
	#define MAX_TRAP_MSG		33

	static const char *trap_msg[] = {
		"",                               /*  0 unused */
		"privileged instruction fault",   /*  1 T_PRIVINFLT */
		"",                               /*  2 unused */
		"breakpoint instruction fault",   /*  3 T_BPTFLT */
		"",                               /*  4 unused */
		"",                               /*  5 unused */
		"arithmetic trap",                /*  6 T_ARITHTRAP */
		"",                               /*  7 unused */
		"",                               /*  8 unused */
		"general protection fault",       /*  9 T_PROTFLT */
		"trace trap",                     /* 10 T_TRCTRAP */
		"",                               /* 11 unused */
		"page fault",                     /* 12 T_PAGEFLT */
		"",                               /* 13 unused */
		"alignment fault",                /* 14 T_ALIGNFLT */
		"",                               /* 15 unused */
		"",                               /* 16 unused */
		"",	                              /* 17 unused */
		"integer divide fault",           /* 18 T_DIVIDE */
		"non-maskable interrupt trap",    /* 19 T_NMI */
		"overflow trap",                  /* 20 T_OFLOW */
		"FPU bounds check fault",         /* 21 T_BOUND */
		"FPU device not available",       /* 22 T_DNA */
		"double fault",                   /* 23 T_DOUBLEFLT */
		"FPU operand fetch fault",        /* 24 T_FPOPFLT */
		"invalid TSS fault",              /* 25 T_TSSFLT */
		"segment not present fault",      /* 26 T_SEGNPFLT */
		"stack fault",                    /* 27 T_STKFLT */
		"machine check trap",             /* 28 T_MCHK */
		"SIMD floating-point exception",  /* 29 T_XMMFLT */
		"reserved (unknown) fault",       /* 30 T_RESERVED */
		"",                               /* 31 unused (reserved) */
		"DTrace pid return trap",         /* 32 T_DTRACE_RET */
		"DTrace fasttrap probe trap",     /* 33 T_DTRACE_PROBE */
	};

	// Get the trap code and trap type based on that code
	code = frame->tf_err;
	type = frame->tf_trapno;

	sdtossd(&gdt[NGDT * PCPU_GET(cpuid) + IDXSEL(frame->tf_cs & 0xffff)], &softseg);

	if (type <= MAX_TRAP_MSG)
		msg = trap_msg[type];
	else
		msg = "UNKNOWN";

	// Print generic crash information
	printf("## Kernel panic: received fatal trap %d (%s) while in %s mode.\n##\n",
		type,
		msg,
		ISPL(frame->tf_cs) == SEL_UPL ? "user" : "kernel"
	);

#ifdef SMP
	// Two separate prints in case of a trap on an unmapped page
	printf("## cpuid = %d; ", PCPU_GET(cpuid));
	printf("## apic id = %02x\n##\n", PCPU_GET(apic_id));
#endif

	if (type == T_PAGEFLT) {
		printf("## fault virtual address: 0x%lx\n", eva);

		printf("## fault code: %s %s %s, %s\n##\n",
			code & PGEX_U ? "user" : "supervisor",
			code & PGEX_W ? "write" : "read",
			code & PGEX_I ? "instruction" : "data",
			code & PGEX_P ? "protection violation" : "page not present"
		);
	}

	printf("## instruction pointer: 0x%lx:0x%lx\n", frame->tf_cs & 0xffff, frame->tf_rip);

	if (ISPL(frame->tf_cs) == SEL_UPL) {
		ss = frame->tf_ss & 0xffff;
		esp = frame->tf_rsp;
	} else {
		ss = GSEL(GDATA_SEL, SEL_KPL);
		esp = (long)&frame->tf_rsp;
	}

	printf("## stack pointer: 0x%x:0x%lx\n", ss, esp);
	printf("## frame pointer: 0x%x:0x%lx\n", ss, frame->tf_rbp);

	printf("## code segment:  base 0x%lx, limit 0x%lx, type 0x%x\n",
		softseg.ssd_base,
		softseg.ssd_limit,
		softseg.ssd_type
	);

	printf("##                DPL %d, pres %d, long %d, def32 %d, gran %d\n",
		softseg.ssd_dpl,
		softseg.ssd_p,
		softseg.ssd_long,
		softseg.ssd_def32,
	  softseg.ssd_gran
	);

	printf("## processor eflags: ");

	if (frame->tf_rflags & PSL_T)
		printf("trace trap, ");
	if (frame->tf_rflags & PSL_I)
		printf("interrupt enabled, ");
	if (frame->tf_rflags & PSL_NT)
		printf("nested task, ");
	if (frame->tf_rflags & PSL_RF)
		printf("resume, ");
	printf("IOPL = %ld\n", (frame->tf_rflags & PSL_IOPL) >> 12);

	printf("## current process: ");

	if (curproc)
		printf("%lu (%s)\n##\n", (u_long)curproc->p_pid, curthread->td_name);
	else
		printf("Idle\n##\n");

	printf("## kernel base: %p\n", gKernelBase);

	// Print mira specific info
	auto s_Framework = Mira::Framework::GetFramework();

	if(s_Framework)
	{
		auto s_InitParams = s_Framework->GetInitParams();

		if(s_InitParams)
		{
			printf("## mira base:   %p (size: %p)\n", s_InitParams->payloadBase, s_InitParams->payloadSize);
			printf("## mira allocated base: %p (size: %p)\n", s_InitParams->allocatedBase, s_InitParams->payloadSize);
			printf("## mira proc:   %p (entry: %p)\n", s_InitParams->process, s_InitParams->entrypoint);
			printf("## mira entrypoint (mira_entry): %p\n", mira_entry);
			printf("## instruction pointer offset (mira allocated base: %p)\n", frame->tf_rip - (uint64_t)s_InitParams->allocatedBase);
		}

		printf("##     messageManager: %p\n", s_Framework->GetMessageManager());
		printf("##     pluginManager:  %p\n", s_Framework->GetPluginManager());
	}

	printf("##\n");

	printf("## instruction pointer offset (kernel: %p) (mira_entry: %p)\n##\n",
		frame->tf_rip - (uint64_t)gKernelBase,
		frame->tf_rip - (uint64_t)mira_entry
	);

	printf("## last branch from: %p\n", frame->tf_last_branch_from);
	printf("## last branch to:   %p\n##\n", frame->tf_last_branch_to);

	// Print register state
	printf("## registers:\n");
	printf("## rax: 0x%016llx  rbx: 0x%016llx\n", frame->tf_rax, frame->tf_rbx);
	printf("## rcx: 0x%016llx  rdx: 0x%016llx\n", frame->tf_rcx, frame->tf_rdx);
	printf("## rsi: 0x%016llx  rdi: 0x%016llx\n", frame->tf_rsi, frame->tf_rdi);
	printf("## rbp: 0x%016llx  rsp: 0x%016llx\n", frame->tf_rbp, frame->tf_rsp);
	printf("## r8 : 0x%016llx  r9 : 0x%016llx\n", frame->tf_r8, frame->tf_r9);
	printf("## r10: 0x%016llx  r11: 0x%016llx\n", frame->tf_r10, frame->tf_r11);
	printf("## r12: 0x%016llx  r13: 0x%016llx\n", frame->tf_r12, frame->tf_r13);
	printf("## r14: 0x%016llx  r15: 0x%016llx\n##\n", frame->tf_r14, frame->tf_r15);

	// Print backtrace if it's available
	printf("## backtrace: \n");

	auto s_Saved = vm_fault_disable_pagefaults();
  auto amdFrame = reinterpret_cast<struct amd64_frame*>(frame->tf_rbp);

	if (amdFrame != nullptr)
	{
		auto amdFrameCount = 0;

		while (Debugger2::IsStackSpace(amdFrame))
		{
			printf("##  [%d] [return: %p] [from: %p]\n", amdFrameCount, amdFrame->f_retaddr, amdFrame);
			amdFrame = amdFrame->f_frame;
			amdFrameCount++;
		}
	}

	vm_fault_enable_pagefaults(s_Saved);

	// Done
	printf("## hanging crashed thread...\n");
	for(;;);

	// Allow the debugger to be placed here manually and continue execution at some point
	__asm__("pop %rbp;leave;ret;");
}


code:
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com

/*
	Implemented from: https://github.com/xvortex/ps4-hen-vtx
	Ported by: kiwidog (@kd_tech_)

	Bugfixes: SiSTRo (https://github.com/SiSTR0), SocraticBliss (https://github.com/SocraticBliss)
*/

#include "FakePkgManager.hpp"
#include <Utils/Kernel.hpp>
#include <Utils/Kdlsym.hpp>
#include <Utils/_Syscall.hpp>
#include <Utils/Logger.hpp>
#include <Utils/SysWrappers.hpp>
#include <Boot/Config.hpp>

#include <OrbisOS/Utilities.hpp>

#include <Mira.hpp>
#include <Boot/Config.hpp>

extern "C"
{
	#include <sys/eventhandler.h>
	#include <sys/sysent.h>
	#include <sys/proc.h>
	#include <sys/mman.h>
	#include <sys/ptrace.h>
	#include <sys/wait.h>
	#include <sys/signal.h>
};

using namespace Mira::Plugins;
using namespace Mira::OrbisOS;

#pragma region "Fake-Self-Keys"
const uint8_t FakePkgManager::g_ypkg_p[] =
{
	0x2D, 0xE8, 0xB4, 0x65, 0xBE, 0x05, 0x78, 0x6A, 0x89, 0x31, 0xC9, 0x5A, 0x44, 0xDE, 0x50, 0xC1,
	0xC7, 0xFD, 0x9D, 0x3E, 0x21, 0x42, 0x17, 0x40, 0x79, 0xF9, 0xC9, 0x41, 0xC1, 0xFC, 0xD7, 0x0F,
	0x34, 0x76, 0xA3, 0xE2, 0xC0, 0x1B, 0x5A, 0x20, 0x0F, 0xAF, 0x2F, 0x52, 0xCD, 0x83, 0x34, 0x72,
	0xAF, 0xB3, 0x12, 0x33, 0x21, 0x2C, 0x20, 0xB0, 0xC6, 0xA0, 0x2D, 0xB1, 0x59, 0xE3, 0xA7, 0xB0,
	0x4E, 0x1C, 0x4C, 0x5B, 0x5F, 0x10, 0x9A, 0x50, 0x18, 0xCC, 0x86, 0x79, 0x25, 0xFF, 0x10, 0x02,
	0x8F, 0x90, 0x03, 0xA9, 0x37, 0xBA, 0xF2, 0x1C, 0x13, 0xCC, 0x09, 0x45, 0x15, 0xB8, 0x55, 0x74,
	0x0A, 0x28, 0x24, 0x04, 0xD1, 0x19, 0xAB, 0xB3, 0xCA, 0x44, 0xB6, 0xF8, 0x3D, 0xB1, 0x2A, 0x72,
	0x88, 0x35, 0xE4, 0x86, 0x6B, 0x55, 0x47, 0x08, 0x25, 0x16, 0xAB, 0x69, 0x1D, 0xBF, 0xF6, 0xFE,
};

const uint8_t FakePkgManager::g_ypkg_q[] =
{
	0x23, 0x80, 0x77, 0x84, 0x4D, 0x6F, 0x9B, 0x24, 0x51, 0xFE, 0x2A, 0x6B, 0x28, 0x80, 0xA1, 0x9E,
	0xBD, 0x6D, 0x18, 0xCA, 0x8D, 0x7D, 0x9E, 0x79, 0x5A, 0xE0, 0xB8, 0xEB, 0xD1, 0x3D, 0xF3, 0xD9,
	0x02, 0x90, 0x2A, 0xA7, 0xB5, 0x7E, 0x9A, 0xA2, 0xD7, 0x2F, 0x21, 0xA8, 0x50, 0x7D, 0x8C, 0xA1,
	0x91, 0x2F, 0xBF, 0x97, 0xBE, 0x92, 0xC2, 0xC1, 0x0D, 0x8C, 0x0C, 0x1F, 0xDE, 0x31, 0x35, 0x15,
	0x39, 0x90, 0xCC, 0x97, 0x47, 0x2E, 0x7F, 0x09, 0xE9, 0xC3, 0x9C, 0xCE, 0x91, 0xB2, 0xC8, 0x58,
	0x76, 0xE8, 0x70, 0x1D, 0x72, 0x5F, 0x4A, 0xE6, 0xAA, 0x36, 0x22, 0x94, 0xC6, 0x52, 0x90, 0xB3,
	0x9F, 0x9B, 0xF0, 0xEF, 0x57, 0x8E, 0x53, 0xC3, 0xE3, 0x30, 0xC9, 0xD7, 0xB0, 0x3A, 0x0C, 0x79,
	0x1B, 0x97, 0xA8, 0xD4, 0x81, 0x22, 0xD2, 0xB0, 0x82, 0x62, 0x7D, 0x00, 0x58, 0x47, 0x9E, 0xC7,
};

const uint8_t FakePkgManager::g_ypkg_dmp1[] =
{
	0x25, 0x54, 0xDB, 0xFD, 0x86, 0x45, 0x97, 0x9A, 0x1E, 0x17, 0xF0, 0xE3, 0xA5, 0x92, 0x0F, 0x12,
	0x2A, 0x5C, 0x4C, 0xA6, 0xA5, 0xCF, 0x7F, 0xE8, 0x5B, 0xF3, 0x65, 0x1A, 0xC8, 0xCF, 0x9B, 0xB9,
	0x2A, 0xC9, 0x90, 0x5D, 0xD4, 0x08, 0xCF, 0xF6, 0x03, 0x5A, 0x5A, 0xFC, 0x9E, 0xB6, 0xDB, 0x11,
	0xED, 0xE2, 0x3D, 0x62, 0xC1, 0xFC, 0x88, 0x5D, 0x97, 0xAC, 0x31, 0x2D, 0xC3, 0x15, 0xAD, 0x70,
	0x05, 0xBE, 0xA0, 0x5A, 0xE6, 0x34, 0x9C, 0x44, 0x78, 0x2B, 0xE5, 0xFE, 0x38, 0x56, 0xD4, 0x68,
	0x83, 0x13, 0xA4, 0xE6, 0xFA, 0xD2, 0x9C, 0xAB, 0xAC, 0x89, 0x5F, 0x10, 0x8F, 0x75, 0x6F, 0x04,
	0xBC, 0xAE, 0xB9, 0xBC, 0xB7, 0x1D, 0x42, 0xFA, 0x4E, 0x94, 0x1F, 0xB4, 0x0A, 0x27, 0x9C, 0x6B,
	0xAB, 0xC7, 0xD2, 0xEB, 0x27, 0x42, 0x52, 0x29, 0x41, 0xC8, 0x25, 0x40, 0x54, 0xE0, 0x48, 0x6D,
};

const uint8_t FakePkgManager::g_ypkg_dmq1[] =
{
	0x4D, 0x35, 0x67, 0x38, 0xBC, 0x90, 0x3E, 0x3B, 0xAA, 0x6C, 0xBC, 0xF2, 0xEB, 0x9E, 0x45, 0xD2,
	0x09, 0x2F, 0xCA, 0x3A, 0x9C, 0x02, 0x36, 0xAD, 0x2E, 0xC1, 0xB1, 0xB2, 0x6D, 0x7C, 0x1F, 0x6B,
	0xA1, 0x8F, 0x62, 0x20, 0x8C, 0xD6, 0x6C, 0x36, 0xD6, 0x5A, 0x54, 0x9E, 0x30, 0xA9, 0xA8, 0x25,
	0x3D, 0x94, 0x12, 0x3E, 0x0D, 0x16, 0x1B, 0xF0, 0x86, 0x42, 0x72, 0xE0, 0xD6, 0x9C, 0x39, 0x68,
	0xDB, 0x11, 0x80, 0x96, 0x18, 0x2B, 0x71, 0x41, 0x48, 0x78, 0xE8, 0x17, 0x8B, 0x7D, 0x00, 0x1F,
	0x16, 0x68, 0xD2, 0x75, 0x97, 0xB5, 0xE0, 0xF2, 0x6D, 0x0C, 0x75, 0xAC, 0x16, 0xD9, 0xD5, 0xB1,
	0xB5, 0x8B, 0xE8, 0xD0, 0xBF, 0xA7, 0x1F, 0x61, 0x5B, 0x08, 0xF8, 0x68, 0xE7, 0xF0, 0xD1, 0xBC,
	0x39, 0x60, 0xBF, 0x55, 0x9C, 0x7C, 0x20, 0x30, 0xE8, 0x50, 0x28, 0x44, 0x02, 0xCE, 0x51, 0x2A,
};

const uint8_t FakePkgManager::g_ypkg_iqmp[] =
{
	0xF5, 0x73, 0xB8, 0x7E, 0x5C, 0x98, 0x7C, 0x87, 0x67, 0xF1, 0xDA, 0xAE, 0xA0, 0xF9, 0x4B, 0xAB,
	0x77, 0xD8, 0xCE, 0x64, 0x6A, 0xC1, 0x4F, 0xA6, 0x9B, 0xB9, 0xAA, 0xCC, 0x76, 0x09, 0xA4, 0x3F,
	0xB9, 0xFA, 0xF5, 0x62, 0x84, 0x0A, 0xB8, 0x49, 0x02, 0xDF, 0x9E, 0xC4, 0x1A, 0x37, 0xD3, 0x56,
	0x0D, 0xA4, 0x6E, 0x15, 0x07, 0x15, 0xA0, 0x8D, 0x97, 0x9D, 0x92, 0x20, 0x43, 0x52, 0xC3, 0xB2,
	0xFD, 0xF7, 0xD3, 0xF3, 0x69, 0xA2, 0x28, 0x4F, 0x62, 0x6F, 0x80, 0x40, 0x5F, 0x3B, 0x80, 0x1E,
	0x5E, 0x38, 0x0D, 0x8B, 0x56, 0xA8, 0x56, 0x58, 0xD8, 0xD9, 0x6F, 0xEA, 0x12, 0x2A, 0x40, 0x16,
	0xC1, 0xED, 0x3D, 0x27, 0x16, 0xA0, 0x63, 0x97, 0x61, 0x39, 0x55, 0xCC, 0x8A, 0x05, 0xFA, 0x08,
	0x28, 0xFD, 0x55, 0x56, 0x31, 0x94, 0x65, 0x05, 0xE7, 0xD3, 0x57, 0x6C, 0x0D, 0x1C, 0x67, 0x0B,
};

const uint8_t FakePkgManager::g_RifDebugKey[] =
{
	0x96, 0xC2, 0x26, 0x8D, 0x69, 0x26, 0x1C, 0x8B, 0x1E, 0x3B, 0x6B, 0xFF, 0x2F, 0xE0, 0x4E, 0x12
};

const uint8_t FakePkgManager::g_FakeKeySeed[] =
{
	0x46, 0x41, 0x4B, 0x45, 0x46, 0x41, 0x4B, 0x45, 0x46, 0x41, 0x4B, 0x45, 0x46, 0x41, 0x4B, 0x45,
};

#pragma endregion

FakePkgManager::FakePkgManager() :
    m_NpdrmDecryptIsolatedRifHook(nullptr),
    m_NpdrmDecryptRifNewHook(nullptr),
    m_SceSblDriverSendMsgHook(nullptr),
    m_SceSblKeymgrInvalidateKey(nullptr),
    m_SceSblPfsSetKeysHook(nullptr),
    m_processStartEvent(nullptr),
    m_resumeEvent(nullptr)
{
	auto sv = (struct sysentvec*)kdlsym(self_orbis_sysvec);
	struct sysent* sysents = sv->sv_table;
	uint8_t* s_TrampolineF = reinterpret_cast<uint8_t*>(sysents[SYS___MAC_GET_LINK].sy_call); // syscall #410
	uint8_t* s_TrampolineG = reinterpret_cast<uint8_t*>(sysents[SYS___MAC_SET_FD].sy_call); // syscall #388
	uint8_t* s_TrampolineH = reinterpret_cast<uint8_t*>(sysents[SYS___MAC_SET_FILE].sy_call); // syscall #389
	uint8_t* s_TrampolineI = reinterpret_cast<uint8_t*>(sysents[SYS___MAC_SET_LINK].sy_call); // syscall #411
	uint8_t* s_TrampolineJ = reinterpret_cast<uint8_t*>(sysents[SYS_MAC_SYSCALL].sy_call); // syscall #394
	uint8_t* s_TrampolineK = reinterpret_cast<uint8_t*>(sysents[SYS___MAC_EXECVE].sy_call); // syscall #415

	Utilities::HookFunctionCall(s_TrampolineF, reinterpret_cast<void*>(OnNpdrmDecryptIsolatedRif), kdlsym(npdrm_decrypt_isolated_rif__sceSblKeymgrSmCallfunc_hook));
	Utilities::HookFunctionCall(s_TrampolineG, reinterpret_cast<void*>(OnNpdrmDecryptRifNew), kdlsym(npdrm_decrypt_rif_new__sceSblKeymgrSmCallfunc_hook));
	Utilities::HookFunctionCall(s_TrampolineH, reinterpret_cast<void*>(OnSceSblPfsSetKeys), kdlsym(mountpfs__sceSblPfsSetKeys_hookA));
	Utilities::HookFunctionCall(s_TrampolineI, reinterpret_cast<void*>(OnSceSblPfsSetKeys), kdlsym(mountpfs__sceSblPfsSetKeys_hookB));
	Utilities::HookFunctionCall(s_TrampolineJ, reinterpret_cast<void*>(OnSceSblDriverSendMsg), kdlsym(sceSblKeymgrSetKeyStorage__sceSblDriverSendMsg_hook));
	Utilities::HookFunctionCall(s_TrampolineK, reinterpret_cast<void*>(OnSceSblKeymgrInvalidateKeySxXlock), kdlsym(sceSblKeymgrInvalidateKey__sx_xlock_hook));

	WriteLog(LL_Debug, "Installed fpkg hooks");
}

FakePkgManager::~FakePkgManager()
{

}

bool FakePkgManager::ShellCorePatch()
{
	WriteLog(LL_Debug, "patching SceShellCore");

	struct ::proc* s_Process = Utilities::FindProcessByName("SceShellCore");
	if (s_Process == nullptr)
	{
		WriteLog(LL_Error, "could not find SceShellCore");
		return false;
	}

	ProcVmMapEntry* s_Entries = nullptr;
	size_t s_NumEntries = 0;
	auto s_Ret = Utilities::GetProcessVmMap(s_Process, &s_Entries, &s_NumEntries);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "could not get vm map");
		return false;
	}

	if (s_Entries == nullptr || s_NumEntries == 0)
	{
		WriteLog(LL_Error, "invalid entries (%p) or numEntries (%d)", s_Entries, s_NumEntries);
		return false;
	}

	uint8_t* s_TextStart = nullptr;
	for (auto i = 0; i < s_NumEntries; ++i)
	{
		if (s_Entries[i].prot == (PROT_READ | PROT_EXEC))
		{
			s_TextStart = (uint8_t*)s_Entries[i].start;
			break;
		}
	}

	if (s_TextStart == nullptr)
	{
		WriteLog(LL_Error, "could not find SceShellCore text start");
		return false;
	}

	WriteLog(LL_Debug, "SceShellCore .text: (%p)", s_TextStart);

	// Free the entries we got returned
	delete [] s_Entries;
	s_Entries = nullptr;

	uint8_t xor__eax_eax[5] = { 0x31, 0xC0, 0x90, 0x90, 0x90 };

	/*
	s_Ret = kptrace_t(PT_ATTACH, s_Process->p_pid, 0, 0, s_MainThread);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "could not attach to shellcore");
		return false;
	}

	int32_t s_Status = 0;
	s_Ret = kwait4_t(s_Process->p_pid, &s_Status, WUNTRACED, nullptr, s_MainThread);
	WriteLog(LL_Debug, "wait4 returned (%d)", s_Ret);*/

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_sceKernelIsGenuineCEX_patchA), sizeof(xor__eax_eax), xor__eax_eax, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_sceKernelIsGenuineCEX_patchA");
		return false;
	}

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_sceKernelIsGenuineCEX_patchB), sizeof(xor__eax_eax), xor__eax_eax, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_sceKernelIsGenuineCEX_patchB");
		return false;
	}

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_sceKernelIsGenuineCEX_patchC), sizeof(xor__eax_eax), xor__eax_eax, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_sceKernelIsGenuineCEX_patchC");
		return false;
	}

#if MIRA_PLATFORM > MIRA_PLATFORM_ORBIS_BSD_455
	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_sceKernelIsGenuineCEX_patchD), sizeof(xor__eax_eax), xor__eax_eax, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_sceKernelIsGenuineCEX_patchD");
		return false;
	}
#endif

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_nidf_libSceDipsw_patchA), sizeof(xor__eax_eax), xor__eax_eax, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_nidf_libSceDipsw_patchA");
		return false;
	}

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_nidf_libSceDipsw_patchB), sizeof(xor__eax_eax), xor__eax_eax, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_nidf_libSceDipsw_patchB");
		return false;
	}

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_nidf_libSceDipsw_patchC), sizeof(xor__eax_eax), xor__eax_eax, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_nidf_libSceDipsw_patchC");
		return false;
	}

#if MIRA_PLATFORM > MIRA_PLATFORM_ORBIS_BSD_455
	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_nidf_libSceDipsw_patchD), sizeof(xor__eax_eax), xor__eax_eax, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_nidf_libSceDipsw_patchD");
		return false;
	}
#endif

#if MIRA_PLATFORM == MIRA_PLATFORM_ORBIS_BSD_405 || (MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_474 && MIRA_PLATFORM <= MIRA_PLATFORM_ORBIS_BSD_620)
	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_enable_fakepkg_patch), 8, (void*)"\xE9\x96\x00\x00\x00", nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_enable_fakepkg_patch");
		return false;
	}
#elif MIRA_PLATFORM == MIRA_PLATFORM_ORBIS_BSD_455
	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_enable_fakepkg_patch), 8, (void*)"\xE9\x90\x00\x00\x00", nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_enable_fakepkg_patch");
		return false;
	}
#elif MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_672
	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_enable_fakepkg_patch), 8, (void*)"\xE9\x98\x00\x00\x00", nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_enable_fakepkg_patch");
		return false;
	}
#endif

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_fake_to_free_patch), 4, (void*)"free", nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_fake_to_free_patch");
		return false;
	}

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_enable_data_mount_patch), 5, (void*)"\x31\xC0\xFF\xC0\x90", nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_enable_data_mount_patch");
		return false;
	}

#if MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_450 && MIRA_PLATFORM != MIRA_PLATFORM_ORBIS_BSD_900
	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_external_hdd_pkg_installer_patch), 1, (void*)"\x00", nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_external_hdd_pkg_installer_patch");
		return false;
	}

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_external_hdd_version_patchA), 1, (void*)"\xEB", nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_external_hdd_version_patchA");
		return false;
	}

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_external_hdd_version_patchB), 1, (void*)"\xEB", nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssc_external_hdd_version_patchB");
		return false;
	}

#endif

	/*Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_ENABLE_DEBUG_PKG_PATCH_1_1_OFFSET), xor__eax_eax, sizeof(xor__eax_eax));
	Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_ENABLE_DEBUG_PKG_PATCH_1_2_OFFSET), xor__eax_eax, sizeof(xor__eax_eax));
	Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_ENABLE_DEBUG_PKG_PATCH_1_3_OFFSET), xor__eax_eax, sizeof(xor__eax_eax));
	Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_ENABLE_DEBUG_PKG_PATCH_1_4_OFFSET), xor__eax_eax, sizeof(xor__eax_eax));
	Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_ENABLE_DEBUG_PKG_PATCH_2_1_OFFSET), xor__eax_eax, sizeof(xor__eax_eax));
	Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_ENABLE_DEBUG_PKG_PATCH_2_2_OFFSET), xor__eax_eax, sizeof(xor__eax_eax));
	Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_ENABLE_DEBUG_PKG_PATCH_2_3_OFFSET), xor__eax_eax, sizeof(xor__eax_eax));
	Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_ENABLE_DEBUG_PKG_PATCH_2_4_OFFSET), xor__eax_eax, sizeof(xor__eax_eax));
	Utilities::PtraceIO(s_Process->p_pid, PIOD_WRITE_I, (void*)(s_TextStart + SHELLCORE_USE_FREE_PREFIX_INSTEAD_OF_FAKE_OFFSET), (void*)"free", 4);
	if (kptrace_t(PT_DETACH, s_Process->p_pid, (caddr_t)SIGCONT, 0, s_MainThread) < 0)
	{
		WriteLog(LL_Error, "could not detach from shellcore");
		return false;
	}*/

	WriteLog(LL_Debug, "SceShellCore successfully patched");

	return true;
}

bool FakePkgManager::ShellUIPatch()
{
	WriteLog(LL_Debug, "patching SceShellUI");

	struct ::proc* s_Process = Utilities::FindProcessByName("SceShellUI");
	if (s_Process == nullptr)
	{
		WriteLog(LL_Error, "could not find SceShellUI");
		return false;
	}

	ProcVmMapEntry* s_Entries = nullptr;
	size_t s_NumEntries = 0;
	auto s_Ret = Utilities::GetProcessVmMap(s_Process, &s_Entries, &s_NumEntries);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "could not get vm map");
		return false;
	}

	if (s_Entries == nullptr || s_NumEntries == 0)
	{
		WriteLog(LL_Error, "invalid entries (%p) or numEntries (%d)", s_Entries, s_NumEntries);
		return false;
	}

	uint8_t* s_LibKernelTextStart = nullptr;
	for (auto i = 0; i < s_NumEntries; ++i)
	{
		if (!memcmp(s_Entries[i].name, "libkernel_sys.sprx", 18) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
		{
			s_LibKernelTextStart = (uint8_t*)s_Entries[i].start;
			break;
		}
	}

	if (s_LibKernelTextStart == nullptr)
	{
		WriteLog(LL_Error, "could not find SceShellUI libkernel_sys.sprx text start");
		return false;
	}

	WriteLog(LL_Debug, "SceShellUI libkernel_sys.sprx .text: (%p)", s_LibKernelTextStart);

	// Free the entries we got returned
	delete [] s_Entries;
	s_Entries = nullptr;

	// TODO: Fix all fw suport; I don't feel like fixing 1.76 support atm -kd
	#if MIRA_PLATFORM <= MIRA_PLATFORM_ORBIS_BSD_176 || (MIRA_PLATFORM > MIRA_PLATFORM_ORBIS_BSD_702 && MIRA_PLATFORM != MIRA_PLATFORM_ORBIS_BSD_900)
	#else

	uint8_t mov__eax_1__ret[6] = { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 };

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_LibKernelTextStart + ssu_sceSblRcMgrIsAllowDebugMenuForSettings_patch), sizeof(mov__eax_1__ret), mov__eax_1__ret, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssu_sceSblRcMgrIsAllowDebugMenuForSettings_patch");
		return false;
	}

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_LibKernelTextStart + ssu_sceSblRcMgrIsStoreMode_patch), sizeof(mov__eax_1__ret), mov__eax_1__ret, nullptr, true);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "ssu_sceSblRcMgrIsStoreMode_patch");
		return false;
	}

	#endif

	WriteLog(LL_Debug, "SceShellUI successfully patched");

	return true;
}

void FakePkgManager::ResumeEvent()
{
	ShellUIPatch();
	WriteLog(LL_Debug, "InstallEventHandlers finished");
	return;
}

void FakePkgManager::ProcessStartEvent(void *arg, struct ::proc *p)
{
	auto strncmp = (int(*)(const char *, const char *, size_t))kdlsym(strncmp);

	if (!p)
		return;

	char* s_TitleId = (char*)((uint64_t)p + 0x390);
	if (strncmp(s_TitleId, "NPXS20000", 9) == 0)
		ShellCorePatch();

	if (strncmp(s_TitleId, "NPXS20001", 9) == 0)
		ShellUIPatch();

	return;
}

bool FakePkgManager::OnLoad()
{
	auto s_MainThread = Mira::Framework::GetFramework()->GetMainThread();
	if (s_MainThread == nullptr)
	{
		WriteLog(LL_Error, "could not get main mira thread");
		return false;
	}

	ShellCorePatch();
	ShellUIPatch();

	// Initialize the event handlers
	auto eventhandler_register = (eventhandler_tag(*)(struct eventhandler_list *list, const char *name, void *func, void *arg, int priority))kdlsym(eventhandler_register);

	m_processStartEvent = eventhandler_register(NULL, "process_exec_end", reinterpret_cast<void*>(FakePkgManager::ProcessStartEvent), NULL, EVENTHANDLER_PRI_LAST);
	m_resumeEvent = eventhandler_register(NULL, "system_resume_phase4", reinterpret_cast<void*>(FakePkgManager::ResumeEvent), NULL, EVENTHANDLER_PRI_LAST);

	return true;
}

bool FakePkgManager::OnUnload()
{
	auto eventhandler_deregister = (void(*)(struct eventhandler_list* a, struct eventhandler_entry* b))kdlsym(eventhandler_deregister);
	auto eventhandler_find_list = (struct eventhandler_list * (*)(const char *name))kdlsym(eventhandler_find_list);

	if (m_processStartEvent) {
		EVENTHANDLER_DEREGISTER(process_exec_end, m_processStartEvent);
		m_processStartEvent = nullptr;
	}

	if (m_resumeEvent) {
		EVENTHANDLER_DEREGISTER(process_exit, m_resumeEvent);
		m_resumeEvent = nullptr;
	}

	return true;
}

bool FakePkgManager::OnSuspend()
{
	return true;
}

bool FakePkgManager::OnResume()
{
	return true;
}

void FakePkgManager::GenPfsCryptoKey(uint8_t* p_EncryptionKeyPFS, uint8_t p_Seed[PFS_SEED_SIZE], uint32_t p_Index, uint8_t p_Key[PFS_FINAL_KEY_SIZE])
{
	auto s_Thread = curthread;
	FakeKeyD s_D;
	memset(&s_D, 0, sizeof(s_D));

	s_D.index = p_Index;
	memcpy(s_D.seed, p_Seed, PFS_SEED_SIZE);

	// fpu_kern_enter
	auto fpu_kern_enter = (int(*)(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags))kdlsym(fpu_kern_enter);
	auto fpu_kern_leave = (int (*)(struct thread *td, struct fpu_kern_ctx *ctx))kdlsym(fpu_kern_leave);

	auto fpu_ctx = (fpu_kern_ctx*)kdlsym(fpu_kern_ctx);
	auto Sha256Hmac = (void (*)(uint8_t hash[0x20], const uint8_t* data, size_t data_size, const uint8_t* key, int key_size))kdlsym(Sha256Hmac);

	fpu_kern_enter(s_Thread, fpu_ctx, 0);
	Sha256Hmac(p_Key, (const uint8_t*)&s_D, sizeof(s_D), p_EncryptionKeyPFS, EKPFS_SIZE);
	fpu_kern_leave(s_Thread, fpu_ctx);
}

void FakePkgManager::GenPfsEncKey(uint8_t* p_EncryptionKeyPFS, uint8_t p_Seed[PFS_SEED_SIZE], uint8_t p_Key[PFS_FINAL_KEY_SIZE])
{
	GenPfsCryptoKey(p_EncryptionKeyPFS, p_Seed, 1, p_Key);
}

void FakePkgManager::GenPfsSignKey(uint8_t* p_EncryptionKeyPFS, uint8_t p_Seed[PFS_SEED_SIZE], uint8_t p_Key[PFS_FINAL_KEY_SIZE])
{
	GenPfsCryptoKey(p_EncryptionKeyPFS, p_Seed, 2, p_Key);
}

int FakePkgManager::DecryptNpdrmDebugRif(uint32_t p_Type, uint8_t* p_Data)
{
	auto s_Thread = __curthread();
	if (s_Thread == nullptr)
		return SCE_SBL_ERROR_NPDRM_ENOTSUP;

	auto fpu_kern_enter = (int(*)(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags))kdlsym(fpu_kern_enter);
	auto fpu_kern_leave = (int (*)(struct thread *td, struct fpu_kern_ctx *ctx))kdlsym(fpu_kern_leave);
	auto fpu_ctx = (fpu_kern_ctx*)kdlsym(fpu_kern_ctx);
	//auto AesCbcCfb128Encrypt = (int (*)(uint8_t* out, const uint8_t* in, size_t data_size, const uint8_t* key, int key_size, uint8_t* iv))kdlsym(AesCbcCfb128Encrypt);
	auto AesCbcCfb128Decrypt = (int (*)(uint8_t* out, const uint8_t* in, size_t data_size, const uint8_t* key, int key_size, uint8_t* iv))kdlsym(AesCbcCfb128Decrypt);

	auto s_Ret = 0;
	fpu_kern_enter(s_Thread, fpu_ctx, 0);
	s_Ret = AesCbcCfb128Decrypt(p_Data + RIF_DIGEST_SIZE, p_Data + RIF_DIGEST_SIZE, RIF_DATA_SIZE, g_RifDebugKey, sizeof(g_RifDebugKey) * 8, p_Data);
	fpu_kern_leave(s_Thread, fpu_ctx);
	if (s_Ret)
		return SCE_SBL_ERROR_NPDRM_ENOTSUP;

	return s_Ret;
}

SblMapListEntry* FakePkgManager::SceSblDriverFindMappedPageListByGpuVa(vm_offset_t p_GpuVa)
{
	if (p_GpuVa == 0)
	{
		WriteLog(LL_Error, "invalid gpu va");
		return nullptr;
	}

	auto _mtx_lock_flags = (void(*)(struct mtx *m, int opts, const char *file, int line))kdlsym(_mtx_lock_flags);
	auto _mtx_unlock_flags = (void(*)(struct mtx *m, int opts, const char *file, int line))kdlsym(_mtx_unlock_flags);
	auto s_SblDrvMsgMtx = (struct mtx*)kdlsym(sbl_drv_msg_mtx);

	SblMapListEntry* s_Entry = *(SblMapListEntry**)kdlsym(gpu_va_page_list);
	SblMapListEntry* s_FinalEntry = nullptr;

	// Lock before we iterate this list, because other paths can absolutely use it concurrently
	_mtx_lock_flags(s_SblDrvMsgMtx, 0, __FILE__, __LINE__);

	while (s_Entry)
	{
		if (s_Entry->gpuVa == p_GpuVa)
		{
			s_FinalEntry = s_Entry;
			break;
		}

		s_Entry = s_Entry->next;
	}

	_mtx_unlock_flags(s_SblDrvMsgMtx, 0, __FILE__, __LINE__);
	return s_FinalEntry;
}

vm_offset_t FakePkgManager::SceSblDriverGpuVaToCpuVa(vm_offset_t p_GpuVa, size_t* p_NumPageGroups)
{
	auto s_Entry = SceSblDriverFindMappedPageListByGpuVa(p_GpuVa);
	if (s_Entry == nullptr)
		return 0;

	if (p_NumPageGroups != nullptr)
		*p_NumPageGroups = s_Entry->numPageGroups;

	return s_Entry->cpuVa;
}

int FakePkgManager::OnSceSblDriverSendMsg(SblMsg* p_Message, size_t p_Size) __attribute__ ((optnone))
{
	auto sceSblDriverSendMsg = (int (*)(SblMsg* msg, size_t size))kdlsym(sceSblDriverSendMsg);
	if (p_Message->hdr.cmd != SBL_MSG_CCP)
		return sceSblDriverSendMsg(p_Message, p_Size);

	union ccp_op* s_Op = &p_Message->service.ccp.op;
	if (CCP_OP(s_Op->common.cmd) != CCP_OP_AES)
		return sceSblDriverSendMsg(p_Message, p_Size);

	uint32_t s_Mask = CCP_USE_KEY_FROM_SLOT | CCP_GENERATE_KEY_AT_SLOT;
	if ((s_Op->aes.cmd & s_Mask) != s_Mask || (s_Op->aes.key_index != PFS_FAKE_OBF_KEY_ID))
		return sceSblDriverSendMsg(p_Message, p_Size);

	s_Op->aes.cmd &= ~CCP_USE_KEY_FROM_SLOT;

	size_t key_len = 16;

	/* reverse key bytes */
	//WriteLog(LL_Debug, "before");
	for (auto i = 0; i < key_len; ++i)
		s_Op->aes.key[i] = g_FakeKeySeed[key_len - i - 1];
	//WriteLog(LL_Debug, "after");

	return sceSblDriverSendMsg(p_Message, p_Size);
}

int FakePkgManager::OnSceSblPfsSetKeys(uint32_t* ekh, uint32_t* skh, uint8_t* eekpfs, Ekc* eekc, uint32_t pubkey_ver, uint32_t key_ver, PfsHeader* hdr, size_t hdr_size, uint32_t type, uint32_t finalized, uint32_t is_disc)
{
	auto sceSblPfsSetKeys = (int(*)(uint32_t* p_Ekh, uint32_t* p_Skh, uint8_t* p_Eekpfs, Ekc* p_Eekc, unsigned int p_PubkeyVer, unsigned int p_KeyVer, PfsHeader* p_Header, size_t p_HeaderSize, unsigned int p_Type, unsigned int p_Finalized, unsigned int p_IsDisc))kdlsym(sceSblPfsSetKeys);
	auto RsaesPkcs1v15Dec2048CRT = (int (*)(RsaBuffer* out, RsaBuffer* in, RsaKey* key))kdlsym(RsaesPkcs1v15Dec2048CRT);
	auto fpu_kern_enter = (int(*)(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags))kdlsym(fpu_kern_enter);
	auto fpu_kern_leave = (int (*)(struct thread *td, struct fpu_kern_ctx *ctx))kdlsym(fpu_kern_leave);
	auto sbl_pfs_sx = (struct sx*)kdlsym(sbl_pfs_sx);
	auto fpu_kern_ctx = (struct fpu_kern_ctx*)kdlsym(fpu_kern_ctx);
	//int	(*A_sx_xlock_hard)(struct sx *sx, uintptr_t tid, int opts, const char *file, int line) = kdlsym(_sx_xlock);
	//void (*A_sx_xunlock_hard)(struct sx *sx, uintptr_t tid, const char *file, int line) = kdlsym(_sx_xunlock);
	auto A_sx_xlock_hard = (int (*)(struct sx *sx, int opts))kdlsym(_sx_xlock);
	auto A_sx_xunlock_hard = (int (*)(struct sx *sx))kdlsym(_sx_xunlock);
	auto AesCbcCfb128Encrypt = (int (*)(uint8_t* out, const uint8_t* in, size_t data_size, const uint8_t* key, int key_size, uint8_t* iv))kdlsym(AesCbcCfb128Encrypt);
	auto sceSblKeymgrSetKeyForPfs = (int (*)(SblKeyDesc* key, unsigned int* handle))kdlsym(sceSblKeymgrSetKeyForPfs);
	auto sceSblKeymgrClearKey = (int (*)(uint32_t kh))kdlsym(sceSblKeymgrClearKey);

	struct thread* td;
	RsaBuffer in_data;
	RsaBuffer out_data;
	RsaKey key;
	uint8_t ekpfs[EKPFS_SIZE];
	uint8_t iv[16];
	SblKeyDesc enc_key_desc;
	SblKeyDesc sign_key_desc;
	int32_t ret, orig_ret = 0;

	ret = orig_ret = sceSblPfsSetKeys(ekh, skh, eekpfs, eekc, pubkey_ver, key_ver, hdr, hdr_size, type, finalized, is_disc);

	if (ret) {
		if (finalized && is_disc != 0)
		{
			ret = sceSblPfsSetKeys(ekh, skh, eekpfs, eekc, pubkey_ver, key_ver, hdr, hdr_size, type, finalized, 0); /* always use is_disc=0 here */
			if (ret) {
				ret = orig_ret;
				goto err;
			}
		} else {
			memset(&in_data, 0, sizeof(in_data));
			in_data.ptr = eekpfs;
			in_data.size = EEKPFS_SIZE;

			memset(&out_data, 0, sizeof(out_data));
			out_data.ptr = ekpfs;
			out_data.size = EKPFS_SIZE;

			memset(&key, 0, sizeof(key));
			key.p = (uint8_t*)g_ypkg_p;
			key.q = (uint8_t*)g_ypkg_q;
			key.dmp1 = (uint8_t*)g_ypkg_dmp1;
			key.dmq1 = (uint8_t*)g_ypkg_dmq1;
			key.iqmp = (uint8_t*)g_ypkg_iqmp;

			td = curthread;

			fpu_kern_enter(td, fpu_kern_ctx, 0);
			{
				ret = RsaesPkcs1v15Dec2048CRT(&out_data, &in_data, &key);
			}
			fpu_kern_leave(td, fpu_kern_ctx);

			if (ret) {
				ret = orig_ret;
				goto err;
			}

			A_sx_xlock_hard(sbl_pfs_sx,0);
			{
				memset(&enc_key_desc, 0, sizeof(enc_key_desc));
				{
					enc_key_desc.Pfs.obfuscatedKeyId = PFS_FAKE_OBF_KEY_ID;
					enc_key_desc.Pfs.keySize = sizeof(enc_key_desc.Pfs.escrowedKey);

					GenPfsEncKey(ekpfs, hdr->cryptSeed, enc_key_desc.Pfs.escrowedKey);

					fpu_kern_enter(td, fpu_kern_ctx, 0);
					{
						memset(iv, 0, sizeof(iv));
						ret = AesCbcCfb128Encrypt(enc_key_desc.Pfs.escrowedKey, enc_key_desc.Pfs.escrowedKey, sizeof(enc_key_desc.Pfs.escrowedKey), g_FakeKeySeed, sizeof(g_FakeKeySeed) * 8, iv);
					}
					fpu_kern_leave(td, fpu_kern_ctx);
				}
				if (ret) {
					WriteLog(LL_Error, "AesCbcCfb128Encrypt returned (%d)", ret);
					A_sx_xunlock_hard(sbl_pfs_sx);
					ret = orig_ret;
					goto err;
				}

				memset(&sign_key_desc, 0, sizeof(sign_key_desc));
				{
					sign_key_desc.Pfs.obfuscatedKeyId = PFS_FAKE_OBF_KEY_ID;
					sign_key_desc.Pfs.keySize = sizeof(sign_key_desc.Pfs.escrowedKey);

					GenPfsSignKey(ekpfs, hdr->cryptSeed, sign_key_desc.Pfs.escrowedKey);

					fpu_kern_enter(td, fpu_kern_ctx, 0);
					{
						memset(iv, 0, sizeof(iv));
						ret = AesCbcCfb128Encrypt(sign_key_desc.Pfs.escrowedKey, sign_key_desc.Pfs.escrowedKey, sizeof(sign_key_desc.Pfs.escrowedKey), g_FakeKeySeed, sizeof(g_FakeKeySeed) * 8, iv);
					}
					fpu_kern_leave(td, fpu_kern_ctx);
				}
				if (ret) {
					WriteLog(LL_Error, "AesCbcCfb128Encrypt returned (%d).", ret);
					A_sx_xunlock_hard(sbl_pfs_sx);
					ret = orig_ret;
					goto err;
				}

				ret = sceSblKeymgrSetKeyForPfs(&enc_key_desc, ekh);
				if (ret) {
					if (*ekh != 0xFFFFFFFF)
						sceSblKeymgrClearKey(*ekh);

					A_sx_xunlock_hard(sbl_pfs_sx);
					ret = orig_ret;
					goto err;
				}

				ret = sceSblKeymgrSetKeyForPfs(&sign_key_desc, skh);
				if (ret) {
					if (*skh != 0xFFFFFFFF)
						sceSblKeymgrClearKey(*skh);
					A_sx_xunlock_hard(sbl_pfs_sx);
					ret = orig_ret;
					goto err;
				}
			}
			A_sx_xunlock_hard(sbl_pfs_sx);
		}
	}

err:
	return ret;

	/*
	auto sceSblPfsSetKeys = (int(*)(uint32_t* p_Ekh, uint32_t* p_Skh, uint8_t* p_Eekpfs, Ekc* p_Eekc, unsigned int p_PubkeyVer, unsigned int p_KeyVer, PfsHeader* p_Header, size_t p_HeaderSize, unsigned int p_Type, unsigned int p_Finalized, unsigned int p_IsDisc))kdlsym(sceSblPfsSetKeys);

	// Call original function, if it succeeds it's not fake signed
	int s_Ret = sceSblPfsSetKeys(p_Ekh, p_Skh, p_EekPfs, p_Eekc, p_PubKeyVersion, p_KeyVersion, p_Header, p_HeaderSize, p_Type, p_Finalized, p_IsDisc);
	int s_OriginalRet = s_Ret;
	if (s_Ret == 0)
	{
		WriteLog(LL_Error, "sceSblPfsSetKeys returned (%x).", s_Ret);
		return s_Ret;
	}

	if (p_Finalized && p_IsDisc != 0)

	uint8_t s_Ekpfs[EKPFS_SIZE] = { 0 };
	RsaBuffer s_InData
	{
		.ptr = s_Ekpfs,
		.size = EEKPFS_SIZE
	};
	RsaBuffer s_OutData
	{
		.ptr = s_Ekpfs,
		.size = EKPFS_SIZE
	};

	RsaKey s_Key;
	memset(&s_Key, 0, sizeof(s_Key));
	s_Key.p = (uint8_t*)g_ypkg_p;
	s_Key.q = (uint8_t*)g_ypkg_q;
	s_Key.dmp1 = (uint8_t*)g_ypkg_dmp1;
	s_Key.dmq1 = (uint8_t*)g_ypkg_dmq1;
	s_Key.iqmp = (uint8_t*)g_ypkg_iqmp;

	auto s_Thread = __curthread();
	auto RsaesPkcs1v15Dec2048CRT = (int (*)(RsaBuffer* out, RsaBuffer* in, RsaKey* key))kdlsym(RsaesPkcs1v15Dec2048CRT);
	auto fpu_kern_enter = (int(*)(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags))kdlsym(fpu_kern_enter);
	auto fpu_kern_leave = (int (*)(struct thread *td, struct fpu_kern_ctx *ctx))kdlsym(fpu_kern_leave);
	auto sbl_pfs_sx = (struct sx*)kdlsym(sbl_pfs_sx);

	auto fpu_ctx = (fpu_kern_ctx*)kdlsym(fpu_kern_ctx);

	fpu_kern_enter(s_Thread, fpu_ctx, 0);
	s_Ret = RsaesPkcs1v15Dec2048CRT(&s_OutData, &s_InData, &s_Key);
	fpu_kern_leave(s_Thread, fpu_ctx);

	if (s_Ret)
	{
		WriteLog(LL_Error, "RsaesPkcs1v15Dec2048CRT returned (%x).", s_Ret);
		return s_OriginalRet;
	}

	auto _sx_xlock = (int (*)(struct sx *sx, int opts))kdlsym(_sx_xlock);
	auto _sx_xunlock = (int (*)(struct sx *sx))kdlsym(_sx_xunlock);

	//auto _sx_xlock_hard = (int(*)(struct sx *sx, uintptr_t tid, int opts, const char *file, int line))kdlsym(_sx_xlock);
	//auto _sx_xunlock_hard = (int(*)(struct sx *sx, uintptr_t tid, const char *file, int line))kdlsym(_sx_xunlock);
	auto AesCbcCfb128Encrypt = (int (*)(uint8_t* out, const uint8_t* in, size_t data_size, const uint8_t* key, int key_size, uint8_t* iv))kdlsym(AesCbcCfb128Encrypt);

	_sx_xlock(sbl_pfs_sx, 0);

	SblKeyDesc s_EncKeyDesc;
	memset(&s_EncKeyDesc, 0, sizeof(s_EncKeyDesc));

	s_EncKeyDesc.Pfs.obfuscatedKeyId = PFS_FAKE_OBF_KEY_ID;
	s_EncKeyDesc.Pfs.keySize = sizeof(s_EncKeyDesc.Pfs.escrowedKey);

	GenPfsEncKey(s_Ekpfs, p_Header->cryptSeed, s_EncKeyDesc.Pfs.escrowedKey);

	uint8_t s_Iv[16];
	memset(&s_Iv, 0, sizeof(s_Iv));

	fpu_kern_enter(s_Thread, fpu_ctx, 0);
	s_Ret = AesCbcCfb128Encrypt(s_EncKeyDesc.Pfs.escrowedKey, s_EncKeyDesc.Pfs.escrowedKey, sizeof(s_EncKeyDesc.Pfs.escrowedKey), g_FakeKeySeed, sizeof(g_FakeKeySeed) * 8, s_Iv);
	fpu_kern_leave(s_Thread, fpu_ctx);

	if (s_Ret)
	{
		WriteLog(LL_Error, "AesCbcCfb128Encrypt returned (%x)", s_Ret);
		_sx_xunlock(sbl_pfs_sx);
		return s_OriginalRet;
	}

	SblKeyDesc s_SignKeyDesc;
	memset(&s_SignKeyDesc, 0, sizeof(s_SignKeyDesc));

	s_SignKeyDesc.Pfs.obfuscatedKeyId = PFS_FAKE_OBF_KEY_ID;
	s_SignKeyDesc.Pfs.keySize = sizeof(s_SignKeyDesc.Pfs.escrowedKey);

	GenPfsSignKey(s_Ekpfs, p_Header->cryptSeed, s_SignKeyDesc.Pfs.escrowedKey);
	memset(&s_Iv, 0, sizeof(s_Iv));

	fpu_kern_enter(s_Thread, fpu_ctx, 0);
	s_Ret = AesCbcCfb128Encrypt(s_SignKeyDesc.Pfs.escrowedKey, s_SignKeyDesc.Pfs.escrowedKey, sizeof(s_SignKeyDesc.Pfs.escrowedKey), g_FakeKeySeed, sizeof(g_FakeKeySeed) * 8, s_Iv);
	fpu_kern_leave(s_Thread, fpu_ctx);

	if (s_Ret)
	{
		WriteLog(LL_Error, "AesCbcCfb128Encrypt returned (%x).", s_Ret);
		_sx_xunlock(sbl_pfs_sx);
		return s_OriginalRet;
	}

	auto sceSblKeymgrSetKeyForPfs = (int (*)(SblKeyDesc* key, unsigned int* handle))kdlsym(sceSblKeymgrSetKeyForPfs);
	auto sceSblKeymgrClearKey = (int (*)(uint32_t kh))kdlsym(sceSblKeymgrClearKey);

	s_Ret = sceSblKeymgrSetKeyForPfs(&s_EncKeyDesc, p_Ekh);
	if (s_Ret)
	{
		if (*p_Ekh != -1)
			sceSblKeymgrClearKey(*p_Ekh);

		_sx_xunlock(sbl_pfs_sx);
		return s_OriginalRet;
	}

	s_Ret = sceSblKeymgrSetKeyForPfs(&s_SignKeyDesc, p_Skh);
	if (s_Ret)
	{
		if (*p_Skh != -1)
			sceSblKeymgrClearKey(*p_Skh);

		_sx_xunlock(sbl_pfs_sx);
		return s_OriginalRet;
	}

	_sx_xunlock(sbl_pfs_sx);
	return 0;*/
}

int FakePkgManager::OnNpdrmDecryptIsolatedRif(KeymgrPayload* p_Payload)
{
	auto sceSblKeymgrSmCallfunc = (int (*)(KeymgrPayload* payload))kdlsym(sceSblKeymgrSmCallfunc);

	// it's SM request, thus we have the GPU address here, so we need to convert it to the CPU address
	KeymgrRequest* s_Request = reinterpret_cast<KeymgrRequest*>(SceSblDriverGpuVaToCpuVa(p_Payload->data, nullptr));

	// // try to decrypt rif normally
	int s_Ret = sceSblKeymgrSmCallfunc(p_Payload);
	if ((s_Ret != 0 || p_Payload->status != 0) && s_Request)
	{
		if (s_Request->DecryptRif.type == 0x200)
		{
			// fake?
			s_Ret = DecryptNpdrmDebugRif(s_Request->DecryptRif.type, s_Request->DecryptRif.data);
			p_Payload->status = s_Ret;
			s_Ret = 0;
		}
	}

	return s_Ret;
}

int FakePkgManager::OnNpdrmDecryptRifNew(KeymgrPayload* p_Payload)
{
	auto sceSblKeymgrSmCallfunc = (int (*)(KeymgrPayload* payload))kdlsym(sceSblKeymgrSmCallfunc);

	// it's SM request, thus we have the GPU address here, so we need to convert it to the CPU address
	uint64_t s_BufferGpuVa = p_Payload->data;
	auto s_Request = reinterpret_cast<KeymgrRequest*>(SceSblDriverGpuVaToCpuVa(s_BufferGpuVa, nullptr));
	auto s_Response = reinterpret_cast<KeymgrResponse*>(s_Request);

	// try to decrypt rif normally
	int s_Ret = sceSblKeymgrSmCallfunc(p_Payload);
	int s_OriginalRet = s_Ret;

	// and if it fails then we check if it's fake rif and try to decrypt it by ourselves
	if ((s_Ret != 0 || p_Payload->status != 0) && s_Request)
	{
		if (s_Request->DecryptEntireRif.rif.format != 2)
		{
			// not fake?
			goto err;
		}

		s_Ret = DecryptNpdrmDebugRif(s_Request->DecryptEntireRif.rif.format, s_Request->DecryptEntireRif.rif.digest);

		if (s_Ret)
		{
			s_Ret = s_OriginalRet;
			goto err;
		}

		/* XXX: sorry, i'm lazy to refactor this crappy code :D basically, we're copying decrypted data to proper place,
		consult with kernel code if offsets needs to be changed */
		memcpy(s_Response->DecryptEntireRif.raw, s_Request->DecryptEntireRif.rif.digest, sizeof(s_Request->DecryptEntireRif.rif.digest));
		memcpy(s_Response->DecryptEntireRif.raw + sizeof(s_Request->DecryptEntireRif.rif.digest), s_Request->DecryptEntireRif.rif.data, sizeof(s_Request->DecryptEntireRif.rif.data));

		memset(s_Response->DecryptEntireRif.raw +
		sizeof(s_Request->DecryptEntireRif.rif.digest) +
		sizeof(s_Request->DecryptEntireRif.rif.data),
		0,
		sizeof(s_Response->DecryptEntireRif.raw) -
		(sizeof(s_Request->DecryptEntireRif.rif.digest) +
		sizeof(s_Request->DecryptEntireRif.rif.data)));

		p_Payload->status = s_Ret;
	}

err:
	return s_Ret;
}

SblKeyRbtreeEntry* FakePkgManager::sceSblKeymgrGetKey(unsigned int p_Handle)
{
	SblKeyRbtreeEntry* s_Entry = *(SblKeyRbtreeEntry**)kdlsym(sbl_keymgr_key_rbtree);

	while (s_Entry)
	{
		if (s_Entry->handle < p_Handle)
			s_Entry = s_Entry->right;
		else if (s_Entry->handle > p_Handle)
			s_Entry = s_Entry->left;
		else if (s_Entry->handle == p_Handle)
			return s_Entry;
	}

	return nullptr;
}

int FakePkgManager::OnSceSblKeymgrInvalidateKeySxXlock(struct sx* p_Sx, int p_Opts, const char* p_File, int p_Line)
{
	//WriteLog(LL_Debug, "OnSceSblKeymgrInvalidateKeySxXlock");
	auto sceSblKeymgrSetKeyStorage = (int (*)(uint64_t key_gpu_va, unsigned int key_size, uint32_t key_id, uint32_t key_handle))kdlsym(sceSblKeymgrSetKeyStorage);
	auto sblKeymgrKeySlots = (_SblKeySlotQueue *)kdlsym(sbl_keymgr_key_slots);
	auto sblKeymgrBufVa = (uint8_t*)kdlsym(sbl_keymgr_buf_va);
	auto sblKeymgrBufGva = (uint64_t*)kdlsym(sbl_keymgr_buf_gva);
	auto _sx_xlock = (int(*)(struct sx *sx, int opts, const char *file, int line))kdlsym(_sx_xlock);

	SblKeyRbtreeEntry *keyDesc;
	SblKeySlotDesc *keySlotDesc;

	unsigned keyHandle;
	int ret, ret2;

	ret = _sx_xlock(p_Sx, p_Opts, p_File, p_Line);

	if (TAILQ_EMPTY(sblKeymgrKeySlots))
		goto done;

	TAILQ_FOREACH(keySlotDesc, sblKeymgrKeySlots, list)
	{
		keyHandle = keySlotDesc->keyHandle;
		if (keyHandle == (unsigned int) -1) {
			/* unbounded */
			WriteLog(LL_Debug, "unbounded");
			continue;
		}
		keyDesc = sceSblKeymgrGetKey(keyHandle);
		if (!keyDesc) {
			/* shouldn't happen in normal situations */
			WriteLog(LL_Debug, "shouldn't happen in normal situations");
			continue;
		}
		if (!keyDesc->occupied) {
			WriteLog(LL_Debug, "!occupied");
			continue;
		}
		if (keyDesc->desc.Pfs.obfuscatedKeyId != PFS_FAKE_OBF_KEY_ID) {
			/* not our key, just skip, so it will be handled by original code */
			WriteLog(LL_Debug, "not our key, just skip, so it will be handled by original code");
			continue;
		}
		if (keyDesc->desc.Pfs.keySize != sizeof(keyDesc->desc.Pfs.escrowedKey)) {
			/* something weird with key params, just ignore and app will just crash... */
			WriteLog(LL_Debug, "something weird with key params, just ignore and app will just crash...");
			continue;
		}
		memcpy(sblKeymgrBufVa, keyDesc->desc.Pfs.escrowedKey, keyDesc->desc.Pfs.keySize);
		//WriteLog(LL_Debug, "sblKeymgrBufGva %p %p", sblKeymgrBufGva, *sblKeymgrBufGva);
		ret2 = sceSblKeymgrSetKeyStorage(*sblKeymgrBufGva, keyDesc->desc.Pfs.keySize, keyDesc->desc.Pfs.obfuscatedKeyId, keySlotDesc->keyId);
		if (ret2) {
			WriteLog(LL_Debug, "wtf?");
			/* wtf? */
			continue;
		}
	}

done:
	/* XXX: no need to call SX unlock because we'll jump to original code which expects SX is already locked */
	return ret;
}


code:
/*
    Implemented from: https://github.com/xvortex/ps4-hen-vtx
    Ported by: kiwidog (@kd_tech_)

    Bugfixes: SiSTRo (https://github.com/SiSTR0), SocraticBliss (https://github.com/SocraticBliss)
*/

#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Types.hpp>
#include <Utils/Hook.hpp>

#include <OrbisOS/FakeStructs.hpp>

extern "C"
{
    #include <sys/eventhandler.h>
};

namespace Mira
{
    namespace Plugins
    {
        class FakePkgManager :
            public Mira::Utils::IModule
        {
        private:
            Utils::Hook* m_NpdrmDecryptIsolatedRifHook;
            Utils::Hook* m_NpdrmDecryptRifNewHook;
            Utils::Hook* m_SceSblDriverSendMsgHook;
            Utils::Hook* m_SceSblKeymgrInvalidateKey;
            Utils::Hook* m_SceSblPfsSetKeysHook;

            eventhandler_entry* m_processStartEvent;
            eventhandler_entry* m_resumeEvent;

            static const uint8_t g_ypkg_p[0x80];
            static const uint8_t g_ypkg_q[0x80];
            static const uint8_t g_ypkg_dmp1[0x80];
            static const uint8_t g_ypkg_dmq1[0x80];
            static const uint8_t g_ypkg_iqmp[0x80];

            static const uint8_t g_RifDebugKey[0x10];
            static const uint8_t g_FakeKeySeed[0x10];

        public:
            FakePkgManager();
            virtual ~FakePkgManager();

            virtual bool OnLoad() override;
            virtual bool OnUnload() override;
            virtual bool OnSuspend() override;
            virtual bool OnResume() override;

        private:
            // Helper functions
            static void GenPfsCryptoKey(uint8_t* p_EncryptionKeyPFS, uint8_t p_Seed[OrbisOS::PFS_SEED_SIZE], uint32_t p_Index, uint8_t p_Key[OrbisOS::PFS_FINAL_KEY_SIZE]);
            static void GenPfsEncKey(uint8_t* p_EncryptionKeyPFS, uint8_t p_Seed[OrbisOS::PFS_SEED_SIZE], uint8_t p_Key[OrbisOS::PFS_FINAL_KEY_SIZE]);
            static void GenPfsSignKey(uint8_t* p_EncryptionKeyPFS, uint8_t p_Seed[OrbisOS::PFS_SEED_SIZE], uint8_t p_Key[OrbisOS::PFS_FINAL_KEY_SIZE]);
            static int DecryptNpdrmDebugRif(uint32_t p_Type, uint8_t* p_Data);
            static OrbisOS::SblMapListEntry* SceSblDriverFindMappedPageListByGpuVa(vm_offset_t p_GpuVa);
            static vm_offset_t SceSblDriverGpuVaToCpuVa(vm_offset_t p_GpuVa, size_t* p_NumPageGroups);

            static int SceSblPfsSetKeys(uint32_t* p_Ekh, uint32_t* p_Skh, uint8_t* p_EekPfs, OrbisOS::Ekc* p_Eekc, uint32_t p_PubKeyVersion, uint32_t p_KeyVersion, OrbisOS::PfsHeader* p_Header, size_t p_HeaderSize, uint32_t p_Type, uint32_t p_Finalized, uint32_t p_IsDisc);
            static OrbisOS::SblKeyRbtreeEntry* sceSblKeymgrGetKey(unsigned int p_Handle);

        protected:
            // Hooked Functions
            static int OnSceSblPfsSetKeys(uint32_t* p_Ekh, uint32_t* p_Skh, uint8_t* p_EekPfs, OrbisOS::Ekc* p_Eekc, uint32_t p_PubKeyVersion, uint32_t p_KeyVersion, OrbisOS::PfsHeader* p_Header, size_t p_HeaderSize, uint32_t p_Type, uint32_t p_Finalized, uint32_t p_IsDisc);
            static int OnNpdrmDecryptIsolatedRif(OrbisOS::KeymgrPayload* p_Payload);
            static int OnNpdrmDecryptRifNew(OrbisOS::KeymgrPayload* p_Payload);
            static int OnSceSblDriverSendMsg(OrbisOS::SblMsg* p_Message, size_t p_Size);
            static int OnSceSblKeymgrInvalidateKeySxXlock(struct sx* p_Sx, int p_Opts, const char* p_File, int p_Line);

            static bool ShellCorePatch();
            static bool ShellUIPatch();
            static void ResumeEvent();
            static void ProcessStartEvent(void *arg, struct ::proc *p);

            };
    }
}


code:
/*
    Implemented from: https://github.com/xvortex/ps4-hen-vtx
    Ported by: kiwidog (@kd_tech_)

    Bugfixes: SiSTRo (https://github.com/SiSTR0), SocraticBliss (https://github.com/SocraticBliss)
*/

#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Types.hpp>
#include <Utils/Hook.hpp>

#include <OrbisOS/FakeStructs.hpp>

extern "C"
{
    #include <sys/elf.h>
    #include <vm/vm.h>
};

namespace Mira
{
    namespace Plugins
    {
        class FakeSelfManager :
            public Mira::Utils::IModule
        {
        private:
            enum
            {
                LoadSelfSegment = 2,
                LoadSelfBlock = 6,

                SelfMagic = 0x1D3D154F,
                ElfMagic = 0x464C457F,

                SelfPtypeFake = 1,

                AuthInfoSize = 136,
            };

            //Utils::Hook* m_SceSblACMgrGetPathIdHook;
            //Utils::Hook* m_SceSblServiceMailboxHook;
            //Utils::Hook* m_SceSblAuthMgrVerifyHeaderHook;
            //Utils::Hook* m_SceSblAuthMgrIsLoadable2Hook;

            //Utils::Hook* m__SceSblAuthMgrSmLoadSelfSegmentHook;
            //Utils::Hook* m__SceSblAuthMgrSmLoadSelfBlockHook;

            //static SelfContext* m_LastContext;

            static const uint8_t c_ExecAuthInfo[AuthInfoSize];
            static const uint8_t c_DynlibAuthInfo[AuthInfoSize];

        public:
            FakeSelfManager();
            virtual ~FakeSelfManager();

            virtual bool OnLoad() override;
            virtual bool OnUnload() override;
            virtual bool OnSuspend() override;
            virtual bool OnResume() override;

        private:
            //
            // Helper Functions
            static int AuthSelfHeader(OrbisOS::SelfContext* p_Context);
            static int SceSblAuthMgrSmLoadSelfBlock_Mailbox(uint64_t p_ServiceId, uint8_t* p_Request, void* p_Response);
            static int SceSblAuthMgrSmLoadSelfSegment_Mailbox(uint64_t service_id, void* p_Request, void* p_Response);
            static OrbisOS::SblMapListEntry* SceSblDriverFindMappedPageListByGpuVa(vm_offset_t p_GpuVa);
            static vm_offset_t SceSblDriverGpuVaToCpuVa(vm_offset_t p_GpuVa, size_t* p_NumPageGroups);
            static bool IsFakeSelf(OrbisOS::SelfContext* p_Context);
            static int BuildFakeSelfAuthInfo(OrbisOS::SelfContext* p_Context, OrbisOS::SelfAuthInfo* p_ParentAuthInfo, OrbisOS::SelfAuthInfo* p_AuthInfo);
            static int SceSblAuthMgrGetSelfAuthInfoFake(OrbisOS::SelfContext* p_Context, OrbisOS::SelfAuthInfo* p_Info);
            static int SceSblAuthMgrGetElfHeader(OrbisOS::SelfContext* p_Context, Elf64_Ehdr** p_OutElfHeader);
            static int SceSblAuthMgrIsLoadable_sceSblACMgrGetPathId(const char* path);

            //
            // Hook Helper Functions
            // This calls the original functions disabling the hooks, calling, reenabling hooks
            //static int SceSblServiceMailbox(uint32_t p_ServiceId, void* p_Request, void* p_Response);
            //static int SceSblAuthMgrIsLoadable2(SelfContext* p_Context, SelfAuthInfo* p_OldAuthInfo, int32_t p_PathId, SelfAuthInfo* p_NewAuthInfo);
            //static int SceSblAuthMgrVerifyHeader(SelfContext* p_Context);

            // 1.76 __int64 __fastcall sceSblAuthMgrSmLoadSelfBlock(__int64 a1, unsigned int a2, unsigned int a3, char *a4, char *a5, char *a6, void* a7, void* a8, void* a9, void* a10, int (__fastcall *a11)(signed __int64, __int64), __int64 a12)
            // 6.72 __int64 __fastcall sceSblAuthMgrSmLoadSelfBlock(SelfContext* a1, unsigned int a2, unsigned int a3, char *a4, char *a5, char* a6, void* a7, void* a8, void* a9, void* a10, void* a11)
            // 5.05 __int64 __fastcall sceSblAuthMgrSmLoadSelfBlock(__int64 a1, unsigned int a2, unsigned int a3, char *a4, char *a5, char* a6, void* a7, void* a8, void* a9, void* a10, void* a11)
            // Fixed thanks to the almighty flatz =]
            //static int _SceSblAuthMgrSmLoadSelfBlock(SelfContext* p_Context, uint32_t p_SegmentIndex, uint32_t p_BlockIndex, uint8_t* p_Data, size_t p_Size, int(*p_ReadCallback)(uint64_t /*p_Offset*/, uint8_t* /*p_Data*/, size_t /*p_Size*/), void* p_CallbackArg, void* unk0, void* unk1, void* unk2, void* unk3);
            //static int _SceSblAuthMgrSmLoadSelfSegment(SelfContext *p_Context, uint32_t p_SegmentIndex, bool p_IsBlockTable, uint8_t* p_Data, size_t p_Size, int(*p_ReadCallback)(uint64_t /*p_Offset*/, uint8_t* /*p_Data*/, size_t /*p_Size*/), void* p_CallbackArg, void* unk0, void* unk1);

            //void HookFunctionCall(uint8_t* p_HookTrampoline, void* p_Function, void* p_Address);

        protected:
            //
            // Hooked function callbacks
            //static int OnSceSblACMgrGetPathId(const char* p_Path);
            //static int OnSceSblServiceMailbox(uint32_t p_ServiceId, void* p_Request, void* p_Response);
            static int OnSceSblAuthMgrVerifyHeader(OrbisOS::SelfContext* p_Context);
            static int OnSceSblAuthMgrIsLoadable2(OrbisOS::SelfContext* p_Context, OrbisOS::SelfAuthInfo* p_OldAuthInfo, int32_t p_PathId, OrbisOS::SelfAuthInfo* p_NewAuthInfo);

            //static int On_SceSblAuthMgrSmLoadSelfBlock(SelfContext* p_Context, uint32_t p_SegmentIndex, uint32_t p_BlockIndex, uint8_t* p_Data, size_t p_Size, int(*p_ReadCallback)(uint64_t /*p_Offset*/, uint8_t* /*p_Data*/, size_t /*p_Size*/), void* p_CallbackArg, void* unk0, void* unk1, void* unk2, void* unk3);
            //static int On_SceSblAuthMgrSmLoadSelfSegment(SelfContext *p_Context, uint32_t p_SegmentIndex, bool p_IsBlockTable, uint8_t* p_Data, size_t p_Size, int(*p_ReadCallback)(uint64_t /*p_Offset*/, uint8_t* /*p_Data*/, size_t /*p_Size*/), void* p_CallbackArg, void* unk0, void* unk1);
        };
    }
}