diff --git a/src/common/Logging.cpp b/src/common/Logging.cpp index 35e800217..777af325b 100644 --- a/src/common/Logging.cpp +++ b/src/common/Logging.cpp @@ -278,7 +278,7 @@ PopupReturn PopupCustomEx(const void* hwnd, const CXBXR_MODULE cxbxr_module, con UINT uType = MB_TOPMOST | MB_SETFOREGROUND; // Make assert whenever the format string is null pointer which isn't allow in here. - assert(!message); + assert(message != nullptr); switch (icon) { case PopupIcon::Warning: { diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 819f2d278..fd05f6882 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -82,7 +82,8 @@ static struct { const char* RecentXbeFiles = "RecentXbeFiles"; const char* DataStorageToggle = "DataStorageToggle"; const char* DataCustomLocation = "DataCustomLocation"; - const char* IgnoreInvalidXbeSig = "IgnoreInvalidXbeSig"; + const char* IgnoreInvalidXbeSig = "IgnoreInvalidXbeSig"; + const char *IgnoreInvalidXbeSec = "IgnoreInvalidXbeSec"; } sect_gui_keys; static const char* section_core = "core"; @@ -315,7 +316,8 @@ bool Settings::LoadConfig() index++; } - m_gui.bIgnoreInvalidXbeSig = m_si.GetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSig, /*Default=*/false); + m_gui.bIgnoreInvalidXbeSig = m_si.GetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSig, /*Default=*/false); + m_gui.bIgnoreInvalidXbeSec = m_si.GetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSec, /*Default=*/false); // ==== GUI End ============= @@ -517,7 +519,8 @@ bool Settings::Save(std::string file_path) m_si.SetValue(section_gui, sect_gui_keys.RecentXbeFiles, m_gui.szRecentXbeFiles[i].c_str(), nullptr, false); } - m_si.SetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSig, m_gui.bIgnoreInvalidXbeSig, nullptr, true); + m_si.SetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSig, m_gui.bIgnoreInvalidXbeSig, nullptr, true); + m_si.SetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSec, m_gui.bIgnoreInvalidXbeSec, nullptr, true); // ==== GUI End ============= diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index cac692f16..648175083 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -88,7 +88,8 @@ public: std::string szRecentXbeFiles[10]; unsigned int DataStorageToggle; std::string szCustomLocation = ""; - bool bIgnoreInvalidXbeSig; + bool bIgnoreInvalidXbeSig; + bool bIgnoreInvalidXbeSec; } m_gui; // Core settings diff --git a/src/common/xbe/Xbe.cpp b/src/common/xbe/Xbe.cpp index b6788c962..8602b682e 100644 --- a/src/common/xbe/Xbe.cpp +++ b/src/common/xbe/Xbe.cpp @@ -779,7 +779,7 @@ const wchar_t *Xbe::GetUnicodeFilenameAddr() return (const wchar_t *)GetAddr(m_Header.dwDebugUnicodeFilenameAddr); } -bool Xbe::CheckXbeSignature() +bool Xbe::CheckSignature() { init_tom_lib(); @@ -810,6 +810,24 @@ bool Xbe::CheckXbeSignature() return false; // signature check failed } +bool Xbe::CheckSectionIntegrity(uint32_t sectionIndex) +{ + uint32_t RawSize = m_SectionHeader[sectionIndex].dwSizeofRaw; + if (RawSize == 0) { + return true; + } + + unsigned char SHADigest[A_SHA_DIGEST_LEN]; + CalcSHA1Hash(SHADigest, m_bzSection[sectionIndex], RawSize); + + if (std::memcmp(SHADigest, m_SectionHeader[sectionIndex].bzSectionDigest, A_SHA_DIGEST_LEN) != 0) { + return false; + } + else { + return true; + } +} + // ported from Dxbx's XbeExplorer XbeType Xbe::GetXbeType() { diff --git a/src/common/xbe/Xbe.h b/src/common/xbe/Xbe.h index f51f27a13..41d2adac9 100644 --- a/src/common/xbe/Xbe.h +++ b/src/common/xbe/Xbe.h @@ -63,8 +63,11 @@ class Xbe : public Error // export to Xbe file void Export(const char *x_szXbeFilename); - // verify the integrity of the loaded xbe - bool CheckXbeSignature(); + // verify the integrity of the xbe header + bool CheckSignature(); + + // verify the integrity of an xbe section + bool CheckSectionIntegrity(uint32_t sectionIndex); // import logo bitmap from raw monochrome data void ImportLogoBitmap(const uint8_t x_Gray[100*17]); diff --git a/src/common/xbe/XbePrinter.cpp b/src/common/xbe/XbePrinter.cpp index 2d7e6ba62..c3237fea1 100644 --- a/src/common/xbe/XbePrinter.cpp +++ b/src/common/xbe/XbePrinter.cpp @@ -276,7 +276,7 @@ std::string XbePrinter::GenGeneralHeaderInfo2() std::string XbePrinter::ValidateXbeSignature() { std::string text("\nInvalid xbe signature. Homebrew, tampered or pirated xbe?\n"); - if (Xbe_to_print->CheckXbeSignature()) { + if (Xbe_to_print->CheckSignature()) { text = "\nValid xbe signature. Xbe is legit\n"; } return text; @@ -416,7 +416,13 @@ std::string XbePrinter::GenSectionHeaders() text << "Section Reference Count : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwSectionRefCount << "\n"; text << "Head Shared Reference Count Addr : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwHeadSharedRefCountAddr << "\n"; text << "Tail Shared Reference Count Addr : 0x" << std::setw(8) << Xbe_to_print->m_SectionHeader[v].dwTailSharedRefCountAddr << "\n"; - text << GenSectionDigest(Xbe_to_print->m_SectionHeader[v]) << "\n"; + text << GenSectionDigest(Xbe_to_print->m_SectionHeader[v]) << "\n"; + if (Xbe_to_print->CheckSectionIntegrity(v)) { + text << "SHA hash check of section " << Xbe_to_print->m_szSectionName[v] << " successful" << "\n\n"; + } + else { + text << "SHA hash of section " << Xbe_to_print->m_szSectionName[v] << " doesn't match, section is corrupted" << "\n\n"; + } } return text.str(); } @@ -454,7 +460,6 @@ std::string XbePrinter::GenSectionDigest(Xbe::SectionHeader section_header) std::string text; text.append("Section Digest : "); text.append(GenHexRow(§ion_header.bzSectionDigest[0], 0, 20)); - text.append("\n"); return text; } diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 8e9a4f94a..c38d383fe 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -993,7 +993,7 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res } // Check the signature of the xbe - if (CxbxKrnl_Xbe->CheckXbeSignature()) { + if (CxbxKrnl_Xbe->CheckSignature()) { EmuLogInit(LOG_LEVEL::INFO, "Valid xbe signature. Xbe is legit"); } else { @@ -1002,18 +1002,11 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res // Check the integrity of the xbe sections for (uint32_t sectionIndex = 0; sectionIndex < CxbxKrnl_Xbe->m_Header.dwSections; sectionIndex++) { - uint32_t RawSize = CxbxKrnl_Xbe->m_SectionHeader[sectionIndex].dwSizeofRaw; - if (RawSize == 0) { - continue; - } - unsigned char SHADigest[A_SHA_DIGEST_LEN]; - CalcSHA1Hash(SHADigest, CxbxKrnl_Xbe->m_bzSection[sectionIndex], RawSize); - - if (memcmp(SHADigest, (CxbxKrnl_Xbe->m_SectionHeader)[sectionIndex].bzSectionDigest, A_SHA_DIGEST_LEN) != 0) { - EmuLogInit(LOG_LEVEL::WARNING, "SHA hash of section %s doesn't match, possible section corruption", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); + if (CxbxKrnl_Xbe->CheckSectionIntegrity(sectionIndex)) { + EmuLogInit(LOG_LEVEL::INFO, "SHA hash check of section %s successful", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); } else { - EmuLogInit(LOG_LEVEL::INFO, "SHA hash check of section %s successful", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); + EmuLogInit(LOG_LEVEL::WARNING, "SHA hash of section %s doesn't match, section is corrupted", CxbxKrnl_Xbe->m_szSectionName[sectionIndex]); } } diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index 863a5a780..32adfa5a8 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -1291,6 +1291,11 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP RefreshMenus(); break; + case ID_SETTINGS_IGNOREINVALIDXBESEC: + g_Settings->m_gui.bIgnoreInvalidXbeSec = !g_Settings->m_gui.bIgnoreInvalidXbeSec; + RefreshMenus(); + break; + case ID_SETTINGS_ALLOWADMINPRIVILEGE: g_Settings->m_core.allowAdminPrivilege = !g_Settings->m_core.allowAdminPrivilege; RefreshMenus(); @@ -1762,6 +1767,9 @@ void WndMain::RefreshMenus() chk_flag = (g_Settings->m_gui.bIgnoreInvalidXbeSig) ? MF_CHECKED : MF_UNCHECKED; CheckMenuItem(settings_menu, ID_SETTINGS_IGNOREINVALIDXBESIG, chk_flag); + chk_flag = (g_Settings->m_gui.bIgnoreInvalidXbeSec) ? MF_CHECKED : MF_UNCHECKED; + CheckMenuItem(settings_menu, ID_SETTINGS_IGNOREINVALIDXBESEC, chk_flag); + chk_flag = (g_Settings->m_core.allowAdminPrivilege) ? MF_CHECKED : MF_UNCHECKED; CheckMenuItem(settings_menu, ID_SETTINGS_ALLOWADMINPRIVILEGE, chk_flag); } @@ -2001,25 +2009,43 @@ void WndMain::OpenXbe(const char *x_filename) return; } + + std::string errorMsg; - if (!g_Settings->m_gui.bIgnoreInvalidXbeSig && !m_Xbe->CheckXbeSignature()) - { - PopupReturn ret = PopupWarningEx(m_hwnd, PopupButtons::YesNo, PopupReturn::No, - "XBE signature check failed!\n" - "\nThis is dangerous, as maliciously modified Xbox titles could take control of your system.\n" + if (!g_Settings->m_gui.bIgnoreInvalidXbeSig && !m_Xbe->CheckSignature()) { + errorMsg += "- XBE signature check failed!\n"; + } + + if (!g_Settings->m_gui.bIgnoreInvalidXbeSec) { + for (uint32_t sectionIndex = 0; sectionIndex < m_Xbe->m_Header.dwSections; sectionIndex++) { + if (!m_Xbe->CheckSectionIntegrity(sectionIndex)) { + errorMsg += "- One or more XBE section(s) are corrupted!\n"; + + // if we find a corrupted section, we won't bother checking the remaining sections since we know + // already at this point that the xbe is invalid + break; + } + } + } + + if (!errorMsg.empty()) { + errorMsg += ("\nThis is dangerous, as maliciously modified Xbox applications could take control of your system." + "\nPlease do not report issues for this application.\n" "\nAre you sure you want to continue?"); + + PopupReturn ret = PopupWarningEx(m_hwnd, PopupButtons::YesNo, PopupReturn::No, errorMsg.c_str()); if (ret != PopupReturn::Yes) { delete m_Xbe; m_Xbe = nullptr; - + RedrawWindow(m_hwnd, nullptr, NULL, RDW_INVALIDATE); - + UpdateCaption(); - + return; } } - + // save this xbe to the list of recent xbe files if(m_XbeFilename[0] != '\0') { bool found = false; diff --git a/src/gui/resource/Cxbx.rc b/src/gui/resource/Cxbx.rc index 795cf18c4..cc62b8c01 100644 --- a/src/gui/resource/Cxbx.rc +++ b/src/gui/resource/Cxbx.rc @@ -679,6 +679,7 @@ BEGIN END MENUITEM "Use Loader Executable", ID_USELOADEREXEC,MFT_STRING,MFS_ENABLED MENUITEM "Ignore Invalid Xbe Signature", ID_SETTINGS_IGNOREINVALIDXBESIG,MFT_STRING,MFS_ENABLED + MENUITEM "Ignore Invalid Xbe Sections", ID_SETTINGS_IGNOREINVALIDXBESEC, MFT_STRING, MFS_ENABLED MENUITEM "Allow Admin Privilege", ID_SETTINGS_ALLOWADMINPRIVILEGE,MFT_STRING,MFS_ENABLED MENUITEM "", -1, MFT_SEPARATOR MENUITEM "Reset To Defaults", ID_SETTINGS_INITIALIZE,MFT_STRING,MFS_ENABLED diff --git a/src/gui/resource/ResCxbx.h b/src/gui/resource/ResCxbx.h index 375a7e584..5faad1741 100644 --- a/src/gui/resource/ResCxbx.h +++ b/src/gui/resource/ResCxbx.h @@ -365,6 +365,7 @@ #define ID_SETTINGS_EXPERIMENTAL 40113 #define ID_USELOADEREXEC 40114 #define ID_SETTINGS_IGNOREINVALIDXBESIG 40115 +#define ID_SETTINGS_IGNOREINVALIDXBESEC 40116 #define IDC_STATIC -1 // Next default values for new objects @@ -372,7 +373,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 136 -#define _APS_NEXT_COMMAND_VALUE 40116 +#define _APS_NEXT_COMMAND_VALUE 40117 #define _APS_NEXT_CONTROL_VALUE 1305 #define _APS_NEXT_SYMED_VALUE 109 #endif