Skip to content

Instantly share code, notes, and snippets.

@mook
Created November 15, 2014 06:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mook/33abbeb13b6bb511fc21 to your computer and use it in GitHub Desktop.
Save mook/33abbeb13b6bb511fc21 to your computer and use it in GitHub Desktop.
#include <windows.h>
#include <stdio.h>
#include <map>
#define print_error(msg) printf(msg ": %08lx\n", GetLastError())
#if defined(PARENT)
struct DebugProcessData {
HANDLE hProcess;
HANDLE hThread;
LPVOID lpStartAddress;
BYTE originalByte;
};
int main() {
STARTUPINFO si = {
};
PROCESS_INFORMATION pi = {0};
BOOL success;
success = CreateProcess(NULL,
(LPSTR)"child.exe",
NULL, NULL,
FALSE,
DEBUG_PROCESS,
NULL,
NULL,
&si,
&pi);
if (!success) {
print_error("Failed to start process");
return 1;
}
printf("Parent started successfully\n");
DEBUG_EVENT debugEvent = {0};
std::map<DWORD, DebugProcessData> debugProcessData;
BOOL done = FALSE;
while (!done) {
if (!WaitForDebugEvent(&debugEvent, INFINITE)) {
print_error("Failed to wait for debug event");
break;
}
BOOL handled = FALSE;
DebugProcessData& processData = debugProcessData[debugEvent.dwProcessId];
switch (debugEvent.dwDebugEventCode) {
case CREATE_PROCESS_DEBUG_EVENT: {
printf("Child %ld started\n", debugEvent.dwProcessId);
success = DuplicateHandle(GetCurrentProcess(),
debugEvent.u.CreateProcessInfo.hProcess,
GetCurrentProcess(),
&processData.hProcess,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (!success) {
print_error("Failed to duplicate process handle");
return 1;
}
success = DuplicateHandle(GetCurrentProcess(),
debugEvent.u.CreateProcessInfo.hThread,
GetCurrentProcess(),
&processData.hThread,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (!success) {
print_error("Failed to duplicate thread handle");
return 1;
}
processData.lpStartAddress = (LPVOID)debugEvent.u.CreateProcessInfo.lpStartAddress;
printf("Child process %p start address: %p\n",
processData.hProcess,
processData.lpStartAddress);
success = ReadProcessMemory(processData.hProcess,
processData.lpStartAddress,
&processData.originalByte,
sizeof(processData.originalByte),
NULL);
if (!success) {
print_error("Failed to read original byte");
return 1;
}
printf("Got original byte: %02x\n", processData.originalByte);
BYTE newData = 0xCC; /* int 3 */
success = WriteProcessMemory(processData.hProcess,
processData.lpStartAddress,
&newData, sizeof(newData), NULL);
if (!success) {
print_error("Failed to write int 3");
return 1;
}
break;
}
case EXCEPTION_DEBUG_EVENT: {
switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) {
case EXCEPTION_BREAKPOINT: {
if (debugEvent.u.Exception.ExceptionRecord.ExceptionAddress == processData.lpStartAddress) {
printf("Start breakpoint hit\n");
success = WriteProcessMemory(processData.hProcess,
processData.lpStartAddress,
&processData.originalByte,
sizeof(processData.originalByte), NULL);
if (!success) {
print_error("Failed to restore code");
return 1;
}
CONTEXT context = {0};
context.ContextFlags = CONTEXT_CONTROL;
success = GetThreadContext(processData.hThread, &context);
if (!success) {
print_error("Failed to get thread context");
return 1;
}
#if defined(_M_X64)
context.Rip = (DWORD64)processData.lpStartAddress;
#elif defined(_M_IX86)
context.Eip = (DWORD)processData.lpStartAddress;
#else
#error "Don't know how to handle thread context"
#endif
success = SetThreadContext(processData.hThread, &context);
if (!success) {
print_error("Failed to set thread context");
return 1;
}
break;
} else {
printf("Unknown breakpoint hit at %p\n",
debugEvent.u.Exception.ExceptionRecord.ExceptionAddress);
}
break;
}
default: {
printf("Debug exception %08lx\n",
debugEvent.u.Exception.ExceptionRecord.ExceptionCode);
break;
}
}
break;
}
case EXIT_PROCESS_DEBUG_EVENT: {
printf("Process %ld exited\n", debugEvent.dwProcessId);
debugProcessData.erase(debugEvent.dwProcessId);
if (debugProcessData.empty()) {
printf("All decendents have exited\n");
done = TRUE;
}
break;
}
case LOAD_DLL_DEBUG_EVENT: {
printf("Loading dll\n");
break;
}
default: {
printf("Unhandled debug event: %08lx\n", debugEvent.dwDebugEventCode);
}
}
if (!handled) {
success = ContinueDebugEvent(debugEvent.dwProcessId,
debugEvent.dwThreadId,
DBG_CONTINUE);
if (!success) {
print_error("Failed to continue debuggee");
return 1;
}
}
}
return 0;
}
#elif defined(CHILD)
int main(int argc, char **) {
printf("hello from child (%d)\n", argc);
if (argc == 1) {
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
BOOL success;
success = CreateProcess(NULL,
(LPSTR)"child.exe 1",
NULL, NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi);
if (!success) {
print_error("Failed to start process");
return 1;
}
}
return 0;
}
#else
#error "Neither parent nor child"
#endif
@mook
Copy link
Author

mook commented Nov 15, 2014

Sample output:

i686-w64-mingw32-g++ -Wall -Wextra -Wno-missing-field-initializers -DPARENT -o parent.exe sample.cpp
i686-w64-mingw32-g++ -Wall -Wextra -Wno-missing-field-initializers -DCHILD -o child.exe sample.cpp
wine parent.exe
Parent started successfully
Child 41 started
Child process 00000060 start address: 004014E0
Got original byte: 83
Loading dll
Loading dll
Loading dll
Unknown breakpoint hit at 7B861106
Start breakpoint hit
hello from child (1)
Child 9 started
Child process 0000007C start address: 004014E0
Got original byte: 83
Loading dll
Loading dll
Process 41 exited
Loading dll
Unknown breakpoint hit at 7B861106
Start breakpoint hit
hello from child (2)
Process 9 exited
All decendents have exited

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment