Upgrade to Pro — share decks privately, control downloads, hide ads and more …

那些年我看過的反外掛爛梗

229b1596ce57cd0935a2bacd410d87a0?s=47 adr
March 31, 2018

 那些年我看過的反外掛爛梗

線上遊戲是許多人的童年,許多人在線上遊戲看到外掛只覺得他們破壞遊戲平衡,讓遊戲變得不公平、不再有趣,
而有些人則投入外掛的懷抱,成為外掛使用者一員。今天將以台灣最知名紅遍大街小巷的線上遊戲作為舉例,
以外掛開發者的立場做分析線上遊戲,分享一些常見的分析遊戲弱點技巧、遊戲架構設計帶來的隱憂、
與這樣的分析技巧曾經成功挖掘出哪些漏洞,解析以往這些看似黑科技的外掛技術如何被挖掘出來的。

議程末將會簡單的介紹一些反外掛技巧,對於記憶體層面的攻防如何讓駭客難以分析與破解的開發者思路。

229b1596ce57cd0935a2bacd410d87a0?s=128

adr

March 31, 2018
Tweet

More Decks by adr

Other Decks in Technology

Transcript

  1. aaaddress1@chroot.org 那些年年我看過的 反外掛爛梗

  2. aaaddress1@chroot.org ./Bio✨ • ⾺馬聖豪, aaaddress1 aka adr • Chroot, TDOH

    • 精通 C/C++、Windows 特性、逆向⼯工程 • Speaker: BlackHat Asia Arsenal 2018 HITCON CMT 2015 HITCON CMT 2016 Lightning HITCON CMT 2017 SITCON 2016 SITCON 2017 iThome#Chatbot 2017 BSidesLV 2016 ICNC'17 資訊安全基礎技術⼯工作坊 資安實務攻防研習營
  3. 這是今天的當事⼈人 為了了受害者權益,已經打上⾺馬賽克

  4. 沒有任何技術, 我今天是來來講脫⼝口秀的 都是⼀一些網路路上就可以搜集來來老歷史。我怕被吉

  5. aaaddress1@chroot.org 記憶體攻防戰 • 線上遊戲怎麼運作的 • 駭客如何分析線上遊戲 1. 動態分析: OllyDBG, Cheat

    Engine 2. 靜態分析: IDA Pro • 常⾒見見的遊戲保護⽅方式 3. 產品保護?套殼就對啦! 4. 套殼不夠?我上混淆跟虛擬機! 5. 虛擬機不夠難?我⾃自幹整個 Ring0 防護 • 通常如何解決那些保護 • 傳說的⿊黑魔法怎麼被做出來來的?
  6. 先聊聊 線上遊戲怎麼運作der?

  7. aaaddress1@chroot.org boringGame.c int nowHp = 100; void getHurt(int HpCost) {

    nowHp -= HpCost; } int main(void) { char buf[0x30]; while (1) { printf( "[1] hp -= 10\n[2] exit()\nopcode: "); gets(buf); if (buf[0] == '1') getHurt(10); else if (buf[0] == '2') break; else puts(":/ unknown opcode"); printf("your hp: %d\n\n", nowHp); if (nowHp < 1) { puts("you die!"); break; } } return 0; }
  8. aaaddress1@chroot.org boringGame.c

  9. 我知道這時你會想說 可是這只是單機遊戲啊(對啊!對啊!)

  10. aaaddress1@chroot.org 客⼾戶端為主遊戲架構 int nowHp = 100; int main(void) { char

    buf[0x30]; while (1) { printf("[1] hp -= 10\n[2] exit()\nopcode: "); gets(buf); if (buf[0] == '1') sendHurtCost(10); else if (buf[0] == '2') break; else puts(":/ unknown opcode"); displyPalyerData(recvAllPlayerData()); if (nowHp < 1) { puts("you die!"); break; } } return 0; }
  11. aaaddress1@chroot.org 伺服端為主遊戲架構 int nowHp = 100; int main(void) { char

    buf[0x30]; while (1) { printf("[1] hp -= 10\n[2] exit()\nopcode: "); gets(buf); if (buf[0] == '1') iNeedToGetHurt(); else if (buf[0] == '2') break; else puts(":/ unknown opcode"); displyPalyerData(recvAllPlayerData()); nowHp = recvMyHpData(); if (nowHp < 1) { puts("you die!"); break; } } return 0; }
  12. aaaddress1@chroot.org 架構⾯面來來說(客⼾戶為主) 客⼾戶端 伺服端 現在有誰在線上啊? 同張地圖 玩家資訊 欸欸, 經過我計算結果 本次要損⾎血

    10 滴 好ㄛ 我知道ㄌ 我要攻擊 那隻 id 為 1 的怪物 好ㄛ攻擊成功! 你剛剛打他造成 10 點傷害
  13. aaaddress1@chroot.org 架構⾯面來來說(客⼾戶為主) 客⼾戶端 伺服端 現在有誰在線上啊? 同張地圖 玩家資訊 欸欸, 經過我計算結果 本次要損⾎血

    10 滴 好ㄛ 我知道ㄌ 我要攻擊 那隻 id 為 1 的怪物 好ㄛ攻擊成功! 你剛剛打他造成 10 點傷害
  14. aaaddress1@chroot.org 架構⾯面來來說(伺服為主) 客⼾戶端 伺服端 現在有誰在線上啊? 同張地圖 玩家資訊 ㄟ, 我現在狀狀況怎麼樣? 你剛剛被BOSS海海K三下

    經由你裝備防護後 你扣了了 1337 滴⾎血 現在⾎血量量 50 滴 ㄟ我要打那隻 id 為 1 的怪物 ㄜ...你只造成ㄌ 1 點傷害
  15. aaaddress1@chroot.org 架構⾯面來來說(伺服為主) 客⼾戶端 伺服端 現在有誰在線上啊? 同張地圖 玩家資訊 ㄟ, 我現在狀狀況怎麼樣? 你剛剛被BOSS海海K三下

    經由你裝備防護後 你扣了了 1337 滴⾎血 現在⾎血量量 50 滴 ㄟ我要打那隻 id 為 1 的怪物 ㄜ...你只造成ㄌ 1 點傷害
  16. 聽你⼀一本正經地講廢話 所以呢?知道這架構可以幹嘛?

  17. aaaddress1@chroot.org boringGame.c int nowHp = 100; void getHurt(int HpCost) {

    nowHp -= HpCost; } int main(void) { char buf[0x30]; while (1) { printf( "[1] hp -= 10\n[2] exit()\nopcode: "); gets(buf); if (buf[0] == '1') getHurt(10); else if (buf[0] == '2') break; else puts(":/ unknown opcode"); printf("your hp: %d\n\n", nowHp); if (nowHp < 1) { puts("you die!"); break; } } return 0; }
  18. aaaddress1@chroot.org boringGame.c

  19. aaaddress1@chroot.org Cheat Engine

  20. aaaddress1@chroot.org Cheat Engine

  21. aaaddress1@chroot.org Cheat Engine

  22. aaaddress1@chroot.org Cheat Engine

  23. aaaddress1@chroot.org Cheat Engine

  24. aaaddress1@chroot.org IDA Pro

  25. aaaddress1@chroot.org IDA Pro

  26. aaaddress1@chroot.org 線上遊戲外掛策略略 1. 盡可能分析封包怎麼發送的 • connect()、send()、recv() 2. 不會分析封包?⼭山不轉路路轉,分析程式邏輯 3. 若若有資料是在客⼾戶端算完才送出,嘗試篡改它

    • 怪物出⽣生座標、攻擊距離、損⾎血量量、是否要損⾎血、要換去哪個頻道 • 吸怪、全圖打、MISS式無敵、完全無敵、⾃自動換頻、⾃自動過圖、全圖吸寶 4. 無法竄改?我模擬單⼀一個攻擊封包狂丟 • 吃我攻擊無延遲啦
  27. 對於遊戲公司⽽而⾔言 ... 線上遊戲外掛多寡決定玩家情感上的品質啊(嘆)

  28. 遊戲公司好棒棒 想出了了三種⼿手段制裁駭客 1. 加殼保護 2. 遊戲搭載反外掛系統 3. ⾃自我程式碼校驗防篡改

  29. aaaddress1@chroot.org Themida www.oreans.com/themida.php

  30. 簡直是救命仙丹丹啊! 動動⼿手指幫程式套保護殼, 就能保護原始碼呢,簡直比犀⽜牛盾還好⽤用!

  31. 原本駭客打算 通通丟去餵 IDA!

  32. aaaddress1@chroot.org IDA

  33. aaaddress1@chroot.org IDA

  34. 沒有錯啦! IDA 只會看到⼀一堆「殼」本⾝身的實作, 根本看不到實際遊戲本⾝身的內容惹。

  35. 打個岔, 我得提提殼怎麼實作的

  36. aaaddress1@chroot.org 你以為殼的保護

  37. aaaddress1@chroot.org 你以為殼的保護 ⼀一切充滿不確定性, 反正能 Work 就好了了嘛?

  38. aaaddress1@chroot.org Process Game Process Game.exe (PE) Reserved 0x00 ~ 0x3fffff

    0x400000+ ntdll.dll KUSER_SHARED_DATA 0x7ffe000+ user32.dll kernel32.dll ... ...
  39. aaaddress1@chroot.org 殼 Game Process 保留留空間 Reserved 0x00 ~ 0x3fffff 0x400000+

    KUSER_SHARED_DATA 0x7ffe000+ ... 殼的主程式 加密並壓縮的內容
  40. aaaddress1@chroot.org 殼 Game Process 保留留空間 Reserved 0x00 ~ 0x3fffff 0x400000+

    KUSER_SHARED_DATA 0x7ffe000+ ... 殼的主程式 加密並壓縮的內容 原始程式內容 (Game.exe) 取出 解密內容 殼的主程式
  41. aaaddress1@chroot.org 殼 Game Process 保留留空間 Reserved 0x00 ~ 0x3fffff 0x400000+

    KUSER_SHARED_DATA 0x7ffe000+ ... 殼的主程式 加密並壓縮的內容 原始程式內容 (Game.exe) 覆寫回執⾏行行程式預期加載的位址 並模擬實作 loader 需做的事情 殼的主程式 Game.exe (PE)
  42. aaaddress1@chroot.org 讀寫別⼈人的 Process boringGame.exe Process Id = 1 0xdead: 01

    23 00 00 gameHacker.exe Process Id = 2 我想寫入 Process id = 1 的 Process 記憶體 0xdead 處連續 4 個 byte 的內容 可以ㄇ WriteProcessMemory
  43. aaaddress1@chroot.org boringGame.exe Process Id = 1 0xdead: 01 23 00

    00 我想寫入 Process id = 1 的 Process 記憶體 0xdead 處連續 4 個 byte 的內容 可以ㄇ WriteProcessMemory 不可以ㄛ 跨 Process 讀/寫/創建 Thread 要先申請權限ㄏㄏ gameHacker.exe Process Id = 2 讀寫別⼈人的 Process
  44. aaaddress1@chroot.org 讀寫別⼈人的 Process boringGame.exe Process Id = 1 0xdead: 01

    23 00 00 OpenProcess() gameHacker.exe Process Id = 2 Token WriteProcessMemory(Token, ...)
  45. aaaddress1@chroot.org 讀寫別⼈人的 Process boringGame.exe Process Id = 1 0xdead: 01

    23 00 00 OpenProcess() gameHacker.exe Process Id = 2 Token ReadProcessMemory(Token, ...) 0xdead = 01 23 00 00
  46. 所以呢? 把程式執⾏行行起來來,跨 Process 讀取遊戲執⾏行行程式內容 1. 修復讀取到的執⾏行行程式內容,就可以餵給 IDA 分析 2. ⽤用動態分析⽅方式除錯遊戲,直接⼀一步步跟蹤遊戲指令

  47. aaaddress1@chroot.org 反外掛系統

  48. aaaddress1@chroot.org 讀寫別⼈人的 Process boringGame.exe Process Id = 1 0xdead: 01

    23 00 00 OpenProcess() gameHacker.exe Process Id = 2 Token ReadProcessMemory(Token, ...) 0xdead = 01 23 00 00
  49. aaaddress1@chroot.org 讀寫別⼈人的 Process boringGame.exe ntdll!ZwOpenProcess gameHacker.exe Token

  50. aaaddress1@chroot.org 實際上運作 boringGame.exe Process Id = 1 ntdll!ZwOpenProcess: 我可不可以申請 Process

    Id = 1 Process 的存取寫入權限R? gameHacker.exe (Ring3) 好R,你要 Token 就給你R,有何不可ㄋ Windows Kernel (Ring0)
  51. aaaddress1@chroot.org 實際上運作 boringGame.exe Process Id = 1 ntdll!ZwOpenProcess: 我可不可以申請 Process

    Id = 1 Process 的存取寫入權限R? gameHacker.exe (Ring3) ㄜ... 有個驅動程式控制ㄌ我, 它跟我說不能給你 Token, Sorry :( Windows Kernel (Ring0)
  52. 你以為到此為⽌止, 遊戲廠商⼤大獲全勝了了嗎 三種奇淫技巧 (⼀一)偽造 PEB!ImagePath (⼆二)DLL Hijacking / DLL Inject

    (三)乾脆把遊戲保護給殺掉
  53. aaaddress1@chroot.org 偽造 ImagePath boringGame.exe Process Id = 1 ntdll!ZwOpenProcess: 我可不可以申請

    Process Id = 1 Process 的存取寫入權限R? ㄜ...你是⼯工作管理理員喔, 好ㄅ,可能遊戲當掉了了玩家想強制關閉遊戲, Token 給你吧 Windows Kernel (Ring0)
  54. aaaddress1@chroot.org 偽造 ImagePath _asm{ mov eax,fs:[0x30] //eax points to PEB

    mov eax,[eax+0x010] //eax points to _PEB->_RTL_USER_PROCESS_PARAMETERS add eax,0x38 //eax points to ImagePathName(UNICODE_STRING) add eax,0x4 //UNICODE_STRING.Buffer mov ebx,wszImagePathName mov [eax],ebx mov eax,[eax] }
  55. aaaddress1@chroot.org 寫⼀一⽀支 DLL 吧 :) BOOL APIENTRY DllMain( HMODULE hModule,

    DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: MessageBoxA(NULL, "hi there!", "info", NULL); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
  56. aaaddress1@chroot.org DLL Entry Game Process Game.exe (PE) 0x400000+ ntdll.dll KUSER_SHARED_DATA

    0x7ffe000+ user32.dll kernel32.dll ... ... “An optional entry point into a dynamic-link library (DLL). When the system starts or terminates a process or thread, it calls the entry-point function for each loaded DLL using the first thread of the process. ” -- MSDN (DllMain entry point) .text: DllEntry .text: DllEntry .text: DllEntry
  57. aaaddress1@chroot.org DLL Hijacking via SestWindowsHookEx resources.infosecinstitute.com/using-setwindowshookex-for-dll-injection-on-windows

  58. aaaddress1@chroot.org DLL Hijacking via Side-Loading www.fireeye.com/content/dam/fireeye-www/global/en/current-threats/pdfs/ rpt-dll-sideloading.pdf

  59. aaaddress1@chroot.org DLL Hijacking via Side-Loading www.fireeye.com/content/dam/fireeye-www/global/en/current-threats/pdfs/ rpt-dll-sideloading.pdf

  60. aaaddress1@chroot.org DLL Hijacking via Side-Loading http://www.studentexplorer.net/soft/51651.html

  61. aaaddress1@chroot.org DLL Inject https://arvanaghi.com/blog/dll-injection-using-loadlibrary-in-C/

  62. aaaddress1@chroot.org 把反外掛函數庫餵 IDA

  63. aaaddress1@chroot.org 把反外掛函數庫餵 IDA

  64. aaaddress1@chroot.org 把反外掛函數庫餵 IDA

  65. aaaddress1@chroot.org 把反外掛函數庫餵 IDA

  66. aaaddress1@chroot.org 還記得我們找到程式邏輯的嗎

  67. aaaddress1@chroot.org 把反外掛函數庫餵 IDA

  68. aaaddress1@chroot.org 把反外掛函數庫餵 IDA

  69. aaaddress1@chroot.org 把反外掛函數庫餵 IDA

  70. aaaddress1@chroot.org 老外寫了了 CE Script MSCRCBypass: push eax lea eax, [ecx]

    cmp eax, 00401000 jb Normal cmp eax, 00BFE000 ja Normal push ebx mov ebx, FakeDump sub eax, 00401000 add eax, ebx movzx ecx, byte ptr [eax] pop ebx pop eax jmp Normal+04 Normal: pop eax movzx ecx, byte ptr [ecx] mov edx, [ebp+14] jmp 00A11487 00A11481: jmp MSCRCBypass nop CreateThread(MSmemcpy) MSmemcpy: mov edi, FakeDump mov esi, 00401000 mov ecx, 001FF400 repe movsd ret ccplz.net/threads/ems-v75-bypass-information.23009/
  71. ⼀一些都市傳說 是怎麼被創造出來來的?

  72. Q0. 可是真的沒辦法 過記憶體校驗怎麼辦 :(

  73. aaaddress1@chroot.org messagebox.c en.wikipedia.org/wiki/X86_calling_conventions #include <Windows.h> const char *lptext = "hi

    there!"; const char *lptitl = "info"; int main() { MessageBoxA(0, lptext, lptitl, 0); return 0; }
  74. aaaddress1@chroot.org messagebox.c en.wikipedia.org/wiki/X86_calling_conventions #include <Windows.h> const char *lptext = "hi

    there!"; const char *lptitl = "info"; int main() { MessageBoxA(0, lptext, lptitl, 0); return 0; }
  75. aaaddress1@chroot.org messagebox.exe en.wikipedia.org/wiki/X86_calling_conventions 00F11000 <con | push 0 00F11002 |

    push "info" 00F11007 | push "hi there!" 00F1100C | push 0 00F1100E | call dword ptr ds:[<&MessageBoxA>] 00F11014 | xor eax,eax 00F11016 | ret
  76. aaaddress1@chroot.org messagebox hijacking en.wikipedia.org/wiki/X86_calling_conventions

  77. aaaddress1@chroot.org messagebox hijacking en.wikipedia.org/wiki/X86_calling_conventions

  78. aaaddress1@chroot.org messagebox hijacking en.wikipedia.org/wiki/X86_calling_conventions

  79. Q1. 虛擬機?

  80. aaaddress1@chroot.org Calling Convention int callee(int, int, int); int caller(void) {

    return callee(1, 2, 3) + 5; } caller: push ebp mov ebp, esp push 3 push 2 push 1 call callee add eax, 5 add esp, 12 mov esp, ebp pop ebp ret en.wikipedia.org/wiki/X86_calling_conventions
  81. aaaddress1@chroot.org 殼本⾝身的虛擬機? int callee(int, int, int); int caller(void) { return

    callee(1, 2, 3) + 5; } callee: push xxxx jmp PackerVM en.wikipedia.org/wiki/X86_calling_conventions caller: push ebp mov ebp, esp push 3 push 2 push 1 call callee ...
  82. aaaddress1@chroot.org 虛擬機構造 www.blackhat.com/docs/asia-18/ asia-18-Blazytko-Breaking-State-Of-The-Art-Binary-Code-Obfuscation-Via-Program-Synthesis.pdf

  83. aaaddress1@chroot.org 虛擬機構造 www.blackhat.com/docs/asia-18/ asia-18-Blazytko-Breaking-State-Of-The-Art-Binary-Code-Obfuscation-Via-Program-Synthesis.pdf

  84. aaaddress1@chroot.org Themida www.oreans.com/themida.php

  85. aaaddress1@chroot.org 殼本⾝身的虛擬機? int callee(int, int, int); int caller(void) { return

    callee(1, 2, 3) + 5; } callee: push xxxx jmp PackerVM en.wikipedia.org/wiki/X86_calling_conventions caller: push ebp mov ebp, esp push 3 push 2 push 1 >> call callee ...
  86. Q2. 全圖吸怪? https://www.youtube.com/watch?v=ORrd1C2vEq0

  87. aaaddress1@chroot.org 還記得嗎 客⼾戶端 伺服端 現在有誰在線上啊? 同張地圖 玩家資訊 欸欸, 經過我計算結果 本次要損⾎血

    10 滴 好ㄛ 我知道ㄌ 我要攻擊 那隻 id 為 1 的怪物 好ㄛ攻擊成功! 你剛剛打他造成 10 點傷害
  88. 不過, 外掛圈是這樣啦。 程式碼開源共享?外掛圈才是龍頭啦!Github落落漆 www.unknowncheats.me/wiki/Maple_Story:GMS_-_V66_Pointers/Addresses_%26_More

  89. 當然外掛製造商 也會有鬧不平的時候。 知⼰己知彼百戰百勝,東抄⻄西抄⾃自成⼀一家 (你有我沒有的?我破解掉你的外掛來來分析看看)

  90. aaaddress1@chroot.org 怪物出⽣生 void bornMob(mob inMob) { // ... sendMob(inMob.type, inMob.x,

    inMob.y, ...); // ... } void initMap() { /* ... 做了了很多進地圖的封包處理理 ... */ wallData curr; recvWallData(&curr); mob mobArr[0xff]; for (int i = 0; i < 255; i++) { if (cmpMobInWall(mobArr[i], curr)) bornMob(mobArr[i]); else dieMob(mobArr[i]); } } struct wallData { int leftWall; int rightWall; int TopWall; int Bottom; } *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。 github.com/aaaddress1/CrackShield-MapleStory-Hack/blob/master/Script/GiFon_.h
  91. aaaddress1@chroot.org 全圖吸怪 void bornMob(mob inMob) { // ... sendMob(inMob.type, inMob.x,

    inMob.y, ...); // ... } void initMap() { /* ... 做了了很多進地圖的封包處理理 ... */ wallData curr; recvWallData(&curr); mob mobArr[0xff]; for (int i = 0; i < 255; i++) { if (cmpMobInWall(mobArr[i], curr)) bornMob(mobArr[i]); else dieMob(mobArr[i]); } } struct wallData { int leftWall; int rightWall; int TopWall; int Bottom; } *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。 github.com/aaaddress1/CrackShield-MapleStory-Hack/blob/master/Script/GiFon_.h
  92. Q3. 全圖攻擊? https://www.youtube.com/watch?v=0B8G2WlC-BA

  93. aaaddress1@chroot.org 技能攻擊判斷 typedef struct _RECT { LONG left; LONG top;

    LONG right; LONG bottom; } RECT, *PRECT; typedef struct tagPOINT { LONG x; LONG y; } POINT, *PPOINT; *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。 github.com/aaaddress1/CrackShield-MapleStory-Hack/blob/master/Script/XY_Fix.h void CALLBACK attack() { // ... wallData curr; recvWallData(&curr); _RECT skillRange; mob arr[0xff]; for (int i = 0; i < 255; i++) { // 確認技能施放 ... tagPOINT p = tagPOINT(arr[i].x, arr[i].y); if (PtinRect(&skillRange, &p)) sendAttackMob(arr[i]); // ... } }
  94. aaaddress1@chroot.org 全圖攻擊 typedef struct _RECT { LONG left; LONG top;

    LONG right; LONG bottom; } RECT, *PRECT; typedef struct tagPOINT { LONG x; LONG y; } POINT, *PPOINT; *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。 github.com/aaaddress1/CrackShield-MapleStory-Hack/blob/master/Script/XY_Fix.h void CALLBACK attack() { // ... wallData curr; recvWallData(&curr); _RECT skillRange; mob arr[0xff]; for (int i = 0; i < 255; i++) { // 確認技能施放 ... tagPOINT p = tagPOINT(skillRange.left, skillRange.top); if (PtinRect(&skillRange, &p)) sendAttackMob(arr[i]); // ... } }
  95. aaaddress1@chroot.org 技能攻擊判斷 *反外掛 *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。 github.com/aaaddress1/CrackShield-MapleStory-Hack/blob/master/Script/XY_Fix.h void CALLBACK attack() { //

    ... wallData curr; recvWallData(&curr); _RECT skillRange; mob arr[0xff]; for (int i = 0; i < 255; i++) { // 確認技能施放 ... tagPOINT p = tagPOINT(arr[i].x, arr[i].y); if (PtinRect(&skillRange, &p)) sendAttackMob(arr[i]); // ... while (!chkMob(arr[i], p.x, p.y)); } } bool chkMob(mob mob, LONG x, LONG y){ if (chkShownMob(mob, x, y)) return 1; else killGame(); }
  96. aaaddress1@chroot.org 技能攻擊判斷 *反反外掛 *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。 github.com/aaaddress1/CrackShield-MapleStory-Hack/blob/master/Script/XY_Fix.h void CALLBACK attack() { //

    ... wallData curr; recvWallData(&curr); _RECT skillRange; mob arr[0xff]; for (int i = 0; i < 255; i++) { // 確認技能施放 ... tagPOINT p = tagPOINT(arr[i].x, arr[i].y); if (PtinRect(&skillRange, &p)) sendAttackMob(arr[i]); // ... while (!chkMob(arr[i], p.x, p.y)); } } bool chkMob(mob mob, LONG x, LONG y){ chkShownMob(mob, x, y); return 1; }
  97. Q4. 遊戲⽅方都沒啥保護嗎?

  98. aaaddress1@chroot.org 任意地圖⼤大概像這樣 四四⽅方⽅方的,你懂我懂

  99. aaaddress1@chroot.org 地圖,你我回憶,對的! 地板 光點 光點 你 來來搶圖的玩家 怪物

  100. aaaddress1@chroot.org 不對,你記錯了了,這才是真正的地圖 地板 光點 光點 你 來來搶圖的玩家 怪物 地圖外打不到的透明怪 地圖外打不到的透明怪

    地圖外打不到的透明怪
  101. 你打到我 就準備去⾒見見 GM 吧你。 這也是為啥遊戲資料片裡⾯面 可以翻到⼀一堆沒有圖片卻是怪物的資料,ㄎㄎ。

  102. Q5. 遇 GM ⾃自動下線

  103. aaaddress1@chroot.org void initMap() { /* ... 做了了很多進地圖的封包處理理 ... */ object

    arr[0xff]; for (int i = 0; i < 255; i++) { if (arr[i].type != TYPE_PLAYER) continue; displyPlayer(arr[i], arr[i].name); } for (int i = 0; i < 255; i++) { if (arr[i].type != TYPE_CHEATMOB) continue; setCheatMobLocation(arr[i]); } wallData curr; recvWallData(&curr); for (int i = 0; i < 255; i++) { if (arr[i].type != TYPE_MOB) continue; if (cmpMobInWall(arr[i], curr)) bornMob(arr[i]); else dieMob(arr[i]); } } 地圖載入階段 *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。
  104. aaaddress1@chroot.org void initMap() { /* ... 做了了很多進地圖的封包處理理 ... */ object

    arr[0xff]; for (int i = 0; i < 255; i++) { if (arr[i].type != TYPE_PLAYER) continue; displyPlayer(arr[i], arr[i].name); } for (int i = 0; i < 255; i++) { if (arr[i].type != TYPE_CHEATMOB) continue; setCheatMobLocation(arr[i]); } wallData curr; recvWallData(&curr); for (int i = 0; i < 255; i++) { if (arr[i].type != TYPE_MOB) continue; if (cmpMobInWall(arr[i], curr)) bornMob(arr[i]); else dieMob(arr[i]); } } 遇 GM 下線 *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。
  105. aaaddress1@chroot.org Thanks! 我剛剛什什麼都沒說,你們什什麼都沒聽到。