← Back to list

[Binary Exploit — EP.1] Introduction to Operating System for Binary Exploitation & Pwnable

การที่เราจะศึกษาเรื่อง Binary Exploitation & Pwnable เราจำเป็นต้องเข้าใจการทำงานของระบบปฏิบัติการหรือไม่ ?

Pattharadanai Sanitjairak · 2026-07-10 15:06 · 4 claps · 8.2 min read
#binary-exploitation #pwnable #operating-systems #cybersecurity #penetration-testing
Open on Medium ↗
Wiki topics: 🔒 · Cybersecurity

[Binary Exploit — EP.1] Introduction to Operating System for Binary Exploitation & Pwnable

การที่เราจะศึกษาเรื่อง Binary Exploitation & Pwnable เราจำเป็นต้องเข้าใจการทำงานของระบบปฏิบัติการหรือไม่ ?

ถ้าหากเราเคยเข้าแข่งขัน CTF (Capture the Flag) บ่อย ๆ ก็มักจะคุ้นเคยกับโจทย์ในหมวด Binary Exploitation, Reverse Engineering และ Pwnable ซึ่งถือเป็นหัวข้อที่ค่อนข้าง Specialized เมื่อเทียบกับสาย Web Application หรือ Mobile (และผู้เขียนก็เพิ่งเริ่มเรียนเรื่องนี้เหมือนกัน ไม่เคยแก้ได้สักข้อเลย😅)

อย่างไรก็ตาม CTF ก็มักจะเป็นการแข่งขันที่โจทย์ถูกออกแบบมาให้มีคำตอบเสมอ ยิ่งไปกว่านั้น Engagement ที่เรามักจะได้รับในฐานะคนทำงานอาชีพ Penetration Tester หรือ Cybersecurity Consultant ส่วนใหญ่ก็มักเกี่ยวข้องกับ Web, Mobile, Network หรือบางครั้งอาจมี Red Teaming เข้ามาผสมบ้าง แต่แทบไม่ค่อยมีโอกาสได้เจองานด้าน Binary Exploitation โดยตรง แล้วทักษะที่ได้จากการเล่น CTF ในสายเหล่านี้ สามารถนำไปใช้งานจริงได้มากน้อยแค่ไหนกันนะ?

แต่เนื่องด้วยความยากของหัวข้อนี้ การที่จะมา Discuss ตรง ๆ ไม่ว่าจะเป็นเรื่องประเภทของงานหรือเทคนิคในการโจมตีต่าง ๆ อาจจะพูดยากมาก ๆ หากเทียบกับหัวข้ออื่นๆ เช่น Web Application Exploitation หรือ Red Teaming ที่มักจะพบเจอในงานจริงเป็นปกติอยู่แล้ว

ดังนั้น เราจะเก็บคำถามเหล่านั้นไว้ก่อน แต่จะค่อย ๆ พยายามปูพื้นฐานทีละนิด เพื่อให้สามารถทำความเข้าใจและพูดคุยเกี่ยวกับหัวข้อนี้ได้มากขึ้น โดยเฉพาะสำหรับคนที่สนใจและเพิ่งเริ่มศึกษาในด้านนี้

ขอขอบคุณภาพจาก Cymulate

ขอขอบคุณภาพจาก Cymulate

Binary Program คืออะไร

Binary Program คือโปรแกรมหรือ Software ที่ต้องติดตั้งหรือเข้าใช้งานบนเครื่องของผู้ใช้งาน และอาศัยทรัพยากรของเครื่องนั้นเป็นหลักในการทำงาน โดยอาจมี Graphical User Interface (GUI) หรือไม่มีก็ได้ เช่นต้องรันผ่าน Terminal เท่านั้น และตัว Executable File จะเป็นไฟล์ที่อยู่ในรูปแบบของ Binary ที่ถูก Compile ไปแล้ว และต้องให้ Operating System มารันเท่านั้น ยกตัวอย่างก็เช่น

  • Desktop Application (Thick Client) คือโปรแกรมที่ผู้ใช้งานต้องติดตั้งและใช้งานบนเครื่องของตนเอง เช่น Microsoft Office Suite, Web Browser, โปรแกรม ERP, เกมต่างๆ หรือโปรแกรม Multimedia Processing ต่าง ๆ ซึ่งมักจะมีการทำ Graphical User Interface (GUI) ออกมาเพื่อให้ผู้ใช้งานทั่วๆ ไปสามารถใช้งานได้อย่างสะดวกและมีประสิทธิภาพ แต่ถ้าหากสนใจการทดสอบเจาะระบบ Application ประเภทนี้ ก็สามารถเริ่มต้นศึกษาได้จากบทความนี้ของผู้เขียนได้เลย
  • Non-GUI Application คือ Software ที่ไม่มีหน้าต่างสำหรับโต้ตอบกับผู้ใช้งาน แต่ทำงานผ่าน Terminal เช่น Bash หรือ Command Prompt ตัวอย่างได้แก่ git, curl และ grep แม้จะดูเหมือนเป็นเพียงคำสั่ง แต่เบื้องหลังแล้วคำสั่งเหล่านี้ก็คือไฟล์ Binary ที่สามารถเป็นเป้าหมายในการวิเคราะห์หรือทดสอบความปลอดภัยได้เช่นกัน

เมื่อรันคำสั่ง curl บน Command Prompt ระบบจะค้นหาและเรียกใช้งานไฟล์ Binary ของโปรแกรม เช่น C:\Windows\System32\curl.exe

เมื่อรันคำสั่ง curl บน Command Prompt ระบบจะค้นหาและเรียกใช้งานไฟล์ Binary ของโปรแกรม เช่น C:\Windows\System32\curl.exe

  • Network Server Application คือ Software ที่จะทำการให้บริการ (Server) บางอย่างแก่ Client หรือ Computer เครื่องอื่นๆ ผ่านระบบเครือข่าย ไม่ว่าจะเป็นภายในหรือภายนอกก็ตาม และเมื่อเริ่มทำงานแล้วมักจะมีการสร้าง Process เพิ่มเติมเพื่อรองรับการให้บริการ อาจจะเป็น GUI ให้เจ้าของ Server สามารถ Configure ค่าต่างๆ ของ Service หรืออาจจะเป็น Daemon Process ที่คอยจัดการงานต่างๆ อยู่เบื้องหลัง ตัวอย่างเช่น XAMPP ที่ใช้เปิดบริการ Apache และ MySQL หรือ Sync Breeze Enterprise ที่ใช้แชร์ไฟล์ภายในเครือข่าย
  • Mobile Application ก็ถือว่าเป็น Binary Program ได้เช่นเดียวกัน เพราะตัวแอปทำงานอยู่บนอุปกรณ์ของผู้ใช้งานและใช้ทรัพยากรของเครื่อง ไม่ว่าจะเป็นแอปธนาคาร เกม หรือแอปทั่วไปบนสมาร์ตโฟน

ลักษณะ Program ที่ว่ามานี้แตกต่างจาก Software as a Service (SaaS) หรือ Web Application ตรงที่ว่า Logic หลักของ Application จะทำงานอยู่บนฝั่ง Server และใช้ทรัพยากรของผู้ให้บริการ (Service Provider) ไม่ใช่ของเครื่องของผู้ใช้งานแต่อย่างใด ดังนั้นก่อนจะพูดถึงการโจมตีหรือการวิเคราะห์ Binary เราจำเป็นต้องแยกความแตกต่างของสองรูปแบบนี้ให้ออกก่อน

แล้วการโจมตีแบบไหนถึงเรียกได้ว่าเป็น Binary Exploitation & Pwnable

Pwnable หรือ Binary Exploitation เป็นหนึ่งในเทคนิคการโจมตี Binary Application หรือ Program ที่มุ่งเน้นการโจมตีตัว Compiled Binary โดยตรง เพื่อบังคับให้โปรแกรมทำงานในลักษณะที่ผู้โจมตีต้องการ เช่น การ Bypass กลไกด้านความปลอดภัย หรือการทำให้เกิด Remote Code Execution (RCE)

ดังนั้นก็จะมีคำถามต่อมาอีกว่า แล้วถ้าเป็นกรณีที่ตัว Program หรือไฟล์ .exe ของมัน มีหน้า GUI ให้กรอกข้อมูล และสามารถใส่อักขระอย่าง ; หรือ | จนเกิด Command Injection ได้ แบบนี้จะถือเป็น Binary Exploitation หรือไม่ คำตอบคือ ไม่ใช่ เพราะการโจมตีลักษณะนี้เป็นการโจมตี Logic ของโปรแกรมที่นำข้อมูลจากผู้ใช้ไปสร้างคำสั่งของระบบปฏิบัติการอย่างไม่ปลอดภัย ไม่ใช่การโจมตีตัว Binary โดยตรง

ขอขอบคุณภาพจาก SentinelOne — Binary Program ที่ชื่อว่า AnythingLLM สามารถใช้ช่องโหว่ Cross-Site Scripting (XSS) ในการทำ Remote Code Execution (RCE) ได้ แบบนี้เรียกว่า Binary Exploitation หรือเปล่า? ไม่!

ขอขอบคุณภาพจาก SentinelOne — Binary Program ที่ชื่อว่า AnythingLLM สามารถใช้ช่องโหว่ Cross-Site Scripting (XSS) ในการทำ Remote Code Execution (RCE) ได้ แบบนี้เรียกว่า Binary Exploitation หรือเปล่า? ไม่!

Binary Exploitation จะเน้นการอาศัยข้อผิดพลาดของตัว Binary ที่ทำให้ผู้โจมตีสามารถควบคุมทรัพยากรที่ Operating System จัดสรรให้โปรแกรมนั้นๆ ได้ เช่น Memory (Stack, Heap, RAM), Process & Thread, CPU Registers หรือ I/O ก่อนนำการควบคุมดังกล่าวไปใช้เพื่อทำสิ่งที่ต้องการ เช่น การยึดการทำงานของโปรแกรมหรือทำให้เกิด RCE

ด้วยเหตุนี้ การศึกษาด้าน Binary Exploitation จึงแทบจะหลีกเลี่ยงไม่ได้ที่จะต้องมีพื้นฐานเกี่ยวกับ Computer Architecture และ Operating System โดยเฉพาะเรื่อง Process, Virtual Memory, Stack, Heap, Calling Convention และการทำงานของ CPU เนื่องจากองค์ประกอบเหล่านี้ล้วนเป็นพื้นฐานสำคัญของการโจมตีในระดับ Binary ทั้งสิ้น

Fundamental of Computer Architecture

CPU เป็น Hardware ที่จะทำงานตามคำสั่งที่ถูกป้อนให้มัน (Instruction) ซึ่งจะอยู่ในรูปแบบของ Binary (0 และ 1) โดยกลุ่มของ Binary ที่เมื่อนำมารวมกันแล้วมีความหมายเป็น Instruction ให้ CPU ทำงาน เราจะเรียกว่า Machine Code หรือ Opcode ตัวอย่างเช่น

  • 10111000 00000010 00000000 00000000 00000000 11000011

การตีความหมายของ Binary หรือ Opcode จะขึ้นอยู่กับสถาปัตยกรรม (Architecture) ของ CPU ที่ใช้งาน หากเรานำ Opcode ข้างต้นไปรันบน CPU ที่เป็น x86 หรือ x86–64 เช่น CPU ของ Intel หรือ AMD ตัว CPU จะตีความว่าเป็นคำสั่งให้ฟังก์ชันในโปรแกรมส่งค่า 2 กลับออกมาเมื่อทำงานเสร็จสมบูรณ์ แต่ถ้าเราเอาไปให้ CPU ที่เป็น ARM64 (เช่น Apple Silicon) ก็จะได้อีกแบบ หรืออาจจะไม่เข้าใจจนทำให้เกิด Error ขึ้นที่ Hardware ได้เลย

แต่ถ้าหากใครที่จบ Computer Engineer ในระดับ Bachelor มาก็คงจะรู้ทันทีว่าเราสามารถจำแนก CPU Architecture ได้เป็น 2 แบบใหญ่ๆ ซึ่งได้แก่

  • CISC (Complex Instruction Set Computer)
  • RISC (Reduced Instruction Set Computer)

แต่ ณ บทความนี้จะยังไม่ขอลงรายละเอียดเพิ่มเติมมากนักเพราะอาจจะยังไม่จำเป็น แต่ถ้าใครสนใจก็เอา Keyword ที่กล่าวมาข้างต้นไปศึกษาต่อได้เลย

ขอขอบคุณภาพจาก EDUCBA

ขอขอบคุณภาพจาก EDUCBA

Low-Level Programming

เราก็จะพบว่ามนุษย์อย่างเราๆ ถ้าจะให้เขียน Program เพื่อติดต่อกับ Computer หรือใช้งาน Hardware ตรงๆ โดยใช้เพียงแค่เลข 1 และ 0 ก็คงจะไม่ใช่เรื่องง่ายสักเท่าไหร่ ดังนั้นจึงได้มีการนำเสนอ Opcode Binary ที่ค่อนข้างยาวให้อยู่ในรูปแบบของเลขฐาน 16 (Hexadecimal หรือ Hex แบบสั้นๆ) ที่มีขนาดสั้นลงและอ่านง่ายขึ้น ซึ่งถ้าเป็นกรณีของ Opcode ที่กล่าวมาข้างต้นก็จะมีหน้าตาประมาณนี้

  • B8 02 00 00 00 C3

ถึงแม้ว่าการแสดงผลในรูปแบบ Hex จะสั้นลงและอ่านง่ายกว่าฐานสองมาก แต่ก็ยังยากสำหรับมนุษย์ที่จะเข้าใจว่า Instruction เหล่านั้นมันเอาไว้ทำอะไร ดังนั้นจึงมีการแทน Opcode เหล่านี้ด้วยชุดคำสั่งที่อ่านเข้าใจได้ง่ายกว่าเดิม ซึ่งจะเรียกว่า Assembly โดย Opcode ข้างต้น เมื่อถูกตีความบน CPU ที่เป็น Architecture x86 จะสามารถแปลออกมาเป็นคำสั่งดังต่อไปนี้

mov eax,2 
ret
  • **B8 02 00 00 00 กลายเป็น mov eax, 2 — เป็นคำสั่งที่จะนำค่า 2 ไปเก็บไว้ใน Register** ที่ชื่อว่า EAX ซึ่งเป็นหน่วยเก็บข้อมูลขนาดเล็กภายใน CPU ที่ใช้สำหรับเก็บข้อมูลและผลลัพธ์ของการคำนวณ
  • **C3 กลายเป็น ret — เป็นคำสั่งที่จะจบการทำงานของฟังก์ชันและส่งค่าที่เก็บอยู่ใน EAX กลับไปยังผู้เรียก ดังนั้นฟังก์ชันนี้จึง Return ค่า 2 **กลับออกมา

ขอขอบคุณ Gemini ที่สามารถสร้างภาพสวยๆ แบบนี้ขึ้นมาได้

ขอขอบคุณ Gemini ที่สามารถสร้างภาพสวยๆ แบบนี้ขึ้นมาได้

ในอดีตที่ Computer Technology ยังไม่ได้มีความก้าวหน้ามากนัก Developer จะต้องพัฒนาโปรแกรมด้วยภาษา Assembly เท่านั้น ถึงแม้ว่ามันจะเป็นภาษาที่มีความเป็นมนุษย์มากกว่า Machine Code ที่เป็น Binary หรือ Hex แต่ Learning Curve ของมันก็ต่ำมากๆ Developer หลายๆ คนกว่าจะเข้าใจการทำงานของมัน อ่านออกเขียนได้ก็ต้องใช้เวลาในการเรียนรู้ค่อนข้างมาก ทำให้กระบวนการพัฒนาโปรแกรมใดๆ ก็ตามในยุคนั้น จะต้องใช้ทั้งเวลาและทรัพยากรที่ค่อนข้างสูง

ตัวอย่างโปรแกรมที่พัฒนาด้วยภาษา Assembly แทบทั้งหมดก็คือ MS-DOS Version แรกๆ ซึ่งถือว่าเป็นระบบปฏิบัติการยุคบุกเบิกและเป็นรากฐานสำคัญของ Microsoft Windows ที่เราใช้งานกันในปัจจุบัน โดยเมื่อไม่นานมานี้ Microsoft ได้เปิดเผย Source Code ของ MS-DOS 1.25 และเวอร์ชั่นอื่นๆ ในรูปแบบ Open-Source เพื่อให้ผู้ที่สนใจสามารถเข้าไปศึกษาแนวทางการพัฒนา Software ในยุคนั้นได้

เมื่อเราลองเปิดดู Source Code บางส่วนของ MS-DOS 1.25 จะพบว่าไฟล์ส่วนใหญ่มีนามสกุล .ASM ซึ่งเป็นไฟล์ภาษา Assembly และเมื่อเปิดเข้าไปอ่านแต่ละไฟล์ก็จะพบว่าอ่านไม่รู้เรื่อง ! (เดี๋ยวจะมาพูดถึงในบทความถัดๆ ไปครับ)

High-Level Programming

ดังนั้นภาษาในการเขียนโปรแกรมจึงได้วิวัฒนาการขึ้นมาอีกขั้น กลายเป็นภาษาที่อ่านง่ายและเขียนง่ายขึ้น ซึ่งเรียกว่า High-Level Programming Language ที่เราใช้งานกันในปัจจุบันนั่นเอง ไม่ว่าจะเป็น Python, Rust, C, C#, C++, JavaScript, HTML หรือ Perl เป็นต้น

Gemini สร้างรูปภาพที่มีข้อความได้เนียนขนาดนี้เลยหรอเนี่ย

Gemini สร้างรูปภาพที่มีข้อความได้เนียนขนาดนี้เลยหรอเนี่ย

การมาของ High-Level Programming ทำให้การพัฒนาโปรแกรมทำได้สะดวกและรวดเร็วมากขึ้น แต่อย่างไรก็ตามสุดท้ายแล้วภาษาเหล่านี้ก็จะต้องถูกแปลงกลับให้เป็น Assembly แล้วแปลงเป็นเลขฐานสอง หรือ Machine Code เพื่อให้ CPU หรือคอมพิวเตอร์เข้าใจอยู่ดี โดยกระบวนการดังกล่าวจะดำเนินการผ่านโปรแกรมที่เรียกว่า Compiler

ขอขอบคุณ Gemini อีกเช่นเคยสำหรับรูปภาพสวยๆ

ขอขอบคุณ Gemini อีกเช่นเคยสำหรับรูปภาพสวยๆ

หลายคนอาจเริ่มนึกขึ้นได้ว่า บางภาษาใช้ Compiler ในการแปลงโค้ด ขณะที่บางภาษาใช้ Interpreter ในการรันโปรแกรม ซึ่งทั้งสองแนวทางมีหลักการทำงานและข้อแตกต่างที่น่าสนใจ แต่เพื่อไม่ให้บทความนี้ยาวเกินไป จะขอเก็บรายละเอียดเรื่องนี้ไว้พูดถึงในบทความถัดๆ ไปครับ

Fundamental of Operating System

ระบบปฏิบัติการ (Operating System) คือ Software ที่ทำหน้าที่เป็นตัวกลางระหว่างผู้ใช้งานหรือโปรแกรมต่าง ๆ กับ Hardware เพื่อให้สามารถเข้าถึงและใช้งานทรัพยากรของเครื่องได้อย่างถูกต้องและมีประสิทธิภาพ ไม่ว่าจะเป็น CPU, Memory, Hard Disk, Network หรือ อุปกรณ์ที่เป็น Input/Output อย่าง จอแสดงผลและลำโพง เป็นต้น

โปรแกรมทุกโปรแกรมเมื่อเริ่มทำงาน ระบบปฏิบัติการจะทำการโหลดเฉพาะส่วนที่จำเป็นของไฟล์โปรแกรม (Machine Code หรือ Binary) จาก Storage เช่น SSD หรือ HDD ไปไว้ใน Memory (RAM) จากนั้น CPU จะค่อย ๆ ดึงชุดคำสั่ง (Instruction) จาก Memory มาประมวลผลตามลำดับจนโปรแกรมทำงานเสร็จสิ้น

แต่อย่างไรก็ตาม มักจะมีความเข้าใจผิดว่าเมื่อโปรแกรมเริ่มทำงาน ไฟล์ทั้งหมดจะต้องถูกโหลดเข้า RAM ทันที ซึ่งในความเป็นจริงไม่ได้เป็นเช่นนั้น ลองนึกภาพเกมอย่าง GTA 6 ที่อาจมีขนาดไฟล์รวมกว่า 200 GB แต่เครื่องของเรามี RAM เพียง 16 GB หากต้องโหลดทุกอย่างเข้า RAM พร้อมกันก็คงเป็นไปไม่ได้ ดังนั้นระบบจะทำการโหลดเฉพาะส่วนที่จำเป็น และจัดการพื้นที่ RAM ที่ไม่ได้ถูกใช้งานโดยโปรแกรมด้วยการสลับข้อมูลเข้าออกอย่างรวดเร็ว จนผู้ใช้งานแทบไม่รู้สึกถึงกระบวนการดังกล่าว

CPU (Central Processing Unit) จะทำการดึง Instruction หรือ Data ที่อยู่บน Memory (RAM) มาเพื่อประมวลผลเท่านั้น จะไม่มีทางดึงจาก Second Storage (Hard-disk) โดยตรงอย่างแน่นอน

CPU (Central Processing Unit) จะทำการดึง Instruction หรือ Data ที่อยู่บน Memory (RAM) มาเพื่อประมวลผลเท่านั้น จะไม่มีทางดึงจาก Second Storage (Hard-disk) โดยตรงอย่างแน่นอน

Memory Allocation

ตามที่กล่าวไปก่อนหน้านี้ เมื่อโปรแกรมเริ่มทำงาน OS จะโหลดบางส่วนของ Binary File (Machine Code) มาไว้บน Memory เพื่อให้ CPU สามารถดึงชุดคำสั่งไปประมวลผลได้ โดยในทางปฏิบัติ คอมพิวเตอร์มักมีหลายโปรแกรมทำงานพร้อมกันอยู่เสมอ นั่นจึงหมายความว่าบน Memory จะมีโค้ดและข้อมูลของหลายๆ โปรแกรมถูกจัดเก็บอยู่พร้อมกัน

หน้าที่สำคัญอย่างหนึ่งของ OS คือการจัดสรรหน่วยความจำ (Memory Allocation) ให้กับแต่ละโปรแกรม โดยจะจองพื้นที่บน RAM และแบ่งให้แต่ละ Program ได้ใช้งานเป็นสัดส่วน พร้อมทั้งแยกพื้นที่และวางกรอบของหน่วยความจำของแต่ละ Program ออกจากกัน เมื่อใดก็ตามที่ Program พยายามจะเข้าถึงพื้นที่ Memory นอกเหนือจากที่ได้รับอนุญาตก็จะถูก OS ปฏิเสธและเกิด Error ขึ้นทันที

OS จะจัดสรรพื้นที่เป็นก้อนๆ ให้แต่ละโปรแกรมเมื่อมันต้องการจะรัน โดยแต่ละโปรแกรมจะไม่ไปยุ่งกับพื้นที่ๆ ไม่ได้รับอนุญาต มิฉะนั้นจะเกิด Error ขึ้นได้

OS จะจัดสรรพื้นที่เป็นก้อนๆ ให้แต่ละโปรแกรมเมื่อมันต้องการจะรัน โดยแต่ละโปรแกรมจะไม่ไปยุ่งกับพื้นที่ๆ ไม่ได้รับอนุญาต มิฉะนั้นจะเกิด Error ขึ้นได้

ตามที่เราทราบกันดีว่า Memory มีหน้าที่เก็บข้อมูลเพื่อรอให้ CPU นำไปประมวลผล โดย CPU จะเข้าถึงข้อมูลแต่ละตำแหน่งใน RAM ผ่านสิ่งที่เรียกว่า Address ซึ่งในระบบคอมพิวเตอร์ทั่วไปจะเป็นแบบ Byte-addressable หมายความว่า 1 Address สามารถอ้างอิงถึงข้อมูลขนาด 1 Byte หรือ 8 bits ได้

ดังนั้น หากเรามี RAM ขนาด 4 GB หรือประมาณ 4,294,967,296 Bytes ระบบจะสามารถมี Address ที่ใช้เพื่ออ้างอิงตำแหน่งในหน่วยความจำได้ทั้งหมด 4,294,967,296 รูปแบบ โดยทั่วไปเรามักจะแสดงตำแหน่ง Address ในรูปแบบของเลขฐาน 16 (Hexadecimal) เพื่อให้อ่านและจดจำได้ง่าย เช่น 0x00001234 หรือ 0x92af45dc เป็นต้น

CPU จะอ้างอิงถึงตำแหน่งของข้อมูลบน Memory หรือ RAM ผ่านสิ่งที่เรียกว่า Address ซึ่งในตำราหลายๆ เล่มมักจะแสดงผลให้อยู่ในรูปของเลขฐาน 16 เพื่อความเข้าใจง่าย

CPU จะอ้างอิงถึงตำแหน่งของข้อมูลบน Memory หรือ RAM ผ่านสิ่งที่เรียกว่า Address ซึ่งในตำราหลายๆ เล่มมักจะแสดงผลให้อยู่ในรูปของเลขฐาน 16 เพื่อความเข้าใจง่าย

อีกความจริงหนึ่งที่ควรทราบเกี่ยวกับ Memory Allocation ก็คือ แต่ละโปรแกรมที่กำลังทำงานอยู่จะไม่สามารถทราบได้ว่าตัวมันเองหรือโปรแกรมอื่น ๆ ถูกจัดเก็บอยู่ที่ตำแหน่งใดบน Physical Memory (RAM) โดย Address ที่แต่ละโปรแกรมสามารถมองเห็นและใช้งานได้นั้นจะเรียกว่า Virtual Address หากเป็น OS แบบ 32-bit โปรแกรมจะสามารถอ้างอิง Address ได้ตั้งแต่ 0x00000000 ไปจนถึง 0xffffffff แต่โปรแกรมจะไม่ทราบว่า Address เหล่านี้ถูกจัดเก็บอยู่ที่ตำแหน่งใดบน Physical Memory จริงๆ โดยหน้าที่ในการแปลงหรือ Mapping ระหว่าง Virtual Address กับ Physical Address จะเป็นของ OS และ CPU นั่นเอง ถ้ามองภาพข้างล่างน่าจะอธิบาย Concept นี้ได้ชัดเจนมากขึ้น

แต่ละ Program จะเข้าใจว่าตัวเองสามารถเรียกใช้งาน Address ได้ตั้งแต่ 0x00000000 จนถึง 0xFFFFFFFF แต่ในความจริงแล้วมันก็เป็นแค่โลกเสมือน (Virtual Address Space) เพราะประเดี๋ยว OS ก็จะต้องเอา Address ที่ว่ามาไป Map กับ Physical Address จริงๆ อยู่ดี

แต่ละ Program จะเข้าใจว่าตัวเองสามารถเรียกใช้งาน Address ได้ตั้งแต่ 0x00000000 จนถึง 0xFFFFFFFF แต่ในความจริงแล้วมันก็เป็นแค่โลกเสมือน (Virtual Address Space) เพราะประเดี๋ยว OS ก็จะต้องเอา Address ที่ว่ามาไป Map กับ Physical Address จริงๆ อยู่ดี

Memory Paging

ถ้าหากเราส่องเข้าไปในพื้นที่ Memory ที่ถูกจัดสรรให้กับแต่ละโปรแกรม จะพบว่าภายใน Virtual Memory ของแต่ละโปรแกรมจะถูกแบ่งออกเป็นก้อน หรือ Block ย่อย ๆ ซึ่งเรียกว่า Page (ภาพตรงกลาง) ที่มีขนาดเท่าๆ กันเสมอไม่ว่าจะเป็น Page ในโปรแกรมเดียวกันหรือต่างโปรแกรมก็ตาม

ในขณะเดียวกัน Physical Memory หรือ RAM จริงที่ OS บริหารจัดการก็จะถูกแบ่งออกเป็นก้อนขนาดเท่าๆ กันเช่นกันอีกที (มีขนาดเท่ากับ Page) โดยไม่สนว่า Region นั้นจะมี Page ของใครผสมอยู่ก็ตาม ซึ่งเรียกว่า Frame (ภาพทางขวา) โดย OS จะทำหน้าที่ Mapping ระหว่าง Page ต่างๆ ของหลายๆ โปรแกรมที่กระจายอยู่บน Physical Memory กับก้อนของ Frame นั่นเอง

อย่างไรก็ตาม ไม่ว่า Memory จะถูกแบ่งและจัดการภายในอย่างไร ตัวโปรแกรมเองจะไม่รับรู้ถึงกลไกเหล่านี้ และยังคงมองเห็นเพียงพื้นที่ Virtual Memory ของตัวเองที่มีลักษณะต่อเนื่อง (Consecutive) สามารถเข้าถึง Address ได้ตามลำดับ โดยไม่จำเป็นต้องทราบว่าแต่ละส่วนถูกจัดเก็บอยู่ที่ตำแหน่งใดบน Physical Memory จริง

เหตุผลที่ OS ต้องแบ่ง Memory ออกเป็นก้อนเล็ก ๆ อย่าง Page และ Frame แทนที่จะจัดการเป็นก้อนใหญ่เพียงก้อนเดียว ก็เพื่อให้สามารถบริหารจัดการพื้นที่บน Memory ได้อย่างมีประสิทธิภาพมากขึ้น เปรียบเทียบง่าย ๆ เหมือนการนำก้อนหินที่มีขนาดแตกต่างกันใส่ลงในขวดโหล หากทุบให้เป็นก้อนเล็ก ๆ จะสามารถจัดเรียงและใช้พื้นที่ได้คุ้มค่ากว่าแทนที่จะพยายามนำก้อนใหญ่ๆ ใส่ลงไปตรงๆ ตั้งแต่แรก โดยขนาดของ Page และ Size จะขึ้นอยู่กับ CPU Architecture และ OS ซึ่งโดยทั่วไปมักอยู่ที่ 4 KB บน Windows/Linux x86/x64 และ 16 KB บน macOS/iOS Apple Silicon เพราะถ้าหากมีขนาดเล็กหรือใหญ่เกินไปจะทำให้เกิด Overhead จากการจัดการ Memory มากขึ้น

เราจำเป็นต้องเข้าใจ Concept นี้ในการทำ Binary Exploitation เนื่องจากการโจมตีส่วนใหญ่มักเกี่ยวข้องกับการแก้ไขหรือเขียนทับ Memory ของโปรแกรม ไม่ว่าจะเป็นการอ่านหรือเขียนข้อมูลลง โดยเวลาที่โปรแกรมทำการขอ Allocate Memory เพิ่มเติมเพื่อทำอะไรสักอย่าง ตัว OS จะทำการจัดสรรเป็นจำนวนตามทวีคูณของ Page Size ไม่ใช่เท่าไหร่ก็ได้ เช่น หาก Page Size ถูกกำหนดไว้ที่ 4 KB จำนวน Memory ที่ขอได้ก็อาจจะเป็น 4KB, 8KB, หรือ 12KB เป็นต้น แต่จะไม่สามารถขอเป็น 1KB, 3KB, 123KB เป็นต้น

อันนี้เป็นเกร็ดเสริมเล็ก ๆ น้อย ๆ เกี่ยวกับ Paging แต่อาจไม่ได้เกี่ยวข้องโดยตรงกับการทำ Binary Exploitation มากนัก โดยเมื่อพื้นที่ว่างของ RAM ใกล้เต็มเนื่องจากมีโปรแกรมทำงานจำนวนมากเกินไป OS สามารถนำ Page ที่ไม่ได้ถูกใช้งานเป็นเวลานานออกจาก Memory ไปเก็บไว้บน Hard Disk ได้ ซึ่งกระบวนการนี้จะเรียกว่า Page Swapping โดยการย้ายข้อมูลจาก Memory ไปยัง Storage จะเรียกว่า Swap Out และเมื่อมีการเรียกใช้งานข้อมูลดังกล่าวอีกครั้งแล้วนำกลับมาไว้ใน Memory จะเรียกว่า Swap In ซึ่งเป็นการนำพื้นที่บน Storage มาต่อเติมเป็นพื้นที่เสริมให้แก่ RAM โดยอ้อมนั่นเอง และเราสามารถกำหนดขนาดของ Page Size หรือ Swap File ได้อีกด้วย

Process & Thread

โปรแกรมหนึ่งตัวมักจะมีหน่วยการทำงานแตกย่อยออกไป เพื่อรับผิดชอบหน้าที่แต่ละอย่าง โดยหน่วยย่อยๆ ที่ว่าก็จะต้องมีการจัดสรรทรัพยากรจาก OS ด้วยอีกที ซึ่งเราจะเรียกมันว่า Process ถ้ายกตัวอย่างง่าย ๆ ก็คงจะเป็นพวก Web Browser

ถ้าเราทำการเปิด Browser เช่น Microsoft Edge ขึ้นมา จากนั้นเปิด Task Manager แล้วไปที่หน้า Details ก็จะพบว่ามี Process ของ Edge เป็นจำนวนมหาศาล ซึ่งแต่ละอันก็อาจจะรับผิดชอบงานที่แตกต่างกัน เช่น Process นี้ดูแล Cookie ของ Tab A, Process นี้ดูแลเรื่อง UI ของ Tab B อะไรเป็นต้น การแยกการทำงานออกเป็นหลายๆ Process จะช่วยให้โปรแกรมสามารถกระจายงานและทำงานแบบคู่ขนาน (Parallel Execution) ได้ ทำให้สามารถใช้ทรัพยากรของระบบได้อย่างมีประสิทธิภาพมากขึ้น รวมถึงเพิ่มความเสถียรของโปรแกรม

แต่ละหน่วยของโปรแกรมหรือ Process จะถูก Track โดย OS ด้วยตัวเลขที่เรียกว่า PID

แต่ละหน่วยของโปรแกรมหรือ Process จะถูก Track โดย OS ด้วยตัวเลขที่เรียกว่า PID

และยิ่งไปกว่านั้น แต่ละ Process ก็มีสิทธิ์ที่จะ Spawn Process ขึ้นมาใหม่ (Fork) เพื่อช่วยงานเพิ่มเติมได้ หรือแบ่งย่อยทรัพยากรของตัวเองออกเป็นหน่วยที่เล็กกว่าเดิมที่เรียกว่า Thread เพื่อให้ทำงานได้อย่างมีประสิทธิภาพมากขึ้นไปอีก ถ้าเราเขียนโปรแกรมที่สามารถทำงานได้หลาย ๆ Process แบบคู่ขนาน และแต่ละ Process ก็สามารถสร้าง Thread เพื่อมาทำงานคู่ขนานย่อย ๆ ซ้ำไปอีก โปรแกรมก็คงจะมีประสิทธิภาพเป็นอย่างมาก

เราสามารถใช้โปรแกรมที่ชื่อว่า Process Explorer มาทำการ Inspect แต่ละ Process ได้ว่ามีการสร้าง Thread อะไรบ้าง ซึ่งแต่ละ Thread ก็จะถูก Track ด้วยตัวเลขที่เรียกว่า TID นั่นเอง

แต่ละ Process เมื่อมีการเรียกใช้งานและรันโดย Computer ตัว OS จะทำการแปะ Metadata ชนิดพิเศษที่เรียกว่า Process Environment Block (PEB) ซึ่งจะเก็บข้อมูลต่าง ๆ เกี่ยวกับ Process นั้น ๆ เพื่อที่ OS หรือโปรแกรมอื่น ๆ จะได้สามารถสอบถามและใช้งานอะไรบางอย่างใน Process นั้นได้อย่างถูกต้องและมีประสิทธิภาพ ซึ่งตัวอย่างสิ่งที่เก็บอยู่ใน PEB จะได้แก่

  • Image Base Address
  • Loader Data Block
  • Process Parameters
  • Process Heap

นอกเหนือจาก PEB แล้ว OS ก็ยังแปะ Metadata ที่เรียกว่า EPROCESS ให้แต่ละ Process ด้วยเช่นกัน ส่วนเรื่องรายละเอียดว่าแต่ละ Data Structure คืออะไรจะขอละเอาไว้ในบทความนี้ให้ไป Research กันดูก่อน แต่ประเดี๋ยวจะมาพูดถึงเพิ่มเติมในบทความถัดๆ ไป

ในทำนองเดียวกัน Thread ก็มีการแปะ Metadata เหมือนกัน เช่น TEB (Thread Environment Block) และ ETHREAD เป็นต้น

แต่สิ่งที่ต้องจำขึ้นใจเกี่ยวกับเรื่องนี้ในการทำ Binary Exploitation ก็คือ 1 Process สามารถมี Thread ได้หลายตัว แต่ Thread 1 ตัวจะต้องทำงานภายใต้ 1 Process ที่เป็นคนสร้างมันเท่านั้น โดย Default เมื่อเราสร้าง Process ขึ้นมา จะมี 1 Thread หลัก (Main Thread) เป็นตัวแทนการทำงานของ Process เกิดขึ้นมาเสมอ ต่อให้เราไม่ได้เขียนโค้ดเพื่อทำ Multithreading ก็ตาม

System Call & Ring Protection

ตามที่ได้เกริ่นเอาไว้แรก ๆ เลยก็คือ OS ทำหน้าที่เป็นตัวกลางระหว่าง Hardware และผู้ใช้งานหรือ Program อื่น ๆ ซึ่งหลาย ๆ OS จะออกแบบมาไม่ให้ผู้ใช้งานสามารถคุยกับ Hardware ได้โดยตรง เวลาจะคุยหรือใช้งาน Hardware จะต้องผ่าน OS เสมอ ผ่านกลไกที่เรียกว่า System Call

OS จะทำการวาง Boundary จำลองระหว่างทรัพยากรต่าง ๆ ในระบบอยู่ใน Model ที่เรียกว่า Ring Protection ซึ่งในปัจจุบันเราจะใช้เพียงแค่ 2 Ring ซึ่งก็คือ Ring 0 หรือ Kernel Mode และ Ring 3 หรือ User Mode เท่านั้น ส่วน Ring อื่น ๆ คนสมัยก่อนออกแบบมาเผื่อไว้สำหรับใช้งาน แต่ปรากฏว่าไม่ได้ถูกใช้งานจริง และไม่อยากเปลี่ยนชื่อให้เกิดความสับสน จึงยังคงใช้ชื่อเดิมต่อกันมา

Ring Protection เป็นกลไกที่ฝังอยู่ในระดับ CPU Hardware และทำงานร่วมกับสัญญาณไฟฟ้าภายในของ CPU โดยตัว CPU จะมีกลไกพิเศษที่ใช้ตรวจสอบ Privilege Level ของตัวเองอยู่เสมอว่ากำลังทำงานอยู่ใน Ring ใด โดยการทำ System Call จะหมายถึงการส่งต่องานบางอย่างที่โปรแกรมไม่สามารถทำได้เนื่องจากกำลังทำงานอยู่ใน Ring 3 ให้ OS เข้ามารับช่วงดำเนินการต่อในสถานะที่ CPU ทำงานอยู่ใน Ring 0

Ring 3 (User Mode): เปรียบเสมือนพื้นที่สาธารณะที่โปรแกรมทั่วไปรันอยู่ (รวมถึงโปรแกรมที่รันด้วยสิทธิ์ Administrator หรือ NT AUTHORITY\SYSTEM) ซึ่งถูกจำกัดสิทธิ์อย่างเข้มงวด ตัวอย่างสิ่งที่ Program สามารถทำงานได้ใน Ring นี้ก็คือ

  • รัน Machine Code หรือ Instruction ที่อยู่ใน Memory ของตัวเอง ซึ่งก็รวมไปถึงการโหลด Library / DLL หรือ สร้าง Function Call ต่างๆ
  • อ่านหรือเขียนลงใน Memory Region ของโปรแกรมตัวเอง
  • Process ที่อยู่ใน Ring 3 ด้วยกันสามารถสื่อสารกันได้ผ่านกลไกจำพวก Share Memory หรือ Inter-Process Communication (IPC)
  • ถ้าต้องการจะทำอะไรอื่นๆ นอกเหนือจากนี้ที่อาจจะกระทบต่อระบบถ้าทำผิดพลาด เช่น ขอจองพื้นที่เพิ่ม ขอเข้าถึง Hardware ขอเข้าถึง File System ก็จะต้องทำการ syscall ไปให้ OS รับช่วงต่อให้ใน Ring 0 อีกที

Ring 0 (Kernel Mode): เปรียบเสมือนหัวใจหลักของระบบ มีสิทธิ์เข้าถึงทรัพยากรทุกอย่าง รวมถึงสามารถสั่งการ Hardware ได้โดยตรง สิ่งที่ควรทราบก็คือ หากเราสามารถทำ Binary Exploitation โดยทำให้โค้ดอันตรายของเราสามารถรันบน Ring 0 ได้ ก็อาจจะทำให้เกิดช่องโหว่ที่เกี่ยวข้องกับการ Privilege Escalation ได้

สิ่งที่ควรทราบอีกอย่างก็คือ ถ้าหาก Program เกิด Error ขึ้นใน User Mode ตัวโปรแกรมนั้น ๆ จะปิดตัวลง แต่ถ้าเมื่อไหร่ก็ตาม Instruction หรือ Program ที่ทำงานบน Kernel Mode เกิด Error สิ่งที่จะปิดตัวลงแทนก็คือ Operating System ซึ่งมักจะทำให้เกิดเหตุการณ์จอฟ้าหรือ Blue Screen of Death (BSOD) นั่นเอง

Program Loader

Executable File ที่วางอยู่บน Storage หรือ Hard Disk นั้น เมื่อเราทำการเปิด Program ขึ้นมา ทุก ๆ อย่างของโปรแกรม ไม่ว่าจะเป็นไฟล์เสริม รูปภาพ เสียง DLL หรือ Library ต่าง ๆ จะไม่ได้ถูก Load เข้า Memory ทั้งหมด แต่จะถูก Load เข้ามาเพียงบางส่วนเท่านั้น ตามที่ได้ย้ำไปก่อนหน้านี้ ทีนี้เราจะมาดูขั้นตอนคร่าว ๆ ว่า OS มีกระบวนการอย่างไรในการแปลง File จาก Storage ให้กลายเป็น Instruction บน Memory เพื่อให้ CPU ประมวลผล

OS จะมีอีก Component ที่เรียกว่า Loader ซึ่งจะทำหน้าที่เตรียม Environment ให้พร้อมเมื่อมีการพยายามรัน Executable File โดยสิ่งที่มันจะเตรียม ได้แก่

  • สร้าง Process ทำการแปะ Metadata ต่างๆ เช่น PEB หรือ EPROCESS เพื่อติดตามการทำงาน
  • สร้าง Virtual Address Space เพื่อให้โค้ดของโปรแกรมมีที่อยู่และ Isolate จาก Memory Region ของโปรแกรมอื่นๆ
  • ทำการ Map Instruction หรือ Data ต่าง ๆ เท่าที่จำเป็นเบื้องต้น ที่อยู่ในตัวไฟล์เข้าไปใน Memory หรือ Virtual Address Space
  • Load Shared Library / DLL ที่จำเป็น
  • สร้าง Main Thread ขึ้นมา เพราะ Process ต้องมีอย่างน้อย 1 Thread เพื่อทำงานเป็น Main Thread เสมอ

จากนั้นจึงทำการ Execute Code โดยเริ่มจากจุดเริ่มต้นของโปรแกรม หรือที่เรียกว่า Entry Point

Conclusion

สิ่งที่อยากให้ศึกษาให้มากที่สุดในบทความนี้ก็คือ การทำความเข้าใจเรื่อง Computer Architecture และ Operating System โดยไม่จำเป็นต้องลงลึกมาก แค่เข้าใจ Concept พื้นฐานก็เพียงพอแล้วครับ ซึ่งทั้งสองหัวข้อนี้มักจะมีการสอนในระดับปริญญาตรีของสาขาวิทยาการคอมพิวเตอร์หรือวิศวกรรมคอมพิวเตอร์เสมอ แต่ถ้าหากเป็นคนนอกสายหรือน้อง ๆ ที่ยังไม่ได้เข้ามหาวิทยาลัย อาจจะรู้สึกว่ายากหรือสับสนในช่วงแรก แต่ก็แนะนำให้ลองศึกษาและทำความเข้าใจพื้นฐานเหล่านี้ไว้เพื่อเตรียมความพร้อมเข้าสู่โลกของ Binary Exploitation & Pwnable ครับ

บทความนี้ถึงแม้ว่าจะไม่ได้ลงลึกถึงการทำ Binary Exploitation แบบเต็มรูปแบบ แต่ผู้เขียนจะพยายามค่อย ๆ ปูพื้นฐานทีละนิด เพื่อให้ผู้อ่านสามารถทำความเข้าใจ Concept ต่าง ๆ ที่จำเป็นก่อนเข้าสู่หัวข้อนี้ได้มากขึ้น สาเหตุที่เลือกเขียนหัวข้อนี้เนื่องจากผู้เขียนกำลังเตรียมสอบ Certificate ที่เกี่ยวข้องกับด้านนี้อยู่พอดี และด้วยความที่ไม่เคยศึกษาหัวข้อนี้มาก่อน ทำให้ช่วงแรกของการเรียนรู้ค่อนข้างยากมาก ต้องใช้เวลาในการแกะบทเรียน ทำความเข้าใจ และอ่านซ้ำหลายรอบ เพราะเป็นหัวข้อที่มีพื้นฐานหลายๆ ส่วนนำมาเชื่อมโยงกันเรื่อยๆ

จนถึงตอนที่จัดทำ Blog นี้ ผู้เขียนเองก็ยังอยู่ในช่วงเรียนรู้และทำความเข้าใจเช่นกัน (และยังไม่พร้อมสอบเป็นอย่างมาก กังวลทุกวัน) จึงพยายามจะ Research และเรียบเรียงเนื้อหาในมุมมองของคนที่เพิ่งเริ่มศึกษา Topic นี้ แต่มีพื้นฐานด้าน Computer และ Cybersecurity อยู่บ้างเล็กน้อย โดยหวังว่าบทความนี้จะเป็นประโยชน์สำหรับผู้ที่กำลังเริ่มต้นศึกษา Binary Exploitation เช่นเดียวกัน แล้วพบกันใหม่ในบทความถัด ๆ ไปครับ ระหว่างนี้ผู้เขียนขอกลับไปอ่านหนังสือเตรียมสอบและ Research เพิ่มเติมก่อนครับ


메타데이터
post_id
b0f1c4c8d9d9
slug
binary-exploit-ep-1-introduction-to-operating-system-for-binary-exploitation-pwnable-b0f1c4c8d9d9
url
https://medium.com/@pat.sanitjairak/binary-exploit-ep-1-introduction-to-operating-system-for-binary-exploitation-pwnable-b0f1c4c8d9d9
canonical_url
https://medium.com/@pat.sanitjairak/binary-exploit-ep-1-introduction-to-operating-system-for-binary-exploitation-pwnable-b0f1c4c8d9d9
author_url
https://medium.com/@pat.sanitjairak
status
ok
fetched_at
2026-09-02 18:13:48