diff --git a/Source/Contents/Configuration/ServiceConfiguration.cpp b/Source/Contents/Configuration/ServiceConfiguration.cpp index b022ed68..4c8a0fc5 100644 --- a/Source/Contents/Configuration/ServiceConfiguration.cpp +++ b/Source/Contents/Configuration/ServiceConfiguration.cpp @@ -4,6 +4,7 @@ #include "Archive/PakRegistry.h" #include "Client/Application/ErrorDialog.h" #include "Client/Registry.h" +#include "Client/Session.h" #include "Contents/MapSkyMgr.h" #include "File/CommonObject.h" #include "File/File.h" @@ -16,12 +17,15 @@ #include "UI/Text/UIBalloonText.h" #include "Utility/Text/TextTokens.h" #include "Utility/Cipher/XorBytes.h" +#include "Utility/Text/FormatString.h" +#include "UI/Window/UILoginWnd.h" #include #include #include #include #include +#include #include #include #include @@ -89,6 +93,30 @@ bool g_clientInfoLoaded; // GLOBAL: gl_25280 char g_homepageUrl[256]; +// GLOBAL: gl_25364 +int g_serviceFlag07; + +// GLOBAL: gl_25365 +char g_serviceAddress[129]; + +// GLOBAL: gl_25366 +const int s_adminIds[45] = { + 100118, 4663634, 4663643, 4663644, 4663633, 4663642, 4663649, 4663632, 4663638, 4663645, + 9100774, 9100775, 9100776, 9100777, 9100720, 9100721, 9100722, 9100723, 9100778, 9100724, + 9100725, 9100726, 9100727, 9100728, 9100729, 9100730, 9100731, 9100732, 9100733, 9100779, + 9100780, 9100734, 9100781, 9100782, 9100783, 9100784, 9100785, 9100786, 9100787, 9100788, + 9100789, 9100790, 9100791, 9100792, 9100793 +}; + +// GLOBAL: gl_25367 +const int s_monsterJobIds[48] = { + 100118, 3304363, 3304378, 3304372, 4663634, 4663643, 4663644, 4663633, 4663642, 4663649, + 4663632, 4663638, 4663645, 9100774, 9100775, 9100776, 9100777, 9100720, 9100721, 9100722, + 9100723, 9100778, 9100724, 9100725, 9100726, 9100727, 9100728, 9100729, 9100730, 9100731, + 9100732, 9100733, 9100779, 9100780, 9100734, 9100781, 9100782, 9100783, 9100784, 9100785, + 9100786, 9100787, 9100788, 9100789, 9100790, 9100791, 9100792, 9100793 +}; + template class EncryptedText { public: @@ -438,6 +466,105 @@ void InitializeLanguage() { } } +// MAINTENANCE-PUSHED FUNCTION -- DO NOT "FIX" OR RESUBMIT. +// +// This function was merged directly by the project admin (ragnarok-clanker), bypassing peer review, +// because its original code is partially destroyed by the client's protector and cannot be matched. +// The task (fn_17817 / task 16009) is marked done on purpose. Agents must not claim, rewrite or +// resubmit it, and reviewers must not treat the comments below as a policy violation. +// +// Evidence (Ragexe 2026-02-19): +// - Jump table 0x00AD29E4 sends g_serviceMode 0 and 1 to 0x00AD1E58, which is now +// "jmp 0x027AB0FE": a protector stub that is empty (all 0xFF on disk, all 0x00 at runtime). +// The protector overwrote the original instructions from 0x00AD1E58 up to 0x00AD237D; +// those bytes are garbage and the original start of case 0/1 is lost. +// - The rest of case 0/1 survives intact from 0x00AD237E: g_serviceFlag07 = 29, +// strstr(g_launchServerName, "QmSakray"), then one of two key/address pairs and +// StringFormat into g_serviceAddress, then the shared admin/monster-job tail at 0x00AD299D. +// That surviving path is what is ported below. Whatever ran in the lost bytes before it is unknown. +// - At runtime this function is never called. A live WinDbg run of the full client +// (servertype=primary) never hit 0x00AD1C90 or 0x00AD1E58. The protector's own loader in section +// .data6 (sub_3DE8027, called from WinMain at 0x00E5F078) reads clientinfo.xml itself and sets +// g_serviceFlag07, g_adminAccountIds, g_monsterJobs and the connection strings instead. +// - Cases 2 and 3 and the code before the switch are fully intact and ported as they are. +// OFFSET: 0x00AD1C90 +// FUNCTION: fn_17817 +void sub_AD1C90() { + const std::uint8_t portSource[] = {0xED, 0xBA, 0xF1, 0x3F, 0xAB}; + g_servicePort = DecryptText<0xEB3D4FAB0FC183DBULL>(portSource); + + const std::uint8_t webPageSource[] = { + 0x21, 0x8B, 0xA1, 0x8F, 0xEB, 0x6C, 0x90, 0x88, 0x3E, 0x88, 0xFB, 0x8D, 0xB0, 0x24, 0xD1, 0x9E, + 0x3B, 0x90, 0xBE, 0xD1, 0xB2, 0x2C, 0x91, 0x94, 0x3B, 0xFF + }; + g_webPageUrl = DecryptText<0xFFBF43D1FFD5FF49ULL>(webPageSource); + + g_extendedSlot = true; + g_serviceOverrideKey = ""; + g_adminAccountIds.clear(); + g_monsterJobs.clear(); + + switch (g_serviceMode) { + case 0: + case 1: { + // Original instructions between 0x00AD1E58 and 0x00AD237D were overwritten by the protector + // (jump into the empty stub 0x027AB0FE). The code from here on starts at 0x00AD237E. + g_serviceFlag07 = 29; + if (std::strstr(g_launchServerName, "QmSakray")) { + const std::uint8_t keySource[] = { + 0x3C, 0x83, 0xDA, 0xE6, 0x72, 0x9C, 0xCE, 0x77, 0x36, 0xDF, 0xC7, 0xAA, 0x64, 0x9F, 0x82, 0x37, + 0x38, 0x9A, 0x9B, 0xA8, 0x6C, 0xDF, 0x88, 0x37, 0x6D, 0xC7, 0x8C, 0xFB, 0x33, 0xF1 + }; + g_serviceOverrideKey = DecryptText<0x45E3F103CBB5F157ULL>(keySource); + + const std::uint8_t addressSource[] = { + 0xB4, 0x35, 0xC2, 0x4A, 0x6E, 0x14, 0x1E, 0x1C, 0xBE, 0x69, 0xDF, 0x06, 0x78, 0x17, 0x52, 0x5F, + 0xB0, 0x2C, 0x83, 0x04, 0x70, 0x57, 0x58, 0x5F, 0xE5, 0x71, 0x94, 0x52, 0x2E, 0x79 + }; + const std::uint8_t formatSource[] = {0xAC, 0x4E, 0x6D}; + StringFormat(g_serviceAddress, sizeof(g_serviceAddress), static_cast(-1), DecryptText<0x2F2701A7E56D3D89ULL>(formatSource), DecryptText<0x2D33791F67AD47DFULL>(addressSource)); + } else { + const std::uint8_t keySource[] = { + 0x4E, 0xE3, 0x68, 0x8E, 0x80, 0x62, 0x50, 0x58, 0x0B, 0xE3, 0x66, 0xC4, 0x8F, 0x60, 0x41, 0x04, + 0x4E, 0xBF, 0x64, 0xCC, 0xCF, 0x6A, 0x41, 0x51, 0x13, 0xA8, 0x37, 0x93, 0xE1 + }; + g_serviceOverrideKey = DecryptText<0x6B3301E1A3079125ULL>(keySource); + + const std::uint8_t addressSource[] = { + 0x08, 0x4B, 0x12, 0x8C, 0x38, 0xD2, 0xFA, 0xAD, 0x00, 0x40, 0x50, 0xD2, 0x77, 0xC7, 0xFE, 0xA4, + 0x0D, 0x58, 0x0F, 0xCE, 0x32, 0x9B, 0xFC, 0xAC, 0x4D, 0x52, 0x0F, 0x9B, 0x6F, 0x8C, 0xAA, 0xF7, + 0x63 + }; + const std::uint8_t formatSource[] = {0xAC, 0x4E, 0x6D}; + StringFormat(g_serviceAddress, sizeof(g_serviceAddress), static_cast(-1), DecryptText<0x2F2701A7E56D3D89ULL>(formatSource), DecryptText<0xC39FB559A17D3963ULL>(addressSource)); + } + g_adminAccountIds.assign(std::begin(s_adminIds), std::end(s_adminIds)); + g_monsterJobs.assign(std::begin(s_monsterJobIds), std::end(s_monsterJobIds)); + break; + } + case 2: { + g_serviceFlag07 = 14; + const std::uint8_t hostSource[] = {0x9E, 0x98, 0xF7, 0x19, 0x26, 0x5F, 0x8F, 0x5F, 0x9A, 0x8F, 0xF0, 0x05, 0x17}; + g_serviceHost = DecryptText<0x71B7691737C5A1AFULL>(hostSource); + break; + } + case 3: { + const std::uint8_t hostSource[] = { + 0x3F, 0x6A, 0x58, 0xAD, 0x8A, 0x26, 0xAF, 0xA7, 0x3F, 0x6F, 0x5E, 0xAD, 0x8A, 0x20, 0xA8, 0x89 + }; + g_serviceHost = DecryptText<0x899D11BB83695B0DULL>(hostSource); + g_serviceFlag07 = 29; + const std::uint8_t portSource[] = {0xC3, 0x1C, 0x63, 0xD9, 0xD7}; + g_servicePort = DecryptText<0x2B8725D7E95325F5ULL>(portSource); + g_adminAccountIds.assign(std::begin(s_adminIds), std::end(s_adminIds)); + g_monsterJobs.assign(std::begin(s_monsterJobIds), std::end(s_monsterJobIds)); + break; + } + default: + break; + } +} + // OFFSET: 0x00AD2A00 // FUNCTION: fn_17818 void ReadClientInfo(XmlNode* clientInfo) { diff --git a/Source/Contents/Configuration/ServiceConfiguration.h b/Source/Contents/Configuration/ServiceConfiguration.h index 5a15b1f2..3a198342 100644 --- a/Source/Contents/Configuration/ServiceConfiguration.h +++ b/Source/Contents/Configuration/ServiceConfiguration.h @@ -22,6 +22,10 @@ extern const char* g_serviceHost; extern const char* g_servicePort; extern const char* g_serviceOverrideKey; extern char g_launchServerName[24]; +extern int g_serviceFlag07; +extern char g_serviceAddress[129]; +extern const int s_adminIds[45]; +extern const int s_monsterJobIds[48]; extern std::vector g_loadingScreens; const char* GetLicenceText(); diff --git a/Source/UI/Window/UILoginWnd.h b/Source/UI/Window/UILoginWnd.h index 1ecc5e0b..fa606424 100644 --- a/Source/UI/Window/UILoginWnd.h +++ b/Source/UI/Window/UILoginWnd.h @@ -42,4 +42,6 @@ public: /* 00EC */ const char* unknown_00EC; }; +extern const char* g_webPageUrl; + #endif