Malware Development
October 9, 2023 ยท View on GitHub
- General
- Payload locations
- Payload encoding & encryption
- Code injection
- Evasion Techniques
- Reflective DLL
- Wow64 and Heaven's Gate
- API Hooking
- Payload Control
- Combined Droppers
General
- For building start
x64 Cross Tools Command Promt for VS 2019
Packer
- Create your own packer
DebugBreak
- Inside the dropper to add a breakpoint add
__debugbreak();to the line. It will add theint3instruction to add a breakpoint. - Run debugger and attach the PE.
DebugMessages
- Use
OutputDebugStringAfunction to send messages to debugviewer from Sysinternals.
Dumpbin
Show imported functions - IAT
dumpbin /imports <PATH TO EXE>
Show exported functions
dumpbin /exports <PATH TO EXE>
Show everything
dumpbin /ALL <PATH TO EXE>
Payload locations
- Payloads in droppers can be stored in the following sections of a PE.
.text, put it inside a function in the code. For example within main..data, set payload, inside global variable.rdata, set payload read only, inside global variable.rsrc, place it in a icon, or image.
- Depending on the compiler and its settings, the .data and .rdata sections may be merged, or even merged into the .text section.
- Saving the payload in the
.rsrcsection is a cleaner method since larger payloads cannot be stored in the.dataor.rdatasections due to size limits
Example payload in text
compile.bat
Example payload in text
compile.bat
Example payload in data
compile.bat
Example payload in rdata
compile.bat
Example payload in resources
- Requires a
.icopayload generated - Example code
compile.bat
Payload encoding & encryption
- Encoding: Mostly used for transfering binary data, for example in Base64
- Encryption: Transform data with a key, for example XOR, AES
Encoding
Base64
- Not enough to avoid detection. Mostly used for transfering binary data
Base64 encode payload
certutil -encode <PAYLOAD>.bin <PAYLOAD>.base64
Example base64 encoded payload
compile.bat
Encryption
- Encrypting a payload is a good way to prevent detection. But encrypted data highers the entropy of the PE which might flag the PE as malicious or place extra scrutiny on it.
XOR
Xor encrypt payload python2
- Change the
KEYvariable with a key - Xor encrypts a
.binfile
python2 xorencrypt.py msgbox64.bin
Example with XOR encrypted payload
- Change the
keyvariable with the key - Example code
compile.bat
AES
AES encrypt python2
- AES encrypts a
.binfile
python2 aesencrypt.py calc.bin
Example with AES encrypted payload
- Change the
keyvariable with the key - Example code
compile.bat
Code injection
- Why do code injection?
- Escape from a short lived process
- Change working context
- Backup C2 channel (Toon, two is one, one is none)
- Classic methods: Shellcode/payload injection w/ debugging Win API or DLL injection
Classic Injection
Injecting code in remote process
- Win32 API functions:
VirtualAllocExAllocate memory buffer in remote processWriteProcessMemoryWrite into memory into the remote processCreateRemoteThreadSpecify which process should start the new threat
Example Code injection notepad.exe
compile.bat
Injecting DLL in remote process
- Win32 API functions:
GetProcAddressGet Loadlibrary address from the dropperVirtualAllocExAllocate memory buffer in remote process Example codeWriteProcessMemoryWrite DLL Address into the memory of remote processCreateRemoteThreadSpecify which process should start the new threat
Example Injecting DLL in remote process
Compile dll
compileDLL.bat
Compile dropper
compileInjector.bat
Classic injection variation
- Win32 API Functions:
VirtualAllocExAllocate memory buffer in remote processWriteProcessMemoryWrite into memory into the remote processRtlCreateUserThreadorNtCreateThreadExSpecify which process should start the new threat
Example code injection explorer.exe
- Used one of the combined dropper projects for it and didn't encode the new strings.
- Uncomment the two lines for
RtlCreateUserThreadorNtCreateThreadEx. - Example code
Thread context injection
- Completely destroys the work of that thread. Might crash the process later
- Win32 API Functions:
CreateToolhelp32Snapshot&Thread32NextFind thread in remote processVirtualAllocExAllocate memory buffer in remote processWriteProcessMemoryWrite into memory into the remote processSuspendThreadSuspend the execution of remote threadGetThreadContext&SetThreadContextChange context of thread, change function pointer register to point to shellcodeResumeThreadResume thread
Example injection notepad.exe
MapView Code Injection
- Share shellcode in memory from one process to another
- Win32 API Functions:
NtCreateSectionCreate section, new region of memory in current processNtMapViewOfSectionCreate a view in the current processmemcpyCopy shellcode to viewNtMapViewOfSectionCreate Remote View of that shellcode section in remote processRtlCreateUserThreadExecute shellcode in remote process
Example injection notepad.exe
Async Procedure Call Injection
- Not as stable, might break the process.
- Win32 API Functions:
CreateToolhelp32Snapshot&Thread32NextFind thread in remote processVirtualAllocExAllocate memory buffer in remote processWriteProcessMemoryWrite into memory into the remote processQueueUserAPCCreate APC object in remote process- Wait & Pray till process gets into alertable state
- Will execute the APC shellcode
Example injection notepad.exe
Earlybird
- Variation of APC. Spawns a new process and inject shellcode.
- Win32 API Functions:
CreateProcessACreate a process in suspended modeVirtualAllocExAllocate memory buffer in remote processWriteProcessMemoryWrite into memory into the remote processQueueUserAPCCreate APC object in remote processResumeThreadResume thread and execute shellcode
Example injection notepad.exe
Evasion Techniques
Making a program invisible
- Two typical ways:
Freeconsole()(Console window shows up a split second) andGUItrick
Example GUItrick
- Instead of the
mainfunction create aWinMainfunction
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
Building
- Use
/SUBSYSTEM:WINDOWSinstead of/SUBSYSTEM:CONSOLE
Function call obfuscation
- Calling external functions, detection based on imported DLLs and functions
- A method of hiding DLL's and external functions that are called during runtime.
- With the API's
GetModuleHandle&GetProcAddress
- With the API's
Run dumpbin to check import adress table
- Prints the imported DLLs and the functions
dumpbin /imports <PAYLOAD EXE>
Look up documentation of function
- For example: https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect and copy the declaration.
- Check which DLL its imported from, for example kernel32.dll
BOOL VirtualProtect(
[in] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flNewProtect,
[out] PDWORD lpflOldProtect
);
Create global variable
- Create a global variable and make it a pointer
BOOL (WINAPI * pVirtualProtect)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
Add the following code
- Add the following line to get the address of the pointer
pVirtualProtect = GetProcAddress(GetModuleHandle("kernel32.dll"), "VirtualProtect");
Hiding win32 API strings in the code
- When running
strings <EXE>the stringVirtualProtectwill show up. Possible to hide by making an array:
char aVirtualProtect[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't' };
VirtualProtect_t pVirtualProtect = (VirtualProtect_t)GetProcAddress(GetModuleHandle(L"kernel32.dll"), aVirtualProtect);
- Best is to encrypt the API string, for example
VirtualProtectfrom the example above and decode it in the code. See Droppers for example code
When GetModuleHandle fails
- When receiving errorcode
126 The specified module could not be found. The library isn't found on the system. Load it usingLoadLibrary`. Example code:
LoadLibraryW_t pLoadLibraryW = (LoadLibraryW_t)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
HMODULE hWinhttp = pLoadLibraryW(L"C:\\windows\\system32\\winhttp.dll");
if (!hWinhttp) {
Error("Failed to get handle to winhttp.dll");
exit(0);
}
// Get handles to Win32 API's using GetProcAddress
WinHttpOpen_t pWinHttpOpen = (WinHttpOpen_t)GetProcAddress(hWinhttp, "WinHttpOpen");
Hiding GetModuleHandle & GetProcAddress
- This is possible by implementing these functions yourself. See
helpers.cppfrom Link - Then use these functions with Unicode (
L"<STRING>") strings to resolve the API's:
VirtualAlloc_t pVirtualAlloc = (VirtualAlloc_t) hlpGetProcAddress(hlpGetModuleHandle(L"KERNEL32.DLL"), "VirtualAlloc");
- If we use these functions the
GetModuleHande&GetProcAddressshouldn't be in our code. But withdumpbin /import implant.exe | findstr /i getprocadordumpbin /import implant.exe | findstr /i getmodulehathe functions still show up. This is because there is some initialization fase, compiler and linker add some additional code that prepares the process before the start. When we use#pragma comment(linker, "/entry:WinMain")inside our headers we can fix this. This changes the linker to entry pointWinMain - Use the helper functions to get pointers to the real
GetProcAddressandGetModuleHandleand use these pointers to resolve the rest of the functions.
GetModuleHandleA_t pGetModuleHandleA = (GetModuleHandleA_t) hlpGetProcAddress(hlpGetModuleHandle(L"KERNEL32.DLL"), "GetModuleHandleA");
GetProcAddress_t pGetProcAddress = (GetProcAddress_t) hlpGetProcAddress(hlpGetModuleHandle(L"KERNEL32.DLL"), "GetProcAddress");
VirtualAlloc_t pVirtualAlloc = (VirtualAlloc_t) pGetProcAddress(pGetModuleHandle(L"KERNEL32.DLL"), "VirtualAlloc");
Reflective DLL
Reflective DLL loader
- Load PE library directy from memory without placing dll on disk
- https://github.com/stephenfewer/ReflectiveDLLInjection
Example Reflective DLL loader
Compile DLL
compileDLL.bat
AES encrypt dll
python .\aesencrypt.py .\implant.dll > out.txt
Compile Implant.cpp
- Place key and payload inside the implant.
- Example code
compile.bat
Shellcode Reflective DLL Injection
- https://www.netspi.com/blog/technical/adversary-simulation/srdi-shellcode-reflective-dll-injection/
- https://github.com/monoxgas/sRDI
- Usefull for then you don't create your own dll and need to call a different function name
- Doesn't need
ReflectiveLoader.hfiles from stephen's solution from above.
Example Shellcode Reflective DLL Injection
Compile DLL
- Optional
compileDLL.bat
Convert dll to shellcode
- Generates a
.binfile
python ConvertToShellcode.py -f Go implant.dll
AES encrypt bin file
python.exe ./aes.py implant.bin > out.txt
Compile Implant.cpp
- Place key and payload inside the implant.
- Example code
compile.bat
Wow64 and Heavens Gate
- Injecting a 32 bit payload & 64 bit compiled implant into a 32 bit process works. But 64 bit payload & 32 bit compiled implant into 64-bit process doesn't.
- The payload gets injected, but it doesn't run.
- Wow64 is sort of emulator which provides a sort of interface between 32 bit NTDLL and the kernel (which runs in 64 bit).
- Three important dll's:
Wow64.dll,Wow64cpu.dll,Wow64Win.dll
Migrating between 32 bit & 64 bit programs
- Possible with a heavens gate.
- Function
EXECUTEX64Transition from 32 bit to 64 bit mode in current process - Function
X64FUNCTION& APIRtlCreateUserThread()call to execute code in target process
- Function
- Parts of code comes from Migrate command from Metasploit.
- Raw byte code in
execute64.binandwownative.binfiles
- Raw byte code in
- Example code
- Switch the comments in main to switch in between payloads. Compile with x86 and x64 depending on the test and start notpad x86 or x64.
- Example code didn't work with
InjectWOW64(hProc, payload64, payload64_len);on my amd 5800x cpu. Did work on my Intell laptop.
API Hooking
- Its a generic way a application executes in memory. Can be used for game hacks to incercept and return other values.
Hooking with Detours
- https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/huntusenixnt99.pdf
- https://github.com/microsoft/Detours/releases/tag/v4.0.1
- Overwriting binary code in memory
- Win32 API Functions:
- Hooking
- Get pointer to the function
DetourTransactionBeginCreate new transactionDetourUpdateThreadEnlists all the threads that this hook will be apllied tooDetourAttachHook the function with new function.DetourTransactionCommitCommit transaction
- Unhooking
- Same as hooking but uses
DetourDetach
- Same as hooking but uses
- Hooking
Example Hooking with Detours
- Example code
- Run
hookme.exeand the first messagebox will appear. - Then open process hacker, right click hookme.exe process --> Miscellaneous --> Inject DLL and select
hookem.dll. - Click OK and the other two messageboxes will be replaced with a new title and message!
Hooking with Import Adress Table
- Change the adresses of imported function in the Import Adress Table (IAT)
Example Hooking with Import Adress Table
- Example code
- Run
hookme.exeand the first messagebox will appear. - Then open process hacker, right click hookme.exe process --> Miscellaneous --> Inject DLL and select
hookem.dll. - Click OK and the other two messageboxes will be replaced with a new title and message!
In-line patching
- IAT hooking relies on swapping the function pointers. With in-line patching the API function itself is modified (patched) to redirect the API to the malicious code.
Example In-line patching
- Run
hookme.exeand the first messagebox will appear.
- Then open process hacker, right click hookme.exe process --> Miscellaneous --> Inject DLL and select
hookem.dll. - Click OK and the other two messageboxes will be replaced with a new title and message!
Payload Control
- To stop injecting the same payload/implant multiple times and creating a lot of artifacts it is usefull to have control over how many times it can get executed.
- Control object for this can be anything. Some examples:
- Global mutant
- Global event
- Global semaphore
- Named pipe
Example code payload control
- Extended on the NoImports implant.
- Example code
Combined Droppers
Dropper XOR Favicon
Generate messagebox
msfvenom -p windows/x64/messagebox TEXT="0xjs" -o msgbox64.bin
XOR encrypt messagebox
- Change the key in script if desired
python2 xorencryptfavicon.py msgbox64.bin
XOR encrypt function calls / strings
- Might want to change the function for this
python2 -i xorencrypt.py
>>> PrintC(xor("<STRING TO ENCRYPT>", "<KEY">)
Compile implant.cpp
- Set the
k2variable with the key - Example code
compile.bat
Dropper AES Favicon
Generate messagebox
msfvenom -p windows/x64/messagebox TEXT="0xjs" -o msgbox64.bin
AES encrypt messagebox
python.exe .\aesencryptfile.py .\msgbox64.bin
AES encrypt function calls / strings
python.exe .\aesencryptstring.py
Compile implant.cpp
- Set the
pkeyvariable with the payload key andkvariable with the encrypted function calls/strings key - Example code
compile.bat
Dropper AES Favicon no imports
- Had to use
GetUserName, with no importspCryptReleaseContextdidn't work. Rather had that API call then the AES one.
Generate messagebox
msfvenom -p windows/x64/messagebox TEXT="0xjs" -o msgbox64.bin
AES encrypt messagebox
python.exe .\aesencryptfile.py .\msgbox64.bin
AES encrypt function calls / strings
python.exe .\aesencryptstring.py
Compile implant.cpp
- Set the
pkeyvariable with the payload key andkvariable with the encrypted function calls/strings key - Example code
compile.bat
VeraCryptPasswordStealer
- VCSniff is a 64 bit dll that uses DeTours to sniff the VeraCrypt password from the WideCharToMultiByte function and write it to
C:\temp\data.txt - VCmigrate is a 32 bit dll that injects reflected dll from VCsniff into the 64bit VeraCrypt process, checks for this proccess every 5 seconds
- VCpersist is a 64 bit program VChelper.exe that injects 64 bit reflected dll VCmigrate into 32 bit OneDrive program.
- Use VChelper.exe (VCpersist) with any persistent method to start at boot and be injected into OneDrive.
- Example code
Compile vcsniff.dll
- Compile as 64 bit.
compile.bat
Create Reflective DLL shellcode vcsniff.dll
- Copy
vcsniff.dlltoVCmigratefolder.
python ..\sRDI\Python\ConvertToShellcode.py -f DllMain vcsniff.dll
AES encrypt shellcode
python aesencryptfile.py vcsniff.dll > out.txt
Compile VCmigrate
- Place the payload and key inside the .cpp file.
- Compile as 32 bit.
compile.bat
Create Reflective DLL shellcode vcmigrate.dll
- Copy
vcmigrate.dlltoVCpersist
python3 ..\sRDI\Python\ConvertToShellcode.py -f Go .\vcmigrate.dll
AES encrypt shellcode
python3 ..\VCmigrate\aesencryptfile.py .\vcmigrate.bin > out.txt
Compile VCpersist
- Place the payload and key inside the .cpp file.
- Compile as 64 bit.
compile.bat
Dropper Mapview Explorer
- Dropper_AES_Favicon_MapView_Explorer
- AES encrypted payload in
.srcsection, inside favicon - MapView injection into
Explorer.exe - Function call obfuscation with GetModuleHandle and GetProcAddress helpers
Generate msfvenom payload
msfvenom -p windows/x64/messagebox TEXT="0xjs" EXITFUNC=thread -o msgbox64.bin
AES encrypt to favicon
python aesencryptfile.py msgbox64.bin
Compile implant.exe
- Place the payload and key inside the
paylandpkeyvalues
compile.bat
Dropper Shellcode Reflected DLL Explorer
- Dropper_AES_Reflected_DLL_MapView_Explorer
- AES encrypted payload compiled to a DLL. Converted to shellcode reflective DLL injection and then AES encrypted again
- MapView injection into
Explorer.exe - Function call obfuscation with GetModuleHandle and GetProcAddress helpers
Generate msfvenom payload
msfvenom -p windows/x64/messagebox TEXT="0xjs" EXITFUNC=thread -o msgbox64.bin
AES encrypt shellcode
python aesencrypt.py msgbox64.bin > out.txt
Generate DLL
- Place payload and key inside DLL and compile it.
compileDLL.bat
Create Reflective DLL shellcode
python ..\sRDI\Python\ConvertToShellcode.py -f Go implant.dll
AES encrypt shellcode
python aesencrypt.py implant.bin > out2.txt
Compile implant.exe
- Place the payload and key inside the
paylandpkeyvalues
compile.bat