SkillAgentSearch skills...

MapleResearch

MapleStory v95 AntiHack Analysis

Install / Use

/learn @Maxcloud/MapleResearch
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

MapleStory v95 Client Analysis

Hello everyone welcome to our analysis on GMS v95.1

  • This document is a work in progress
  • This is not a professional document
  • The primary focus is on what I d to do to create localhost
  • There is too much for me to go into excruciating detail about
  • Please contribute if you know anything more !!!

CSecurityClient

Class used to handle anti cheat integration

  • Houses HackShield related fields in this version
  • In other versions houses NGS and XignCode3 relations fields
  • Is a TSingleton<CSecurityClient>

In lots of places in the client usage of CSecurityClient looks like such (pseudo):


  if ( TSingleton<CSecurityClient>::IsInstantiated() )
  {
    TSingleton<CSecurityClient>::GetInstance();
    
    //Usage of class such as
    CSecurityClient::InitModule();
  }

PatchRetZero here can save you lots of patches you'd have to do in other places otherwise.

Class Pseudo
// write access to const memory has been detected, the output may be wrong!
void __thiscall CSecurityClient::CSecurityClient(CSecurityClient *this)
{
  CSecurityClient *v1; // edi
  TSecType<int> *v2; // esi
  int v3; // eax
  char v4; // dl
  TSecData<int> *v5; // ecx
  int v6; // eax
  TSecData<int> *v7; // edx
  int v8; // eax
  char v9; // cl

  v1 = this;
  v2 = &this->m_bInitModule;
  if ( this == (CSecurityClient *)-4 )
    TSingleton<CSecurityClient>::ms_pInstance = 0;
  else
    TSingleton<CSecurityClient>::ms_pInstance = this;
  this->vfptr = (CSecurityClientVtbl *)&CSecurityClient::`vftable';
  this->m_bInitModule.m_secdata = (TSecData<int> *)ZAllocEx<ZAllocAnonSelector>::Alloc(
                                                     &ZAllocEx<ZAllocAnonSelector>::_s_alloc,
                                                     0xCu);
  v2->FakePtr1 = (unsigned int)&v2[-1365].FakePtr2 + rand();
  v3 = rand();
  v4 = v2->FakePtr1;
  v5 = v2->m_secdata;
  v2->FakePtr2 = (unsigned int)&v2[-1365].FakePtr2 + v3;
  v5->FakePtr1 = v4;
  v2->m_secdata->FakePtr2 = v2->FakePtr2;
  TSecType<int>::SetData(v2, 0);
  v1->m_bStartModule.m_secdata = (TSecData<int> *)ZAllocEx<ZAllocAnonSelector>::Alloc(
                                                    &ZAllocEx<ZAllocAnonSelector>::_s_alloc,
                                                    0xCu);
  v1->m_bStartModule.FakePtr1 = (unsigned int)&v1[-52].m_szHShieldPath[rand() + 20];
  v6 = rand();
  v7 = v1->m_bStartModule.m_secdata;
  v1->m_bStartModule.FakePtr2 = (unsigned int)&v1[-52].m_szHShieldPath[v6 + 20];
  v7->FakePtr1 = v1->m_bStartModule.FakePtr1;
  v1->m_bStartModule.m_secdata->FakePtr2 = v1->m_bStartModule.FakePtr2;
  TSecType<int>::SetData(&v1->m_bStartModule, 0);
  v1->m_nThreatCode = 0;
  v1->m_nThreatParamSize.m_secdata = (TSecData<long> *)ZAllocEx<ZAllocAnonSelector>::Alloc(
                                                         &ZAllocEx<ZAllocAnonSelector>::_s_alloc,
                                                         0xCu);
  v1->m_nThreatParamSize.FakePtr1 = (unsigned int)&v1[-52].m_szHShieldPath[rand() + 36];
  v8 = rand();
  v9 = v1->m_nThreatParamSize.FakePtr1;
  v1->m_nThreatParamSize.FakePtr2 = (unsigned int)&v1[-52].m_szHShieldPath[v8 + 36];
  v1->m_nThreatParamSize.m_secdata->FakePtr1 = v9;
  v1->m_nThreatParamSize.m_secdata->FakePtr2 = v1->m_nThreatParamSize.FakePtr2;
  TSecType<long>::SetData(&v1->m_nThreatParamSize, 0);
  v1->m_pThreatParam = 0;
  v1->m_hMainWnd = 0;
}
void __thiscall CSecurityClient::InitModule(CSecurityClient *this)
{
  CSecurityClient *v1; // esi
  unsigned int v2; // eax
  int v3; // eax
  int (__stdcall **pExceptionObject)(ZXString<char> *); // [esp+4h] [ebp-214h]
  unsigned int v5; // [esp+8h] [ebp-210h]
  CHAR sModulePath; // [esp+Ch] [ebp-20Ch]
  char v7; // [esp+Dh] [ebp-20Bh]
  unsigned __int8 sModuleFolderPath; // [esp+110h] [ebp-108h]
  char v9; // [esp+111h] [ebp-107h]

  v1 = this;
  sModuleFolderPath = 0;
  memset(&v9, 0, 0x103u);
  sModulePath = 0;
  memset(&v7, 0, 0x103u);
  GetModuleFolderName((char *)&sModuleFolderPath);
  _mbsnbcpy((unsigned __int8 *)&sModulePath, &sModuleFolderPath, 0x104u);
  _mbsnbcat((unsigned __int8 *)&sModulePath, "\\HShield", 8u);
  _mbsnbcpy((unsigned __int8 *)v1->m_szHShieldPath, (const unsigned __int8 *)&sModulePath, 0x104u);
  v2 = _AhnHS_HSUpdateA(&sModulePath, 600000u, 20000u);
  if ( v2 )
  {
    v5 = v2;
    pExceptionObject = CSecurityUpdateFailed::`vftable';
    _CxxThrowException(&pExceptionObject, &_TI2_AVCSecurityUpdateFailed__);
  }
  _mbsnbcpy((unsigned __int8 *)&sModulePath, &sModuleFolderPath, 0x104u);
  _mbsnbcat((unsigned __int8 *)&sModulePath, "\\HShield\\EHSvc.dll", 0x12u);
  v3 = _AhnHS_InitializeA(&sModulePath, (int)_AhnHS_Callback, 9947, (int)"B7621D704ED72C489EE54605", 46808511, 1);
  if ( v3 )
  {
    v5 = v3;
    pExceptionObject = CSecurityInitFailed::`vftable';
    _CxxThrowException(&pExceptionObject, &_TI2_AVCSecurityInitFailed__);
  }
  TSecType<int>::SetData(&v1->m_bInitModule, 1);
}
void __thiscall CSecurityClient::ClearModule(CSecurityClient *this)
{
  TSecType<int> *v1; // esi
  signed int v2; // eax
  int (__stdcall **pExceptionObject)(ZXString<char> *); // [esp+4h] [ebp-8h]
  int v4; // [esp+8h] [ebp-4h]

  v1 = &this->m_bInitModule;
  if ( TSecType<int>::GetData(&this->m_bInitModule) )
  {
    v2 = _AhnHS_Uninitialize();
    if ( v2 )
    {
      v4 = v2;
      pExceptionObject = CSecurityClearFailed::`vftable';
      _CxxThrowException(&pExceptionObject, &_TI2_AVCSecurityClearFailed__);
    }
    TSecType<int>::SetData(v1, 0);
  }
}
void __thiscall CSecurityClient::StartModule(CSecurityClient *this)
{
  CSecurityClient *v1; // esi
  signed int v2; // eax
  int (__stdcall **v3)(ZXString<char> *); // [esp+0h] [ebp-Ch]
  int v4; // [esp+4h] [ebp-8h]

  v1 = this;
  v2 = _AhnHS_StartService();
  if ( v2 )
  {
    v4 = v2;
    v3 = CSecurityInitFailed::`vftable';
    _CxxThrowException(&v3, &_TI2_AVCSecurityInitFailed__);
  }
  _AhnHS_CheckHackShieldRunningStatus();
  v1->m_dwCallbackTime = GetTickCount();
  TSecType<int>::SetData(&v1->m_bStartModule, 1);
}
void __thiscall CSecurityClient::StopModule(CSecurityClient *this)
{
  TSecType<int> *v1; // esi
  signed int v2; // eax
  int (__stdcall **pExceptionObject)(ZXString<char> *); // [esp+4h] [ebp-8h]
  int v4; // [esp+8h] [ebp-4h]

  v1 = &this->m_bStartModule;
  if ( TSecType<int>::GetData(&this->m_bStartModule) )
  {
    v2 = _AhnHS_StopService();
    if ( v2 )
    {
      v4 = v2;
      pExceptionObject = CSecurityClearFailed::`vftable';
      _CxxThrowException(&pExceptionObject, &_TI2_AVCSecurityClearFailed__);
    }
    TSecType<int>::SetData(v1, 0);
  }
}

//Just throws an exception if HS error code is set
//Checks CSecurityClient->m_nThreatCode is a bad HS return code and throw ( result > 0x10501 )
signed int __thiscall CSecurityClient__Update(_DWORD *this)
{
  signed int result; // eax
  bool v2; // zf
  bool v3; // sf
  unsigned __int8 v4; // of
  int (__stdcall **v5)(int); // [esp+0h] [ebp-8h]
  int v6; // [esp+4h] [ebp-4h]

  result = this[7];
  if ( result > 0x10501 )
  {
    if ( result > 0x10801 )
    {
      if ( result != 0x10A01 )
        return result;
LABEL_18:
      v6 = this[7];
      v5 = &off_BF643C;
      sub_A68B61((int)&v5, &_TI2_AVCSecurityThreatDetected__);
      JUMPOUT(*(_DWORD *)algn_A52B42);
    }
    if ( result == 0x10801 || result == 67073 )
      goto LABEL_18;
    if ( result <= 0x10700 )
      return result;
    v4 = __OFSUB__(result, 67333);
    v2 = result == 67333;
    v3 = result - 67333 < 0;
LABEL_10:
    if ( !((unsigned __int8)(v3 ^ v4) | v2) )
      return result;
    goto LABEL_18;
  }
  if ( result == 0x10501 )
    goto LABEL_18;
  if ( result > 0x10303 )
  {
    if ( result < 0x10306 )
      return result;
    v4 = __OFSUB__(result, 66312);
    v2 = result == 66312;
    v3 = result - 66312 < 0;
    goto LABEL_10;
  }
  if ( result >= 0x10301 || result == 0x10102 || result == 0x10104 )
    goto LABEL_18;
  return result;
}

Other Weird Checks

  • Game checks ws2_32.dll dos header magic to see if its been tampered
  • Game removes loopback adapters ( TODO: Add the winapi call name here )
  • GetIpAddrTable GetAdaptersInfo calls used to check adapter stuff ?
  • Client checks for the HackShield mutex meteora
  • Client checks to see if ehsvc.dll is loaded
  • Client literally does an IAT count on the ehsvc.dll to see if its been tampered. I just loaded original
  • Client checks WvsClientMutex mutex for multi client

IP Checks

  • Game is fucking booby trapped with IP checks
  • It's not worth me pointing out where ( will eventually )
  • But basically getpeername is called, just return the expected IP 63.251.217.1
  • Sad thing is they have heavy API checks on winsock so use the WSP variants like I do
  • TODO: Talk more about the MyGetProcAddress and heavy winapi checks ( xxxx.nst )

CWvsApp Checks

  • CSecurityClient::Update is called in CWvsApp::Run
  • CWvsApp->m_tLastServerIPCheck is in CWvsApp::CallUpdate
  • CWvsApp->m_tLastServerIPCheck2 is in CWvsApp::Run | Also contains CSecurityClient check below
  • CWvsApp->m_tLastSecurityCheck is in CWvsApp::Run

CWvsApp->m_tLastSecurityCheck

Everyday I pray and ask god what this done but I am unsure. All i know is i have to spoof it so client doesn't crash.

CSecurityClient Check

Thisis inside m_tLastServerIPCheck2 Checks if some files in the HShield folder exist 3N.mhe, v3warpds.v3d, v3warpns.v3d Checks _AhnHS_StartSerice ret and expects HS_ERR_ALREADY_SERVICE_RUNNING ( 0x00000201 ) Checks CSecurityClient->m_dwCallbackTime is <= 60000

    if ( TSingleton_CSecurityClient__IsInstantiated() )
    {
      v22 = '\x01';
      v15 = '3';
      v16 = 'N';
      v17 = '.';
      v18 = 'm';
      v19 = 'h';
      v20 = 'e';
      v21 = '\0';
      v25 = 'v';
      v26 = '3';
      v27 = 'w';
      v28 = 'a';
      v29 = 'r';
      v30 = 'p'
View on GitHub
GitHub Stars17
CategoryEducation
Updated8mo ago
Forks16

Security Score

67/100

Audited on Jul 30, 2025

No findings