Debug iOS Application ด้วย LLDB และ Debugserver 101

โดย admin

4 นาที
แชร์
Blog Thumbnail

Debug iOS Application ด้วย LLDB และ Debugserver 101

By Permpoon Phokakulkanon,

Penetration Tester Team, Datafarm Company Limited

ในโลกของ Reverse Engineering และ Mobile Security Research การ “Debug” แอปพลิเคชันถือเป็นหนึ่งในทักษะที่สำคัญที่สุด โดยเฉพาะบนระบบปฏิบัติการของ Apple อย่าง iOS และ macOS ที่มีระบบป้องกันหลายชั้น ทั้ง Code Signing, Sandbox และ ASLR เมื่อพูดถึงเครื่องมือ Debug ระดับ Low-Level บน Ecosystem ของ Apple ชื่อที่แทบทุกคนต้องเจอคือ “LLDB” และ “debugserver” สององค์ประกอบนี้เป็นหัวใจสำคัญของการวิเคราะห์แอปพลิเคชัน การแกะ logic ภายใน การตรวจสอบ Runtime Behavior รวมถึงการทำ Dynamic Analysis ระหว่างการทดสอบความปลอดภัยของ Mobile Application

บทความนี้ผมจะพาทุกท่านไปลองติดตั้งและใช้งาน LLDB และ debugserver เพื่อทำความเข้าใจหลักการทำงานของระบบ Debugging บน iOS ในเบื้องต้น รวมถึงการ Attach เข้า Process การควบคุม Execution Flow และการตรวจสอบการทำงานของแอประหว่าง Runtime ซึ่งเป็นพื้นฐานสำคัญทั้งในด้าน Reverse Engineering และ Mobile Security Testing ครับ

ก่อนอื่นเรามาทำความรู้จัก LLDB, debugserver และเรื่องของ Entitlements กันก่อนครับ เริ่มจาก!!!

LLDB คืออะไร

LLDB คือ Debugger ที่พัฒนาในโครงการ LLVM ใช้สำหรับวิเคราะห์และควบคุมการทำงานของแอปพลิเคชันระหว่างการทำงาน

พูดง่าย ๆ คือ LLDB เป็นโปรแกรมที่ช่วยให้เราสามารถ:

  • หยุดการทำงานของโปรแกรมชั่วคราว
  • อ่านค่า Memory
  • ดู Register CPU
  • แก้ไขค่า Runtime
  • Inspect Object
  • วิเคราะห์ Behavior ของแอประหว่างการทำงาน

Debugserver คืออะไร

Debugserver คือ Process ฝั่ง Target Device ที่ทำหน้าที่เป็น “ตัวกลาง” ระหว่าง LLDB กับแอปพลิเคชัน ที่ถูก Debug ซึ่ง LLDB ทำหน้าที่เป็น Client ส่วน Debugserver ทำหน้าที่เป็น Server

เมื่อ LLDB ต้องการ:

  • Attach Process
  • Read Memory
  • Set Breakpoint

คำสั่งจะถูกส่งไปยัง Debugserver ก่อน แล้ว Debugserver จะสื่อสารกับ kernel ของ iOS/macOS อีกที

Entitlements คืออะไร

Entitlements คือกลไกความปลอดภัยบน iOS และ macOS ที่ใช้กำหนดว่าแอปพลิเคชัน หรือ Process ใดมีสิทธิ์ใช้งานความสามารถพิเศษของระบบ โดยข้อมูล Entitlement จะถูกฝังอยู่ใน Code Signature ของแอป เปรียบเสมือน “ใบอนุญาต” สำหรับเข้าถึงความสามารถระดับระบบบางอย่าง

ตัวอย่าง Entitlement ด้านการ Debug ได้แก่ com.apple.security.get-task-allow, task_for_pid-allow เป็นต้น

ซึ่งอนุญาตให้ Debugger สามารถ Attach เข้า Process อื่น อ่าน Memory หรือควบคุมการทำงานของแอปพลิเคชันได้ครับ

เรามาเริ่มกันเลยครับ

ขั้นตอนแรกเรามาติดตั้ง Debugserver กันก่อนครับโดยเริ่มจากการ Copy Debugserver จากเครื่อง Macbook ของเราก่อน ซึ่งปกติแล้ว Apple ไม่ได้ใส่ Debugserver ไว้ถาวรในเครื่องมือถือ เวลาเราจะต่อ iPhone กับ Xcode แล้วเปิด debug ::> Xcode จะ mount ไฟล์ “DeveloperDiskImage.dmg” เข้า iPhone

เราจะใช้คำสั่ง “hdiutil mount /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/16.0/DeveloperDiskImage.dmg”

หลังจากที่ใช้คำสั่ง mount แล้วเราจะได้ Path “/Volumes/DeveloperDiskImage” มา จากนั้นเราก็เข้าไปเอาไฟล์ที่ Path “/Volumes/DeveloperDiskImage/usr/bin” โดย Copy ไฟล์ Debugserver ไปไว้โฟลเดอร์ที่เราต้องการ

มาตรวจสอบไฟล์ Debugserver ของเราสะหน่อยว่ามีสิทธิ์ Entitlements อะไรบ้างโดยใช้เครื่องมือ jtool2 โดยจากรูปหากใช้คำสั่ง “ARCH=arm64 jtool2 — ent debugserver” เราจะเห็นไฟล์ XML ที่มีสิทธิ์ Entitlements อยู่

สิ่งที่เราต้องทำคือนำไฟล์ Debugserver ไปไว้ที่อุปกรณ์ iOS ที่เราต้องการ Debug โดยใช้เครื่องมือ scp ด้วยคำสั่ง “scp debugserver [email protected]:/private/var”

จะเห็นว่าที่อุปกรณ์ iOS ของเราที่ Path “/private/var” จะมีไฟล์ “debugserver” แล้ว

เริ่ม Debug กันเลยครับ โดยการเริ่มด้วยการรันคำสั่ง “ps aux | grep -i “Frida” เพื่อหา Path ที่เก็บแอปพลิเคชัน ที่เราต้องการ Debug กันก่อนเลยและตามด้วยคำสั่ง “./debugserver 0.0.0.0:6666 — waitfor=”/var/containers/Bundle/Application/CE63769B-CEFA-4FF9-B351–21CE166F99FC/Frida Labs.app/Frida Labs” เพื่อ Debug แอปพลิเคชันที่เราต้องการ

ซึ่งผลที่ได้จะพบ Process Failed เนื่องจากไฟล์ “debugserver” ที่เรา Copy มานั้นมีสิทธิ์ Entitlements ไม่เพียงพอทำให้เราจำเป็นต้องเพิ่มสิทธิ์ Entitlements เข้าไปที่ไฟล์ “debugserver” โดยผมได้ใช้เครื่องมือ nano ในการสร้างไฟล์ ent.xml เพื่อสร้างสิทธิ์ Entitlements ให้ไฟล์ “debugserver” ใหม่ดังรูปครับ

จากนั้นก่อนการใช้งานไฟล์ “debugserver” เราต้องทำการ sign “ent.xml” ให้ไฟล์ “debugserver” ใหม่ด้วยคำสั่ง “ldid -Sent.xml debugserver” และทำการตรวจสอบอีกครั้งว่าไฟล์ “ent.xml” ถูก sign แล้วด้วยคั่ง “ldid -e debugserver” ซึ่งผลก็คือไฟล์ “debugserver” มีสิทธิ์ Entitlements ตามที่เราต้องการแล้ว

เริ่ม Debug กันอีกครั้งครับด้วยคำสั่งเดิม “./debugserver 0.0.0.0:6666 — waitfor=”/var/containers/Bundle/Application/CE63769B-CEFA-4FF9-B351–21CE166F99FC/Frida Labs.app/Frida Labs”

สำเร็จครับ!!! “debugserver” ทำงานแล้วพร้อมให้เรา Debug จากภาพจะเห็นว่าเครื่องมือถือเปิด Listening ที่ Port “6666” เพื่อรอ lldb เชื่อมต่อมา

โดยรอเพียงเรากดเปิด Application ก่อนและรัน lldb ที่เครื่อง Macbook ซึ่ง lldb จะถูกติดตั้งมาพร้อมกับตอนที่เรา Install Xcode ด้วยคำสั่ง “lldb” >> “process connect connect://172.20.10.5:6666” โดยใช้ IP เครื่องมือถือและ Port ที่เราเปิดไว้ที่เครื่องมือถือ ผลที่ได้เราก็จะสามารถหยุด Process ได้แล้วตามที่เราต้องการ

เรามาดูตัวอย่างการใช้งานกันครับโดยผมจะลองยกตัวอย่าง Lab “DVIA-v2” ข้อ “Application Patching”โดยสามารถ Download แอปพลิเคชัน ได้ที่ URL “https://github.com/prateek147/dvia-v2” ซึ่งเราจะลอง Patching ข้อความจาก “I Love Google” เป็น “I Love Apple” ในจังหวะที่เรากดปุ่ม “Show Alert” ด้วย lldb กันครับ

เริ่มด้วยการค้นหาข้อความ “I Love Google” ที่ Executable ไฟล์ของแอปพลิเคชัน “DVIA-v2” ด้วยโปรแกรม Hopper

ซึ่งจะพบว่าข้อความดังกล่าวอยู่ที่ Address “0x10015708c” โดยเป้าหมายของเราคือต้องการจะ Break point ที่ Address นี้

แน่นอนเรายังไม่สามารถ Break point ที่ Address นี้ได้โดยตรงเนื่องจาก iOS มีความปลอดภัยที่ทำให้ตำแหน่งของ Code และข้อมูลใน Memory “สุ่มทุกครั้งที่รันแอปพลิเคชัน” นั้นคือ ASLR ทำให้เราต้องคำนวณหา ASLR Slide ก่อนด้วยคำสั่ง “image dump sections DVIA-v2”

ผลที่ได้เราจะพบค่า Static Base “0x0000000100000000” และ Runtime Base “0x0000000104280000”

นำทั้งสองค่ามาลบกันก็จะได้ค่า ASLR Slide หรือ offset ที่ระบบเลื่อน Mach-O ตอนโหลดเข้า memory ด้วยเครื่องมือ python3 คำสั่ง “hex(0x0000000100324000–0x0000000100000000)” ค่า ASLR Slide ที่ได้ก็คือ “0x4280000”

นำค่า ASLR Slide ที่ได้มาบวกกับ Address ที่เราต้องการ Break point ด้วยคำสั่ง “breakpoint set — address 0x4280000+0x10015708c” ตามด้วยคำสั่ง “c” ให้แอปพลิเคชัน Process ต่อได้เลย จากนั้นเราก็ไปกดที่ปุ่ม “Show Alert” จะเห็นว่าแอปพลิเคชัน Break Point แล้วโดยยังไม่ทำการแสดง Alert Box ขึ้นมา

รันคำสั่ง “disassemble” ดูจะเห็นว่า Break Point หยุดตรง Address ที่เราต้องการ ณ จุดที่ 1

และจุดที่สอง ที่จะ Break Point คือ Address “0x1043d709c” เพราะเป็นฟังก์ชั่นแสดง Alert Box ด้วยข้อความ “I Love Google” เช่นเคยเราก็จะใช้คำสั่ง Break Point แบบย่อ “b 0x1043d709c” ตามด้วยคำสั่ง “c” ผลที่ได้จะเห็นว่า Break Point ขยับมาจุดที่สองตามที่เราต้องการ

ลองอ่านค่าใน Register x0 ที่ฟังก์ชัน Return ด้วยคำสั่ง “register read x0” โดยจะเห็นข้อความ “I Love Google”

ทำการอ่านข้อมูลจาก Memory Address ที่อยู่ใน register x0 ด้วยคำสั่ง “memory read -l 1 $x0”

(memory read = อ่าน memory, -l 1 = อ่านทีละ 1 byte, $x0 = ใช้ค่า address จาก register x0) ผลที่ได้เราก็จะพบ Address ของตัวอักษรที่เราจะทำการแก้ไข

เริ่มการ Patch ได้เลยค่อย ๆ ทำไปทีละตัวอักษร ด้วยคำสั่ง “memory write 0x10460641d -s 1 0x41”

(memory write = เขียนข้อมูลลง memory, 0x10460641d = address ที่ต้องการแก้ ,-s 1 = เขียนขนาด 1 byte , 0x41 = ค่าที่จะเขียน)

เหลือตัวสุดท้ายก็ Patch ให้เป็นค่า “0x00” ซะเลย!!! จากนั้นรันคำสั่ง “c” ปล่อย Process ให้ทำงานต่อ ผลที่ได้ก็จะพบว่าข้อความ “I love Google” เปลี่ยนเป็น “I Love Apple” แล้วเป็นอันสำเร็จครับผม!!!

สุดท้ายแล้ว การ Debug ด้วย LLDB และ Debugserver ไม่ได้เป็นแค่เรื่องของการ “แกะแอป” หรือดู Assembly เท่านั้น แต่มันคือการเข้าใจว่าแอปพลิเคชันหนึ่งตัวทำงานยังไง ตั้งแต่ Memory, Register ไปจนถึง Flow ภายในระบบ หลายครั้งสิ่งที่เราเห็นจาก Source Code กับสิ่งที่เกิดขึ้นตอน Runtime อาจต่างกันมาก และนี่คือเหตุผลที่เครื่องมือพวกนี้ยังสำคัญมากในสาย Reverse Engineering และ Mobile Security Testing ซึ่งผมหวังว่าบทความนี้จะช่วยให้หลายคนเข้าใจภาพรวมของการ Debug ระดับ Low-Level ได้มากขึ้น ไม่มากก็น้อย แล้วพบกันใหม่ในบทความหน้าครับ

แชร์
กลับไปด้านบน

บทความที่เกี่ยวข้อง

อัปเดตข้อมูลด้านไซเบอร์ ทุกสัปดาห์
รับข่าวสารความรู้เชิงลึกเกี่ยวกับความปลอดภัยไซเบอร์จากดาต้าฟาร์มก่อนใคร

ฟีเจอร์นี้จะเปิดให้ใช้งานเร็ว ๆ นี้ โปรดติดตาม

ส่งสัปดาห์ละ 1 ครั้ง ไม่มีสแปม ยกเลิกการรับข่าวสารได้ทุกเมื่อ