3 poin oleh GN⁺ 2025-07-14 | 1 komentar | Bagikan ke WhatsApp
  • Ini adalah pengenalan artikel pertama dari seri untuk pemula assembly x86-64
  • Menyediakan penjelasan pemasangan alat dan struktur dasar berdasarkan sistem 64-bit modern
  • Menggunakan Flat Assembler (FASM) dan WinDbg sebagai alat utama untuk pengembangan dan debugging
  • Mencakup ringkasan pengetahuan inti yang dibutuhkan di praktik nyata seperti format PE, impor DLL, dan calling convention Windows
  • Berfokus pada pengalaman praktik menulis program sederhana untuk keluar dan prosedur debugging

Pengantar dan makna

  • Saat pertama kali mempelajari assembly x86, penulis pernah mengikutinya di kampus dengan pendekatan berbasis lingkungan lama (16-bit, DOS, memori tersegmentasi)
  • Karena saat ini prosesor 64-bit sudah menjadi arus utama, seri ini hanya membahas lingkungan x86-64 yang benar-benar digunakan dan menyingkirkan semua elemen lama
  • Tutorial ini berfokus pada pengembangan program 64-bit yang berjalan di lingkungan sistem operasi Windows
  • Dimulai dari kode minimum yang mengakses OS secara langsung tanpa menggunakan library
  • Artikel ini ditujukan bagi pengembang yang baru ingin belajar assembly, dengan asumsi memiliki pengetahuan dasar C/C++

Menyiapkan alat pengembangan

Assembler

  • CPU hanya dapat menafsirkan machine code yang sulit dipahami manusia, dan assembly language adalah bentuk kode yang dapat dibaca manusia untuk itu
  • Program yang mengubah assembly language menjadi machine code disebut assembler
  • Assembly x86-64 tidak memiliki standar tunggal, sehingga setiap assembler memiliki sintaks dan cara kerja yang berbeda
  • Seri ini menggunakan Flat Assembler(FASM), yang kecil, mudah digunakan, serta menyediakan sistem makro dan editor yang kuat

Debugger

  • Untuk menganalisis kode assembly yang ditulis dan mengamati alur eksekusinya, debugger digunakan sebagai alat yang wajib
  • WinDbg direkomendasikan, dan memungkinkan pengecekan serta manipulasi register, memori, dan kode assembly secara terpisah
  • Dapat diinstal dengan memilih komponen saja dari Windows 10 SDK
  • Melalui debugger, keadaan internal program, struktur memori, dan perubahan register dapat diamati secara langsung

Sudut pandang pemrograman assembly

Struktur CPU dan instruction set

  • CPU hanya dapat melakukan tindakan terbatas sesuai instruction set tertentu
  • Instruksi adalah unit kerja dasar yang dapat dijalankan CPU
  • Setiap instruksi bekerja sangat sederhana bersama parameternya (menyimpan nilai, operasi aritmetika, dan sebagainya)
  • Dalam pemrograman tingkat rendah dan debugging, memahami bahwa struktur ini adalah dasar dari semua konsep tingkat tinggi merupakan hal yang penting

Register

  • Register adalah area memori khusus yang sangat cepat dan tertanam di dalam CPU
  • Di x86-64 terdapat 16 general-purpose register, semuanya berukuran 64-bit
  • Setiap register dapat diakses sebagian dalam satuan byte, word, dan doubleword
Register Byte bawah Word bawah Doubleword bawah
rax al ax eax
rbx bl bx ebx
rcx cl cx ecx
rdx dl dx edx
rsp spl sp esp
rsi sil si esi
rdi dil di edi
rbp bpl bp ebp
r8~r15 r8b~r15b r8w~r15w r8d~r15d
  • rsp berfungsi sebagai stack pointer, rsi/rdi berfungsi sebagai indeks pemrosesan string, sehingga beberapa register memiliki tujuan khusus
  • rip adalah instruction pointer, dan rflags adalah register khusus yang menyimpan flag status hasil operasi

Memori dan alamat

  • Memori bekerja seperti array byte berurutan mulai dari indeks 0
  • Pada arsitektur x86 lama, metode segment-offset wajib digunakan, tetapi pada x86-64 semua memori diperlakukan sebagai ruang alamat flat
  • Dalam praktiknya, sistem operasi dan hardware memetakan ruang alamat virtual tiap proses ke memori fisik secara dinamis
  • Artinya, bahkan alamat virtual yang sama akan berkorespondensi dengan memori fisik yang berbeda pada proses yang berbeda
  • Instruksi dan data berada di memori yang sama (arsitektur von Neumann), dan ini berbeda dari arsitektur Harvard seperti AVR yang digunakan pada Arduino, yang menyimpan data secara terpisah

Menulis program assembly pertama

  • Setelah memasang FASM, lakukan praktik menulis dan membangun kode program sederhana berikut
format PE64 NX GUI 6.0
entry start

section '.text' code readable executable
start:
        int3
        ret

Penjelasan kode

  • format PE64 NX GUI 6.0 : Menentukan format executable yang akan dihasilkan FASM, di sini berupa PE (Portable Executable) 64-bit GUI
  • entry start : Mendefinisikan entry point tempat program akan mulai masuk, dan eksekusi dimulai dari label (start) tersebut
  • section '.text' code readable executable : Menentukan bahwa ini adalah bagian kode dari PE, yaitu area yang dapat dieksekusi
  • start: : Memberi nama pada entry point yang telah ditentukan sebelumnya
  • int3 : Breakpoint untuk debugger yang menghentikan program sementara untuk memeriksa keadaan
  • ret : Instruksi yang mengambil alamat dari stack dan memindahkan kontrol ke lokasi tersebut; pada program ini menghasilkan respons keluar secara langsung

Praktik debugging

  • Buka executable (.exe) program di atas di WinDbg dan siapkan berbagai jendela seperti disassembly dan register

  • Tekan F5 agar program mencapai breakpoint, lalu tekan F8 untuk mengeksekusi satu instruksi setiap kali (langkah demi langkah)

  • Perubahan register (rip dan lainnya) dapat diamati secara real-time

  • Setelah ret dijalankan, kontrol diserahkan ke sistem operasi, lalu proses berlanjut dengan pemanggilan RtlExitUserThread untuk mengakhiri thread dan proses

  • Perhatian: jika keluar hanya dengan instruksi ret, proses bisa tetap tersisa tergantung ada tidaknya eksekusi background tambahan selain thread tersebut, sehingga untuk keluar secara normal sebaiknya selalu memanggil ExitProcess

Format PE dan impor DLL

Gambaran struktur impor fungsi DLL

  • Fungsi WinAPI seperti ExitProcess berada di KERNEL32.DLL
  • Untuk menggunakan fungsi eksternal seperti ini, tabel impor (.idata section) pada executable harus disusun
  • Import Directory Table (IDT) pada section idata berisi informasi alamat RVA seperti nama DLL, nama fungsi, dan IAT/ILT
  • IAT (Import Address Table) akan ditimpa saat runtime oleh OS loader dengan alamat fungsi yang sebenarnya
  • Hint/Name Table terdiri dari nama setiap fungsi dan informasi hint

Contoh definisi section .idata di FASM

section '.idata' import readable writeable
idt: 
    dd rva kernel32_iat
    dd 0
    dd 0
    dd rva kernel32_name
    dd rva kernel32_iat
    dd 5 dup(0)
name_table: 
    _ExitProcess_Name dw 0
                      db "ExitProcess", 0, 0
kernel32_name: db "KERNEL32.DLL", 0
kernel32_iat: 
    ExitProcess dq rva _ExitProcess_Name
    dq 0 
  • db/dw/dd/dq : Menyisipkan nilai dalam satuan byte/word/doubleword/quadword (8 byte)
  • rva : Menghitung alamat virtual relatif (Relative Virtual Address) dari simbol
  • IAT dan Name Table dapat disusun secara manual untuk mereferensikan fungsi DLL

Calling convention Windows 64-bit (MS x64 Calling Convention)

  • Standar aturan yang menentukan cara pengiriman argumen dan penggunaan stack saat memanggil fungsi
  • Di Windows 64-bit digunakan Microsoft x64 Calling Convention
  • Karakteristik utama:
    • Stack pointer harus selalu selaras 16 byte
    • 4 argumen integer/pointer pertama menggunakan register rcx, rdx, r8, r9
    • 4 argumen floating-point pertama dimasukkan ke xmm0~xmm3
    • Argumen tambahan menggunakan stack
    • Terlepas dari jumlah argumen, shadow space 32 byte harus disediakan di stack
    • Pembersihan stack menjadi tanggung jawab pemanggil

Contoh pemanggilan ExitProcess

format PE64 NX GUI 6.0
entry start

section '.text' code readable executable
start:
    int3
    sub rsp, 8 * 5
    xor rcx, rcx
    call [ExitProcess]

section '.idata' import readable writeable
idt: 
    dd rva kernel32_iat
    dd 0
    dd 0
    dd rva kernel32_name
    dd rva kernel32_iat
    dd 5 dup(0)
name_table: 
    _ExitProcess_Name dw 0
                      db "ExitProcess", 0, 0
kernel32_name db "KERNEL32.DLL", 0
kernel32_iat: 
    ExitProcess dq rva _ExitProcess_Name
    dq 0 

Analisis kode baru

  • sub rsp, 8 * 5 : Menyesuaikan stack pointer (menyediakan 40 byte), sekaligus menangani alignment 16 byte dan penyediaan shadow space

  • xor rcx, rcx : Menetapkan 0 ke register rcx sebagai argumen pertama (digunakan sebagai kode EXIT)

  • call [ExitProcess] : Melompat ke alamat fungsi ExitProcess yang benar-benar dicatat di import table

  • Saat dieksekusi langkah demi langkah di WinDbg, perubahan pada stack pointer (rsp) dan register rcx, serta alur terminasi proses dapat diamati secara langsung

Penutup

  • Artikel ini memandu alur umum assembly x86-64 secara praktik mulai dari setup alat dasar, format PE, impor DLL, calling convention x64, hingga penulisan program pertama dan debugging
  • Pada bagian berikutnya akan dibahas implementasi fitur yang lebih beragam dan kode nyata

1 komentar

 
GN⁺ 2025-07-14
Komentar Hacker News
  • Ingin membagikan proyek yang telah dikembangkan selama beberapa tahun
    https://asm-editor.specy.app
    Ini adalah IDE interaktif online yang mendukung berbagai bahasa assembly seperti M68K, MIPS, RISC-V, dan X86
    Memiliki banyak fitur untuk mengajarkan pemrograman assembly
    Juga bisa di-embed ke situs web lain

  • Tidak tahu bahwa ada fitur akses langsung ke byte beralamat rendah pada register pengindeks pointer (misalnya pada 16/32-bit, si/esi bisa diakses sebagai sil)
    Konsepnya mirip dengan mengakses al dari ax/eax
    Penasaran apakah opcode yang baru ditambahkan di x86_64 benar-benar ada
    Jadi merasa perlu memeriksa lagi spesifikasi platformnya
    Ini ditanyakan murni karena rasa ingin tahu

  • Membagikan materi pengantar assembly yang ditulis sendiri
    https://www.nayuki.io/page/a-fundamental-introduction-to-x86-assembly-programming

  • Mencoba optimasi dengan assembly karena penasaran apakah dispatch emulator CPU buatan sendiri bisa dibuat lebih cepat daripada C++
    Sudah mencoba menjalankan program Fibonacci, tetapi hasilnya sama sekali tidak mendekati
    Akhirnya hanya digabungkan dengan opsi nonaktif secara bawaan
    Meski begitu, tetap yakin pasti ada cara untuk membuatnya lebih cepat
    https://github.com/libriscv/libriscv/blob/master/lib/libriscv/amd64/inaccurate_dispatch.nasm
    Sedikit meningkatkan performa sambil mempelajari cara akses memori
    Tabel lompat diperkecil dari 64-bit menjadi 32-bit dan ditempatkan di bagian .text agar bisa diakses secara RIP-relative
    Program Fibonacci tidak membutuhkan banyak bytecode
    Sangat ingin mendengar tips tentang hal-hal yang masih bisa ditingkatkan

    • Penasaran apakah sudah membandingkan langsung kode yang ditulis sendiri dengan kode yang dihasilkan compiler C++
      Tidak terlalu paham konteksnya, tetapi rasanya perbedaannya mungkin bukan karena mekanisme dispatch (cara fetch instruksi), melainkan karena perbedaan implementasi instruksi yang sebenarnya
      Sebagai optimasi, register yang diemulasikan bisa dipetakan ke register x86-64 asli agar sama sekali tidak tumpah ke memori
      Dengan begitu, operasi seperti add bisa dijalankan langsung tanpa mengambil dari memori
      Namun, pendekatan ini membuat penulisan emulator jauh lebih merepotkan
  • Ini adalah materi pengantar x86 assembly yang bisa dipraktikkan langsung di browser
    Contohnya bisa langsung dijalankan tanpa setup lokal khusus
    https://shikaan.github.io/assembly/x86/guide/2024/09/08/x86-64-introduction-hello.html
    Sebagai catatan, ini ditulis sendiri

    • Penasaran apakah ada validasi input terpisah
      Karena tampaknya langsung di-assemble dengan NASM lalu menjalankan binarinya, jadi jadi penasaran soal keamanannya
  • Awalnya mengira itu junferno hanya dari foto profilnya

  • Bahkan hanya dengan sekali mencoba assembly, pemahaman secara keseluruhan bisa jadi lebih dalam, jadi ini selalu menjadi pengalaman yang bagus
    Tidak perlu sampai membuat proyek besar, jadi disarankan untuk memberanikan diri dan mencoba sedikit secara langsung

  • Membagikan tautan diskusi HN saat itu (2020)
    https://news.ycombinator.com/item?id=24195627

  • Senang karena ini memakai sintaks assembly gaya Intel

    • Jadi penasaran sintaks assembly lain itu seperti apa
  • Ingin mencoba membuat sesuatu dengan assembly, tetapi tidak punya ide khusus

    • Merekomendasikan game bernama TIS-100
      Ini adalah game memecahkan teka-teki dengan semacam pseudo-assembly
      Rasanya game seperti ini bisa memuaskan keinginan untuk bermain-main dengan assembly