Files

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(), &copy, 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(), &copy, 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();
}