ทำไม Ethical Hacker ควรรู้จัก Assembly Language Basic

Assembly พื้นฐาน

Suppapan S.
suppapan
4 min readJun 10, 2020

--

ก่อนอื่นผมต้องขอออกตัวก่อนว่าที่มาเขียนบล็อคนี้ผมเองก็ไม่ได้มีความเชี่ยวชาญอะไรในศาสตร์ด้าน Assembly แต่ว่าได้ไปอ่านหนังสือ “ Gray Hat Hacking: The Ethical Hacker’s Handbook” ก็เลยคิดว่าอยากจะเขียนบล็อคเพื่อนำเอาความรู้บางส่วนที่ได้อ่านและคิดว่าจะมีประโยชน์ต่อผู้ที่สนใจสามารถนำไปต่อยอดได้ ถ้าใครสนใจอยากจะอ่านต่อเต็มๆก็สามารถไปหาอ่านกันได้ครับ

ที่มา : https://en.wikipedia.org/wiki/Assembly_language#/media/File:Motorola_6800_Assembly_Language.png
ที่มา : https://en.wikipedia.org/wiki/Assembly_language#/media/File:Motorola_6800_Assembly_Language.png

Machine VS Assembly VS C

จริงๆแล้วคอมพิวเตอร์นั้นจะสามารถเข้าใจภาษาที่เรียกกันว่า Machine language หรือ ภาษาเครื่องนั่นเอง โดยภาษาเครื่องจะเป็นในรูปแบบของ 0 กับ 1 แล้วลองจินตนาการกันดูครับถ้าเกิดว่าให้เรา อ่าน 0 1 นี่กันมันจะใช้เวลาขนาดไหนกันกว่าจะเข้าใจโปรแกรมสักโปรแกรม มันจึงเกิด ภาษาที่เรียกว่า Assembly เกิดขึ้นมาเพื่อช่วยเหลือ โปรแกรมเมอร์ให้สามารถที่จะเข้าใจกระบวนการคิดของคอมพิวเตอร์ เพราะในความเป็นจริงถ้าเราอยากจะเข้าใจการทำงานของสักโปรแกรมคงจะไม่มีเจ้าของคนไหนจะให้ ตัว Source Code ให้เราดูกันง่ายๆหรอกใช่มั้ยครับ Hacker จริงใช้การเรียนรู้จาก Assembly นี่แหละครับเพื่อทำความเข้าใจว่าโปรแกรมนั้นทำงานยังไง และการวิเคราะห์ของไวรัสเราก็จะอาศัยหลักการแบบนี้เช่นเดียวกัน และจะมีภาษาระดับสูงที่ใกล้เคียงกับภาษาเครื่องเช่นเดียวกันนั่นก็คือ C เพื่อที่จะช่วยให้โปรแกรมเมอร์สามารถเข้าใจได้ง่านกว่าการอ่าน 0 และ 1 นั่นเลยเป็นสาเหตุที่ว่าทำไมการเป็น Ethical Hacker นั้นสมควรที่จะเรียนรู้ภาษา Assembly อีกสักภาษา

Cpu Registers

ภายใน Cpu จะมี registers ขนาด 32 bits ใช้ในการเก็บข้อมูล

  • EIP (Extended Instruction Pointer) เก็บ address ของคำสั่งที่จะถูกประมวลผลในลำดับถัดไป
  • EBP (Extended Base Pointer) เก็บ address ที่อยู่ด้านล่างที่สุดของ frame ที่ทำงานอยู่ใน Stack
  • ESP (Extended Stack Pointer) เก็บ address บนสุดของ stack
  • EAX (Extended Accumulator Register)
  • EBX (Extended base Register )
  • ECX (Extended Counter Register)
  • EDX (Extended Data Register)
  • ทั้งสี่ตัวนี้ใช้สำหรับเก็บข้อมูลทั่วไป (General Purpose Registers)
  • ESI (Extended Source Index), EDI (Extended Destination Index) ใช้สำหรับคำสั่งที่ต้องการ index เช่น array, copy string แต่ในบางครั้งก็ถูกใช้กับ register 4 ตัวข้างบน คือเก็บข้อมูลทั่วไป

General Purpose Registers (EAX, EBX, ECX, EDX) สามารถเข้าถึงแบบ 16 bits และ 8 bits โดยแบ่งตามรูปข้างล่าง

Flags

Flags ใช้สำหรับบอกสถานะของผลลัพท์ของคำสั่ง บางคำสั่งจะไม่มีการเปลี่ยนค่า Flags บางคำสั่งจะเปลี่ยน

  • ZF เป็น flag ที่ถูกเซ็ต เมื่อผลลัพธ์ของ กระบวนการเป็น 0
  • SF เป็น flag ที่ถูกเซ็ต เมื่อผลลัพธ์ของกระบวนการทำงานเป็น ลบ

Assembly Language

SYNTAX หลักๆจะมีอยู่สองตัวคือ AT&T และ Intel

AT&T จะมีอยู่ใน GNU Assembler ส่วนมากจะเป็นค่า default ของ Linux

Intel (NASM) ส่วนมากจะใช้เป็น Syntax นี้ เพราะคือ Netwide Assembler และ Windows assemblers

ทั้งสอง Syntax นั้นจะมีความต่างกันอยู่บ้างแต่เมื่อแปลงเป็น machine code แล้วจะได้ผลลัพธ์ที่ไม่ต่างกัน

  • คำสั่งจะแตกต่างตรงที่ Source ของ AT&T จะอยู่ข้างหน้า แต่ Intel จะอยู่ด้านหลัง
  • AT&T : CMD <source>, <destination> <#comment>
  • Intel : CMD <destination>, <source> <; comment>
  • AT&T ใช้ % ด้านหน้า register แต่ Intel ไม่ใช้
  • AT&T ใช้ $ ด้านหน้า immediate แต่ Intel ไม่ใช้
  • AT&T จะมี Suffix(ตัวต่อท้ายคำสั่ง) เพื่อระบุขนาด
  • l สำหรับ long (4byte)
  • w สำหรับ word 2 byte
  • b สำหรับ byte
  • GNU จะใส่ suffix ไม่ได้ถ้า operand นั้น ระบุขนาดไว้
  • แต่ Intel จะมีเมื่อใช้อ้างอิงที่อยู่ เช่น dword ptr, byte ptr
  • เรื่องการอ้างอิงที่อยู่ memory โดย AT&T ใช้ ( ) Intel ใช้ [ ] และตำแหน่งของ index ก็จะต่างกัน

Assembly commands

mov

คือ การ copy (คัดลอก) ข้อมูลจาก source ไปยัง destination

AT&T syntax
CMD <source>, <destination>
movl $1234h, %eax ; กำหนดค่า register eax เป็น 0x1234 assembly ใช้ได้ทั้ง 1234h or 0x1234
mov %eax, %ebx ; คัดลอกค่าจาก eax ไปสู่ ebx
movw %ax, %bx
movb %al, %bl
NASM syntax
CMD <destination>, <source>
mov eax, 1234h ; กำหนดค่า register eax เป็น 0x1234 assembly ใช้ได้ทั้ง 1234h or 0x1234
mov ebx, eax ; คัดลอกค่าจาก eax ไปสู่ ebx
mov bx, ax
mov bl, al

add, sub

ใช้สำหรับการบวกและลบ โดยนำค่า source ไปบวก/ลบกับ destination แล้วเก็บผลลัพธ์ไว้ที่ destination

AT&T syntax
CMD <source>, <destination>
addl $1234h, %eax ; บวกค่า 1234h เข้าสู่ eax เเล้วเก็บเข้าสู่ eax
subl $1234h, %eax ; ลบค่าจาก eax 1234h แล้วเก็บไปใส่ eax
NASM sybntax
CMD <destination>, <source>
add eax, 1234h ; บวกค่า 1234h เข้าสู่ eax เเล้วเก็บเข้าสู่ eax
sub eax, 1234h ; ลบค่าจาก eax 1234h แล้วเก็บไปใส่ eax

push, pop

ที่มา : https://th.aliexpress.com/item/32798653872.html

ก่อนอื่นอยากจะอธิบายหลักการของ push และ pop ก่อนว่าคืออะไรให้เราจำลองภาพเป็นตัวเก็บแผ่นซีดีที่เป็นกองๆของสมัยก่อน

ถ้าเราใส่แผ่นซีดีลงไปทั้งหมด 10 แผ่น โดยแผ้นแรกที่ใส่จะอยู่ด้านล่างสุดและแผ่นที่สองจะอยู่ถัดมาจนแผ่นที่ 10 จะอยู่ด้านบนสุด อันนี้คือหลักการของ push หรือการเก็บค่าเข้าใน stack

ส่วน Pop ก็เหมือนกับการหยิบแผ่นซีดีออกมาแต่เราไม่สามารถที่จะหยิบแผ่นไหนก็ได้เช่นอยากหยิบแผ่นที่ 1 เราต้องหยิบอีก 9 แผ่นด้านบนออกก่อนถึงจะหยิบ แผ่นที่ 1 ได้ อันนี้ก็คือหลักการของ pop

AT&T syntax
CMD <value>
pushl %eax ; push value
popl %eax ; pop destination
NASM sybntax
CMD <value>
push eax ; push eax(ค่า)
pop eax; pop value to eax

xor

หลักการแล้วมันคือการบวนการทางคณิตแต่อยากจะพูดสั้นๆให้เข้าใจได้เลยคือ ถ้าเราเอา ค่าเดียวกันไป xor กันได้ค่าผลลัพท์ เท่ากับ 0 เค้าเลยใช้การxor เพื่อการรีเซ็ตค่าให้เท่ากับศูนย์โดยการ

AT&T syntax
CMD <source>, <destination>
xor %eax, %eax ; เซ็ตค่าใน eax ให้เท่ากับ 0
NASM syntax
CMD <source>, <destination>
xor eax, eax ; เซ็ตค่าใน eax ให้เท่ากับ 0

jne, je, jnz and jmp

เป็นคำสั่งสำหรับการข้ามไปคำสั่งอื่นตามค่า eflag “zero flag”

jne/jnz jump if the zero flag = 0 ข้ามไปถ้า zero flag เท่ากับ 0

je/jz jump if zero flag = 1 ข้ามไปถ้า zero flag เท่ากับ 1

และ jmp always jump ข้ามเสมอ

AT&T syntax
CMD <destination>
jne/jnz start ;
jz/je loop ;
jmp end ;
NASM syntax
CMD <destination>
jne/jnz start ;
jz/je loop ;
jmp end ;

call, ret

คำสั่งcall เปรียบเสมือนการรันคำสั่งที่จากฟังค์ชั่นอื่น ตาม address ที่กำหนดไว้

คำสั่ง ret คือ การคืนค่าที่โปรแกรมทำเสร็จแล้ว เพื่อรอการเรียกใช้ต่อ

AT&T syntax
CMD <destination>
call subroutine1 ; เรียกใช้งานฟังค์ชั่น subroutine1
ret ; คืนค่าเมื่อสิ้นสุดโปรแกรม
NASM syntax
CMD <destination>
call subroutine1 ; เรียกใช้งานฟังค์ชั่น subroutine1
ret ; คืนค่าเมื่อสิ้นสุดโปรแกรม

lea

lea ย่อมาจาก load effective address ใช้สำหรับคำนวณค่า address ของ source แล้วเก็บที่ destination คำสั่งนี้หลายๆ คน จะสับสนกับ mov โดย mov ใช้สำหรับ copy ค่าที่อยู่ใน address ของ source สมมติว่าค่าใน EAX เป็น 0xdeadbee0 และค่าที่อยู่ใน address 0xdeadbee4 คือ 8

leal 4(%eax),%ebx  # คำนวณค่า address ของ source ได้ 0xdeadbeee4 แล้วเก็บที่ EBX

แต่ถ้าเป็น mov

movl 4(%eax),%ebx  # เอาค่า address ที่คำนวณได้ แล้วไปดึงค่าที่ address นั้น (คือ 8) แล้วเก็บที่ EBX

intใช้สำหรับเรียก interrupt handler ในการเขียน exploit บน linux ตัวที่จะได้ใช้บ่อย คือค่า 0x80 ซึ่งใช้สำหรับเรียก system call เช่น

int $0x80

nop คือ no operation (ไม่มีการทำงาน) ใช้สำหรับบอกว่าไม่ต้องทำอะไร คล้ายๆ กับบรรทัดที่มี semicolon เฉยๆ ใน C ตัวนี้ผมจะพูดถึงประโยชน์ทีหลัง เมื่อมีการใช้งาน และขอให้จำด้วยว่ามีค่าเป็น 0x90

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

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

Reference:

--

--

Suppapan S.
suppapan

I have a deep interest in internet, technology, people and business. With my ability to listen, my enthusiasm and knowledge, I help people to grow