basic assembly

cpu registers

ใน cpu จะมี registers ต่างๆ ขนาด 32 bits ที่ใช้เก็บข้อมูล สำหรับ alu (arithmetic logic unit) นำมาประมวลผล โดยมี register ที่สำคัญ มีดังนี้

  • 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) ทั้ง 4 ตัวนี้ใช้สำหรับเก็บข้อมูลทั่วไป (general purpose registers)
  • esi (extended source index), edi (extended destination index) ใช้สำหรับคำสั่งที่ต้องการ indexing เช่น array, copy string แต่ในบางครั้ง ก็ถูกใช้เหมือนกับ register 4 ตัวข้างบน คือเก็บข้อมูลทั่วไป

general purpose registers (eax, ebx, ecx, edx) สามารถ access แบบ 16 bits และ 8 bits โดยแบ่งตามรูปข้างล่าง

eax

ส่วน register ตัวอื่นๆ สามารถ access แบบ 16 bits ตามนี้ ip, bp, sp, si, di

flags

flags ใช้สำหรับบอกสถานะของผลลัพธ์ของคำสั่ง บางคำสั่งจะไม่มีการเปลี่ยนค่า flags บางคำสั่งจะมีการเปลี่ยนบาง flags โดยใน cpu นั้นมี flags อยู่หลายตัว แต่ในที่นี้ ผมจะพูดเฉพาะ zf (zero flag), sf (sign flag)

  • zf เป็น flag ที่ถูก set เมื่อผลลัพธ์ของ operation เป็น 0
  • sf เป็น flag ที่ถูก set เมื่อผลลัพธ์ของ operation เป็นลบ

assembly language

คราวนี้ก็มาถึงตัว assembly เองแล้ว โดยตัว syntax เองก็จะมีหลักๆ อยู่ 2 แบบที่ใช้กัน คือ at&t กับ intel โดย

  • ตัว at&t syntax จะถูกใช้ใน gnu assembler และส่วนมากจะเป็น default สำหรับ linux
  • ตัว intel syntax ก็จะเป็น netwide assembler (nasm) และ windows assemblers ส่วนมากจะใช้ nasm

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

  • คำสั่งที่ต้องการ source กับ destination จะสลับกัน โดย at&t จะใช้ source ข้างหน้า แต่ nasm จะใช้ destination ข้างหน้า คือ
    • at&t: cmd <source>, <dest> <# comment>
    • nasm: cmd <dest>, <source> <; comment>
  • at&t ใช้ % ข้างหน้า registers แต่ nasm ไม่ใช้
  • at&t ใช้ $ ข้างหน้า immediate value แต่ nasm ไม่ใช้
  • at&t จะมี suffix (ตัวต่อท้ายคำสั่ง) เพื่อระบุขนาดของ operand โดยใช้ l สำหรับ long (4 byte), w สำหรับ word (2 byte), b สำหรับ byte (สำหรับ gnu assembler เราสามารถไม่ใส่ suffix ถ้าคำสั่งนั้นมี operand ที่ระบุขนาด) แต่ nasm จะมีเมื่อใช้กับการอ้างอิงที่อยู่ เช่น dword ptr, byte ptr
  • เรื่องการอ้างที่อยู่ memory โดย at&t ใช้ () ส่วน nasm ใช้ [] และตำแหน่งของ index ก็จะต่างกัน จะพูดถึงอีกทีในเรื่องของ assembly command

เนื่องจากเรากำลังเขียน exploit บน linux ผมจะพูดถึง at&t syntax เป็นหลัก

assembly commands

ในที่นี้ ผมจะพูดเฉพาะคำสั่งที่ผมคิดว่าสำคัญมากๆ ถ้าใครต้องการรู้เพิ่มเติม คงต้องหาอ่านเพิ่มเอาเองนะครับ

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

ASM
movl $1234h, %eax
mov  %eax, %ebx   # gnu assembler สามารถเดาได้ว่าเป็น movl เพราะ ebx มีขนาด 4 bytes
movw %ax, %bx
movb %al, %bl

คำสั่งแรกคือ กำหนดค่าของ register eax ให้เป็น 0×1234 (ใน assembly สามารถใช้ได้ทั้้ง 1234h และ 0×1234) ส่วนคำสั่งที่ 2 คือ กำหนดค่าของ ebx ให้เหมือน eax ถ้าทำงานต่อกัน ebx ก็จะเป็นค่า 0×1234
ส่วนถ้า assembly นี้เขียนเป็น nasm syntax ก็จะเป็น

ASM
mov eax, 1234h
mov ebx, eax
mov bx, ax
mov bl, al

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

ASM
addl $1234h, %eax  # นำค่าที่อยู่ใน eax บวก 0x1234 แล้วเก็บใน eax
subl $1234h, %eax  # นำค่าที่อยู่ใน eax ลบ 0x1234 แล้วเก็บใน eax

xor, or, and
เป็น bitwise operation ของการทำ xor, or หรือ and ของ source กับ destination แล้วเก็บผลลัพธ์ไว้ที่ destination เช่น

ASM
xorl %eax, %eax  # xor ค่าของ eax กับ eax เป็นเทคนิคหนึ่ง ที่ทำให้ eax เป็น 0
orl %ebx, %eax
andl %ebx, $ffh

push, pop
ใช้สำหรับ push กับ pop ค่าบน stack (ตำแหน่งบนสุดของ stack ดูได้จากค่า register esp) เช่น

ASM
pushl $10h  # push ค่า 0x10 ลงใน stack
pushl %eax  # push ค่าของ eax ลงใน stack
popl %ebx   # pop ค่าจาก stack เก็บใน ebx

cmp
ใช้สำหรับเปรียบเทียบค่า source กับ destination แล้ว set ค่า flag ต่างๆ ตามผลลัพธ์ เพื่อใช้สำหรับคำสั่ง jump ต่างๆ เช่น

ASM
cmpl $55, %eax

jne, je, jnz, jz, jmp
ใช้ สำหรับ jump (กระโดด) ไปคำสั่งที่ตำแหน่งอื่นๆ โดยจะกระโดดหรือไม่ ขึ้นอยู่กับชนิดของ jump และค่าของ flag ต่างๆ แต่ในที่นี้ ผมจะไม่พูดถึง flag นะครับ เพราะจำยาก แต่ให้ดูที่ความหมายเอา โดยในตัวอย่างข้างล่างสมมติว่ามีการใช้ cmp ตามตัวอย่างข้างบน และค่า eax เป็น 10

ASM
jne 5   # jump if not equal คือ 55 ไม่เท่ากับ 10 ดังนั้นก็จะ jump
je 5    # jump if equal คือ 55 ไม่เท่ากับ 10 ดังนั้นจะไม่ jump
jnz 5   # jump if not zero คือถ้า zero flag ไม่ถูก set ซึ่งจะเหมือนกัน jne
jz 5    # jump if zero คือถ้า zero flag ถูก set ซึ่งจะเหมือนกัน je
jmp 5   # jump โดยไม่มีเงื่อนไข

การ jump จะมีทั้งแบบ absolute address (คือระบุว่าจะไปที่ address ไหน) และ relative address (คือระบุว่าจะไปข้างหน้าหรือข้างหลังจากตำแหน่งปัจจุบันเท่าไร) โดยตัวอย่างที่ผมเขียนมา เป็นแบบ relative ทั้งหมด

inc, dec
ใช้สำหรับเพิ่มค่า (+1) หรือลดค่า (-1) ใน register เช้น

ASM
inc %eax
dec %ebx

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

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

แต่ถ้าเป็น mov

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

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

ASM
int $0x80

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

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

reference

credit : sleepya [ http://thtutz.blogspot.com ]



Related post :

  1. hello assembly
  2. ollydbg howto 01 – ollydbg interface
  3. basic buffer overflow
  4. basic crack 06 – keygen by inline patching
  5. x86 calling convention

Comments (0)

› No comments yet.

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Pingbacks (1)