mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-10-28 21:25:06 +00:00
490 lines
22 KiB
C
490 lines
22 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 *copy_memory)(HANDLE, void *, void *, SIZE_T, SIZE_T *);
|
|
typedef LONG (WINAPI *open_thread)(HANDLE *, DWORD, void *, void *);
|
|
|
|
struct thread_attributes {
|
|
ULONG length;
|
|
HANDLE root;
|
|
void *name;
|
|
ULONG attributes;
|
|
void *security, *quality;
|
|
};
|
|
|
|
struct thread_information {
|
|
LONG exit_status;
|
|
void *teb;
|
|
ULONG_PTR pid, tid, affinity;
|
|
LONG priority, base_priority;
|
|
};
|
|
|
|
struct basic_information {
|
|
LONG exit_status;
|
|
void *peb;
|
|
ULONG_PTR affinity;
|
|
LONG priority;
|
|
ULONG_PTR pid, parent;
|
|
};
|
|
|
|
static volatile DWORD child_value = 0x13579bdf;
|
|
static volatile BYTE child_buffer[120017];
|
|
static BYTE transferred[120017];
|
|
|
|
static int test_image_name(HANDLE process, const WCHAR *expected)
|
|
{
|
|
WCHAR path[512];
|
|
char narrow[512], expected_a[512];
|
|
DWORD size = 512, length = 0;
|
|
while (expected[length]) ++length;
|
|
if (!QueryFullProcessImageNameW(process, 0, path, &size) || size != length || path[size]) return 100;
|
|
for (unsigned index = 0; index < length; ++index)
|
|
if (path[index] != expected[index]) return 101;
|
|
const int bytes = WideCharToMultiByte(CP_ACP, 0, expected, -1, expected_a, sizeof expected_a, 0, 0);
|
|
size = sizeof narrow;
|
|
if (!bytes || !QueryFullProcessImageNameA(process, 0, narrow, &size) || size != (DWORD)bytes - 1) return 102;
|
|
for (unsigned index = 0; index < (unsigned)bytes; ++index)
|
|
if (narrow[index] != expected_a[index]) return 103;
|
|
return 0;
|
|
}
|
|
|
|
static int test_handle_count(query_process query, HANDLE process, BOOL own)
|
|
{
|
|
DWORD before, during, count;
|
|
DWORD handles[256];
|
|
ULONG length;
|
|
HANDLE event, sent, received;
|
|
if (!GetProcessHandleCount(process, &before) || query(process, 20, &count, sizeof(count), &length) || count != before || length != sizeof(count))
|
|
return 90;
|
|
event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
if (!event || !GetProcessHandleCount(process, &during) || during != before + (own ? 1 : 0) ||
|
|
!DuplicateHandle(GetCurrentProcess(), event, process, &sent, 0, FALSE, DUPLICATE_SAME_ACCESS) ||
|
|
!GetProcessHandleCount(process, &during) || during != before + (own ? 2 : 1))
|
|
return 91;
|
|
if (query(process, 58, handles, sizeof(handles), &length) || length != during * sizeof(DWORD))
|
|
return 97;
|
|
BOOL found = FALSE;
|
|
for (unsigned index = 0; index < length / sizeof(DWORD); ++index) {
|
|
if (handles[index] == (DWORD)(ULONG_PTR)sent) found = TRUE;
|
|
if (!handles[index] || (index && handles[index] <= handles[index - 1])) return 98;
|
|
}
|
|
if (!found || query(process, 58, handles, sizeof(DWORD), &length) || length != sizeof(DWORD) || !handles[0] ||
|
|
(ULONG)query(process, 58, (void *)1, sizeof(DWORD), &length) != 0xc0000005)
|
|
return 99;
|
|
if (!DuplicateHandle(process, sent, GetCurrentProcess(), &received, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE) ||
|
|
!GetProcessHandleCount(process, &during) || during != before + (own ? 2 : 0))
|
|
return 92;
|
|
CloseHandle(received);
|
|
CloseHandle(event);
|
|
if (!GetProcessHandleCount(process, &during) || during != before)
|
|
return 93;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
static int test_thread_thunk(open_thread open, ULONG_PTR *client)
|
|
{
|
|
BYTE original[11], *source = (BYTE *)open;
|
|
BYTE *code = VirtualAlloc(NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
HANDLE handle = NULL;
|
|
DWORD previous, ignored;
|
|
LONG patched, copied;
|
|
unsigned index;
|
|
if (!code || source[0] != 0x4c || source[1] != 0x8b || source[2] != 0xd1 || source[3] != 0xb8 ||
|
|
source[8] != 0x0f || source[9] != 0x05 || source[10] != 0xc3)
|
|
return 64;
|
|
for (index = 0; index < sizeof(original); ++index)
|
|
code[index] = original[index] = source[index];
|
|
if (!VirtualProtect(code, 4096, PAGE_EXECUTE_READ, &previous) ||
|
|
!VirtualProtect(source, sizeof(original), PAGE_EXECUTE_WRITECOPY, &previous))
|
|
return 65;
|
|
source[0] = 0xb8;
|
|
source[1] = 0x22;
|
|
source[2] = source[3] = 0;
|
|
source[4] = 0xc0;
|
|
source[5] = 0xc3;
|
|
FlushInstructionCache(GetCurrentProcess(), source, sizeof(original));
|
|
patched = open(&handle, THREAD_QUERY_INFORMATION, NULL, client);
|
|
copied = ((open_thread)code)(&handle, THREAD_QUERY_INFORMATION, NULL, client);
|
|
for (index = 0; index < sizeof(original); ++index)
|
|
source[index] = original[index];
|
|
VirtualProtect(source, sizeof(original), previous, &ignored);
|
|
FlushInstructionCache(GetCurrentProcess(), source, sizeof(original));
|
|
VirtualFree(code, 0, MEM_RELEASE);
|
|
if ((ULONG)patched != 0xc0000022 || copied || !handle || GetThreadId(handle) != client[1])
|
|
return 66;
|
|
CloseHandle(handle);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int test_open_thread(HMODULE ntdll)
|
|
{
|
|
open_thread open = (open_thread)GetProcAddress(ntdll, "NtOpenThread");
|
|
query_process query = (query_process)GetProcAddress(ntdll, "NtQueryInformationThread");
|
|
struct thread_attributes attributes = {sizeof(attributes), NULL, NULL, 2, NULL, NULL};
|
|
struct thread_information information;
|
|
ULONG_PTR client[2] = {GetCurrentProcessId(), GetCurrentThreadId()};
|
|
HANDLE handle = NULL, sentinel = (HANDLE)(ULONG_PTR)0x12345678;
|
|
ULONG length = 0;
|
|
DWORD flags = 0, previous;
|
|
void *readonly;
|
|
if (!open || !query)
|
|
return 50;
|
|
if (open(&handle, THREAD_QUERY_INFORMATION, &attributes, client) || !handle || GetThreadId(handle) != client[1] ||
|
|
!GetHandleInformation(handle, &flags) || !(flags & HANDLE_FLAG_INHERIT))
|
|
return 51;
|
|
if (query(handle, 0, &information, sizeof(information), &length) || length != sizeof(information) ||
|
|
information.pid != client[0] || information.tid != client[1] || !information.teb || information.exit_status != 259)
|
|
return 52;
|
|
if ((ULONG)query(handle, 0, (void *)1, sizeof(information), &length) != 0xc0000005 ||
|
|
(ULONG)query(handle, 0, &information, sizeof(information), (ULONG *)1) != 0xc0000005)
|
|
return 53;
|
|
CloseHandle(handle);
|
|
if (open(&handle, READ_CONTROL, NULL, client) ||
|
|
(ULONG)query(handle, 0, &information, sizeof(information), &length) != 0xc0000022)
|
|
return 54;
|
|
CloseHandle(handle);
|
|
handle = OpenThread(GENERIC_READ, FALSE, (DWORD)client[1]);
|
|
if (!handle || query(handle, 0, &information, sizeof(information), &length) ||
|
|
!GetHandleInformation(handle, &flags) || (flags & HANDLE_FLAG_INHERIT))
|
|
return 55;
|
|
CloseHandle(handle);
|
|
handle = sentinel;
|
|
client[0] = GetCurrentProcessId() + 1;
|
|
if ((ULONG)open(&handle, THREAD_ALL_ACCESS, NULL, client) != 0xc000000b || handle != sentinel)
|
|
return 56;
|
|
client[0] = GetCurrentProcessId();
|
|
client[1] = 0xffffffff;
|
|
if ((ULONG)open(&handle, THREAD_ALL_ACCESS, NULL, client) != 0xc000000b || handle != sentinel)
|
|
return 57;
|
|
client[1] = GetCurrentThreadId();
|
|
if ((ULONG)open(NULL, THREAD_ALL_ACCESS, NULL, client) != 0xc0000005 ||
|
|
(ULONG)open((HANDLE *)1, THREAD_ALL_ACCESS, NULL, client) != 0xc0000005 ||
|
|
(ULONG)open(&handle, THREAD_ALL_ACCESS, NULL, (void *)1) != 0xc0000005 || handle != sentinel)
|
|
return 58;
|
|
attributes.length = 0;
|
|
if ((ULONG)open(&handle, THREAD_ALL_ACCESS, &attributes, client) != 0xc000000d || handle != sentinel)
|
|
return 59;
|
|
attributes.length = sizeof(attributes);
|
|
attributes.name = (void *)1;
|
|
if ((ULONG)open(&handle, THREAD_ALL_ACCESS, &attributes, client) != 0xc000000d || handle != sentinel)
|
|
return 60;
|
|
attributes.name = NULL;
|
|
attributes.attributes = 0x80000000;
|
|
if ((ULONG)open(&handle, THREAD_ALL_ACCESS, &attributes, client) != 0xc00000bb || handle != sentinel)
|
|
return 61;
|
|
readonly = VirtualAlloc(NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
if (!readonly || !VirtualProtect(readonly, 4096, PAGE_READONLY, &previous))
|
|
return 62;
|
|
if ((ULONG)open((HANDLE *)readonly, THREAD_ALL_ACCESS, NULL, client) != 0xc0000005 ||
|
|
(ULONG)query(GetCurrentThread(), 0, readonly, sizeof(information), &length) != 0xc0000005)
|
|
return 63;
|
|
VirtualFree(readonly, 0, MEM_RELEASE);
|
|
#ifdef _WIN64
|
|
return test_thread_thunk(open, client);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static int test_allocation(HANDLE process)
|
|
{
|
|
MEMORY_BASIC_INFORMATION information;
|
|
DWORD value = 1234, read_back = 1, previous = 0;
|
|
SIZE_T copied = 0;
|
|
void *block = VirtualAllocEx(process, NULL, 8192, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
if (!block || !ReadProcessMemory(process, block, &read_back, sizeof(read_back), &copied) || copied != sizeof(read_back) || read_back)
|
|
return 30;
|
|
if (!WriteProcessMemory(process, block, &value, sizeof(value), &copied) || copied != sizeof(value) ||
|
|
!VirtualProtectEx(process, block, 8192, PAGE_READONLY, &previous) || previous != PAGE_READWRITE)
|
|
return 31;
|
|
if (VirtualQueryEx(process, block, &information, sizeof(information)) != sizeof(information) || information.BaseAddress != block ||
|
|
information.RegionSize != 8192 || information.State != MEM_COMMIT || information.Protect != PAGE_READONLY)
|
|
return 32;
|
|
if (WriteProcessMemory(process, block, &value, sizeof(value), &copied) || GetLastError() != ERROR_PARTIAL_COPY || copied ||
|
|
!ReadProcessMemory(process, block, &read_back, sizeof(read_back), &copied) || read_back != value)
|
|
return 33;
|
|
if (VirtualProtectEx(process, block, 8192, PAGE_READWRITE, NULL) ||
|
|
VirtualQueryEx(process, block, &information, sizeof(information)) != sizeof(information) || information.Protect != PAGE_READONLY)
|
|
return 34;
|
|
if (!VirtualFreeEx(process, block, 0, MEM_RELEASE) || VirtualQueryEx(process, block, &information, sizeof(information)) != sizeof(information) ||
|
|
information.State != MEM_FREE)
|
|
return 35;
|
|
return 0;
|
|
}
|
|
|
|
static int test_child(query_process query, copy_memory read_memory, copy_memory write_memory, PROCESS_INFORMATION *child)
|
|
{
|
|
open_thread open = (open_thread)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtOpenProcess");
|
|
struct basic_information information;
|
|
ULONG length = 0;
|
|
SIZE_T copied = 0;
|
|
ULONG_PTR image = 0, address, buffer;
|
|
DWORD value = 0, replacement = 0x2468ace0, exit_code = 0;
|
|
HANDLE limited;
|
|
unsigned index;
|
|
int result;
|
|
{
|
|
ULONG_PTR client[2] = {child->dwProcessId, 0};
|
|
HANDLE handle = NULL;
|
|
if (!open || open(&handle, PROCESS_QUERY_INFORMATION, NULL, client) ||
|
|
query(handle, 0, &information, sizeof(information), &length) || information.pid != child->dwProcessId)
|
|
return 72;
|
|
CloseHandle(handle);
|
|
}
|
|
if (query(child->hProcess, 0, &information, sizeof(information), &length) || length != sizeof(information) ||
|
|
information.pid != child->dwProcessId || information.parent != GetCurrentProcessId() || information.exit_status != 259 || !information.peb)
|
|
return 10;
|
|
if (!ReadProcessMemory(child->hProcess, (BYTE *)information.peb + 2 * sizeof(void *), &image, sizeof(image), &copied) ||
|
|
copied != sizeof(image) || !image)
|
|
return 11;
|
|
address = image + (ULONG_PTR)&child_value - (ULONG_PTR)GetModuleHandleW(NULL);
|
|
buffer = image + (ULONG_PTR)child_buffer - (ULONG_PTR)GetModuleHandleW(NULL);
|
|
if (read_memory(child->hProcess, (void *)address, &value, sizeof(value), &copied) || copied != sizeof(value) || value != child_value)
|
|
return 12;
|
|
if (write_memory(child->hProcess, (void *)address, &replacement, sizeof(replacement), &copied) || copied != sizeof(replacement))
|
|
return 13;
|
|
if (!ReadProcessMemory(child->hProcess, (void *)address, &value, sizeof(value), &copied) || copied != sizeof(value) || value != replacement)
|
|
return 14;
|
|
for (index = 0; index < sizeof(transferred); ++index)
|
|
transferred[index] = (BYTE)(index * 17 + 3);
|
|
if (!WriteProcessMemory(child->hProcess, (void *)buffer, transferred, sizeof(transferred), &copied) || copied != sizeof(transferred))
|
|
return 15;
|
|
for (index = 0; index < sizeof(transferred); ++index)
|
|
transferred[index] = 0;
|
|
if (!ReadProcessMemory(child->hProcess, (void *)buffer, transferred, sizeof(transferred), &copied) || copied != sizeof(transferred))
|
|
return 16;
|
|
for (index = 0; index < sizeof(transferred); ++index)
|
|
if (transferred[index] != (BYTE)(index * 17 + 3))
|
|
return 17;
|
|
if (ReadProcessMemory(child->hProcess, (void *)1, &value, sizeof(value), &copied) || GetLastError() != ERROR_PARTIAL_COPY || copied)
|
|
return 18;
|
|
if (WriteProcessMemory(child->hProcess, (void *)1, &value, sizeof(value), &copied) || GetLastError() != ERROR_PARTIAL_COPY || copied)
|
|
return 19;
|
|
limited = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, child->dwProcessId);
|
|
if (!limited)
|
|
return 20;
|
|
if (ReadProcessMemory(limited, (void *)address, &value, sizeof(value), &copied) || GetLastError() != ERROR_ACCESS_DENIED || copied ||
|
|
WriteProcessMemory(limited, (void *)address, &replacement, sizeof(replacement), &copied) || GetLastError() != ERROR_ACCESS_DENIED || copied) {
|
|
CloseHandle(limited);
|
|
return 21;
|
|
}
|
|
if (query(limited, 0, &information, sizeof(information), &length)) {
|
|
CloseHandle(limited);
|
|
return 22;
|
|
}
|
|
if (VirtualAllocEx(limited, NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) || GetLastError() != ERROR_ACCESS_DENIED) {
|
|
CloseHandle(limited);
|
|
return 24;
|
|
}
|
|
CloseHandle(limited);
|
|
result = test_allocation(child->hProcess);
|
|
if (result)
|
|
return result;
|
|
#ifdef _WIN64
|
|
{
|
|
BYTE patch[6] = {0xb8, 0x22, 0, 0, 0xc0, 0xc3};
|
|
MEMORY_BASIC_INFORMATION memory;
|
|
DWORD previous, ignored;
|
|
void *target = (void *)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtOpenThread");
|
|
if (VirtualQueryEx(child->hProcess, target, &memory, sizeof(memory)) != sizeof(memory) || memory.Type != MEM_IMAGE ||
|
|
!VirtualProtectEx(child->hProcess, target, sizeof(patch), PAGE_WRITECOPY, &previous))
|
|
return 70;
|
|
if (!WriteProcessMemory(child->hProcess, target, patch, sizeof(patch), &copied) || copied != sizeof(patch) ||
|
|
!VirtualProtectEx(child->hProcess, target, sizeof(patch), previous, &ignored) || ignored != PAGE_WRITECOPY)
|
|
return 71;
|
|
}
|
|
#endif
|
|
if (WaitForSingleObject(child->hProcess, 0) != WAIT_TIMEOUT || ResumeThread(child->hThread) != 1 ||
|
|
WaitForSingleObject(child->hProcess, 15000) != WAIT_OBJECT_0 || !GetExitCodeProcess(child->hProcess, &exit_code) || exit_code)
|
|
return 23;
|
|
return 0;
|
|
}
|
|
|
|
int raven_entry(void)
|
|
{
|
|
const WCHAR *line = GetCommandLineW();
|
|
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
|
|
query_process query = (query_process)GetProcAddress(ntdll, "NtQueryInformationProcess");
|
|
copy_memory read_memory = (copy_memory)GetProcAddress(ntdll, "NtReadVirtualMemory");
|
|
copy_memory write_memory = (copy_memory)GetProcAddress(ntdll, "NtWriteVirtualMemory");
|
|
open_thread open_process = (open_thread)GetProcAddress(ntdll, "NtOpenProcess");
|
|
struct basic_information information;
|
|
STARTUPINFOW startup;
|
|
PROCESS_INFORMATION child;
|
|
WCHAR command[512], source[512], child_image[512], child_directory[512];
|
|
ULONG length = 0;
|
|
ULONG_PTR peb = 0;
|
|
DWORD used;
|
|
DWORD value = 123, replacement = 456, count;
|
|
HANDLE limited;
|
|
SIZE_T copied;
|
|
unsigned index;
|
|
int result;
|
|
for (index = 0; line[index]; ++index)
|
|
#ifdef _WIN64
|
|
if (line[index] == '-' && line[index + 1] == '-' && line[index + 2] == 'u') {
|
|
__asm__ volatile("mov $39, %%eax; syscall" : : : "rax", "rcx", "r11", "memory");
|
|
return 0;
|
|
} else
|
|
#endif
|
|
if (line[index] == '-' && line[index + 1] == '-' && line[index + 2] == 'c') {
|
|
#ifdef _WIN64
|
|
ULONG_PTR client[2] = {GetCurrentProcessId(), GetCurrentThreadId()};
|
|
HANDLE handle;
|
|
open_thread open = (open_thread)GetProcAddress(ntdll, "NtOpenThread");
|
|
if (!open || (ULONG)open(&handle, THREAD_QUERY_INFORMATION, NULL, client) != 0xc0000022)
|
|
return 92;
|
|
#endif
|
|
if (child_value != 0x2468ace0)
|
|
return 90;
|
|
for (index = 0; index < sizeof(child_buffer); ++index)
|
|
if (child_buffer[index] != (BYTE)(index * 17 + 3))
|
|
return 91;
|
|
return 0;
|
|
}
|
|
if (!query || !read_memory || !write_memory || !open_process)
|
|
return 1;
|
|
result = test_handle_count(query, GetCurrentProcess(), TRUE);
|
|
if (result) return result;
|
|
if (GetProcessHandleCount((HANDLE)(ULONG_PTR)0x12345678, &count) || GetLastError() != ERROR_INVALID_HANDLE ||
|
|
GetProcessHandleCount(GetCurrentProcess(), (DWORD *)1) || GetLastError() != ERROR_NOACCESS)
|
|
return 94;
|
|
limited = OpenProcess(PROCESS_VM_READ, FALSE, GetCurrentProcessId());
|
|
if (!limited || GetProcessHandleCount(limited, &count) || GetLastError() != ERROR_ACCESS_DENIED) return 95;
|
|
CloseHandle(limited);
|
|
limited = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
|
|
if (!limited || !GetProcessHandleCount(limited, &count)) return 96;
|
|
CloseHandle(limited);
|
|
result = test_open_thread(ntdll);
|
|
if (result)
|
|
return result;
|
|
{
|
|
ULONG_PTR client[2] = {GetCurrentProcessId(), 0};
|
|
struct thread_attributes attributes = {sizeof(attributes), NULL, NULL, 2, NULL, NULL};
|
|
HANDLE handle = NULL, sentinel = (HANDLE)(ULONG_PTR)0x12345678;
|
|
DWORD flags = 0;
|
|
if (open_process(&handle, GENERIC_READ, &attributes, client) || !GetHandleInformation(handle, &flags) ||
|
|
!(flags & HANDLE_FLAG_INHERIT) || query(handle, 0, &information, sizeof(information), &length) || information.pid != client[0])
|
|
return 73;
|
|
CloseHandle(handle);
|
|
if (open_process(&handle, READ_CONTROL, NULL, client) ||
|
|
(ULONG)query(handle, 0, &information, sizeof(information), &length) != 0xc0000022)
|
|
return 74;
|
|
CloseHandle(handle);
|
|
handle = sentinel;
|
|
if ((ULONG)open_process(NULL, GENERIC_READ, NULL, client) != 0xc0000005 ||
|
|
(ULONG)open_process((HANDLE *)1, GENERIC_READ, NULL, client) != 0xc0000005 ||
|
|
(ULONG)open_process(&handle, GENERIC_READ, NULL, (void *)1) != 0xc0000005 || handle != sentinel)
|
|
return 75;
|
|
if ((ULONG)open_process(&handle, GENERIC_READ, NULL, NULL) != 0xc0000030 || handle != sentinel)
|
|
return 76;
|
|
attributes.name = (void *)1;
|
|
if ((ULONG)open_process(&handle, GENERIC_READ, &attributes, client) != 0xc0000030 || handle != sentinel)
|
|
return 77;
|
|
client[0] = 0xffffffff;
|
|
if ((ULONG)open_process(&handle, GENERIC_READ, NULL, client) != 0xc000000b || handle != sentinel)
|
|
return 78;
|
|
}
|
|
#ifdef _WIN64
|
|
__asm__("movq %%gs:0x60,%0" : "=r"(peb));
|
|
#else
|
|
__asm__("movl %%fs:0x30,%0" : "=r"(peb));
|
|
#endif
|
|
if (query(GetCurrentProcess(), 0, &information, sizeof(information), &length) || length != sizeof(information) ||
|
|
(ULONG_PTR)information.peb != peb || information.pid != GetCurrentProcessId() || !information.affinity || information.priority != 8)
|
|
return 2;
|
|
if ((ULONG)query(GetCurrentProcess(), 0, &information, sizeof(information) - 1, &length) != 0xc0000004 || length != sizeof(information))
|
|
return 3;
|
|
if ((ULONG)query((HANDLE)(ULONG_PTR)0x12345678, 0, &information, sizeof(information), &length) != 0xc0000008)
|
|
return 4;
|
|
if ((ULONG)query(GetCurrentProcess(), 0xffffffff, &information, sizeof(information), &length) != 0xc0000003)
|
|
return 5;
|
|
if ((ULONG)query(GetCurrentProcess(), 0, NULL, sizeof(information), &length) != 0xc0000005)
|
|
return 6;
|
|
if ((ULONG)query(GetCurrentProcess(), 0, (void *)1, sizeof(information), &length) != 0xc0000005 ||
|
|
(ULONG)query(GetCurrentProcess(), 0, &information, sizeof(information), (ULONG *)1) != 0xc0000005)
|
|
return 42;
|
|
if ((ULONG)read_memory(GetCurrentProcess(), &value, &replacement, sizeof(value), (SIZE_T *)1) != 0xc0000005 || replacement != 456)
|
|
return 43;
|
|
if ((ULONG)write_memory(GetCurrentProcess(), &value, &replacement, sizeof(value), (SIZE_T *)1) != 0xc0000005 || value != 123)
|
|
return 44;
|
|
limited = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
|
|
if (!limited || (ULONG)read_memory(limited, &value, &replacement, sizeof(value), &copied) != 0xc0000022 || copied ||
|
|
ReadProcessMemory(limited, &value, &replacement, sizeof(value), &copied) || GetLastError() != ERROR_ACCESS_DENIED ||
|
|
VirtualAllocEx(limited, NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) || GetLastError() != ERROR_ACCESS_DENIED)
|
|
return 45;
|
|
CloseHandle(limited);
|
|
limited = OpenProcess(PROCESS_VM_READ, FALSE, GetCurrentProcessId());
|
|
if (!limited || (ULONG)query(limited, 0, &information, sizeof(information), &length) != 0xc0000022)
|
|
return 46;
|
|
CloseHandle(limited);
|
|
{
|
|
MEMORY_BASIC_INFORMATION memory;
|
|
void *block = VirtualAllocEx(GetCurrentProcess(), NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
if (!block || VirtualProtectEx(GetCurrentProcess(), block, 4096, PAGE_READONLY, (DWORD *)block) ||
|
|
VirtualQueryEx(GetCurrentProcess(), block, &memory, sizeof(memory)) != sizeof(memory) || memory.Protect != PAGE_READWRITE ||
|
|
!VirtualFreeEx(GetCurrentProcess(), block, 0, MEM_RELEASE))
|
|
return 47;
|
|
}
|
|
for (index = 0; index < sizeof(startup); ++index)
|
|
((BYTE *)&startup)[index] = 0;
|
|
startup.cb = sizeof(startup);
|
|
command[0] = '"';
|
|
used = GetModuleFileNameW(NULL, source, 400);
|
|
if (!used || used >= 400)
|
|
return 7;
|
|
for (index = 0; index < used; ++index) child_directory[index] = source[index];
|
|
const WCHAR suffix[] = L".image-\u00e9";
|
|
for (index = 0; index < sizeof suffix / sizeof(WCHAR); ++index) child_directory[used + index] = suffix[index];
|
|
if (!CreateDirectoryW(child_directory, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) return 105;
|
|
DWORD name = used;
|
|
while (name && source[name - 1] != '\\') --name;
|
|
used += sizeof suffix / sizeof(WCHAR) - 1;
|
|
if (used + 1 + lstrlenW(source + name) >= 500) return 106;
|
|
for (index = 0; index < used; ++index) child_image[index] = child_directory[index];
|
|
child_image[used++] = '\\';
|
|
for (index = name; source[index]; ++index) child_image[used++] = source[index];
|
|
child_image[used] = 0;
|
|
if (!CopyFileW(source, child_image, FALSE)) return 104;
|
|
for (index = 0; index < used; ++index) command[index + 1] = child_image[index];
|
|
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)) {
|
|
DeleteFileW(child_image);
|
|
RemoveDirectoryW(child_directory);
|
|
return 8;
|
|
}
|
|
result = test_image_name(child.hProcess, child_image);
|
|
if (!result) result = test_handle_count(query, child.hProcess, FALSE);
|
|
if (!result) result = test_child(query, read_memory, write_memory, &child);
|
|
if (result) {
|
|
TerminateProcess(child.hProcess, 99);
|
|
WaitForSingleObject(child.hProcess, 5000);
|
|
}
|
|
CloseHandle(child.hThread);
|
|
CloseHandle(child.hProcess);
|
|
#ifdef _WIN64
|
|
if (!result) {
|
|
DWORD exit_code = 0;
|
|
command[used - 1] = 'u';
|
|
if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &child))
|
|
return 67;
|
|
if (WaitForSingleObject(child.hProcess, 15000) != WAIT_OBJECT_0 || !GetExitCodeProcess(child.hProcess, &exit_code) || exit_code != 1)
|
|
result = 68;
|
|
CloseHandle(child.hThread);
|
|
CloseHandle(child.hProcess);
|
|
}
|
|
#endif
|
|
DeleteFileW(child_image);
|
|
RemoveDirectoryW(child_directory);
|
|
return result;
|
|
}
|