1 คะแนน โดย GN⁺ 2023-12-06 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ใน Magic: The Gathering Arena สามารถบังคับให้คู่ต่อสู้ ยอมแพ้ ได้ในจังหวะที่ต้องการ จึงทำให้สร้างสถานะที่ไม่แพ้ในเกมแบบแมตช์เมกกิงได้
  • โดยปกติเกมการ์ดเหมาะกับ สถาปัตยกรรมแบบ server-authoritative ที่เซิร์ฟเวอร์เป็นผู้จัดการสถานะทั้งหมด แต่ Sparky คู่ต่อสู้บอทของ MTGA ถูกทำเป็นลอจิกบนไคลเอนต์ภายในเครื่อง
  • ไคลเอนต์ MTGA ที่พัฒนาด้วย C# สามารถเข้าถึงอ็อบเจ็กต์ขณะรันไทม์และฟิลด์ private ได้ผ่าน reflection และในโค้ดที่ถอดกลับมาพบชื่ออย่าง JoinMatch, ConnectAndJoinMatch, HeadlessClient
  • ในแมตช์กับบอท มีการใช้โครงสร้างที่เชื่อมต่อทั้งสองฝั่งด้วย PersonaID และ JWT ของบัญชีเดียวกัน และเมื่อนำแนวทางนี้ไปใช้กับแมตช์ปกติ ก็สามารถแนบ headless client เข้ากับที่นั่งของคู่ต่อสู้แล้วเรียก ConcedeGame() ได้
  • หลังจากนั้นเซิร์ฟเวอร์ถูก แพตช์ ไม่ให้ทั้งสองที่นั่งในเกมแบบแมตช์เมกกิงใช้บัญชีและ JWT เดียวกันได้อีก และกรณีนี้ก็เป็นตัวอย่างว่าขอบเขตระหว่างการทำบอทฝั่งไคลเอนต์กับการตรวจสอบสิทธิ์ของที่นั่งส่งผลต่อความปลอดภัยจริงอย่างไร

ทำไมการแฮ็กเกมการ์ดถึงยาก

  • เกมการ์ดเป็นแบบเทิร์นเบส และมีข้อมูลที่รับส่งระหว่างไคลเอนต์กับเซิร์ฟเวอร์ไม่มาก จึงเหมาะกับ โครงสร้างแบบ server-authoritative
  • เซิร์ฟเวอร์เป็นผู้ดูแลสถานะของเกมทั้งหมด และส่งเฉพาะข้อมูลที่จำเป็นให้ไคลเอนต์
    • ข้อมูลที่ไม่เปิดเผย เช่น ไพ่ในมือหรือเด็คของฝ่ายตรงข้าม จะไม่มีอยู่ในเครื่อง
    • ความพยายามอย่างการสลับลำดับเด็คหรือบังคับไพ่ที่จะจั่วทำได้ยาก เพราะเซิร์ฟเวอร์เป็นผู้ดำเนินการและแจ้งเพียงผลลัพธ์กลับมา
  • ต่างจากเกมยิงมุมมองบุคคลที่หนึ่ง เกมการ์ดมีการกระทำของผู้เล่นที่จำกัดและเกิดขึ้นในจังหวะที่กำหนดไว้
    • ในเกม FPS ข้อมูลอย่างตำแหน่งโมเดลศัตรูอาจถูกแคชไว้ล่วงหน้าบนไคลเอนต์ จึงทำให้เกิดสิ่งอย่าง wallhack ได้
    • บล็อก anti-wallhack ของ Riot กล่าวถึงแนวทางลดข้อมูลตำแหน่งผู้เล่นที่อยู่ฝั่งไคลเอนต์
  • การตรวจจับพฤติกรรมที่ผิดปกติก็ค่อนข้างง่ายกว่าเช่นกัน
    • เล่นไพ่ที่ไม่มีอยู่ในมือ
    • กระทำการทั้งที่ไม่ใช่เทิร์นของตัวเอง

จุดเริ่มต้นของการวิเคราะห์: เครือข่ายและไคลเอนต์ C#

  • เลือกแนวทางเริ่มจากการดู การสื่อสารเครือข่าย เป็นจุดตั้งต้นของการแฮ็กเกม
  • งานบรรยาย DEF CON ของ Manfred ที่พูดถึงกรณีแฮ็ก MMO แสดงให้เห็นว่า reverse engineering โปรโตคอลเครือข่ายเป็นกุญแจสำคัญในการวิเคราะห์บั๊กหลายแบบ
  • MTGA เขียนด้วย C# จึงสามารถจัดการอ็อบเจ็กต์ในรันไทม์ได้ แทนที่จะต้อง hook ฟังก์ชันรับส่งทราฟฟิก
    • ใช้ .NET reflection เพื่อเข้าถึงฟิลด์และเมธอด private ได้ด้วย
    • มีการเชื่อมไปยังตัวอย่างพื้นฐานที่เกี่ยวข้องคือ Unity game reflection hacking tutorial
  • แอสเซมบลี .NET ที่ไม่ได้ทำให้สับสนชื่อไว้ สามารถดูชื่อฟังก์ชัน ตัวแปร และคลาสในรูปแบบที่มนุษย์อ่านได้จาก metadata token
    • ทำให้ผลการถอดโค้ดกลับมาแทบไม่ต่างจากการรีวิวซอร์สโค้ด

โครงสร้างของ Sparky ที่พบใน JoinMatch

  • ระหว่างค้นหาชื่อฟังก์ชันที่เกี่ยวข้องเพื่อหาเส้นทางเริ่มต้นการเข้าร่วมแมตช์ ก็พบฟังก์ชัน JoinMatch
  • JoinMatch เป็นฟังก์ชันยาวกว่า 200 บรรทัด และบริเวณท้ายฟังก์ชันพบการเรียก ConnectAndJoinMatch
    • ฟังก์ชันนี้ดูเหมือนจะรับข้อมูลการตั้งค่าแมตช์แล้วเชื่อมต่อไปยังเซิร์ฟเวอร์เกม
  • ในโฟลว์โค้ดเดียวกันมีการแตกแขนงตาม MatchType.NPE และ MatchType.Familiar
    • NPE คาดว่าเป็นแมตช์สายบทสอนสำหรับประสบการณ์ผู้เล่นใหม่
    • Familiar คือแมตช์บอทมาตรฐาน
  • ลอจิกที่ถูกเรียกในแขนงนี้เชื่อมโยงกับ Sparky คู่ต่อสู้บอทของ MTGA
    • Sparky คือคู่ต่อสู้เชิงมาสคอตของ MTGA ที่ใช้ในบทสอนและการเล่นกับบอท
    • ในแมตช์บอท ลอจิกของบอทจะรันอยู่ภายในไคลเอนต์เกมบนเครื่องเดียวกัน

บอทภายในเครื่องและ HeadlessClient

  • ตัวจัดการลอจิกจริงของบอทอยู่ในคลาส HeadlessClient
  • HeadlessClient คือ headless client ที่ไม่เรนเดอร์กระดานเกม แต่เชื่อมต่อเซิร์ฟเวอร์และเล่นเกมได้
  • ไคลเอนต์บอทที่สร้างขึ้นในเครื่องจะใช้ข้อมูลยืนยันตัวตนผู้ใช้ชุดเดียวกับไคลเอนต์เกม
    • PersonaID ที่ทำหน้าที่เป็นรหัสผู้ใช้
    • JSON web token ที่เกมมอบให้หลังล็อกอิน
  • ในแมตช์บอท โครงสร้างนี้ทำให้ไคลเอนต์เดียวกันเชื่อมต่อได้เหมือนอยู่ทั้งสองฝั่งของแมตช์ และเซิร์ฟเวอร์ก็ไม่มองว่าเป็นปัญหา
  • seat ถูกใช้เป็นวิธีแยกว่าผู้เล่นเป็นฝ่ายใดในเกม
    • ในแมตช์บอท สามารถเติมคนละ seat ได้ด้วยข้อมูลยืนยันตัวตนชุดเดียวกัน

วิธีเข้ายึดแมตช์ปกติ

  • มีการทดสอบว่าสามารถนำลอจิกของแมตช์บอทไปใช้กับแมตช์ปกติเพื่อเชื่อมต่อทั้งสอง seat ได้หรือไม่
  • ข้อมูลที่ต้องใช้ดึงมาจากอ็อบเจ็กต์เกมในรันไทม์
    • การตั้งค่าแมตช์ปัจจุบัน
    • โฮสต์และพอร์ตของเซิร์ฟเวอร์แมตช์
    • controllerFabricUri
    • matchId
    • PersonaID
    • Jwt
    • ฐานข้อมูลการ์ด
    • ตัวจัดการแมตช์
    • ระบบค้นหาแอสเซ็ต
  • คำนวณ seat ของคู่ต่อสู้จาก seat ของตัวเอง
    • ในโค้ดใช้ man.LocalPlayerSeatId % 2U + 1U เพื่อหาอีก seat
  • ใช้ UnityFamiliar.SpawnFamiliar_DEBUG(...) เพื่อเชื่อมบอทเข้ากับ seat ของคู่ต่อสู้
  • จากนั้นหาอ็อบเจ็กต์ UnityFamiliar ที่สร้างขึ้น แล้วเรียก cheatbot.Client.Gre.ConcedeGame() เพื่อบังคับยอมแพ้ทันที

ผลลัพธ์และแพตช์

  • วิธีนี้ใช้งานได้แม้ในแมตช์ปกติ
    • ใช้ได้แม้คู่ต่อสู้จะเชื่อมต่ออยู่แล้วและเกมกำลังดำเนินอยู่
    • เพราะเป็นเกมแบบแมตช์เมกกิง จึงได้รับรางวัลเหมือนชนะผู้เล่นจริง
  • แก่นของช่องโหว่อยู่ที่เซิร์ฟเวอร์แมตช์ปกติยอมให้ทั้งสอง seat เชื่อมต่อด้วยบัญชีและ JWT เดียวกัน
  • หลังจากนั้นเซิร์ฟเวอร์ก็ถูกแพตช์ไม่ให้ ทั้งสอง seat ใช้บัญชีและ JWT เดียวกัน ในเกมแบบแมตช์เมกกิงได้อีก
  • โค้ด InstaWin ในภาคผนวกเป็น Unity MonoBehaviour ที่สร้างปุ่ม GUI และเมื่อกดปุ่มจะรวบรวมข้อมูลแมตช์ปัจจุบัน แนบบอทเข้ากับ seat ของคู่ต่อสู้ แล้วสั่งให้ยอมแพ้

1 ความคิดเห็น

 
GN⁺ 2023-12-06
ความคิดเห็นบน Hacker News
  • สิ่งที่ทำให้ผมเริ่มขุด Linux อย่างจริงจังครั้งแรก คือการใช้ ShowEQ สำหรับ EverQuest เพื่อส่องดูทราฟฟิกเครือข่าย
    ตอนนั้นทราฟฟิกไม่ได้เข้ารหัส และมีข้อมูลที่มีประโยชน์อยู่มาก ผมใช้ฮับทำสำเนาทราฟฟิกไปยังเครื่อง Linux เพื่อวาดแผนที่แบบเรียลไทม์ของโซน แสดงตำแหน่งมอนสเตอร์, NPC และผู้ใช้ รวมถึงแสดงแม้กระทั่ง loot ที่มอนสเตอร์มี ทำให้เลือกตีเฉพาะมอนสเตอร์บางตัวได้ ข้อดีคือเป็นวิธีแบบ passive จึงตรวจจับไม่ได้ และสุดท้าย SOE ก็รู้ตัวแล้วเริ่มเข้ารหัสทราฟฟิก

    • สุดท้ายข้อมูลก็ต้องถูกถอดรหัสเพื่ออ่านอยู่ดี จึงลงเอยด้วยการ reverse engineer ไคลเอนต์เพื่อหาวิธีถอดรหัสแบบเรียลไทม์
      จากนั้นอีกฝ่ายก็เริ่มใช้ลายเซ็นแบบอิงคีย์ แล้วเราก็พยายามขโมยคีย์จากไคลเอนต์อีกครั้งเพื่อเจาะการเข้ารหัส ต่อมาพอมีระบบป้องกันการโกงเข้ามา เกมแมวจับหนู ก็เริ่มขึ้น
    • ตอนวัยรุ่นเคยลองทำอะไรคล้าย ๆ กันใน Dark Age of Camelot ด้วย และมันมีประโยชน์มากต่อการเรียนรู้ network sniffing, ความแตกต่างระหว่างฮับกับสวิตช์ และ Linux
      ถ้าถามว่าคุ้มพอจะได้เปรียบในเกมไหม ก็ไม่ ผมไม่ได้เล่นจริงจัง เลยใช้เวลาติดตั้ง 2 สัปดาห์ แล้วใช้จริงประมาณ 1 สัปดาห์เท่านั้น แต่ในฐานะประสบการณ์การเรียนรู้ถือว่ายอดเยี่ยม
    • จำได้ว่า ShowEQ ถูกใช้พิสูจน์ทฤษฎีและบั๊กหลายอย่างที่ Verant/Sony ปฏิเสธมาตลอด
      เช่น การมีอยู่ของ hell level, ข้อเท็จจริงที่ว่าไม่ใช่มนุษย์แต่เป็นฮาฟลิงที่ได้โบนัสประสบการณ์ และจริง ๆ แล้วมีความต่างของประสบการณ์ตามเผ่า/อาชีพ, รวมถึง Shaman alchemy ช่วงแรกที่เสียจริง ๆ และผมคิดว่านี่อาจเป็นสิ่งที่นำไปสู่ eqemulator.org ด้วย
    • สงสัยว่าการเข้ารหัสช่วยได้อย่างไร ไคลเอนต์ก็ต้องถอดรหัสอยู่ดี ดังนั้นก็แค่เกาะไปกับตรงนั้นไม่ได้หรือ?
    • ShowEQ ยังใช้งานได้อยู่ และยังมี MySEQ ที่เป็นแบบ Windows และอ่านหน่วยความจำด้วย
      ดูเหมือนเจ้าของ EQ ปัจจุบันจะไม่ได้ใส่ใจมากนัก เลยค่อนข้างโอเคที่จะใช้ อย่างไรก็ตาม ทั้งสองแอปไม่เคยแสดง loot ที่มอนสเตอร์มี ยกเว้นอุปกรณ์ที่มองเห็นได้ เมื่อเวลาผ่านไปข้อมูลบางอย่างก็เปลี่ยนไปด้วย เมื่อก่อนมีการส่งค่าพลังชีวิตมอนสเตอร์แบบแม่นยำ แต่ตอนนี้ส่งแค่เปอร์เซ็นต์
  • ผมไม่ค่อยเข้าใจส่วนที่ว่า “บอทที่เกือบสมบูรณ์ซึ่งเล่นเกมใด ๆ ของ Magic: The Gathering ได้ มีขนาดเล็กพอที่จะรันบนเครื่องโลคัล”
    ถ้า MTG AI หนักจนเป็นภาระสำหรับเครื่องลูกค้า ผมก็ไม่คิดว่าเขาจะเอาไปรันบนเซิร์ฟเวอร์เหมือนกัน การแข่งกับบอทในเกมไพ่โดยปกติไม่ได้คิดเงินต่อกระดาน ดังนั้นต้นทุนจะสูงขึ้น เซิร์ฟเวอร์ก็ไม่ใช่เวทมนตร์ ส่วนใหญ่ใช้ CPU x86 เหมือนเครื่องโลคัล และมักมี clock ต่ำกว่าเดสก์ท็อปด้วย ถ้าจะลดเวลาเทิร์นของบอทให้เร็วกว่าบนโลคัล ก็คงต้องใช้คอร์มากกว่าลูกค้าอย่างมาก แต่ถ้าจัดสรรคอร์ 8–16 คอร์ต่อผู้เล่น ตอนพีกที่มีผู้ใช้ออนไลน์พร้อมกันคงเป็นฝันร้าย ถ้า CPU player ไม่รองรับมัลติคอร์ การรันในเครื่องโลคัลก็ควรจะเร็วกว่าอยู่ดี

    • สิ่งที่พูดถึงตรงนี้ไม่ใช่ประสิทธิภาพการประมวลผล แต่เป็น การใช้หน่วยความจำ
      หมายความว่า rules engine ของบอทเล็กพอที่จะใส่ในหน่วยความจำของ iPhone หรืออุปกรณ์ Android รุ่นเก่าได้ ถ้าเป็นเซิร์ฟเวอร์ก็สามารถโหลด state machine หรือ rules engine ไว้ในหน่วยความจำจำนวนมากได้ และการรันคำขอเฉพาะหนึ่ง ๆ อาจแทบไม่ใช้พลังประมวลผลเลย
    • ถ้าเป็นเดสก์ท็อปก็ใช่ แต่อย่าลืมว่า MTGA รันบนมือถือได้ด้วย
    • MTG เป็นเกมที่มีระบบกฎซับซ้อนมาก
  • Daniel ขอแสดงความยินดีอีกครั้งที่ขึ้นหน้าแรก หลังจากบทความนี้ถูกโพสต์ ผมลองแฮ็ก MTGA และคุยกันเล็กน้อยบน GitHub ด้วย [0]
    สำหรับคนที่สนใจ ตอนนี้ผมกำลังทำไคลเอนต์ MTGA แบบไม่เป็นทางการที่แทบยังไม่มีฟีเจอร์อะไรอยู่แบบไม่ค่อยแอ็กทีฟ เป้าหมายคือทำให้การเล่น ranked game เป็นอัตโนมัติ และมีคู่ต่อสู้บอทที่แข็งแกร่งกว่า ช่วงหลังผมติดงานอื่น และยังมืดแปดด้านว่าจะทำ UI ที่ดีและดูชัดเจนอย่างไร เลยยากจะคาดเดาได้ด้วยซ้ำว่าเมื่อไรถึงจะมีประโยชน์ขั้นต่ำได้ นอกจากนี้ผมยังอยากฟังเรื่องการแฮ็กเกมจาก Daniel หรือคนอื่น ๆ ต่อไป เช่น หา bug แบบนี้ได้อย่างไร, ทำอย่างไรถึงไม่กังวลว่าจะโดนแบนหลังแฮ็ก, วิธีเปิดเผย bug อย่างที่ @aethros พูดถึง, และการวางโครงสร้างไคลเอนต์เกมไพ่แบบไม่เป็นทางการ
    [0] https://github.com/MayerDaniel/mayerdaniel.github.io/issues/...

  • การบอกว่าการทำ AI opponent สำหรับเกมซับซ้อนอย่าง MTG น่าจะมี overhead สูงมากนั้นยังเป็นการประเมินต่ำไปเยอะ
    เกมนี้แทบจะ Turing-complete และถึงไม่นับ infinite loop คนก็เอามันไปเล่นอะไรได้เยอะมากอยู่ดี แต่ผมคิดว่างานวิจัยด้านกลยุทธ์ AI คงมีอยู่มากแล้ว และในเมื่อผู้เขียนเป็นคนโพสต์เอง ชื่อเรื่องก็น่าจะใส่ “Show HN:” ได้

    • Show HN มีไว้สำหรับโปรเจกต์ที่คนอื่นเข้าไปลองจับต้องได้จริง ไม่ใช่บล็อกโพสต์: https://news.ycombinator.com/showhn.html
    • คำว่า “สามารถเข้ารหัส Turing machine ด้วยเกมได้” กับ “การเขียนโปรแกรมที่ทำ action ที่ถูกกฎหมายได้ในทุกสถานการณ์เป็นเรื่องยาก” ไม่ใช่เรื่องเดียวกันเลย
      สิ่งที่ยากสำหรับคนเขียนบอทดูเหมือนจะเป็นอย่างหลัง
    • มัน Turing-complete จริง ๆ: https://arxiv.org/abs/1904.09828
    • เมื่อชุดการ์ดใหม่หมุนเวียนเข้ามา เกมก็เปลี่ยนไปเรื่อย ๆ แต่เท่าที่รู้ ใน interaction บางแบบสามารถสร้าง infinite loop ได้ หรือเคยทำได้ในหลายช่วงเวลา
      เช่น การสร้างและฆ่า creature token ด้วยเอฟเฟกต์เข้า/ออกสนาม/untap เป็นต้น loop แบบนี้ก็ไม่ได้สร้างความเสียหายให้ฝ่ายใดฝ่ายหนึ่งเสมอไป
    • สงสัยว่ามีกลยุทธ์จริงที่เข้าใกล้ความซับซ้อนระดับนี้ไหม
      ผมไม่เคยเล่น MTG แต่ข้ออ้างนี้ดูเหมือนจะหมายความว่ามันเป็นไปได้ในเชิงเทคนิค ถ้าจงใจสร้างโครงสร้างที่มีสถานะ ไม่ใช่เพื่อเป้าหมายในการชนะ
  • การได้เล่น Old School Magic 93/94 ด้วยการ์ดจริงกับลูกชายเป็นเรื่องที่สนุกมาก
    ทุกปีจะไป Madrid เพื่อเข้าร่วมการแข่งขันชิงแชมป์โลก 7pts Singleton ปีนี้ช่วงฤดูร้อนลูกชายได้อันดับ 9 เลยภูมิใจมาก 7pts Singleton เป็นรูปแบบที่ยอดเยี่ยม เพราะทำเด็คได้หลากหลาย และให้เกมเพลย์ที่สมดุลในค่าใช้จ่ายที่ค่อนข้างไม่หนักเกินไป (https://7pts-singleton.com)

    • คงเรียกรูปแบบที่ Black Lotus, Ancestral Recall, Moxen ใช้ได้ตามกติกาว่า ราคาถูก ได้ยาก
      ถึงใน 7pts Singleton จะใช้ทั้งหมดไม่ได้ แต่แค่ใบเดียวก็มีราคาตั้งแต่หลายพันถึงหลายหมื่นดอลลาร์แล้ว อย่างไรก็ดี ดีใจที่ได้สนุกกับเกมกับลูกชาย และขอแสดงความยินดีที่ติดอันดับด้วย
  • ตรรกะเกมที่อยู่ฝั่งไคลเอนต์ล้วน ๆ เลยเหรอ สมัยก่อนตอนทำเกมเล็ก ๆ เคยมีบางครั้งที่ต้องใส่ตรรกะเกมไว้ในไคลเอนต์เพื่อให้ตอบสนองเร็ว แต่ก็ไม่ได้มีข้อห้ามอะไรที่บอกว่าอย่ารันตรรกะเดียวกันซ้ำบนเซิร์ฟเวอร์ เลยทำแบบนั้น
    ในเกมเรียลไทม์อย่าง FPS หรือ RTS อาจทำได้ยาก แต่สำหรับเกมการ์ดไม่มีข้อแก้ตัวเลย เกมการ์ดแบบนี้ไม่ควรส่งข้อมูลไปให้ไคลเอนต์มากกว่าข้อมูลที่ผู้เล่นจริงสามารถเห็นได้ เช่น อย่าส่งรายละเอียดไพ่ในมือของคู่ต่อสู้ ส่งแค่จำนวนใบก็พอ การกระทำที่ส่งไปยังเซิร์ฟเวอร์ก็ควรเป็นการกระทำเกี่ยวกับตัวเองเท่านั้น ดังนั้นจึงไม่ควรประกาศยอมแพ้แทนคู่ต่อสู้ได้ ถ้าพูดว่า “ยอมแพ้!” เซิร์ฟเวอร์ควรตีความว่านั่นคือฉันยอมแพ้

    • จากบทความถือได้ว่าเกมถูกเขียนไว้แบบนั้นเลย คือได้รับเฉพาะข้อมูลที่จำเป็นในจังหวะที่จำเป็น และส่งได้เฉพาะการกระทำของตัวเอง
      ช่องโหว่คือสามารถเปิดไคลเอนต์ตัวที่สองแล้วเชื่อมต่อเข้าเกมที่กำลังดำเนินอยู่ในที่นั่งของฝ่ายตรงข้ามได้ พอทำได้แล้วก็ส่งการกระทำของคู่ต่อสู้ได้ รวมถึงการยอมแพ้
    • ตามที่บทความระบุชัดเจน เกมเพลย์ทั้งหมดประมวลผลที่ ฝั่งเซิร์ฟเวอร์
      สิ่งที่ผู้เขียนใช้ประโยชน์ไม่ใช่ตรรกะเกมฝั่งไคลเอนต์ แต่เป็นปัญหาในโค้ดการอนุญาตสิทธิ์และการเข้าร่วมเกม คำว่า “ไม่ควรประกาศยอมแพ้แทนคู่ต่อสู้ได้” ก็คือการพูดซ้ำตรง ๆ ว่า exploit ที่ผู้เขียนพบทำงานอย่างไร
    • ในหนึ่งในสามส่วนแรกของบทความบอกไว้อย่างชัดเจนว่าเกมถูก implement แบบนั้น
  • ใน League of Legends เคยมี บั๊กหารด้วยศูนย์ ในชุดผสมระหว่างแชมเปียนบางตัวกับไอเท็มบางชิ้น ทำให้เซิร์ฟเวอร์เตะผู้เล่นทุกคนออกแล้ว crash
    เพราะผู้ที่ใช้ช่องโหว่ถูกเตะออกเป็นคนสุดท้าย ทีมนั้นจึงถูกนับว่าชนะ ส่วนทีมตรงข้ามได้รับ Loss Prevented แทนผลลัพธ์ปกติ

    • ถ้าฝ่ายตรงข้ามไม่ได้รับผลลัพธ์ปกติและไม่ถูกนับว่าแพ้ ทีมที่ชนะก็ไม่ควรได้รับชัยชนะเช่นกัน
  • บทความนี้ดีตรงที่เข้าถึงง่ายแต่มีรายละเอียดที่ลึกซึ้ง
    แต่ไม่เข้าใจกรณีที่เชื่อมต่อบอทระหว่างการแข่งขันจริง ทำไมเกมถึงอนุญาตให้เข้าร่วมกลางแมตช์ได้ และทำไมเมื่อบอทยอมแพ้จึงถูกนับเป็นการยอมแพ้ของคู่ต่อสู้? ถ้ากำลังสร้างเกมแบบ 3 คน ต่อให้ผู้เล่นคนที่ 3 ยอมแพ้ ก็ไม่ควรทำให้ผู้เล่นคนที่ 2 ยอมแพ้ไปด้วย

    • มันไม่ได้กลายเป็นเกม 3 คน แต่ยังคงเป็น เกม 2 คน ต่อไป
      โค้ดค้นหาดัชนีที่นั่งของบัญชีเรา แล้วให้บอทเข้าร่วมด้วยดัชนีที่นั่งอีกตำแหน่งหนึ่ง ปัญหาคือไม่มีการตรวจสอบว่าผู้ใช้ที่เข้าร่วมนั้นเป็นผู้ใช้ที่ถูกต้องซึ่งควรอยู่ในที่นั่งนั้นหรือไม่ อาจคิดได้ว่าควรไม่อนุญาตให้เชื่อมต่อซ้ำกับที่นั่งที่เชื่อมต่ออยู่แล้ว แต่ถ้าเป็นเกมที่รองรับมือถือด้วย ก็คงอยากตั้ง timeout การหลุดการเชื่อมต่อให้ค่อนข้างนาน เพราะไม่อยากบล็อกผู้เล่นที่หลุดไปชั่วครู่แล้วกลับมาเชื่อมต่อใหม่ก่อนที่ timeout จะรับรู้ว่า connection เดิมตายไปแล้ว เคยเห็นเกมอื่น ๆ เวลา reconnect ก็ขึ้นว่า “ไม่สามารถเข้าร่วมเกมที่กำลังดำเนินอยู่ได้” ประมาณ 10 วินาที แล้วค่อยเชื่อมต่อกลับได้ภายหลัง ถ้าเปรียบเทียบก็เหมือนมีคนโผล่มาที่ทัวร์นาเมนต์ MTG ในร้านการ์ดแถวบ้าน ผลักใครบางคนออกจากเก้าอี้แล้วนั่งแทน พร้อมตะโกนว่า “ขอยอมแพ้!” แล้วกรรมการยอมรับว่าผู้เล่น B ถอนตัว เพราะคนที่นั่งอยู่บนเก้าอี้นั้นเป็นคนประกาศ
      1. น่าจะเป็นวิธีจัดการการเชื่อมต่อใหม่หลังหลุด connection โดยเป็นการปิด connection เก่า
      2. หลังจากบอทแทนที่ผู้เล่น 2 แล้วส่งการยอมแพ้ เซิร์ฟเวอร์ก็บันทึกสิ่งนั้นเป็นการยอมแพ้ของผู้เล่น 2
    • MTG: Arena ไม่อนุญาตให้เล่น 3 คน ดังนั้นบอทจึง แทรกเข้าไป ในที่นั่งของคู่ต่อสู้
      จึงดูเหมือนว่าสามารถยอมแพ้แทนคู่ต่อสู้ได้ นักพัฒนาอาจไม่ได้ตรวจ เพราะไม่คิดว่าจะมีใครมีเหตุผลต้องพยายามทำแบบนั้น
  • ทำให้นึกถึงสมัย Diablo 2 ที่สามารถใช้แพ็กเก็ตเชื่อมต่อเดิมซ้ำเพื่อให้ ตัวละครบนเซิร์ฟเวอร์เปิด (LAN) เข้าเชื่อมต่อกับเซิร์ฟเวอร์อินเทอร์เน็ต bnet อย่างเป็นทางการได้
    ข้อมูลของเซิร์ฟเวอร์เปิดถูกเก็บไว้ในเครื่องทั้งหมด จึงสามารถสร้างไอเท็มสารพัดแบบที่ปกติไม่ควรมีอยู่ได้ และเซิร์ฟเวอร์ทางการก็ยอมรับมันด้วย

  • เพิ่งกลับมาเริ่มเล่น MTG อีกครั้งผ่าน MTGA ช่วงไม่นานนี้ เป็นเกม Unity และไม่ใช่ il2cpp เลยลอง decompile ดูอย่างรวดเร็ว ถึงจะเป็น il2cpp ก็ไม่น่าจะป้องกันได้มากนัก และเจอของที่น่าสนใจอยู่พอสมควร
    มีอย่างเช่น key สำหรับ build ของ Epic Launcher หรือ API ที่ไม่ได้ทำเอกสารไว้ ไม่ได้อยากเอาไปใช้โกง แค่อยากให้มีประวัติการต่อสู้ เช่น ชนะหรือแพ้แมตช์ไหนบ้าง หรือฟีเจอร์ย้อนดูสถานะสนามของเกมที่จบไปแล้ว จะลองดูบทความนี้ด้วย และหวังว่าจะถูก patch เร็ว ๆ

    • ช่องโหว่นี้ถูก patch ไปแล้วก่อนเขียนบทความ และได้เปิดเผยต่อ MTG แล้ว
      ถ้าอยากดูประวัติ ลองดู https://untapped.gg/en ได้ เคยคุยกับฝั่งนั้นเล็กน้อย และโดยพื้นฐานแล้วเขาทำสิ่งที่ต้องการได้ ข้อมูลส่วนใหญ่ดึงมาจาก debug log ของ MTG ในไดเรกทอรีแอปพลิเคชัน MTGA ดังนั้นถ้าต้องการก็ทำ tracker เองได้ เว็บไซต์ก็อธิบายเรื่องนี้ไว้เช่นกัน: https://help.hearthsim.net/en/articles/3620440-how-do-i-supp...
    • https://www.17lands.com/ เก็บสถิติแพ้ชนะของเกม Limited และยังบันทึกประวัติเกมแบบราย turn ทั้งใน Limited และ Constructed ด้วย เคยร่วมเป็น contributor
    • สำหรับการเก็บข้อมูลการเล่น เข้าใจว่า https://mtgaassistant.net/ เป็นตัวที่ใช้กันค่อนข้างแพร่หลายที่สุด
    • เข้าใจว่าฟีเจอร์นี้มีอยู่แล้ว น่าจะเป็น player log
      จำได้ว่ามีแอปหลายตัวที่ใช้ log นั้นในการติดตาม