Home

Published

- 14 min read

Anti-Cheat ไม่ใช่แค่ตรวจ Cheat — บทเรียนจาก HerculesAC

img of Anti-Cheat ไม่ใช่แค่ตรวจ Cheat — บทเรียนจาก HerculesAC

บทนำ

เมื่อพูดถึง Anti-Cheat หลายคนมักนึกถึงโปรแกรมที่เปิดพร้อมเกม แล้วคอยค้นหาชื่ออย่าง Cheat Engine, debugger หรือโปรแกรมสำหรับแก้ไข memory

ภาพจำนี้ไม่ผิด แต่เป็นเพียงส่วนเล็กที่สุดของปัญหา

Anti-Cheat ที่ดีไม่ได้ตอบเพียงคำถามว่า

ตอนนี้มีโปรแกรมโกงเปิดอยู่หรือไม่?

แต่มันต้องตอบคำถามที่ยากกว่า เช่น

  • Process ของเกมยังเป็น process ที่เราเริ่มต้นขึ้นมาจริงหรือไม่
  • Code และ data ภายใน process ถูกแก้ไขไปแล้วหรือยัง
  • Thread ใหม่เกิดจาก execution path ปกติหรือถูกสร้างขึ้นจากภายนอก
  • Process อื่นกำลังขอ handle ที่มีสิทธิ์อ่านหรือเขียน memory ของเกมหรือไม่
  • Sensor ที่ใช้ตรวจสอบระบบยังทำงานอยู่ หรือถูก hook และทำให้รายงานข้อมูลปลอมแล้ว
  • Signal ที่ตรวจพบเป็นพฤติกรรมโกงจริง หรือเป็นเพียง debugger, overlay, accessibility tool หรือ software ที่ทำงานถูกต้อง
  • เมื่อเครื่อง client ไม่สามารถเชื่อถือได้ทั้งหมด เราควรย้าย validation ส่วนใดไปไว้ที่ game server

ดังนั้น Anti-Cheat จึงไม่ใช่เพียง scanner แต่เป็นงานด้าน trust engineering

การสร้าง Anti-Cheat คือการออกแบบว่าเราจะเชื่อข้อมูลจากส่วนใดของระบบ เชื่อได้มากเพียงใด และต้องตรวจสอบข้อมูลนั้นซ้ำจากชั้นไหน

บทความนี้จะอธิบายแนวคิดดังกล่าวผ่าน HerculesAC ซึ่งเป็น Anti-Cheat research prototype ที่ผมเคยพัฒนา โดยจะถอด architecture จาก source code จริง ตั้งแต่ launcher, controller, process monitor, injected protection DLL, shared memory และ Windows kernel callbacks

บทความนี้เขียนในมุม defensive engineering และ software architecture ไม่ใช่คู่มือสำหรับหลบหรือโจมตีระบบ Anti-Cheat


1. Anti-Cheat กำลังปกป้องอะไร

ก่อนสร้างระบบตรวจจับ เราต้องระบุให้ได้ก่อนว่าสิ่งใดคือ asset ที่ต้องปกป้อง

สำหรับเกมบน Windows สิ่งที่มีค่ามักไม่ได้มีเพียง executable file แต่รวมถึง

  1. Game process — process ที่กำลัง execute game logic
  2. Process memory — state ของผู้เล่น, entity, coordinate, health และข้อมูล runtime
  3. Execution flow — thread, callback และ control flow ภายใน process
  4. Loaded modules — DLL และ executable code ที่ถูกโหลดเข้ามา
  5. Input path — เส้นทางจาก input device ไปถึง game logic
  6. Network protocol — packet และ state ที่แลกเปลี่ยนกับ server
  7. Game economy — ranking, item, currency และผลการแข่งขัน
  8. Trust relationship — ความสัมพันธ์ระหว่าง launcher, game, Anti-Cheat และ backend

การแก้ไขเกมจึงไม่ได้มีรูปแบบเดียว

   File Modification

      ├── Patch executable on disk
      ├── Replace DLL
      └── Modify configuration

Runtime Modification

      ├── Read process memory
      ├── Write process memory
      ├── Create or hijack thread
      ├── Load additional module
      └── Change execution flow

External Automation

      ├── Input automation
      ├── Screen analysis
      └── External hardware

Protocol and Logic Abuse

      ├── Invalid client state
      ├── Packet manipulation
      └── Server-side logic abuse

ไม่มี sensor ตัวเดียวที่ตรวจจับทุกประเภทได้

Anti-Cheat จึงต้องเป็นระบบหลายชั้นที่รวม signal จากหลายแหล่งเข้าด้วยกัน


2. ทำไมการสร้าง Anti-Cheat จึงเป็นงานโชว์ความรู้ด้านระบบ

Anti-Cheat หนึ่งระบบแตะองค์ความรู้หลายแขนงพร้อมกัน

ความสามารถความรู้ที่เกี่ยวข้อง
เปิดเกมผ่าน launcherProcess creation, token, command line, environment
ตรวจ process รอบข้างToolhelp, Native API, process security
ตรวจ window และ debuggerWindow manager, desktop, session, user-mode telemetry
ตรวจ module และ resourcePE format, resource directory, version information
ตรวจ code hookAssembly, instruction boundary, integrity checking
เฝ้าการสร้าง threadThread lifecycle, loader, execution provenance
ตรวจ memory accessProcess handles, access mask, virtual memory
Inject protection componentDLL lifecycle, loader lock, architecture boundary
สื่อสารข้าม processIPC, shared memory, synchronization, authentication
ป้องกัน process ด้วย driverObject Manager, callbacks, kernel synchronization
รองรับ x86 และ x64WOW64, ABI, pointer size, hook compatibility
ลด false positiveTelemetry, statistics, risk scoring, product design
ทำงานโดยไม่ทำเกมพังPerformance, race condition, deadlock, crash recovery

ด้วยเหตุนี้ การสร้าง Anti-Cheat จึงไม่ได้แสดงเพียงว่าเรารู้จัก API สำหรับค้นหา Cheat Engine

มันแสดงว่าเราสามารถนำความรู้ด้าน Windows Internals, reverse engineering, kernel development, concurrency และ security architecture มาประกอบเป็นระบบเดียวได้หรือไม่

Anti-Cheat เป็นหนึ่งใน portfolio ที่โหดที่สุดของ Windows system programmer เพราะคู่ต่อสู้ของมันไม่ได้เป็นเพียง bug แต่เป็นโปรแกรมอีกชุดหนึ่งที่พยายามศึกษาการทำงานและเปลี่ยนผลลัพธ์ของมันโดยตั้งใจ


3. HerculesAC คืออะไร

HerculesAC เป็น Anti-Cheat prototype ที่ถูกออกแบบให้มี component หลายตัว แทนที่จะรวมทุกอย่างไว้ใน executable เดียว

จาก source code สามารถแบ่งระบบออกได้เป็นส่วนหลักดังนี้

Componentหน้าที่หลัก
GameLauncherEntry point สำหรับเปิด HerculesAC
HerculesACController, launcher orchestration และ detection หลัก
GameMonเฝ้าสถานะ game client และติดตั้ง message hook
GameProtectProtection DLL และ in-process memory sensor
herculeskernelKernel callbacks สำหรับจำกัด process/thread handle rights
CommonIPC, hashing, filesystem, logging และ hooking utilities
BypassAdversarial test component สำหรับทดสอบสมมติฐานของระบบ
ExampleDLLDLL ตัวอย่างสำหรับการทดลอง

Architecture โดยสรุปเป็นดังนี้

   ┌──────────────────────────────────────────────────────────┐
│                     GameLauncher                         │
│                starts HerculesAC.aes                     │
└──────────────────────────┬───────────────────────────────┘


┌──────────────────────────────────────────────────────────┐
│                    HerculesAC                            │
│  - validates configuration                              │
│  - launches game                                        │
│  - starts GameMon x86/x64                               │
│  - scans processes, windows and file metadata           │
│  - checks selected code integrity                       │
└───────────────┬───────────────────────┬──────────────────┘
                │                       │
                │                       ▼
                │            ┌──────────────────────┐
                │            │   herculeskernel     │
                │            │ Object callbacks     │
                │            │ Handle mediation     │
                │            └──────────────────────┘

┌──────────────────────────────────────────────────────────┐
│                     GameMon                              │
│  - tracks game PID and path                             │
│  - loads matching GameProtect DLL                       │
│  - installs WH_GETMESSAGE hook                          │
│  - keeps monitor alive while game runs                  │
└──────────────────────────┬───────────────────────────────┘


┌──────────────────────────────────────────────────────────┐
│                    GameProtect                           │
│  - receives target information through shared memory    │
│  - observes ReadProcessMemory / WriteProcessMemory       │
│  - supports hash-based whitelist                         │
└──────────────────────────────────────────────────────────┘

สิ่งที่น่าสนใจคือ HerculesAC ใช้ทั้ง orchestration, observation, integrity checking, behavioral detection และ kernel access mediation ภายในโปรเจกต์เดียว


4. GameLauncher — จุดเริ่มต้นของ Trust Chain

GameLauncher/WinMain.cpp มีหน้าที่ค่อนข้างเล็ก แต่มีความสำคัญทาง architecture

มันค้นหา directory ของตัวเอง แล้วเปิด HerculesAC.aes พร้อมส่ง path ไปให้

   void InitHercules()
{
    std::wstring wsProcPath = FileSystem::GetModuleDirectory(NULL);

    if (!wsProcPath.empty())
    {
        StartProcess(
            wsProcPath,
            L"HerculesAC\\HerculesAC.aes",
            L" " + wsProcPath
        );
    }
}

แนวคิดของ launcher คือทำให้เกมไม่ได้ถูกเปิดอย่างโดดเดี่ยว แต่เริ่มต้นผ่าน chain ที่ระบบ Anti-Cheat ควบคุม

   User


GameLauncher


HerculesAC Controller

  ├── Validate files and configuration
  ├── Start protection threads
  ├── Start game
  └── Start monitors

การเริ่มเกมจาก controller ทำให้ระบบทราบข้อมูลสำคัญตั้งแต่ต้น เช่น

  • path ที่คาดหวังของเกม
  • process ID ที่ถูกสร้างขึ้น
  • process handle จาก CreateProcess
  • เวลาที่ game process เริ่มทำงาน
  • monitor ที่ควรเริ่มพร้อมกัน

นี่คือการสร้าง chain of custody สำหรับ process

อย่างไรก็ตาม process ที่ถูกเปิดโดย launcher ไม่ได้แปลว่าจะเชื่อถือได้ตลอดอายุของมัน เพราะหลังจากนั้น memory, thread และ module ภายใน process ยังสามารถเปลี่ยนแปลงได้

Launcher จึงเป็นเพียงจุดเริ่มต้นของ trust chain ไม่ใช่จุดจบ


5. HerculesAC Controller — Orchestrator และ User-Mode Detector

HerculesAC/WinMain.cpp คือ controller หลักของระบบ

เมื่อเริ่มทำงาน มันจะ

  1. โหลด configuration จาก hac.dat
  2. ตรวจว่าไฟล์ที่จำเป็นอยู่ครบ
  3. ติดตั้ง user-mode hooks
  4. สร้าง integrity baseline
  5. เปิด detection threads
  6. เริ่ม game process
  7. เปิด GameMon ทั้งรุ่น x86 และ x64
  8. ตรวจ process และ window ที่น่าสงสัยเป็นระยะ

ส่วนที่เปิด game และ monitor มีรูปแบบดังนี้

   pi = StartProcess(Global::GamePath, config[L"starter"], L"");

root["GamePath"] = Common::wideStringToString(Global::GamePath);
root["pid"] = (UInt)pi.dwProcessId;
root["hProcess"] = (UInt)pi.hProcess;

StartProcess(filename, config[L"GameMon"], jsonCommandLine);
StartProcess(filename, config[L"GameMon64"], jsonCommandLine);

การเปิด monitor สอง architecture ไม่ใช่รายละเอียดเล็กน้อย

Windows แบ่งโลกของ user-mode hook และ DLL ตาม bitness ตัว DLL 32-bit ไม่สามารถทำหน้าที่แทน DLL 64-bit ได้ทุกกรณี และในทางกลับกัน เอกสารของ Microsoft สำหรับ SetWindowsHookEx ก็อธิบายข้อจำกัดระหว่าง 32-bit และ 64-bit hook ไว้โดยตรง

ดังนั้น HerculesAC จึงมี

   GameMon x86  ──> GameProtect.dll
GameMon x64  ──> GameProtect64.dll

นี่เป็นตัวอย่างที่ดีว่า Anti-Cheat ไม่ได้ต้องเข้าใจเพียง game logic แต่ต้องเข้าใจ architecture boundary ของ Windows ด้วย


6. Configuration และ File Manifest

HerculesAC ใช้ไฟล์ hac.dat เป็น configuration และ manifest อย่างง่าย

Build script จะสร้าง section ประมาณนี้

   [Game]
starter=cstrike.exe
Client=cstrike.exe
GameMon=GameMon.aes
GameMon64=GameMon64.aes

[MD5]
hash0=...
hash1=...
Count=...

Controller จะตรวจว่า executable ที่กำหนดไว้มีอยู่จริงใน directory ของเกมและ directory ของ Anti-Cheat

ขณะที่ GameProtect จะอ่านรายการ MD5 เพื่อสร้าง whitelist สำหรับ process ที่ควรข้ามการติดตั้ง hook บางส่วน

แนวคิดนี้ประกอบด้วยสองเรื่อง

  1. Expected layout — ระบบคาดหวังว่ามีไฟล์ใดอยู่ตรงไหน
  2. Expected identity — ระบบคาดหวังว่าไฟล์หนึ่งควรมี hash ใด

นี่เป็นรูปแบบพื้นฐานของ integrity manifest

อย่างไรก็ตาม MD5 ไม่เหมาะกับการใช้เป็น security boundary ในระบบใหม่ เนื่องจากมีปัญหา collision และ Microsoft แนะนำให้ใช้ SHA-256 หรือ SHA-512 สำหรับงานใหม่

สิ่งสำคัญยิ่งกว่าการเปลี่ยน hash คือ manifest ควรถูก authenticate ด้วย

   Plain Hash List
    └── ผู้ที่แก้ไฟล์ได้ อาจแก้รายการ hash ได้ด้วย

Signed Manifest
    ├── File hash
    ├── Version
    ├── Build identifier
    ├── Public-key signature
    └── Verification policy

Hash บอกได้ว่าไฟล์สองชุดเหมือนกันหรือไม่ แต่ digital signature ช่วยตอบว่า manifest หรือ binary นั้นมาจากผู้สร้างที่เชื่อถือได้หรือไม่


7. Signature Detection — ชื่อ Process และ Window

HerculesAC มีรายการชื่อ process และข้อมูล window ที่ถือว่าน่าสงสัย เช่น debugger หรือเครื่องมือวิเคราะห์ memory บางชนิด

Controller ใช้สองมุมมองหลัก

   Process Enumeration
    └── IsProcessRunning(name)

Window Enumeration
    ├── Window class
    └── Window title

วิธีนี้มีข้อดีคือ

  • implementation ไม่ซับซ้อน
  • ตอบสนองได้รวดเร็ว
  • ตรวจเครื่องมือทั่วไปได้ดีในช่วงเริ่มต้น
  • เหมาะกับ prototype และการทดสอบ flow

แต่ข้อจำกัดก็ชัดเจน

  • filename เปลี่ยนได้
  • window title และ class name เปลี่ยนได้
  • software ถูกต้องบางตัวอาจมีชื่อใกล้เคียง
  • ไม่สามารถพิสูจน์พฤติกรรมที่เกิดขึ้นจริงได้
  • การพบ debugger ไม่ได้แปลว่ามีการโกงเสมอไป

ดังนั้น signature แบบชื่อควรถูกใช้เป็น signal ไม่ใช่ verdict สุดท้าย

   Weak Design
    One name match
        └── Ban or kill immediately

Stronger Design
    Name signal
      + Access behavior
      + Module evidence
      + Integrity anomaly
      + Server-side anomaly
        └── Risk score and response policy

Anti-Cheat production system ต้องแยกคำว่า พบเครื่องมือที่มีความเสี่ยง ออกจากคำว่า พิสูจน์ว่าผู้เล่นโกง


8. Resource และ Version Metadata Fingerprinting

จุดหนึ่งที่น่าสนใจใน HerculesAC/Threads/ActiveThread.cpp คือระบบไม่ได้ตรวจเพียง filename

มันเปิด executable ของ process อื่นด้วย LoadLibraryEx(..., LOAD_LIBRARY_AS_DATAFILE) แล้วตรวจ resource เช่น

  • icon
  • bitmap
  • version information
  • company name
  • file description
  • internal name
  • original filename
  • product name

จากนั้นจึงคำนวณ hash แล้วเปรียบเทียบกับ signature ที่เก็บไว้

แนวคิดนี้พยายามแก้ปัญหาว่า

ถ้าเปลี่ยนชื่อ executable แล้ว เรายังระบุตัวตนจาก artifact ภายในไฟล์ได้หรือไม่?

   Executable Identity

    ├── File name                 weak
    ├── Window title              weak
    ├── Icon / bitmap resource    stronger fingerprint
    ├── Version metadata          stronger fingerprint
    ├── Code section hash         build-specific
    └── Authenticode signer       publisher identity

Resource fingerprinting เป็นการเพิ่มมุมมองที่ดีสำหรับ research prototype เพราะทำให้เห็นว่า identity ของโปรแกรมไม่ได้มีเพียงชื่อไฟล์

แต่ signature แบบ static ยังมีข้อจำกัด

  • เปลี่ยนเมื่อโปรแกรมอัปเดต
  • เกิด false positive ได้ถ้าใช้ resource ร่วมกัน
  • ถูกตัด resource ออกได้
  • ต้องดูแลฐานข้อมูล signature ตลอดเวลา

ระบบสมัยใหม่จึงมักรวม static fingerprint กับ behavioral telemetry และ signer information แทนการพึ่งค่าใดค่าหนึ่ง


9. Self-Integrity — เมื่อ Sensor เองก็อาจถูกแก้ไข

Anti-Cheat ไม่สามารถตรวจสอบผู้อื่นได้อย่างน่าเชื่อถือ หาก code ที่ใช้ตรวจสอบถูกแก้ไขไปแล้ว

HerculesAC จึงสร้าง checksum baseline ให้ function สำคัญบางตัว ได้แก่

  • FindWindowW
  • BaseThreadInitThunk
  • CreateThread

ตัวอย่างแนวคิดจาก code คือ

   CheckSum::FindWindowW_CheckSum = CRC32((BYTE*)FindWindowW, 5);
CheckSum::BaseThreadInitThunk_CheckSum =
    CRC32((BYTE*)Original_BaseThreadInitThunk, 5);
CheckSum::CreateThread_CheckSum = CRC32((BYTE*)CreateThread, 5);

จากนั้น background thread จะคำนวณใหม่เป็นระยะ หากค่าเปลี่ยนก็ถือว่า selected function ถูกแก้ไข

นี่คือแนวคิด sensor integrity

   Detector

   ├── observes the game
   └── observes itself

อย่างไรก็ตาม การตรวจเพียงห้า byte แรกเป็น baseline แบบ prototype เพราะ

  • hook ไม่จำเป็นต้องแก้ byte แรกเสมอไป
  • code อาจถูกเปลี่ยนที่ call site หรือ pointer อื่น
  • checksum function เองอาจถูกแทรกแซง
  • baseline อาจถูกสร้างหลังจาก code ถูกแก้ไขไปแล้ว
  • legit hotpatch หรือ compatibility layer อาจทำให้ค่าเปลี่ยน

บทเรียนที่สำคัญไม่ใช่ว่าต้องเพิ่มจาก 5 byte เป็นจำนวนใด แต่คือ integrity checking ต้องพิจารณาทั้ง สิ่งที่วัด, เวลาที่สร้าง baseline และ ผู้ที่มีสิทธิ์แก้ตัววัด


10. Thread Provenance — Thread นี้มาจากไหน

อีกแนวคิดหนึ่งใน HerculesAC คือการติดตามที่มาของ thread

Controller hook CreateThread เพื่อบันทึก start address ที่ถูกสร้างผ่านเส้นทางที่รู้จัก แล้วตรวจที่ BaseThreadInitThunk ว่า thread ที่กำลังเริ่มทำงานมี start address อยู่ในรายการหรือไม่

   CreateThread called by expected code


Record start address


BaseThreadInitThunk

          ├── Known start address   → allow
          └── Unknown start address → suspicious

ใน source ยังมี logic ที่มอง start routine ซึ่งชี้ตรงไปยัง LoadLibraryA หรือ LoadLibraryW ว่าน่าสงสัย

นี่เป็นตัวอย่างของ execution provenance

แทนที่จะถามเพียงว่า “มี thread อยู่หรือไม่” ระบบถามว่า

  • ใครเป็นผู้สร้าง thread
  • start address อยู่ใน module ใด
  • memory page นั้นเป็น image-backed หรือ private memory
  • page protection เป็นแบบใด
  • start address ตรงกับ known code path หรือไม่
  • call stack และ creation event สอดคล้องกันหรือไม่

Prototype ของ HerculesAC เริ่มจาก allow-list ของ start address แต่แนวคิดสามารถพัฒนาไปสู่ thread telemetry ที่มีบริบทมากขึ้นได้

ข้อควรระวังคือ application จริงอาจสร้าง thread ผ่าน API หรือ runtime หลายชนิด เช่น thread pool, C runtime, COM, graphics driver หรือ middleware การตั้ง policy แบบ “ไม่รู้จักเท่ากับผิด” จึงอาจสร้าง false positive สูง


11. GameMon — แยก Monitoring ออกจาก Controller

GameMon รับข้อมูลจาก command line ในรูปแบบ JSON ซึ่งประกอบด้วย

  • game path
  • process ID
  • process handle

จากนั้นมันจะ

  1. โหลด GameProtect.dll หรือ GameProtect64.dll ตาม architecture
  2. ขอ function pointer ที่ DLL export ไว้
  3. เขียนข้อมูล game client ลง shared memory
  4. ติดตั้ง message hook
  5. ตรวจว่า game client ยังทำงานอยู่หรือไม่
  6. ถอน hook เมื่อ game ปิด

การแยก GameMon ออกจาก controller มีข้อดีหลายด้าน

   HerculesAC Controller
    └── policy, orchestration, detection

GameMon
    └── lifecycle and hook deployment

GameProtect
    └── process-local observation

หากทุกอย่างอยู่ใน process เดียว failure หนึ่งจุดอาจทำให้ทั้งระบบหยุดพร้อมกัน การแยก component ทำให้สามารถกำหนด responsibility และ recovery policy ได้ชัดขึ้น

แต่จำนวน process ที่มากขึ้นก็เพิ่มสิ่งที่ต้องออกแบบ

  • process authentication
  • lifecycle dependency
  • watchdog policy
  • IPC security
  • version compatibility
  • shutdown order
  • update consistency

Anti-Cheat แบบหลาย process จึงเป็น distributed system ขนาดเล็กที่ทำงานอยู่บนเครื่องเดียว


12. WH_GETMESSAGE Hook และการวาง GameProtect

GameMon โหลด protection DLL แล้วเรียก SetupMsgHook

ภายใน GameProtect/Hook/MsgHook/MsgHook.cpp ใช้

   SetWindowsHookEx(
    WH_GETMESSAGE,
    GetMsgProc,
    hinstDLL,
    0
);

WH_GETMESSAGE hook ใช้เฝ้าข้อความที่กำลังถูกนำออกจาก message queue ผ่าน GetMessage หรือ PeekMessage

ใน architecture ของ HerculesAC กลไกนี้ถูกใช้เพื่อทำให้ GameProtect เข้าไปทำงานใน process ที่เข้ากันได้กับ hook

นี่อธิบายว่าทำไมโปรเจกต์ต้องมีทั้ง monitor และ protection DLL แบบ 32-bit และ 64-bit

อย่างไรก็ตาม global hook เป็นกลไกที่มี blast radius กว้าง

  • DLL อาจถูกโหลดใน process มากกว่าที่ต้องการ
  • compatibility แตกต่างกันในแต่ละ application
  • bug ใน DLL สามารถทำให้ process อื่นมีปัญหา
  • session และ desktop boundary มีผลต่อ behavior
  • ต้องจัดการ architecture ให้ตรงกัน

สำหรับระบบ production การนำ sensor เข้า process จึงควรมี target policy ที่แคบที่สุด และต้องออกแบบ failure containment อย่างจริงจัง


13. Named Shared Memory — การส่ง Target Context

GameProtect จำเป็นต้องรู้ว่า process ใดคือ game client ที่ต้องเฝ้าระวัง

HerculesAC ใช้ named shared memory โดยสร้าง file mapping ชื่อ

   hacSharedMemory
hacSharedMemory64

ข้อมูลหลักที่แลกเปลี่ยนมีลักษณะดังนี้

   typedef struct _GAME_CLIENT {
    DWORD dwPid;
    TCHAR szClient[100];
    TCHAR szGamePath[256];
} GAME_CLIENT;

Flow คือ

   HerculesAC
    │ starts game and knows PID

GameMon
    │ writes GAME_CLIENT data

Named Shared Memory
    │ read by injected component

GameProtect

Microsoft อธิบาย named shared memory บน Windows ผ่าน CreateFileMapping และ MapViewOfFile ซึ่งทำให้หลาย process เปิด mapping object ชื่อเดียวกันแล้วแลกเปลี่ยนข้อมูลได้

HerculesAC ใช้แนวคิดนี้ได้ตรงไปตรงมาและเหมาะกับ payload ขนาดเล็ก

แต่ implementation ใน prototype มี comment ปิด synchronization ไว้ หมายความว่า production version ควรพิจารณาเพิ่ม

  • synchronization primitive
  • message version
  • sequence number
  • writer identity
  • access control list
  • integrity หรือ authentication tag
  • validation ของ length และ string termination
  • handling เมื่อ process หนึ่งตายระหว่างเขียนข้อมูล

IPC ไม่ได้เป็นเพียงท่อส่งข้อมูล แต่เป็น trust boundary ที่ attacker อาจพยายามส่งข้อมูลปลอมเข้ามาได้


14. GameProtect — Sensor ที่อยู่ใกล้ Behavior

GameProtect โหลด configuration และสร้าง shared memory จากนั้นติดตั้ง detour สำหรับ

  • ReadProcessMemory
  • WriteProcessMemory

เมื่อ process ที่มี DLL นี้เรียก API ดังกล่าว ระบบจะตรวจว่า target handle ชี้ไปยัง game process หรือไม่

14.1 WriteProcessMemory

หากพบความพยายามเขียน memory ของ game client ตัว prototype จะสั่งปิดเกม

   Process calls WriteProcessMemory


Is target PID the game?
      │          │
      No         Yes
      │          │
      ▼          ▼
   Continue   Record and respond

14.2 ReadProcessMemory

สำหรับการอ่าน memory ระบบใช้ counter ภายใน time window หากจำนวนการอ่านสูงเกิน threshold ก็ถือว่าน่าสงสัย

นี่เป็นตัวอย่างของความแตกต่างระหว่าง

  • event detection — พบ write หนึ่งครั้งแล้วตอบสนอง
  • rate-based detection — ประเมินจำนวน read ภายในช่วงเวลา

แนวคิด rate-based detection สำคัญ เพราะบาง API สามารถถูกเรียกอย่างถูกต้องโดยเครื่องมือระบบ ขณะที่การอ่านถี่ต่อเนื่องอาจสะท้อน behavior ที่ต่างออกไป

อย่างไรก็ตาม user-mode API hook มองเห็นเฉพาะ operation ที่ผ่าน function ที่ถูก hook ใน process ที่ DLL เข้าไปถึงเท่านั้น

มันไม่ควรถูกมองว่าเป็น complete mediation

User-mode hook เป็น sensor ที่มีประโยชน์ แต่ไม่ใช่แหล่งความจริงสูงสุด

นั่นคือเหตุผลที่ HerculesAC มี kernel component เพิ่มเข้ามา


15. Kernel Handle Mediation ด้วย ObRegisterCallbacks

herculeskernel ใช้ ObRegisterCallbacks เพื่อลงทะเบียน callback สำหรับ operation ที่เกี่ยวกับ process และ thread handles

Microsoft ระบุว่า API นี้ใช้ลงทะเบียน callback สำหรับ handle operation ของ process, thread และ desktop object

HerculesAC ลงทะเบียนทั้ง

   PsProcessType
    ├── Handle create
    └── Handle duplicate

PsThreadType
    ├── Handle create
    └── Handle duplicate

ใน pre-operation callback ระบบตรวจ target object แล้วตัด access rights บางส่วนออก

สำหรับ process ได้แก่

   DesiredAccess &= ~PROCESS_VM_READ;
DesiredAccess &= ~PROCESS_VM_WRITE;

สำหรับ thread ได้แก่

   DesiredAccess &= ~THREAD_SUSPEND_RESUME;

Windows กำหนดให้ PROCESS_VM_READ เป็นสิทธิ์ที่ต้องใช้กับ ReadProcessMemory และ PROCESS_VM_WRITE เป็นสิทธิ์ที่ต้องใช้กับ WriteProcessMemory

ดังนั้นแทนที่จะรอให้ API ถูกเรียกแล้วค่อยตรวจ HerculesAC พยายามลดสิทธิ์ตั้งแต่ตอนที่ handle กำลังถูกสร้างหรือ duplicate

   External Process

      │ requests handle with VM_READ / VM_WRITE

Windows Object Manager


Hercules pre-operation callback

      ├── target is not protected → keep requested rights
      └── target is protected     → remove selected rights

นี่เป็นการย้าย control point จาก API layer ลงไปยัง Object Manager

Prototype detail ที่สำคัญ

ใน source ปัจจุบัน target PID ภายใน callback ถูก hard-code ไว้เป็นค่าหนึ่ง ซึ่งแสดงว่าส่วน kernel ยังเป็น experimental prototype มากกว่า production implementation

ระบบจริงควรมี protected-object registry ที่

  • รับ PID จาก trusted controller
  • ตรวจ identity ของ caller
  • รองรับ process restart และ PID reuse
  • ลบ entry เมื่อ process exit
  • ป้องกัน race condition
  • รองรับหลาย game process
  • ไม่เปิด IOCTL ที่ให้ process ใดก็ได้เปลี่ยน policy

จุดนี้เป็นตัวอย่างที่ดีของความต่างระหว่าง พิสูจน์ว่าแนวคิดทำงานได้ กับ สร้าง security product ที่ deploy ได้จริง


16. Detection กับ Prevention ไม่ใช่สิ่งเดียวกัน

HerculesAC มีทั้งกลไก detection และ prevention

กลไกประเภท
ตรวจชื่อ processDetection
ตรวจ window class/titleDetection
Hash resource และ version metadataDetection
ตรวจ checksum ของ functionDetection
ตรวจ unknown thread startDetection/Prevention
Hook memory APIObservation/Response
ตัด process handle rightsPrevention
ตัด thread suspend rightPrevention
ปิดเกมเมื่อพบ signalResponse

การแยกสามคำนี้ออกจากกันมีความสำคัญ

   Detection
    └── เราพบ signal อะไร

Prevention
    └── เราหยุด operation ใดได้

Response
    └── เราจะทำอะไรหลังพบหรือหยุด operation

Anti-Cheat ที่ตรวจพบทุกอย่างแต่ตอบสนองไม่ดี อาจทำให้ผู้เล่นถูกเตะผิด

Anti-Cheat ที่ block ทุกอย่างอาจทำให้ overlay, streaming, accessibility หรือ support tools ใช้งานไม่ได้

Anti-Cheat ที่รีบเปิดเผย detection ทันทีอาจทำให้คู่ต่อสู้เรียนรู้ rule ได้ง่ายขึ้น

ดังนั้น response policy ต้องคำนึงถึง

  • confidence
  • severity
  • repeatability
  • player impact
  • evidence retention
  • server authority
  • appeal และ support process

17. User Mode ไม่พอ แต่ Kernel Mode ก็ไม่ใช่เวทมนตร์

การเพิ่ม kernel driver ทำให้ Anti-Cheat มีมุมมองและ control point ที่ user mode ไม่มี

แต่มันไม่ได้ทำให้ระบบ “ตรวจได้ทุกอย่าง” โดยอัตโนมัติ

User-mode strengths

  • พัฒนาและ debug ง่ายกว่า
  • update ได้เร็วกว่า
  • เข้าถึง application context ได้ดี
  • crash มักไม่ทำให้ทั้งระบบล่ม
  • เหมาะกับ UI, orchestration และ high-level telemetry

User-mode limitations

  • อยู่ใน privilege level เดียวกับโปรแกรมอื่นจำนวนมาก
  • hook และ result สามารถถูกแก้ไขได้
  • coverage ขึ้นกับ API และ process ที่ sensor เข้าถึง
  • ไม่สามารถควบคุม kernel handle operation ได้โดยตรง

Kernel-mode strengths

  • เห็น object และ handle operation ในระดับล่างกว่า
  • บังคับ process/thread access policy ได้
  • ยากกว่าสำหรับ user-mode process ที่จะเปลี่ยนผลลัพธ์โดยตรง
  • รวม telemetry จากหลาย process ได้

Kernel-mode costs

  • bug สามารถทำให้ระบบ BSOD
  • compatibility กับ Windows build และ security feature ซับซ้อน
  • driver signing และ deployment มีต้นทุน
  • vulnerable driver อาจกลายเป็นเครื่องมือให้ attacker ใช้สิทธิ์ kernel
  • privacy และ security impact สูงกว่า

Microsoft แนะนำให้ kernel driver จำกัด privileged behavior ให้อยู่ในขอบเขตที่จำเป็น ตรวจ input และไม่เปิด primitive อันตรายแบบ arbitrary ให้ user mode

ดังนั้นหลักคิดที่ถูกต้องไม่ใช่

ย้ายทุกอย่างลง kernel เพื่อให้ปลอดภัย

แต่คือ

ย้ายเฉพาะ enforcement ที่จำเป็นลง kernel และทำ interface ระหว่าง user mode กับ kernel ให้แคบ ตรวจสอบได้ และมี least privilege


18. Bypass Directory — เหตุผลที่ Defender ต้องสร้าง Attacker Model

ภายใน repository มี project ชื่อ Bypass

การมี component นี้ไม่ได้ลดคุณค่าของ Anti-Cheat แต่กลับสะท้อนวิธีคิดที่สำคัญมากในการทำ security engineering

ระบบป้องกันที่ไม่เคยถูกทดสอบจากมุมของผู้โจมตี เป็นเพียงระบบที่เราหวังว่าจะทำงาน

Bypass ทำหน้าที่เป็น adversarial test harness สำหรับตั้งคำถามกับสมมติฐาน เช่น

  • ถ้า detection API ถูก hook ผลลัพธ์จะเป็นอย่างไร
  • ถ้า integrity routine ถูกแทรกแซง ระบบยังเชื่อ checksum ได้หรือไม่
  • ถ้า function address หรือ call path เปลี่ยน detection จะยังทำงานหรือไม่
  • sensor รู้ได้อย่างไรว่าข้อมูลที่อ่านเป็นข้อมูลจริง

ในบทความนี้จะไม่ลงรายละเอียด implementation ของ bypass แต่สิ่งที่ควรเรียนรู้คือ workflow

   Build Detection


Build an Adversarial Test


Break the Assumption


Add Independent Signal


Repeat

นี่คือวัฒนธรรมเดียวกับ secure code review, red teaming และ threat modeling

Anti-Cheat ไม่ควรมีเพียงทีมที่เขียน detector แต่ต้องมีคนที่พยายามพิสูจน์ว่า detector นั้นมองไม่เห็นอะไร


19. VMProtect และการปกป้องตัว Anti-Cheat

HerculesAC ใช้ VMProtect SDK ครอบบาง code path ผ่าน VMProtectBeginVirtualization, VMProtectEnd และ RAII wrapper

เป้าหมายของ software protector คือเพิ่มต้นทุนของการวิเคราะห์ static และ dynamic

แต่ protection layer ควรถูกมองว่าเป็น cost multiplier ไม่ใช่ root of trust

   Without protection
    Analysis cost = lower

With virtualization/obfuscation
    Analysis cost = higher

But
    Client code is still delivered to an untrusted machine

หาก Anti-Cheat ใช้ secret หรือ detection logic เดียวที่ฝังอยู่ใน client ในที่สุดข้อมูลนั้นอาจถูกศึกษาได้

การออกแบบที่แข็งแรงกว่าคือ

  • ไม่พึ่ง client secret เพียงอย่างเดียว
  • ใช้ server-side authority
  • rotate rules และ manifests
  • เก็บ evidence หลายประเภท
  • ทำ protocol authentication
  • ลดข้อมูลสำคัญที่ client จำเป็นต้องรู้

Obfuscation ช่วยซื้อเวลา แต่ architecture เป็นตัวกำหนดเพดานความปลอดภัย


20. บทเรียนจาก HerculesAC ในฐานะ Prototype

HerculesAC มีคุณค่าเพราะมันทำให้แนวคิดหลายอย่างกลายเป็น code ที่ทดลองได้จริง

ขณะเดียวกัน source ก็แสดงช่องว่างระหว่าง prototype กับ production ซึ่งเป็นบทเรียนที่สำคัญไม่แพ้ feature

20.1 Static name signature เปราะบาง

ชื่อ process และ window เหมาะกับ early detection แต่ควรรวมกับ behavior และ signer identity

20.2 MD5 ควรถูกแทนที่

ควรใช้ SHA-256 หรือ SHA-512 และใช้ signed manifest เพื่อป้องกันการแก้ทั้ง binary และรายการ hash

20.3 Polling มีต้นทุนและ race window

บาง thread ตรวจทุก 100 ms ขณะที่บาง loop ตรวจทุก 5 วินาที

Polling เขียนง่าย แต่ระบบขนาดใหญ่ควรประเมิน event-driven telemetry, adaptive interval และ CPU budget

20.4 Shared memory ต้องมี authentication และ synchronization

ชื่อ mapping ที่รู้ร่วมกันไม่เพียงพอสำหรับพิสูจน์ตัวตนของ writer

20.5 Kernel policy ต้อง dynamic

Hard-coded PID ควรถูกแทนที่ด้วย protected-process registry ที่จัดการ lifecycle และ PID reuse อย่างปลอดภัย

20.6 Kill-on-first-signal มี UX risk

การปิดเกมทันทีเหมาะกับ demo แต่ production ควรมี confidence model และ response tier

   Low confidence
    └── collect more telemetry

Medium confidence
    └── restrict sensitive action / challenge / monitor

High confidence
    └── end session and retain evidence

Confirmed server-side abuse
    └── account enforcement according to policy

20.7 Global hook มี blast radius

ควรจำกัด target และออกแบบ cleanup เมื่อ monitor หรือ game crash

20.8 Kernel driver ต้องถูกออกแบบเหมือน security boundary

Driver ไม่ควรเปิด arbitrary read/write, process termination หรือ privileged primitive โดยไม่มี validation เพราะตัว driver อาจกลายเป็น vulnerability ใหม่ของระบบ


21. ถ้าจะพัฒนา HerculesAC เป็นรุ่นถัดไป

ถ้านำแนวคิดของ HerculesAC มาสร้างใหม่ในปัจจุบัน ผมจะแบ่งระบบออกเป็นชั้นดังนี้

   ┌──────────────────────────────────────────────────────┐
│                 Game Server / Backend                │
│  authoritative state, risk scoring, evidence policy │
└──────────────────────────┬───────────────────────────┘
                           │ authenticated telemetry

┌──────────────────────────────────────────────────────┐
│             Local Anti-Cheat Service                 │
│  orchestration, update, policy, component health     │
└──────────────┬──────────────────────┬────────────────┘
               │                      │
               ▼                      ▼
┌────────────────────────┐   ┌─────────────────────────┐
│ In-Process Game Sensor │   │ Signed Kernel Driver    │
│ code/module/thread     │   │ handle mediation        │
│ game-aware telemetry   │   │ constrained telemetry   │
└────────────────────────┘   └─────────────────────────┘
               │                      │
               └──────────┬───────────┘

                 Evidence Correlation

หลักการสำคัญคือ

  1. Server authoritative — สิ่งที่ server ตัดสินได้ไม่ควรเชื่อ client อย่างเดียว
  2. Multiple independent signals — detector หนึ่งตัวไม่ควรเป็น single point of truth
  3. Least privilege — แต่ละ component มีสิทธิ์เท่าที่จำเป็น
  4. Authenticated IPC — message ต้องระบุผู้ส่งและตรวจความถูกต้องได้
  5. Signed update chain — binary, config และ manifest ต้องตรวจที่มาได้
  6. Event-driven telemetry — ลด polling ที่ไม่จำเป็น
  7. Risk scoring — แยก anomaly ออกจาก confirmed cheating
  8. Evidence-first response — เก็บข้อมูลพอสำหรับ debugging และ appeal
  9. Privacy-aware collection — เก็บเฉพาะข้อมูลที่สัมพันธ์กับการป้องกันเกม
  10. Fail safely — Anti-Cheat ขัดข้องไม่ควรทำให้ระบบปฏิบัติการเสียหาย

22. Anti-Cheat คือระบบตรวจสอบความเชื่อใจ ไม่ใช่โปรแกรมล่ารายชื่อ

สิ่งที่ผมได้เรียนรู้จาก HerculesAC คือการตรวจชื่อโปรแกรมเป็นส่วนที่เขียนง่ายที่สุด

ส่วนที่ยากจริงคือ

  • เชื่อม lifecycle ของ launcher, game และ monitor
  • ส่ง context ให้ sensor หลาย architecture
  • ตรวจว่า sensor ถูกแก้ไขหรือไม่
  • แยก thread ปกติออกจาก execution ที่ไม่คาดคิด
  • ควบคุม process handle ใน kernel
  • ทำให้ policy ไม่รบกวน software ปกติ
  • รักษา performance ของเกม
  • ป้องกันไม่ให้ driver กลายเป็นช่องโหว่
  • สร้าง evidence ที่อธิบายได้ว่าทำไมจึงตอบสนอง

Anti-Cheat จึงอยู่กึ่งกลางระหว่างหลายสาขา

   Windows Internals
       +
Reverse Engineering
       +
Kernel Development
       +
Application Security
       +
Distributed Systems
       +
Telemetry Engineering
       +
Game Design
       +
Adversarial Thinking
       =
Anti-Cheat Engineering

23. HerculesAC ในฐานะ Portfolio

HerculesAC อาจไม่ใช่ commercial Anti-Cheat และ source บางส่วนยังมีลักษณะเป็น experiment

แต่นั่นไม่ได้ทำให้มันไม่มีคุณค่า

ตรงกันข้าม มันเป็นหลักฐานของกระบวนการเรียนรู้ที่ครอบคลุมหลายชั้น

ส่วนของ HerculesACสิ่งที่แสดงออกมา
Launcher chainProcess orchestration และ application lifecycle
x86/x64 monitorความเข้าใจ Windows architecture boundary
Shared memoryIPC และ cross-process state sharing
DLL sensorLoader, hooks และ process-local observation
Resource fingerprintingPE resources และ executable identity
Code checksumSelf-integrity และ tamper detection
Thread trackingExecution provenance และ runtime behavior
Kernel callbacksObject Manager และ handle access control
Bypass test projectAdversarial validation และ threat modeling
Build/config scriptsPackaging, manifest และ deployment flow

การสร้างระบบประเภทนี้คือการบอกว่า

“ผมไม่ได้เพียงรู้ว่า cheat ทำอะไร แต่ผมสามารถสร้างระบบหลาย component เพื่อสังเกต ควบคุม และทดสอบ trust boundary ของ Windows ได้”

นี่คือเหตุผลที่ Anti-Cheat สามารถเป็น portfolio ของ Windows system programmer ได้ในแบบเดียวกับที่ ARK Tool แสดงความรู้ด้าน kernel inspection

ความแตกต่างคือ ARK ถามว่า

ระบบกำลังซ่อนอะไรจากเรา?

ขณะที่ Anti-Cheat ถามว่า

เราจะรู้ได้อย่างไรว่าสถานะของเกมและ execution path ยังไม่ได้ถูกเปลี่ยนโดยบุคคลอื่น?

ทั้งสองงานเริ่มจากหลักคิดเดียวกัน

อย่าเชื่อข้อมูลจากมุมมองเดียว โดยเฉพาะเมื่อผู้ที่ถูกตรวจสอบสามารถแก้ไขมุมมองนั้นได้


24. สรุปท้ายบท

HerculesAC แสดงให้เห็นว่า Anti-Cheat ไม่ได้ประกอบด้วย detector เพียงหนึ่งตัว แต่เป็นระบบที่มีหลาย responsibility

  1. GameLauncher สร้างจุดเริ่มต้นของ trust chain
  2. HerculesAC ทำหน้าที่ orchestrate game และตรวจ signal ใน user mode
  3. GameMon จัดการ lifecycle และ architecture-specific deployment
  4. GameProtect วาง sensor ใกล้ memory-access behavior
  5. Named shared memory ส่ง target context ระหว่าง component
  6. Resource และ metadata hashing เพิ่มมุมมองมากกว่าการตรวจชื่อไฟล์
  7. Code checksum ทำให้ detector เริ่มตรวจสอบตัวเอง
  8. Thread tracking พยายามอธิบาย provenance ของ execution
  9. herculeskernel ย้าย enforcement ลงไปยัง process/thread handle layer
  10. Bypass สะท้อนว่าระบบป้องกันต้องถูกทดสอบจากมุมของฝ่ายตรงข้าม

สิ่งสำคัญที่สุดไม่ใช่ว่า HerculesAC ตรวจพบเครื่องมือได้กี่ตัว

แต่คือการที่โปรเจกต์นี้ทำให้ผมเห็นว่า Anti-Cheat เป็นปัญหาของ trust boundary, visibility และ evidence

Client machine ไม่เคยเป็นสภาพแวดล้อมที่เราเชื่อถือได้ทั้งหมด

User-mode sensor สามารถถูกแก้ไข

Kernel driver สามารถมีช่องโหว่

Static signature สามารถล้าสมัย

Behavioral rule สามารถสร้าง false positive

และ game server ก็ไม่สามารถมองเห็นทุกสิ่งที่เกิดขึ้นในเครื่องผู้เล่น

ดังนั้น Anti-Cheat ที่แข็งแรงไม่ได้เกิดจากการค้นหา “Ring ที่ลึกที่สุด” หรือ API ที่ตรวจได้มากที่สุด

มันเกิดจากการนำหลายมุมมองมาประกอบกัน แล้วออกแบบให้ความล้มเหลวของ sensor หนึ่งตัวไม่ทำให้ทั้งระบบสูญเสียความจริงทั้งหมด

Anti-Cheat ไม่ใช่การแข่งขันว่าใครซ่อนหรือค้นหาโปรแกรมได้เก่งกว่าเพียงอย่างเดียว แต่มันคือการแข่งขันว่าใครเข้าใจระบบ ความเชื่อใจ และข้อจำกัดของหลักฐานได้ลึกกว่ากัน

และสำหรับผม HerculesAC คือหนึ่งในโปรเจกต์ที่ทำให้เริ่มเข้าใจปัญหานั้นผ่าน code จริง

Happy Hacking :)


References