mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-10-28 21:25:06 +00:00
324 lines
18 KiB
C
324 lines
18 KiB
C
#define WIN32_LEAN_AND_MEAN
|
|
#define _WIN32_WINNT 0x0601
|
|
#include <windows.h>
|
|
|
|
typedef LONG (WINAPI *query_process)(HANDLE, ULONG, void *, ULONG, ULONG *);
|
|
typedef LONG (WINAPI *query_event)(HANDLE, ULONG, void *, ULONG, ULONG *);
|
|
|
|
struct basic_information {
|
|
LONG exit_status;
|
|
void *peb;
|
|
ULONG_PTR affinity;
|
|
LONG priority;
|
|
ULONG_PTR pid, parent;
|
|
};
|
|
|
|
static HANDLE transferred[8];
|
|
static HANDLE sibling_handle;
|
|
|
|
static int extended_events(void)
|
|
{
|
|
query_event query = (query_event)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryEvent");
|
|
ULONG state[2], length;
|
|
HANDLE modify = CreateEventExW(NULL, NULL, 0, EVENT_MODIFY_STATE);
|
|
HANDLE query_only = CreateEventExA(NULL, NULL, 3, 1);
|
|
HANDLE empty = CreateEventExW(NULL, NULL, 2, 0);
|
|
if (!query || !modify || !query_only || !empty || !SetEvent(modify) ||
|
|
WaitForSingleObject(modify, 0) != WAIT_FAILED || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
query(query_only, 0, state, sizeof(state), &length) || state[0] || state[1] != 1)
|
|
return 100;
|
|
if (SetEvent(query_only) || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
WaitForSingleObject(query_only, 0) != WAIT_FAILED || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
(ULONG)query(empty, 0, state, sizeof(state), &length) != 0xc0000022)
|
|
return 101;
|
|
if (!CloseHandle(modify) || !CloseHandle(query_only) || !CloseHandle(empty))
|
|
return 102;
|
|
if (CreateEventExW(NULL, NULL, 4, EVENT_ALL_ACCESS) || GetLastError() != ERROR_INVALID_PARAMETER ||
|
|
CreateEventExA(NULL, NULL, 0, 4) || GetLastError() != ERROR_INVALID_PARAMETER)
|
|
return 103;
|
|
char name[] = "Local\\RavenEventEx-00000000";
|
|
DWORD pid = GetCurrentProcessId();
|
|
for (unsigned index = 0; index < 8; ++index) {
|
|
name[sizeof(name) - 2 - index] = "0123456789abcdef"[pid & 15];
|
|
pid >>= 4;
|
|
}
|
|
WCHAR wide[sizeof(name)];
|
|
for (unsigned index = 0; index < sizeof(name); ++index) wide[index] = (BYTE)name[index];
|
|
SECURITY_ATTRIBUTES attributes = {sizeof(attributes), NULL, TRUE};
|
|
HANDLE first = CreateEventExW(&attributes, wide, 3, EVENT_ALL_ACCESS);
|
|
DWORD flags;
|
|
if (!first || GetLastError() == ERROR_ALREADY_EXISTS || !GetHandleInformation(first, &flags) || !(flags & HANDLE_FLAG_INHERIT))
|
|
return 104;
|
|
HANDLE second = CreateEventExA(NULL, name, 0, SYNCHRONIZE);
|
|
if (!second || GetLastError() != ERROR_ALREADY_EXISTS || !GetHandleInformation(second, &flags) || (flags & HANDLE_FLAG_INHERIT) ||
|
|
WaitForSingleObject(second, 0) != WAIT_OBJECT_0 || WaitForSingleObject(second, 0) != WAIT_OBJECT_0 ||
|
|
SetEvent(second) || GetLastError() != ERROR_ACCESS_DENIED)
|
|
return 105;
|
|
if (!ResetEvent(first) || WaitForSingleObject(second, 0) != WAIT_TIMEOUT || !SetEvent(first))
|
|
return 106;
|
|
HANDLE legacy = CreateEventW(NULL, FALSE, FALSE, wide);
|
|
if (!legacy || GetLastError() != ERROR_ALREADY_EXISTS || WaitForSingleObject(legacy, 0) != WAIT_OBJECT_0 ||
|
|
WaitForSingleObject(legacy, 0) != WAIT_OBJECT_0 || !CloseHandle(first) ||
|
|
WaitForSingleObject(second, 0) != WAIT_OBJECT_0 || !CloseHandle(legacy) || !CloseHandle(second))
|
|
return 107;
|
|
/* A descriptor of its own, as services give the events they share with other sessions, is accepted with the event. */
|
|
SECURITY_DESCRIPTOR descriptor;
|
|
if (!InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION) || !SetSecurityDescriptorDacl(&descriptor, TRUE, NULL, FALSE))
|
|
return 108;
|
|
attributes.lpSecurityDescriptor = &descriptor;
|
|
WCHAR global[sizeof(name) + 1] = L"Global";
|
|
for (unsigned index = 5; index < sizeof(name); ++index) global[index + 1] = wide[index];
|
|
HANDLE shared = CreateEventExW(&attributes, global, 0, EVENT_ALL_ACCESS);
|
|
if (!shared || GetLastError() == ERROR_ALREADY_EXISTS || !SetEvent(shared) || !CloseHandle(shared))
|
|
return 109;
|
|
return 0;
|
|
}
|
|
|
|
static int child_entry(void)
|
|
{
|
|
query_event query = (query_event)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryEvent");
|
|
ULONG state[2], length;
|
|
HANDLE copy;
|
|
if (!query || query(transferred[2], 0, state, sizeof(state), &length) || state[0] || state[1] != 1)
|
|
return 20;
|
|
if (SetEvent(transferred[2]) || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
SetEvent(transferred[3]) || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
WaitForSingleObject(transferred[3], 0) != WAIT_FAILED || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
WaitForSingleObject(transferred[4], 0) != WAIT_FAILED || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
(ULONG)query(transferred[3], 0, state, sizeof(state), &length) != 0xc0000022)
|
|
return 21;
|
|
if (WaitForSingleObject(transferred[5], 0) != WAIT_OBJECT_0 || WaitForSingleObject(transferred[5], 0) != WAIT_TIMEOUT)
|
|
return 22;
|
|
if (!DuplicateHandle(GetCurrentProcess(), transferred[2], GetCurrentProcess(), ©, GENERIC_READ, FALSE, 0) ||
|
|
query(copy, 0, state, sizeof(state), &length) || !state[1] ||
|
|
SetEvent(copy) || GetLastError() != ERROR_ACCESS_DENIED)
|
|
return 23;
|
|
CloseHandle(copy);
|
|
if (WaitForSingleObject(transferred[6], 0) != WAIT_TIMEOUT || ReleaseMutex(transferred[6]) ||
|
|
GetLastError() != ERROR_NOT_OWNER || WaitForSingleObject(transferred[7], 0) != WAIT_FAILED ||
|
|
GetLastError() != ERROR_ACCESS_DENIED)
|
|
return 26;
|
|
if (!SetEvent(transferred[1]) || WaitForSingleObject(transferred[0], 10000) != WAIT_OBJECT_0 ||
|
|
WaitForSingleObject(transferred[0], 0) != WAIT_TIMEOUT || WaitForSingleObject(transferred[2], 0) != WAIT_TIMEOUT ||
|
|
WaitForSingleObject(transferred[6], 0) != WAIT_TIMEOUT || !SetEvent(transferred[4]) || !SetEvent(transferred[1]))
|
|
return 24;
|
|
if (WaitForSingleObject(transferred[0], 10000) != WAIT_OBJECT_0 ||
|
|
WaitForSingleObject(transferred[2], 0) != WAIT_TIMEOUT ||
|
|
WaitForSingleObject(transferred[6], 10000) != WAIT_OBJECT_0 || WaitForSingleObject(transferred[6], 0) != WAIT_OBJECT_0 ||
|
|
!ReleaseMutex(transferred[6]) || !SetEvent(transferred[1]) || WaitForSingleObject(transferred[0], 10000) != WAIT_OBJECT_0 ||
|
|
!ReleaseMutex(transferred[6]) || !SetEvent(transferred[1]))
|
|
return 25;
|
|
for (unsigned index = 0; index < 8; ++index) CloseHandle(transferred[index]);
|
|
return 0;
|
|
}
|
|
|
|
static int detached_child(void)
|
|
{
|
|
if (WaitForSingleObject(transferred[1], 10000) != WAIT_OBJECT_0) return 130;
|
|
HANDLE parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, (DWORD)(ULONG_PTR)transferred[0]);
|
|
HANDLE event = CreateEventW(NULL, TRUE, TRUE, NULL), remote = NULL, copy = NULL;
|
|
if (!parent || !event || !DuplicateHandle(GetCurrentProcess(), event, parent, &remote, EVENT_ALL_ACCESS, FALSE, 0)) return 131;
|
|
if (!CloseHandle(event) || !DuplicateHandle(parent, remote, GetCurrentProcess(), ©, SYNCHRONIZE, FALSE, DUPLICATE_CLOSE_SOURCE) ||
|
|
WaitForSingleObject(copy, 0) != WAIT_OBJECT_0 || WaitForSingleObject(copy, 0) != WAIT_OBJECT_0 ||
|
|
SetEvent(copy) || GetLastError() != ERROR_ACCESS_DENIED || !CloseHandle(copy) || !CloseHandle(parent)) return 132;
|
|
if (!SetEvent(transferred[2]) || WaitForSingleObject(transferred[1], 10000) != WAIT_OBJECT_0) return 133;
|
|
CloseHandle(transferred[1]);
|
|
CloseHandle(transferred[2]);
|
|
return 0;
|
|
}
|
|
|
|
static int sibling_child(void)
|
|
{
|
|
if (WaitForSingleObject(transferred[1], 10000) != WAIT_OBJECT_0) return 160;
|
|
HANDLE parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, (DWORD)(ULONG_PTR)transferred[0]);
|
|
HANDLE event = CreateEventW(NULL, TRUE, (BOOL)(ULONG_PTR)transferred[3], NULL);
|
|
HANDLE denied = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)(ULONG_PTR)transferred[0]);
|
|
HANDLE unchanged = (HANDLE)(ULONG_PTR)0x1234;
|
|
if (!denied || DuplicateHandle(GetCurrentProcess(), event, denied, &unchanged, EVENT_ALL_ACCESS, FALSE, 0) ||
|
|
GetLastError() != ERROR_ACCESS_DENIED || unchanged != (HANDLE)(ULONG_PTR)0x1234 || !CloseHandle(denied)) return 163;
|
|
DWORD access = transferred[3] ? EVENT_ALL_ACCESS : SYNCHRONIZE;
|
|
if (!parent || !event || !DuplicateHandle(GetCurrentProcess(), event, parent, &sibling_handle,
|
|
access, (BOOL)(ULONG_PTR)transferred[3], 0) || !CloseHandle(parent) || !CloseHandle(event)) return 161;
|
|
if (!SetEvent(transferred[2]) || WaitForSingleObject(transferred[1], 10000) != WAIT_OBJECT_0) return 162;
|
|
CloseHandle(transferred[1]);
|
|
CloseHandle(transferred[2]);
|
|
return 0;
|
|
}
|
|
|
|
static int sibling_transfers(void)
|
|
{
|
|
query_process query = (query_process)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationProcess");
|
|
STARTUPINFOW startup = {sizeof(startup)};
|
|
PROCESS_INFORMATION child[2];
|
|
WCHAR command[512];
|
|
HANDLE gate[2], done[2], remote[2];
|
|
ULONG_PTR image[2];
|
|
SIZE_T copied;
|
|
for (unsigned index = 0; index < 2; ++index) {
|
|
command[0] = '"';
|
|
DWORD used = GetModuleFileNameW(NULL, command + 1, 480);
|
|
if (!query || !used || used >= 480) return 140;
|
|
command[++used] = '"'; command[++used] = ' '; command[++used] = '-'; command[++used] = '-'; command[++used] = 's'; command[++used] = 0;
|
|
gate[index] = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
done[index] = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
if (!gate[index] || !done[index] || !CreateProcessW(NULL, command, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &child[index])) return 141;
|
|
HANDLE payload[4] = {(HANDLE)(ULONG_PTR)GetCurrentProcessId(), NULL, NULL, (HANDLE)(ULONG_PTR)(index == 0)};
|
|
struct basic_information information;
|
|
ULONG length;
|
|
if (!DuplicateHandle(GetCurrentProcess(), gate[index], child[index].hProcess, &payload[1], SYNCHRONIZE, FALSE, 0) ||
|
|
!DuplicateHandle(GetCurrentProcess(), done[index], child[index].hProcess, &payload[2], EVENT_MODIFY_STATE, FALSE, 0) ||
|
|
query(child[index].hProcess, 0, &information, sizeof(information), &length) ||
|
|
!ReadProcessMemory(child[index].hProcess, (BYTE *)information.peb + 2 * sizeof(void *), &image[index], sizeof(image[index]), &copied) ||
|
|
!WriteProcessMemory(child[index].hProcess, (void *)(image[index] + (ULONG_PTR)&transferred - (ULONG_PTR)GetModuleHandleW(NULL)), payload, sizeof(payload), &copied) ||
|
|
copied != sizeof(payload) || ResumeThread(child[index].hThread) != 1) return 142;
|
|
}
|
|
for (unsigned index = 0; index < 2; ++index) {
|
|
if (!SetEvent(gate[index]) || WaitForSingleObject(done[index], 10000) != WAIT_OBJECT_0 ||
|
|
!ReadProcessMemory(child[index].hProcess, (void *)(image[index] + (ULONG_PTR)&sibling_handle - (ULONG_PTR)GetModuleHandleW(NULL)),
|
|
&remote[index], sizeof(remote[index]), &copied) || copied != sizeof(remote[index])) return 143;
|
|
}
|
|
if (!remote[0] || !remote[1] || remote[0] == remote[1]) return 144;
|
|
DWORD first_flags, second_flags;
|
|
if (!GetHandleInformation(remote[0], &first_flags) || !(first_flags & HANDLE_FLAG_INHERIT) ||
|
|
!GetHandleInformation(remote[1], &second_flags) || (second_flags & HANDLE_FLAG_INHERIT)) return 145;
|
|
if (WaitForSingleObject(remote[0], 0) != WAIT_OBJECT_0 || WaitForSingleObject(remote[0], 0) != WAIT_OBJECT_0 ||
|
|
WaitForSingleObject(remote[1], 0) != WAIT_TIMEOUT || SetEvent(remote[1]) || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
!ResetEvent(remote[0]) || WaitForSingleObject(remote[0], 0) != WAIT_TIMEOUT || WaitForSingleObject(remote[1], 0) != WAIT_TIMEOUT) return 146;
|
|
for (unsigned index = 0; index < 2; ++index) {
|
|
DWORD code = STILL_ACTIVE;
|
|
if (!CloseHandle(remote[index]) || !SetEvent(gate[index]) || WaitForSingleObject(child[index].hProcess, 10000) != WAIT_OBJECT_0 ||
|
|
!GetExitCodeProcess(child[index].hProcess, &code) || code) return 147;
|
|
CloseHandle(child[index].hThread);
|
|
CloseHandle(child[index].hProcess);
|
|
CloseHandle(gate[index]);
|
|
CloseHandle(done[index]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int closed_process_handles(void)
|
|
{
|
|
query_process query = (query_process)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationProcess");
|
|
STARTUPINFOW startup = {sizeof(startup)};
|
|
PROCESS_INFORMATION child;
|
|
struct basic_information information;
|
|
WCHAR command[512];
|
|
command[0] = '"';
|
|
DWORD used = GetModuleFileNameW(NULL, command + 1, 480);
|
|
if (!query || !used || used >= 480) return 120;
|
|
command[++used] = '"'; command[++used] = ' '; command[++used] = '-'; command[++used] = '-'; command[++used] = 'd'; command[++used] = 0;
|
|
HANDLE gate = CreateEventW(NULL, FALSE, FALSE, NULL), done = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
DWORD baseline, held;
|
|
if (!gate || !done || !GetProcessHandleCount(GetCurrentProcess(), &baseline) ||
|
|
!CreateProcessW(NULL, command, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &child)) return 121;
|
|
HANDLE payload[3] = {(HANDLE)(ULONG_PTR)GetCurrentProcessId(), NULL, NULL};
|
|
ULONG length;
|
|
ULONG_PTR image;
|
|
SIZE_T copied;
|
|
if (!DuplicateHandle(GetCurrentProcess(), gate, child.hProcess, &payload[1], SYNCHRONIZE, FALSE, 0) ||
|
|
!DuplicateHandle(GetCurrentProcess(), done, child.hProcess, &payload[2], EVENT_MODIFY_STATE, FALSE, 0) ||
|
|
query(child.hProcess, 0, &information, sizeof(information), &length) ||
|
|
!ReadProcessMemory(child.hProcess, (BYTE *)information.peb + 2 * sizeof(void *), &image, sizeof(image), &copied) ||
|
|
!WriteProcessMemory(child.hProcess, (void *)(image + (ULONG_PTR)&transferred - (ULONG_PTR)GetModuleHandleW(NULL)), payload, sizeof(payload), &copied) ||
|
|
copied != sizeof(payload) || ResumeThread(child.hThread) != 1) return 122;
|
|
DWORD pid = child.dwProcessId;
|
|
if (!CloseHandle(child.hThread) || !CloseHandle(child.hProcess) ||
|
|
!GetProcessHandleCount(GetCurrentProcess(), &held) || held != baseline || !SetEvent(gate)) return 123;
|
|
if (WaitForSingleObject(done, 10000) != WAIT_OBJECT_0) return 124;
|
|
HANDLE reopened = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
|
DWORD code = STILL_ACTIVE;
|
|
if (!reopened || !SetEvent(gate) || WaitForSingleObject(reopened, 10000) != WAIT_OBJECT_0 || !GetExitCodeProcess(reopened, &code) || code) return 125;
|
|
if (!CloseHandle(reopened) || !CloseHandle(gate) || !CloseHandle(done)) return 126;
|
|
return 0;
|
|
}
|
|
|
|
int raven_entry(void)
|
|
{
|
|
const WCHAR *line = GetCommandLineW();
|
|
for (unsigned index = 0; line[index]; ++index)
|
|
if (line[index] == '-' && line[index + 1] == '-' && line[index + 2] == 's')
|
|
return sibling_child();
|
|
for (unsigned index = 0; line[index]; ++index)
|
|
if (line[index] == '-' && line[index + 1] == '-' && line[index + 2] == 'd')
|
|
return detached_child();
|
|
for (unsigned index = 0; line[index]; ++index)
|
|
if (line[index] == '-' && line[index + 1] == '-' && line[index + 2] == 'c')
|
|
return child_entry();
|
|
const int extended = extended_events();
|
|
if (extended) return extended;
|
|
query_process query = (query_process)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationProcess");
|
|
STARTUPINFOW startup = {0};
|
|
PROCESS_INFORMATION child;
|
|
struct basic_information information;
|
|
WCHAR command[512];
|
|
HANDLE ping = CreateEventExW(NULL, NULL, 0, SYNCHRONIZE | EVENT_MODIFY_STATE);
|
|
HANDLE pong = CreateEventExA(NULL, NULL, 0, SYNCHRONIZE | EVENT_MODIFY_STATE);
|
|
HANDLE manual = CreateEventExW(NULL, NULL, 3, EVENT_ALL_ACCESS), orphan = CreateEventExA(NULL, NULL, 2, EVENT_ALL_ACCESS);
|
|
HANDLE mutex = CreateMutexW(NULL, TRUE, NULL);
|
|
HANDLE sent[8], fetched = NULL, empty = NULL;
|
|
HANDLE sources[8] = {ping, pong, manual, manual, manual, orphan, mutex, mutex};
|
|
DWORD rights[8] = {SYNCHRONIZE | EVENT_MODIFY_STATE, SYNCHRONIZE | EVENT_MODIFY_STATE,
|
|
SYNCHRONIZE | 1, 0, EVENT_MODIFY_STATE, SYNCHRONIZE, SYNCHRONIZE | 2, 0};
|
|
DWORD used, code = 0;
|
|
ULONG length;
|
|
ULONG_PTR image;
|
|
SIZE_T copied;
|
|
int result = 0;
|
|
startup.cb = sizeof(startup);
|
|
command[0] = '"';
|
|
used = GetModuleFileNameW(NULL, command + 1, 480);
|
|
if (!query || !used || used >= 480 || !ping || !pong || !manual || !orphan || !mutex || WaitForSingleObject(mutex, 0) != WAIT_OBJECT_0)
|
|
return 1;
|
|
command[++used] = '"'; command[++used] = ' '; command[++used] = '-'; command[++used] = '-'; command[++used] = 'c'; command[++used] = 0;
|
|
if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &child))
|
|
return 2;
|
|
for (unsigned index = 0; index < 8; ++index)
|
|
if (!DuplicateHandle(GetCurrentProcess(), sources[index], child.hProcess, &sent[index], rights[index], FALSE, 0)) {
|
|
result = 3;
|
|
goto done;
|
|
}
|
|
if (!DuplicateHandle(child.hProcess, sent[0], GetCurrentProcess(), &fetched, SYNCHRONIZE, FALSE, 0) ||
|
|
SetEvent(fetched) || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
!DuplicateHandle(child.hProcess, sent[0], GetCurrentProcess(), &empty, 0, FALSE, 0) ||
|
|
WaitForSingleObject(empty, 0) != WAIT_FAILED || GetLastError() != ERROR_ACCESS_DENIED) {
|
|
result = 4;
|
|
goto done;
|
|
}
|
|
if (query(child.hProcess, 0, &information, sizeof(information), &length) ||
|
|
!ReadProcessMemory(child.hProcess, (BYTE *)information.peb + 2 * sizeof(void *), &image, sizeof(image), &copied) ||
|
|
!WriteProcessMemory(child.hProcess, (void *)(image + (ULONG_PTR)&transferred - (ULONG_PTR)GetModuleHandleW(NULL)),
|
|
sent, sizeof(sent), &copied) || copied != sizeof(sent)) {
|
|
result = 5;
|
|
goto done;
|
|
}
|
|
CloseHandle(orphan);
|
|
orphan = NULL;
|
|
if (ResumeThread(child.hThread) != 1 || WaitForSingleObject(pong, 10000) != WAIT_OBJECT_0 ||
|
|
WaitForSingleObject(pong, 0) != WAIT_TIMEOUT || !ResetEvent(manual) || !ReleaseMutex(mutex) || !SetEvent(ping) ||
|
|
WaitForSingleObject(pong, 10000) != WAIT_OBJECT_0 || WaitForSingleObject(manual, 0) != WAIT_OBJECT_0 ||
|
|
WaitForSingleObject(manual, 0) != WAIT_OBJECT_0 || !ResetEvent(manual) || !ReleaseMutex(mutex) || !SetEvent(ping) ||
|
|
WaitForSingleObject(pong, 10000) != WAIT_OBJECT_0 || WaitForSingleObject(mutex, 0) != WAIT_TIMEOUT || !SetEvent(ping) ||
|
|
WaitForSingleObject(pong, 10000) != WAIT_OBJECT_0 || WaitForSingleObject(mutex, 10000) != WAIT_OBJECT_0 || !ReleaseMutex(mutex) ||
|
|
WaitForSingleObject(child.hProcess, 10000) != WAIT_OBJECT_0 || !GetExitCodeProcess(child.hProcess, &code) || code)
|
|
result = code ? (int)code : 6;
|
|
done:
|
|
if (result) {
|
|
GetExitCodeProcess(child.hProcess, &code);
|
|
if (code && code != STILL_ACTIVE) result = (int)code;
|
|
TerminateProcess(child.hProcess, 99);
|
|
WaitForSingleObject(child.hProcess, 5000);
|
|
}
|
|
if (fetched) CloseHandle(fetched);
|
|
if (empty) CloseHandle(empty);
|
|
if (orphan) CloseHandle(orphan);
|
|
CloseHandle(ping);
|
|
CloseHandle(pong);
|
|
CloseHandle(manual);
|
|
CloseHandle(mutex);
|
|
CloseHandle(child.hThread);
|
|
CloseHandle(child.hProcess);
|
|
if (result) return result;
|
|
const int closed = closed_process_handles();
|
|
return closed ? closed : sibling_transfers();
|
|
}
|