
With 2019 approaching fast I’ve got my heart set on one thing OSCE! I’ve been using tons of blogs and assorted resources to help me get up to game speed. Just like any other new language, the first thing we do is print “Hello World” to the screen. Usually this is a one-liner w/ a simple print function (statement) in the respective language. Not so much in assembly. It takes a little more elbow grease. Qualifying Statement: I am NOT an assembly ninja – most of this is still new to me, it’s yet to feel natural to me (not sure it will ever feel that way xD). Be that as it may, I’m still trying my hardest & learning as I go along! One thing about me I never quit. Ever. In addition, you can find much better articulated, in depth blogs so I’ll spare you some of the details in the spirit of keeping things concise. With that being said let’s jump into it.
On my system 32 bit Kali Linux VM – the list of system calls are defined in C header file:
/usr/include/i386-linux-gnu/asm/unistd_32.h. For this post the system call we’re interested in is:
#define __NR_write 4.
Now we determine the prototype to better understand the arguments (if any) of this particular call. Here’s the prototype:
ssize_t write(int fd, const void *buf, size_t count) It never ceases to amaze me at how cryptic some of these prototypes and descriptions are from the man pages. Anyway we’re learning with military precision so we won’t let words distract us. Let’s break down the 3 parameters, which really aren’t that bad & intuitive (after-the-fact lol).
- fd – This is the file descriptor. Anyone w/ any hacking or bash scripting experience should understand where we’re going. stdin=0 stdout=1 and stderr=2. We’re printing to the screen we’ll use stdout which is always mapped to fd 1
- const void *buf – This is a fancy way of saying a pointer to our buffer or what ever it is we want to print.
- size_t count – The size of the above buffer
Great! With that out the way we’re going places. But how do we use any of it? One needs to understand the layout of binaries in virtual address space. The actual instructions (assembly) go inside the .text section, initialized data goes in .data section & I leave it up to you to better understand these sections along w/ the rest (there are more!). In x86 architecture, there’s a convention used when calling functions. EAX gets the syscall number (4 in this case, from unistd_32), EBX gets the 1st argument, ECX 2nd argument so on and so fourth. After the registers are all set, we issue a soft interrupt to the kernel (inform him that we want to invoke the write() function). Also For this post those two are all we need to know. That’s it! It’s similar for all the system calls we want to use in the future, setup the registers w/ the appropriate values and issue the interrupt.
So here’s the logic:
- Copy the value 4 inside EAX for the write() system call
- Copy the value 1 inside EBX for file descriptor 1 (stdout aka your monitor)
- Copy the reference to message label, which defined our Hello World string inside ECX
- Copy the message length into EDX which was calculated using another variable. One could also copy 0xc or 12
- Issue interrupt (0x80 – always the same)
- Issue exit system call (#1 .. only one parameter in EBX if you want as return code, default is 0
Final Code:

Now we have the .asm file. Remember we invented & write in assembly because we can’t understand 32 digit sequences of 1’s and 0’s like the almighty processor! Assembly translates 1 to 1 w/ the specific machine code which is what actually gets executed on the processor. So we need to turn this file into a binary. First we turn it into an object file w/ nasm and then we link it to an elf executable with ld. Because of laziness here a script I shamelessly found to do the compiling & linking in one shot:

Awesome! We successfully printed our string to the screen. I was originally going to kill the post at this moment, but figured what the heck, let’s go a little further. Let’s use objdump to inspect the binary:

A simple breakdown, you can see the instruction we wrote in the .text section. To the far left is the memory address, the middle are the actual machine instructions (in hex) and to the right is our assembly. Let’s extract the shellcode (machine instructions) and see if we can run it in another programs process. Using this cool one liner we can point it at a binary and parse the machine instructions
for i in $(objdump -d HelloWorld |grep "^ " |cut -f2); do echo -n '\x'$i; done; echo
Here’s the hex:
\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\xb9\x00\xa0\x04\x08\xba\x0d\x00\x00\x00\xcd\x80\xb8\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80
One should immediately notice that the shellcode contains the most notorious offender the null byte \x00 which in most languages terminates strings, meaning it would render our shellcode useless. Luckily there ways around this, mainly using the lower 16 and 8 bits of the general purpose registers. Here’s what the updated code looks like:

Repeating the above here’s the objdump:

Crap! Although we corrected the null bytes in regards to the registers, we still end up w/ a nullbyte because of the instruction to move our shellcode buffer into the appropriate register:
8049008: b9 00 a0 04 08 mov ecx,0x804a000
In addition, since shellcode is meant to run in another programs virtual address space, this memory address would be garbage on another system so we fail twice.
Let’s extract the shellcode anyway:
\x31\xc0\xb0\x04\x31\xdb\xb3\x01\xb9\x00\xa0\x04\x08\x31\xd2\xb2\x0d\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80
Alright so our 1st way of loading our message using data section & jumping to the label isn’t feasible anymore. We need to make things more robust. There’s a technique that allows you to deterministically find the address of your string. It exploit the fact that when you use a call instruction the first thing that happens before execution travels to the invoked function, the address of the following instruction is always pushed on the stack (How else would we know we to resume after function call xD). Here’s the logic:
- Jump to a label
- Make a “call” to another label w/ you shellcode right below this call instruction. (remember the address of the next instruction gets pushed onto the stack)
- Once execution is here, you simple need to “pop” the stack into your register as it holds the address of our string, Hello World still in this case.
- Enjoy the breeze
Here’s what the code looks like:

We compile and link the assembly file and then objdump it:

Anyone see any \x00’s this time? Good! Me either.
Let’s extract the shellcode:
\xeb\x13\x31\xc0\xb0\x04\x31\xdb\xb3\x01\x59\x31\xd2\xb2\x0d\xcd\x80\xb0\x01\xcd\x80\xe8\xe8\xff\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21\x0a
Beautiful.
Let’s throw it in our C wrapper:

Compile that with: gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

And we are done!
Or are we? Let’s wrap up w/ an alternative way of doing this. Instead of Jmp Call Pop we’ll just use the stack and ESP. This is mostly the same except for the how we’re getting our string in memory and it’s address. In this case we push our string on the string reversed (little endian) and then just put ESP into ECX (pointer to our buffer, did you forget so soon). Here’s some shortcuts, first we need our string reverse and then we need it in hex, and then we push it on the stack.
We use python:

Great now it’s a matter of pushing it onto the stack and done! 97% of the .asm file remains the same. Here’s the final code:

Thank for stopping by – I hope I was able to explain things in a non-complex way & you learned a little. I will continue to post all the things I do in prep for OSCE in efforts of being another source for others in the future.
Major shoutout to the Vivek & all his wonderful videos from which I learned. I can only aspire to be as knowledgeable, clear and concise as you some day in the future.
2 Comments
Zack
Nice write up! I found it very easy to read and will check out your other post. I’m just getting started with Python so Assembly is a bit advanced for me (at least for now, I love to learn new things so I’m sure I’ll be diving into someday.)
s7acktrac3
Hey buddy – I’m happy you enjoyed it & learned a little. Thanks for leaving a comment!