Blog


X64 Linux Assembly Environment Setup

Jul 22, 2018 | 4 minutes read

Tags: assembly, slae-64

I recently started the SecurityTube Linux Assembly Expert certification, and found myself in need of a solid assembly development environment. Outlined below are the tools and functions I found useful.

Vim - the ubiquitous text editor

Vim is my go-to text editor for just about anything aside from large development projects. Vim comes installed on most flavors of linux. You can check out my .vimrc if you’re interested in my personal vim environment setup.

NASM - Netwide Assembler && binutils

nasm and binutils are the commandline utilities that allow me to link and assemble assembly code as well as dump shellcode from executables.

sudo apt install nasm binutils

GDB: The GNU Project Debugger

gdb is the GNU Project Debugger. I was already familiar with GDB from writing C/C++, so picking it up for assembly was a natural choice.

sudo apt install gdb

PEDA - Python Exploit Development Assistance for GDB

During my time spent practicing for and certfying OSCP, I came across PEDA and really liked its interface for showing additional heads-up information on top of what GDB already offered. If you end up taking SLAE-64, the instructor will walk you through a lot of useful GDB commands and different ways to display information that you’ll need to know when debugging assembly. PEDA takes most, if not all, of those commands and rolls them into a single coherent (colored!) sight picture. On top of the nice GDB overlay, there are a lot of helpful commands specific to PEDA that make exploit development less painful.

git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
echo "DONE! debug your program with gdb and enjoy"
PEDA in action

nasmshell

Part of creating shellcode is janking™ around with the instructions to find what works in the smallest amount of space without known bad characters. nasmshell makes it incredibly easy to check which opcodes are generated by which instructions. It allows me to quickly determine which instruction I should include in my shellcode.

git clone https://github.com/fishstiqz/nasmshell.git
cd nasmshell
./nasmshell
ndisasm> bits 64
ndisasm> as
assemble mode
nasm> push rax
50                       push rax
nasm> push rax ; push rbx
50                       push rax
53                       push rbx
nasm> jmp pastsym; sym: db 0x11,0x01,0x11,0xff; pastsym: lea rax, [rel sym]
EB04                     jmp short 0x6
1101                     adc [rcx],eax
11FF                     adc edi,edi
488D05F5FFFFFF           lea rax,[rel 0x2]

Helper Functions

To make use of the functions below, just add them to your .bashrc and then source the resulting file however you see fit. The simplest is likely to just spawn another bash shell. If you’re interested in the other functions and aliases I use outside of assembly, check out my .bashrc.

┌(epi@main)─(09:21 AM Sun Jul 22)
└─(~)─> bash

┌(epi@main)─(09:24 AM Sun Jul 22)
└─(~)─> # helper functions can now be used in this sub-shell
assemble attempts to link and assemble YOURPATH.[n]asm and dumps the resulting object file and executable in your current directory.

assemble() {
    name="${1}"
    base="$(basename ${name} .nasm)"
    base="$(basename ${base} .asm)"
    nasm -f elf64 "${name}" -o "${base}".o
    ld "${base}".o -o "${base}"
}
┌(epi@main)─(09:39 AM Sun Jul 22)
└─(~)─> lt
total 12
-rw-rw-r--  1 epi epi  686 Jul 18 18:57 execve-stack.asm

┌(epi@main)─(09:39 AM Sun Jul 22)
└─(~)─> assemble execve-stack.asm

┌(epi@main)─(09:39 AM Sun Jul 22)
└─(~)─> lt
total 20
-rw-rw-r--  1 epi epi  686 Jul 18 18:57 execve-stack.asm
-rw-rw-r--  1 epi epi  608 Jul 22 09:39 execve-stack.o
-rwxrwxr-x  1 epi epi  744 Jul 22 09:39 execve-stack

dump-shellcode, as advertised, dumps your shellcode to the screen. Additionally, it displays the length of the shellcode as well as if there were any null-bytes encountered.

dump-shellcode() {
    accum=0
    sentry="No nulls found"
    for i in $(objdump -d "${1}" -M intel | grep "^ " | cut -f 2)
    do
        echo -n '\x'$i
        accum=$(( accum + 1 ))
        if [[ "${i}" = "00" ]]
        then
            sentry="You have nulls, try again"
        fi
    done
    echo && echo "length of shellcode: $accum"
    echo "${sentry}"
}
┌(epi@main)─(09:43 AM Sun Jul 22)
└─(~)─> dump-shellcode execve-stack
\x48\x89\xd8\x48\x29\xd8\x48\x89\x44\x24\xf8\x48\x83\xec\x08\x48\x89\xe2\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05
length of shellcode: 43
No nulls found

findsyscall just grabs the syscall I’m looking for so that I know what number corresponds to the syscall I intend to use.

findsyscall() {
    egrep -i "${1}" /usr/include/x86_64-linux-gnu/asm/unistd_64.h
}
┌(epi@main)─(09:34 AM Sun Jul 22)
└─(~)─> findsyscall access
#define __NR_access 21

The flipstring function is useful for converting a string to hex, then reversing it so that it’s ready to be pushed onto the stack.

flipstring() {
    python3 -c "import binascii; print(binascii.hexlify('${1}'[::-1].encode()))"
}
┌(epi@main)─(09:36 AM Sun Jul 22)
└─(~)─> flipstring /bin//sh
b'68732f2f6e69622f'


comments powered by Disqus