PDA

View Full Version : [assembly] Salti relativi


Teo@Unix
20-01-2010, 21:37
è un pò di tempo che non mi capacito di questa cosa...

qualcosa mi vieta di fare dei salti relativi in assembly?
Mi spiego meglio...
l'istruzione:
jmp 0x2a
non si può fare?

a me da segmentation fault. (su Ubuntu 9.10)

ma lo spostamento che eseguo utilizzando il registro IP lo calcolato e non sconfina, perchè dunque non c'è modo di eseguire salti di questo tipo?

Per essere sicuro di quello che dico ho fatto questa prova:
un banale programma che stampa "Hello world!" con codice assembly funzionante:

;---> sintassi intel <---

section .data

section .text
hello db "Hello world!",0xa
global main
mov eax,4
mov ebx,1
mov ecx,hello
mov edx,13
int 80h

mov eax,1
mov ebx,0
int 80h

ho inserito nel programma un salto relativo subito dopo la stampa del massaggio. Questo salto non salta da nessuna parte in particolare, solo alla istruzione successiva, ma l'errore permane sempre. Ecco il codice con il salto "inutile":

section .data

section .text
hello db "Hello world!",0xa
global main
main:
mov eax,4
mov ebx,1
mov ecx,hello
mov edx,13
int 80h

jmp 0x5 ; <<- jmp è 5 bytes, quindi salta qui |
mov eax,1 ;<------------------------------------/
mov ebx,0
int 80h

in questo caso, dopo la stampa, invece di eseguire la exit, il programma viene terminato da SIGSEGV.
Eventualmente posso postarvi anche la traccia del programma in esecuzione....

la mia esperienza in assembly è piuttosto breve ancora...
che ne pensate?
Grazie mille.:D

cdimauro
21-01-2010, 04:59
Non sai se l'assemblatore ti ha convertito la jmp in versione "short" (un byte per l'opcode, e uno per l'offset a 8 bit con segno) oppure ha lasciato quella "long" (quest'ultima non richiede un offset, ma l'indirizzo di memoria vero e proprio).

Assembly e linguaggio macchina sono diversi anche per questo: quando usi uno mnemonico, non hai la certezza assoluta di quale opcode verrà generato.

Supponendo che ti abbia generato la versione "short" devi conoscere in che modo calcolare l'offset. Adesso su due piedi non ricordo se l'offset con x86 viene calcolato prendendo come riferimento la stessa istruzione o quella successiva (come capita con tante architetture).
Nel primo caso dovresti mettere 2 come offset, mentre nel secondo 0.

Se invece la versione utilizzata è quella "lunga", devi utilizzare un'etichetta, altrimenti ti sarà impossibile conoscere l'indirizzo fisico che verrà generato per l'istruzione successiva alla jmp.

Teo@Unix
21-01-2010, 07:28
sono risalito alla dimensione della istruzione jmp con il metodo che avevo descritto, ovvero disassemblando con gdb.
In molti documenti in rete vi leggo che è affidabile...:rolleyes: e riportano anche esempi che dovrebbero funzionare... supponendo che non dicano tutti il falso ... perchè a me non funzionano?:(

cmq, anche mettendo 2 il programma genera l'errore di memoria...

se volessi provare con l'indirizzo di memoria? Non credo di avere modo si saperlo....

cdimauro
21-01-2010, 07:42
Non credo proprio.

Comunque riporta i byte che codificano l'opcode jmp, così vediamo intanto di cosa si tratta.

rеpne scasb
21-01-2010, 08:20

Teo@Unix
21-01-2010, 09:05
Grazie ragazzi, allora ...cominzio a postare le prove che ho fatto ...
innanzi tutto con objdump -d hello.o ricavo la codifica del salto.

istruzione: jmp 0x5:
21: cd 80 int $0x80
23: e9 01 00 00 00 jmp 29 <main+0x1c>
28: b8 01 00 00 00 mov $0x1,%eax

istruzione jmp 0x4:
21: cd 80 int $0x80
23: e9 00 00 00 00 jmp 28 <main+0x1b>
28: b8 01 00 00 00 mov $0x1,%eax

mi sembrerebbe quasi più giusta la seconda, perchè salta a main+28
o mi sto imbrogliando?

cmq si vede che anche se 3 sono nulli jmp è 5 bytes. Purtroppo in entrambi i casi SIGSEGV...:rolleyes:

ora faccio la prova dichiarando anche come ha specificato rеpne scasb...

Teo@Unix
21-01-2010, 09:12
prova a sostituire con 'DB 0xEB, 0x0' e vedi che succede.

scusa intendi così:
jmp 'db 0x05, 0x0'

nel caso lo abbia scritto correttamente mi da un warning:
hello.asm:15: warning: character constant too long

e purtroppo non cambia l'esito finale.

rеpne scasb
21-01-2010, 09:26

rеpne scasb
21-01-2010, 09:35

Teo@Unix
21-01-2010, 11:04
ho ricontrollato per essere sicuro. la traduzione di jmp 0x4 è 09 00 00 00 00, quella cho ho riportato per intenderci.

l'assemblatore che ho usato è nasm versione:
NASM version 2.05.01 compiled on Nov 5 2008

è incredibile ma il mio programma hello world arrivato a quella istruzione provoca segm. fault....
come se qualcosa mi impedisce di eseguire jmp relativi...

provando invece con ciò che mi hai suggerito, l'assemblatore me lo vede come un add, guarda:

nel file .asm ho messo al posto di jmp:
db 4h,0h
codifica:
23: 04 00 add $0x0,%al

avete provato a compilarlo e ad eseguirlo anche voi?

rеpne scasb
21-01-2010, 11:22

Teo@Unix
21-01-2010, 11:37
Non ti ho detto di metterci db 4h,0h ma db 0ebh,0h.

pardon...
non avevo capito che si trattava direttamente dell'opcode:doh:

così funziona, sembra quindi che debba inserire i salti relativi direttamente come OPCODE in questo modo. Possibile?

Ora proverò con il programma che mi dava problemi in principio, poi vi dico.

edit:
a! una cosa, un consiglio per ottenere i valori dei codici corretti da inserire pertemdo dall'istruzione presentata per prima? (ad esempio jmp 0x2a)

Teo@Unix
21-01-2010, 13:17
a! una cosa, un consiglio per ottenere i valori dei codici corretti da inserire pertendo dall'istruzione presentata per prima? (ad esempio jmp 0x2a)

thank you

Teo@Unix
23-01-2010, 18:47
:mad: allora i salti relativi li ho calcolati con esattezza.
ma c'è ancora quacosa che non mi torna..... errore: "segmentation fault" ... credo che centri qualcosa la stringa "/bin/sh". Questo programma dovrebbe semplicemente eseguire una shell!! ma perchè mi dà SIGSEGV?????:muro:

void main() {
__asm__(
"jmp 0x25\n\t"
"popl %esi\n\t"
"movl %esi, 0x8(%esi)\n\t"
"xorl %eax, %eax\n\t"
"movb %eax, 0x7(%esi)\n\t"
"movl %eax, 0xc(%esi)\n\t"
"movb $0xb, %eax\n\t"
"movl %esi, %ebx\n\t"
"leal 0x8(%esi), %ecx\n\t"
"leal 0xc(%esi), %edx\n\t"
"int $0x80\n\t"
"movl $0x1, %eax\n\t"
"xorl %ebx, %ebx\n\t"
"int $0x80\n\t"
"call -0x22\n\t"
".string \"/bin/sh\"\n\t"
);
}

so cha la sintassi AT&T non piace, portate pazienza....
se volete anche compilarlo vi dico che io sto provando su Debian 5 e gcc 4.3.2

ci stò uscendo matto.

EDIT: vi metto anche la versione assembly, stesso problema... e qui non ci sono salti relativi.....
.text
.globl main

main:
jmp offset

shellcode:
popl %esi
movl %esi, 0x8(%esi) //inserisco la stringa dopo il byte nullo
xorl %eax, %eax //azzero eax
mov %al, 0x7(%esi) //inserisco 0 alla fine della stringa
mov %al, 0xc(%esi) //fine stringa
movb $0xb, %al //n° interrupt
movl %esi, %ebx //1°arg. - stringa "/bin/sh"
leal 0x8(%esi),%ecx //2°arg. - indirizzo stringa
leal 0xc(%esi),%edx //3°arg. - byte nullo
int $0x80 //execve(name[0],name,NULL)
// exit(0):
xorl %ebx, %ebx
movl $0x1, %eax
int $0x80
offset:
call shellcode
.string "/bin/sh"

Teo@Unix
24-01-2010, 14:41
call shellcode
.string "/bin/sh"

credo sia questo il problema, come posso risolvere?

Teo@Unix
24-01-2010, 15:11
popl %esi

dopo questa istruzione non dovrei avere aver recuperato l'indirizzo della stringa "/bin/sh" messa nello stack dalla call?

perchè debuggando non mi sembra.
Il comando successivo che lavora su esi provoca l'errore:(

Tesinevb
24-01-2010, 15:13
credo sia questo il problema, come posso risolvere?

prova così:
.string '/bin/sh'

Teo@Unix
24-01-2010, 15:22
no, credo che ' sia un carattere che gcc non digerisce per quanto riguarda l'assembly...
infatti il compilatore non lo riconosce.
e non credo sia un problema di formattazione....

cdimauro
25-01-2010, 07:08
Non sembra neppure a me. Hai modo di postare il dump degli opcode per quel pezzo di codice?

Teo@Unix
25-01-2010, 11:09
allora il problema l'ho risolto inserendo la stringa direttamente in codifica esadeciamale, evitando così di usare la call per salvare l'indirizzo della stringa seguente nello stack. Mi sembra dopo tutto una piu che buona soluzione...

push $0x2f68732f //Inserisco la codifica di "/sh/" nello stack
push $0x6e69622f //Inserisco la codifica di "/bin" nello stack
mov %esp, %ebx //Prelevo dallo stack l'indirizzo della stringa "/bin/sh/"
mov %al, 0x7(%ebx) //Inserisco il byte terminatore di stringa alla fine

rimane un mistero l'errore con la call.
posto comunque (anche perchè mi piacerebbe capire perchè non funziona) il dump degli opcode relativo al modulo precedente:
shellcode.o: file format elf32-i386

Disassembly of section .text:

00000000 <main>:
0: eb 21 jmp 23 <offset>

00000002 <shellcode>:
2: 5e pop %esi
3: 89 76 08 mov %esi,0x8(%esi)
6: 31 c0 xor %eax,%eax
8: 88 46 07 mov %al,0x7(%esi)
b: 88 46 0c mov %al,0xc(%esi)
e: b0 0b mov $0xb,%al
10: 89 f3 mov %esi,%ebx
12: 8d 4e 08 lea 0x8(%esi),%ecx
15: 8d 56 0c lea 0xc(%esi),%edx
18: cd 80 int $0x80
1a: 31 db xor %ebx,%ebx
1c: b8 01 00 00 00 mov $0x1,%eax
21: cd 80 int $0x80

00000023 <offset>:
23: e8 da ff ff ff call 2 <shellcode>
28: 2f das
29: 62 69 6e bound %ebp,0x6e(%ecx)
2c: 2f das
2d: 73 68 jae 97 <offset+0x74>

se lo provate sulla vostra macchina, ditemi se funziona o meno. Grazie.

cdimauro
25-01-2010, 13:12
Diciamo che avrei qualche difficoltà a provarlo. :D

Vediamo se c'è qualche amico linuxiano che può farlo. :)

Z80Fan
19-06-2010, 14:27
Ciao.
Mi scuso di aver riaperto un vecchio thread, ma se sei interessato, io potrei darti una mano, solo che non riesco a far assemblare il codice, ne ad as, ne a gcc. Mi danno entrambi:
Error: suffix or operands invalid for `pop'
per il
popl %esi
Se mi dici come lo compili, posso aiutarti :)

Teo@Unix
19-06-2010, 20:49
ti ringrazio per l'interesse, poi comunque ho risolto quella questione come vedi dai post...

ora a memoria non mi ricordo come è andata a finire la storia della call, cmq se vuoi provare io avevo compilato con gcc su ubuntu 9.10.. mi sembra ...:D

Z80Fan
19-06-2010, 21:10
ti ringrazio per l'interesse, poi comunque ho risolto quella questione come vedi dai post...

ora a memoria non mi ricordo come è andata a finire la storia della call, cmq se vuoi provare io avevo compilato con gcc su ubuntu 9.10.. mi sembra ...:D

Ok, niente allora :)
Solo un'altra domanda: stavi mica leggendo "L'arte dell'Hacking" di Jon Erickson? Visto che il sorgente si chiama "shellcode", e usi il trucco della call per prendere l'indirizzo della stringa ... :D

Teo@Unix
19-06-2010, 21:18
Ok, niente allora :)
Solo un'altra domanda: stavi mica leggendo "L'arte dell'Hacking" di Jon Erickson? Visto che il sorgente si chiama "shellcode", e usi il trucco della call per prendere l'indirizzo della stringa ... :D

quello in particolare non l'ho letto...

si in effetti quello è un vecchio trucco per ottenere l'indirizzo della stringa.