Maintenance: direct admin merge of fn_17817 sub_AD1C90 (0xAD1C90), protector-damaged
Merged directly by the admin, bypassing peer review, because part of the original function was overwritten by the client's protector and can never match. Task 16009 is marked done on purpose; do not resubmit it. - Jump table 0xAD29E4: modes 0/1 go to 0xAD1E58, now "jmp 0x027AB0FE" into an empty protector stub. Bytes 0xAD1E58..0xAD237D are garbage. - The rest of case 0/1 survives from 0xAD237E (g_serviceFlag07 = 29, strstr(g_launchServerName, "QmSakray"), key/address pair, StringFormat into g_serviceAddress, then the admin/monster-job tail); ported as is. - Live WinDbg run (servertype=primary): 0xAD1C90 is never called; the protector loader in .data6 (sub_3DE8027) replaces it at runtime. - Based on attempt 57915 (batch 10359), with g_session.unknown_58FA replaced by g_launchServerName (same address, 0x1737F32). Key/string decryption verified against the binary. td check --includers: no errors.
This commit is contained in:
parent
3506359556
commit
c8cd69a8bf
3 changed files with 133 additions and 0 deletions
|
|
@ -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 <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
|
@ -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 <std::size_t Length, std::uint64_t Key>
|
||||
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<std::size_t>(-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<std::size_t>(-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) {
|
||||
|
|
|
|||
|
|
@ -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<std::string> g_loadingScreens;
|
||||
|
||||
const char* GetLicenceText();
|
||||
|
|
|
|||
|
|
@ -42,4 +42,6 @@ public:
|
|||
/* 00EC */ const char* unknown_00EC;
|
||||
};
|
||||
|
||||
extern const char* g_webPageUrl;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue