MessageBox Shellcode
With the foundational knowledge in place, we can now proceed to construct shellcode that accomplishes the task of displaying a basic message box.
Writing shellcode to display a message box might seem a bit pointless but it includes all the elements needed to write more complex shellcode, such as a reverse shell.
To display a message box we are required to do the following:
Find the base address of
kernel32.dll
.Resolve the
GetProcAddress
VMA.Call
GetProcAddress
to get the VMA ofLoadLibraryA
.Load the
user32.dll
module using aLoadLibraryA
call.Call
GetProcAddress
to get the VMA ofMessageBoxA
.Call
MessageBoxA
to display our message.Call
GetProcAddress
to get the VMA ofTerminateProcess
.Call
TerminateProcess
to terminate our process.
We have discussed all of these in previous sections, the shellcode is presented in the following small chunks.
Whilst working through these sections you should test it with Windbg preview, using the workflow presented or your own. As you build the shellcode up, insert breakpoints and examine registers and memory to ensure what you expect to be there is there.
Groundwork
The first chunk has been discussed in depth and will not be discussed further. It locates kernel32.dll
, resolves the VMA of GetProcAddress
and prepares us for the rest of the shellcode:
This shellcode snippet can be used as a foundation for a lot of user land shellcode.
LoadLibraryA
The next snippet will get the VMA of LoadLibraryA
. We will do this by calling the GetProcAddress
function. The syntax for this call is shown below:
Remember, when calling a function in 64-bit Windows the first parameter is passed in via the rcx
register, and the second parameter is passed in using the rdx
register:
The
hModule
parameter is passed in thercx
register.The
lpProcName
parameter is passed in therdx
register.
hModule
is the module/DLL where the function resides, in this case kernel32.dll
(we already have the base address for this module in rbx
). lProcName
is a pointer to a string; this means we need to place "LoadLibraryA" somewhere in memory and put a pointer to it in rdx
:
On line 2
we store the base address of kernel32
in the memory at rbx-0x28
. This isn't strictly necessary in this instance but there might be times when we may need to reference it later.
On line 3
the base address is placed in to rcx
which is the hModule
parameter.
The string "LoadLibraryA" is pushed on to the stack in reverse order and a pointer to the string is moved in to rdx
via rsp
(which points to the string that was just pushed on to the stack). This is done on lines 4
through 8
.
The call is made on line 11
and the return value (the VMA of the function) is stored in [rbx-0x30]
on line 14
.
We now have a reference to the LoadLibraryA
function.
User32.DLL
This snippet uses the LoadLibraryA
function to load the user32.dll
module in to memory and return the base address. We will use this to locate the VMA for the MessageBoxA
function.
The syntax for this call is shown below:
This call is very simple and only has one paramater, which is a pointer to a string and is moved in to the rcx
register:
Lines 2
through 6
push the string on to the stack and move the pointer in to the rcx
register. Line 8
calls LoadLibraryA
(remember from the previous section that [rbp-0x30]
holds the address for the function LoadLibraryA
.
The function returns the base address of the module in the rax
register, which we will use next.
MessageBoxA
The next snippet gets the VMA of MessageBoxA
by calling the GetProcAddress
function. This should be familiar by now and does not require any explanation:
Finally we make the call to MessageBoxA
. The syntax for the call is shown below:
This was discussed in the Calling Conventions section, but let's recap. When calling the MessageBoxA
function:
The
hWnd
parameter is passed in thercx
register.The
lpText
parameter is passed in therdx
register.The
lpCaption
parameter is passed in ther8
register.The
uType
parameter is passed in ther9
register.
The shellcode is shown below:
Exercises
Complete the shellcode to call the
TerminateProcess
function.Write the MessageBox shellcode out and debug it in Windbg Preview.
Change the
MessageBoxA
call for aWinExec
call.Tidy up the shellcode; the
LoadLibraryA
function is not needed for exercise 2.
Last updated