Basic assembly shellcode
thm.asm
:
global _start
section .text
_start:
jmp MESSAGE ; 1) let's jump to MESSAGE
GOBACK:
mov rax, 0x1
mov rdi, 0x1
pop rsi ; 3) we are popping into `rsi`; now we have the
; address of "THM, Rocks!\r\n"
mov rdx, 0xd
syscall
mov rax, 0x3c
mov rdi, 0x0
syscall
MESSAGE:
call GOBACK ; 2) we are going back, since we used `call`, that means
; the return address, which is, in this case, the address
; of "THM, Rocks!\r\n", is pushed into the stack.
db "THM, Rocks!", 0dh, 0ah
Compile and link to create an x64 Linux executable file:
$ nasm -f elf64 thm.asm
$ ls
thm.asm thm.o
$ ld thm.o -o thm
$ ls
thm thm.asm thm.o
./thm
THM, Rocks!
Extract the shellcode by dumping the .text
section of the compiled binary.
$ objdump -d thm
thm: file format elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: eb 1e jmp 401020 <MESSAGE>
0000000000401002 <GOBACK>:
401002: b8 01 00 00 00 mov $0x1,%eax
401007: bf 01 00 00 00 mov $0x1,%edi
40100c: 5e pop %rsi
40100d: ba 0d 00 00 00 mov $0xd,%edx
401012: 0f 05 syscall
401014: b8 3c 00 00 00 mov $0x3c,%eax
401019: bf 00 00 00 00 mov $0x0,%edi
40101e: 0f 05 syscall
0000000000401020 <MESSAGE>:
401020: e8 dd ff ff ff call 401002 <GOBACK>
401025: 54 push %rsp
401026: 48 rex.W
401027: 4d 2c 20 rex.WRB sub $0x20,%al
40102a: 52 push %rdx
40102b: 6f outsl %ds:(%rsi),(%dx)
40102c: 63 6b 73 movsxd 0x73(%rbx),%ebp
40102f: 21 .byte 0x21
401030: 0d .byte 0xd
401031: 0a .byte 0xa
Extract the hex value from the above output by dumping the .text
section into a new file called thm.text
in a
binary format:
$ objcopy -j .text -O binary thm thm.text
$ ls
thm thm.asm thm.o thm.text
The thm.text
file now contains the shellcode in binary format. To be able to use it, it needs to be converted to
hex
first. The xxd
command has the -i
option that will output the binary file in a C string directly:
$ xxd -i thm.text
unsigned char thm_text[] = {
0xeb, 0x1e, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00,
0x5e, 0xba, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xb8, 0x3c, 0x00, 0x00,
0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xe8, 0xdd, 0xff, 0xff,
0xff, 0x54, 0x48, 0x4d, 0x2c, 0x20, 0x52, 0x6f, 0x63, 0x6b, 0x73, 0x21,
0x0d, 0x0a
};
unsigned int thm_text_len = 50;
To confirm that the extracted shellcode works as expected, execute the shellcode and inject it into a C program:
#include <stdio.h>
int main(int argc, char **argv) {
unsigned char message[] = {
0xeb, 0x1e, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00,
0x5e, 0xba, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xb8, 0x3c, 0x00, 0x00,
0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xe8, 0xdd, 0xff, 0xff,
0xff, 0x54, 0x48, 0x4d, 0x2c, 0x20, 0x52, 0x6f, 0x63, 0x6b, 0x73, 0x21,
0x0d, 0x0a
};
(*(void(*)())message)();
return 0;
}
Compile and execute:
$ gcc -g -Wall -z execstack thm.c -o thmx
$ ./thmx
THM, Rocks!