Hello guys in this post I'm gonna show you how you can create a shellcode for Windows 10 x64.
In this tuto I'm going just to pop calc.exe, you can do other things as you like.
Let's get started.
You can find the shellcode in my GitHub repo here :
First of all Linux shellcode is way easier that Windows shellcode, because not all processes are allowed to trigger syscalls and the syscalls are not well defined in Windows and they are not well documented.
We will be calling functions from Kernel32.dll, and to do this we need first to know it's base address.
Find Kernel32.dll base address :
To find it we will be accessing some structs that are private to our process. The first struct we need to find is TEB (Thread Environment Block), this structure can be accessed using GS register offset 0x0, from that we can access the PEB (Process Environment Block) at offset 0x60.
so the PEB can be accessed by gs:0x60 in our shellcode. Keep note of that.
At offset 0x18 from the PEB we can find the Loader
At offset 0x20 from the PEB we can find the InMemoryOrder
InMemoryOrder is just the head of a doubly linked list containing the DLLs ordered by their placement in memory. They arranged like this : executable name -> ntdll.dll -> Kernel32.dll
We can traverse the doubly linked list from InMemoryOrder, as you can see Kernel32.dll is the third element. All we need to do now is to reach Kernel32.dll (third element in the doubly linked list), and 0x20 offset from that pointer we have the Kernel32.dll Base address !
This is the part of assembly translate the process I was talking about :
Find the address of GetProcAddress()
To find the address of GetProcAddress() or any other function in the Kernel32.dll the process is always the same:
We will be traversing header by header.
Find the address RVA (Relative Virtual Memory) of the PE header, 0x3C offset from the base address of Kernel32.dll.
0x88 offset from the PE header is the Export Table offset.
0x20 offset from the Export Table is the Names Table offset.
Names Table is simply functions names.
Setup a counter like (RCX) and traverse this table element by element and compare if the name of the function is equal to GetProcAddress. When done and the function is found inside this table you will need the counter for the Ordinals Table.
The Ordinals Table is at offset 0x24 from the Export Table. So we will use the counter (RCX) to find the real offset of the function we want inside the Address Table.
The Address Table is where all the addresses for all the functions of Kernel32.dll resides.
This is the block of assembly that do what I said :
Ok now we have the address of GetProcAddress() we can have the address of any other function in Kernel32.dll or other DLLs but they need to be imported using the function LoadLibraryA() for example. For the sake of this tuto I'm just gonna search for WinExec() and pop Calc.exe
Just as a reminder the calling convention for Windows x64 takes arguments like this (rcx, rdx, r8, r9)
So to find WinExec() we need to make RCX = Kernel32.dll (base address) RDX = "WinExec" function name. Then we are ready to call GetProcAddress(rcx, rdx)
Now we know where WinExec() resides in the virtual memory.
All left to do is : WinExec("C:\Windows\System32\calc.exe", 10)
For a clean exit we can find ExitProcess() and call it like we did for WinExec()
This shellcode isn't ready for real-life use as it is long, not optimized, and it has NULL bytes inside.
tincbitikuDowney Carlos Ruiz Click
ReplyDeleteThis is there
carnidoma