I understand that a qword is a data of size 64 bits but when I remove qword the shellcode doesn't work. Why I need to add qword?
Perché stai spostando una costante qword. Quando digiti '//bin/sh'
stai esprimendo un array di 8 caratteri. Premendo il prefisso con qword si sta istruendo l'assemblatore a trattare l'operando a destra come un intero in linea a 64 bit. Di default lo tratterà probabilmente come un puntatore a quella stringa, o qualche altro comportamento.
And after the instruction shr, my strings should be looks like '%00//bin/s' no?
I numeri interi dei processori di architettura x86 sono memorizzati come little-endian . Se il tuo compilatore l'ha preso alla lettera, la tua stringa verrebbe codificata in ASCII come segue:
/ / b i n / s h
2f 2f 62 69 6e 2f 73 68
Che puoi anche mostrare nelle seguenti istruzioni:
mov rbx, 0x2f2f62696e2f7368
Questo codifica come segue:
48 BB 68 73 2F 6E 69 62 2F 2F
Possiamo dividerlo in 3 sezioni:
48 BB 68 73 2F 6E 69 62 2F 2F
| | |---------------------|
\ \ literal
64-bit B8 = MOV instr
prefix + reg operand
+ r/m operand
In questo caso il byte dell'istruzione mov ( BB
) contiene anche un campo a 7 bit che descrive il registro in cui ci stiamo spostando ( rbx
) e il tipo di operando a destra (letterale).
Ma attenzione: il letterale è non nello stesso ordine della rappresentazione ASCII che abbiamo visto sopra. Invece è invertito a causa di little-endianness.
Il problema qui, naturalmente, è che questo non può essere ciò che accade nel tuo shellcode. Se il nome è stato invertito nei byte, la funzione chiamata vedrebbe hs/nib//
e fallirà. Invece, il tuo assemblatore è abbastanza intelligente da capire che vuoi quei caratteri ASCII in ordine di byte, il che significa che codifica davvero le seguenti istruzioni:
mov rbx, 0x68732f6e69622f2f
Questo produce le seguenti istruzioni codificate:
48 BB 2F 2F 62 69 6E 2F 73 68
Come puoi vedere, //
viene prima ( 2F 2F
) nella rappresentazione dell'ordine dei byte.
Why not use shl instead of shr?
Fai entrambi. Nel tuo codice manca un'istruzione, che può essere vista nel tutorial. Dopo il shl rbx, 0x8
segue immediatamente un shr rbx, 0x8
.
La loro spiegazione non rende giustizia:
After shifting 0x08 to the left (think of each numeric placeholder in the string as a 4, so moving 8 bytes over actually moves us two spaces) pushes the 11 right off the end. Now we have this:
0x68732f6e69622f00
Then we put it back like before by using shr by the same value, and we get this:
0x0068732f6e69622f
This successfully gives us our string terminated by a nullbyte without generating a single nullbyte in the machine code.
La prima barra è semplicemente un carattere sacrificale che viene scartato durante shl
.
Il motivo di questo trucco, invece di caricare il null al primo posto o mascherare il byte più a destra con zero è che non richiede byte null nel payload di exploit, che è molto utile se l'input viene ignorato dopo un null ( ad esempio se una stringa viene copiata con strcpy).