I have the following working NASM code:
global _start
section .text
_start:
mov eax, 0x4
mov ebx, 0x1
mov ecx, message
mov edx, 0xF
int 0x80
mov eax, 0x1
mov ebx, 0x0
int 0x80
section .data
message: db "Hello, World!", 0dh, 0ah
which prints "Hello, World!\n" to the screen. I also have the following C wrapper which contains the previous NASM object code:
char code[] =
"\xb8\x04\x00\x00\x00"
"\xbb\x01\x00\x00\x00"
"\xb9\x00\x00\x00\x00"
"\xba\x0f\x00\x00\x00"
"\xcd\x80\xb8\x01\x00"
"\x00\x00\xbb\x00\x00"
"\x00\x00\xcd\x80";
int main(void)
{
(*(void(*)())code)();
}
However when I run the code, it seems like the assembler code isn't executed, but the program exits fine. Any ideas?
Thanks
When you inject this shellcode, you don't know what is at
message
:in the injected process, it can be anything but it will not be
"Hello world!\r\n"
since it is in the data section while you are dumping only the text section. You can see that your shellcode doesn't have"Hello world!\r\n"
:This is common problem in shellcode development, the way to work around it is this way:
Now dump the text section:
The lines I marked are our
"Hello, World!\r\n"
string:So our C wrapper will be:
Lets test it:
it works.
As BSH mentioned, your shellcode does not contain the message bytes. Jumping to the
MESSAGE
label and calling theGOBACK
routine just before defining themsg
byte was a good move as the address of msg would be on the top of the stack as return address which could be popped toecx
, where the address of msg is stored.But both yours and BSH's code has a slight limitation. It contains
NULL bytes ( \x00 )
which would be considered as end of string when dereferenced by the function pointer.There is a smart way around this. The values you store into
eax, ebx and edx
are small enough to be directly written into the lower nibbles of the respective registers in one go by accessingal, bl and dl
respectively. The upper nibble may contain junk value so it can be xored.becomes
Unlike the prior instruction set, the new instruction set does not contain any NULL byte.
So, the final program looks like this :
Assembling and linking :
Now extract the shellcode from the hello binary :
output:
Now we can have our driver program to launch the shellcode.
There are certain security features in modern compilers like NX protection which prevents execution of code in data segment or stack. So we should explicitly specify the compiler to disable these.
Now the
launcher
can be invoked to launch the shellcode.For more complex shellcodes, there would be another hurdle. Modern Linux kernels have ASLR or
Address Space Layout Randomization
You may need to disable this before your inject the shellcode, especially when it is through buffer overflows.