Stupid callbacks for malware evasion
I saw@KlezVirusdo 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.
#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:

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