Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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 資訊安全基礎技術⼯工作坊 資安實務攻防研習營

Slide 3

Slide 3 text

這是今天的當事⼈人 為了了受害者權益,已經打上⾺馬賽克

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

aaaddress1@chroot.org 記憶體攻防戰 • 線上遊戲怎麼運作的 • 駭客如何分析線上遊戲 1. 動態分析: OllyDBG, Cheat Engine 2. 靜態分析: IDA Pro • 常⾒見見的遊戲保護⽅方式 3. 產品保護?套殼就對啦! 4. 套殼不夠?我上混淆跟虛擬機! 5. 虛擬機不夠難?我⾃自幹整個 Ring0 防護 • 通常如何解決那些保護 • 傳說的⿊黑魔法怎麼被做出來來的?

Slide 6

Slide 6 text

先聊聊 線上遊戲怎麼運作der?

Slide 7

Slide 7 text

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; }

Slide 8

Slide 8 text

aaaddress1@chroot.org boringGame.c

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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; }

Slide 11

Slide 11 text

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; }

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

聽你⼀一本正經地講廢話 所以呢?知道這架構可以幹嘛?

Slide 17

Slide 17 text

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; }

Slide 18

Slide 18 text

aaaddress1@chroot.org boringGame.c

Slide 19

Slide 19 text

aaaddress1@chroot.org Cheat Engine

Slide 20

Slide 20 text

aaaddress1@chroot.org Cheat Engine

Slide 21

Slide 21 text

aaaddress1@chroot.org Cheat Engine

Slide 22

Slide 22 text

aaaddress1@chroot.org Cheat Engine

Slide 23

Slide 23 text

aaaddress1@chroot.org Cheat Engine

Slide 24

Slide 24 text

aaaddress1@chroot.org IDA Pro

Slide 25

Slide 25 text

aaaddress1@chroot.org IDA Pro

Slide 26

Slide 26 text

aaaddress1@chroot.org 線上遊戲外掛策略略 1. 盡可能分析封包怎麼發送的 • connect()、send()、recv() 2. 不會分析封包?⼭山不轉路路轉,分析程式邏輯 3. 若若有資料是在客⼾戶端算完才送出,嘗試篡改它 • 怪物出⽣生座標、攻擊距離、損⾎血量量、是否要損⾎血、要換去哪個頻道 • 吸怪、全圖打、MISS式無敵、完全無敵、⾃自動換頻、⾃自動過圖、全圖吸寶 4. 無法竄改?我模擬單⼀一個攻擊封包狂丟 • 吃我攻擊無延遲啦

Slide 27

Slide 27 text

對於遊戲公司⽽而⾔言 ... 線上遊戲外掛多寡決定玩家情感上的品質啊(嘆)

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

aaaddress1@chroot.org IDA

Slide 33

Slide 33 text

aaaddress1@chroot.org IDA

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

aaaddress1@chroot.org Process Game Process Game.exe (PE) Reserved 0x00 ~ 0x3fffff 0x400000+ ntdll.dll KUSER_SHARED_DATA 0x7ffe000+ user32.dll kernel32.dll ... ...

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

aaaddress1@chroot.org 殼 Game Process 保留留空間 Reserved 0x00 ~ 0x3fffff 0x400000+ KUSER_SHARED_DATA 0x7ffe000+ ... 殼的主程式 加密並壓縮的內容 原始程式內容 (Game.exe) 覆寫回執⾏行行程式預期加載的位址 並模擬實作 loader 需做的事情 殼的主程式 Game.exe (PE)

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

所以呢? 把程式執⾏行行起來來,跨 Process 讀取遊戲執⾏行行程式內容 1. 修復讀取到的執⾏行行程式內容,就可以餵給 IDA 分析 2. ⽤用動態分析⽅方式除錯遊戲,直接⼀一步步跟蹤遊戲指令

Slide 47

Slide 47 text

aaaddress1@chroot.org 反外掛系統

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

aaaddress1@chroot.org 讀寫別⼈人的 Process boringGame.exe ntdll!ZwOpenProcess gameHacker.exe Token

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

aaaddress1@chroot.org 實際上運作 boringGame.exe Process Id = 1 ntdll!ZwOpenProcess: 我可不可以申請 Process Id = 1 Process 的存取寫入權限R? gameHacker.exe (Ring3) ㄜ... 有個驅動程式控制ㄌ我, 它跟我說不能給你 Token, Sorry :( Windows Kernel (Ring0)

Slide 52

Slide 52 text

你以為到此為⽌止, 遊戲廠商⼤大獲全勝了了嗎 三種奇淫技巧 (⼀一)偽造 PEB!ImagePath (⼆二)DLL Hijacking / DLL Inject (三)乾脆把遊戲保護給殺掉

Slide 53

Slide 53 text

aaaddress1@chroot.org 偽造 ImagePath boringGame.exe Process Id = 1 ntdll!ZwOpenProcess: 我可不可以申請 Process Id = 1 Process 的存取寫入權限R? ㄜ...你是⼯工作管理理員喔, 好ㄅ,可能遊戲當掉了了玩家想強制關閉遊戲, Token 給你吧 Windows Kernel (Ring0)

Slide 54

Slide 54 text

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] }

Slide 55

Slide 55 text

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; }

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

aaaddress1@chroot.org DLL Hijacking via SestWindowsHookEx resources.infosecinstitute.com/using-setwindowshookex-for-dll-injection-on-windows

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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/

Slide 71

Slide 71 text

⼀一些都市傳說 是怎麼被創造出來來的?

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

aaaddress1@chroot.org messagebox.exe en.wikipedia.org/wiki/X86_calling_conventions 00F11000 ] 00F11014 | xor eax,eax 00F11016 | ret

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

Q1. 虛擬機?

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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 ...

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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 ...

Slide 86

Slide 86 text

Q2. 全圖吸怪? https://www.youtube.com/watch?v=ORrd1C2vEq0

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

不過, 外掛圈是這樣啦。 程式碼開源共享?外掛圈才是龍頭啦!Github落落漆 www.unknowncheats.me/wiki/Maple_Story:GMS_-_V66_Pointers/Addresses_%26_More

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

Q3. 全圖攻擊? https://www.youtube.com/watch?v=0B8G2WlC-BA

Slide 93

Slide 93 text

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]); // ... } }

Slide 94

Slide 94 text

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]); // ... } }

Slide 95

Slide 95 text

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(); }

Slide 96

Slide 96 text

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; }

Slide 97

Slide 97 text

Q4. 遊戲⽅方都沒啥保護嗎?

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

Q5. 遇 GM ⾃自動下線

Slide 103

Slide 103 text

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]); } } 地圖載入階段 *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。

Slide 104

Slide 104 text

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 下線 *年年代久遠、資料不可考,按照印象⼤大概是這樣啦。

Slide 105

Slide 105 text

aaaddress1@chroot.org Thanks! 我剛剛什什麼都沒說,你們什什麼都沒聽到。