La “potenza” del linguaggio assembly (nasm)

Ecco alcuni semplici esempi di programmazione in assembly, che dimostrano la “potenza” di questo linguaggio.

Il linguaggio assembly è sicuramente il più “potente” che ci sia; infatti vi permette di fare qualsiasi cosa, a vostro rischio e pericolo. Con “potenza” intendo la possibilità teorica che offre di poter fare le cose… non certo la semplicità di programmazione; quest’ultima appartiene ai linguaggi di alto livello.

Partendo da un semplicissimo esempio, scritto in c, vi mostrerò altri programmi “derivati” in assembly. Andiamo subito al cuore della questione.

Ecco il sorgente c del programma di partenza ( file nominato “salta.c” )

#include <stdio.h>

int main(void) {

   puts("sono qui");
   return 0;
               }

A partire da questo sorgente c è possibile ottenere un sorgente assembly, generato dallo stesso compilatore gcc, attraverso il comando

PROMPT> gcc salta.c -S -masm=intel

Questo comando genera un file nominato “salta.s”, scritto in assembly, con sintassi intel (vicina alla sintassi nasm, che utilizzeremo).

Ora rinomino il file con estensione .asm digitando: PROMPT> ren salta.s salta.asm

Dopo qualche necessaria elaborazione manuale, ottengo il sorgente assembly seguente ( file “salta-asm.asm”)

bits 64
	extern puts
	global	main

section .text	

main:
	push	rbp

	mov	rbp, rsp

	sub	rsp, 32

	lea	rcx, LC0
	call	puts
	mov	eax, 0
	add	rsp, 32
	pop	rbp
	ret

section .data

LC0: db "sono qui",0

Ora è possibile ottenere l’eseguibile, con i 2 passaggi, sotto descritti:

PROMPT> nasm -f win64 salta-asm.asm -o salta-asm.o

PROMPT> gcc salta-asm.o -o salta-asm.exe

Con il primo comando creo il file oggetto “salta-asm.o” e con il secondo creo l’eseguibile. L’uso di gcc è necessario, per il fatto che utilizzo la funzione puts del c.

Lanciando il programma “salta-asm.exe”, verrà visualizzato il messaggio: “sono qui”.

E adesso viene il bello…

Adesso viene il bello. E’ infatti possibile manipolare il sorgente assembly per ottenere alcuni interessanti risultati. Ecco un esempio…

bits 64

	extern puts
	global	main

section .text	

main:
	push	rbp
	mov	rbp, rsp
	sub	rsp, 32
	
eti:    
       
        ; call funzione

        lea rax, funzione ; carico in rax l'indirizzo di "funzione"
        jmp rax           ; salto all'indirizzo contenuto in rax
	
eti2:	
        nop
        nop
        nop
        nop
        nop

	mov	eax, 0
	add	rsp, 32
	pop	rbp
	ret


funzione:

; lea	rcx, LC0    con questa istruzione, carico in rcx l'indirizzo di LC0.
  lea	rcx, eti2     ; carico in rcx l'indirizzo dell'etichetta eti2
	call	puts

        jmp eti2

; ret



section .data

LC0: db "sono qui",0

Rispetto al precedente sorgente, ci sono alcune differenze. Per prima cosa, mi sono inventato la funzione chiamata semplicemente “funzione” che chiama la puts del c, per stampare a video un messaggio. Inutile complicazione, direte voi. Tutto però serve per capire meglio l’assembly.

A questo punto ho sostituito “lea rcx, LC0” con “lea rcx, eti2”. Cosa comporta questo?

Semplice, invece di stampare la stringa “sono qui”, delimitata dal carattere ‘\0’, stamperò a video tutto ciò che parte dall’etichetta “eti2” fino a un carattere ‘\0’ che incontrerò in memoria, o prima o poi…

Che importa se fa parte del codice!!! I bit e i byte possono essere sia codice, sia istruzioni; dipende da come vengono interpretati dalla CPU. Quando sto chiamando la puts all’interno di “funzione”, le cinque nop ( codice operativo 0x90 ) e quel che segue, verranno considerati dati.

Dopo aver eseguito “jmp eti2” le cinque nop e tutto quel che segue, sarà considerato codice da eseguire.

Ecco, dunque la POTENZA dell’assembly, di cui parlavo all’inizio… I byte possono essere interpretati, ora come DATI, ora come CODICE.

Non è sicuramente consigliabile programmare in questo modo, anzi è pericoloso, ma, con l’assembly, è possibile. E allora, buon divertimento!

Ultima raccomandazione: certi programmi fateli girare in un computer che usate per gli “esperimenti”, non su quello che vi serve per lavoro! Se sbagliate, infatti, potete fare anche gravi danni. Meglio essere prudenti.

Andrea Paolini (Amministratore del Blog)