├── .gitignore ├── README.md ├── src ├── common │ ├── log.zig │ ├── guids.zig │ ├── tp.zig │ ├── rt.zig │ ├── vfs.zig │ ├── PE.zig │ ├── ntdll.zig │ └── symbols.zig └── launcher.zig └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | test/ 2 | zig-cache/ 3 | zig-out/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Champagne 2 | 3 | Run an entire windows userspace on linux 4 | -------------------------------------------------------------------------------- /src/common/log.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn scoped(comptime tag: anytype) fn (comptime fmt: []const u8, args: anytype) callconv(.Inline) void { 4 | return struct { 5 | pub inline fn f(comptime fmt: []const u8, args: anytype) void { 6 | std.debug.print(@tagName(tag) ++ ": " ++ fmt ++ "\n", args); 7 | } 8 | }.f; 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2022 by Hannes Bredberg 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 6 | -------------------------------------------------------------------------------- /src/common/guids.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const rt = @import("rt.zig"); 4 | 5 | pub const GUID = extern struct { 6 | data1: rt.ULONG, 7 | data2: rt.USHORT, 8 | data3: rt.USHORT, 9 | data4: [8]u8, 10 | 11 | pub fn format( 12 | self: GUID, 13 | comptime layout: []const u8, 14 | opts: std.fmt.FormatOptions, 15 | writer: anytype, 16 | ) !void { 17 | _ = layout; 18 | _ = opts; 19 | try writer.print("{{{X:0>8}-{X:0>4}-{X:0>4}-{X:0>2}{X:0>2}-{X}}}", .{ 20 | self.data1, 21 | self.data2, 22 | self.data3, 23 | self.data4[0], 24 | self.data4[1], 25 | std.fmt.fmtSliceHexUpper(self.data4[2..]), 26 | }); 27 | if (@import("guids.zig").lookupName(self)) |guid_name| { 28 | try writer.print("('{s}')", .{guid_name}); 29 | } else { 30 | try writer.print("(unknown)", .{}); 31 | } 32 | } 33 | }; 34 | 35 | const known_guids = .{ 36 | .{ .{ 0x43E63DA5, 0x41D1, 0x4FBF, .{ 0xAD, 0xED, 0x1B, 0xBE, 0xD9, 0x8F, 0xDD, 0x1D } }, "Microsoft-Windows-Subsys-SMSS" }, 37 | // .{ .{ 0xBDE5A307, 0x3888, 0x46CC, .{ 0x85, 0x1E, 0x5C, 0x15, 0x1F, 0xCE, 0xBD, 0x05 } }, "" }, 38 | }; 39 | 40 | pub fn lookupName(guid: GUID) ?[]const u8 { 41 | inline for (known_guids) |g| { 42 | const gg = GUID{ 43 | .data1 = g.@"0".@"0", 44 | .data2 = g.@"0".@"1", 45 | .data3 = g.@"0".@"2", 46 | .data4 = g.@"0".@"3", 47 | }; 48 | if (std.meta.eql(gg, guid)) 49 | return g.@"1"; 50 | } 51 | return null; 52 | } 53 | -------------------------------------------------------------------------------- /src/launcher.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const os = std.os; 3 | 4 | const PE = @import("common/PE.zig"); 5 | const ntdll = @import("common/ntdll.zig"); 6 | const rt = @import("common/rt.zig"); 7 | const vfs = @import("common/vfs.zig"); 8 | 9 | const log_lib = @import("common/log.zig"); 10 | const logger = log_lib.scoped(.launcher); 11 | 12 | pub fn log( 13 | comptime level: std.log.Level, 14 | comptime scope: anytype, 15 | comptime fmt: []const u8, 16 | args: anytype, 17 | ) void { 18 | _ = level; 19 | _ = scope; 20 | _ = fmt; 21 | _ = args; 22 | //log_lib.scoped(scope)(@tagName(level) ++ ": " ++ fmt, args); 23 | } 24 | 25 | const ResolveContext = @import("common/symbols.zig").ResolveContext; 26 | 27 | var smss_path = std.unicode.utf8ToUtf16LeStringLiteral("C:\\Windows\\system32\\smss.exe").*; 28 | var smss_command_line = std.unicode.utf8ToUtf16LeStringLiteral("C:\\Windows\\system32\\smss.exe").*; 29 | 30 | fn setSymlink(path: []const u8, comptime value: []const u8) !void { 31 | const node = try vfs.resolve8(path, true); 32 | defer vfs.close(node); 33 | node.get(.symlink).?.* = std.unicode.utf8ToUtf16LeStringLiteral(value); 34 | } 35 | 36 | fn doVfsInit() !void { 37 | try setSymlink("\\KnownDlls\\KnownDllPath", "C:\\Windows\\System32"); 38 | try setSymlink("\\KnownDlls32\\KnownDllPath", "C:\\Windows\\System32"); 39 | } 40 | 41 | fn trapHandler(signum: c_int, info: *const std.os.siginfo_t, ctx: ?*const anyopaque) callconv(.C) void { 42 | const context = @ptrCast(*const std.os.ucontext_t, @alignCast(@alignOf(std.os.ucontext_t), ctx)); 43 | const gregs = context.mcontext.gregs; 44 | const eax = @truncate(u32, gregs[std.os.REG.RAX]); 45 | 46 | _ = signum; 47 | _ = info; 48 | 49 | const rip = gregs[std.os.REG.RIP] - 1; 50 | logger("Trap at addr 0x{X}", .{rip}); 51 | const rbp = gregs[std.os.REG.RBP]; 52 | std.debug.dumpStackTraceFromBase(rbp, rip); 53 | 54 | switch(eax) { 55 | 1 => { 56 | const unk0 = std.mem.span(@intToPtr([*:0]u8, gregs[std.os.REG.RCX])); 57 | const unk1 = @truncate(u16, gregs[std.os.REG.RDX]); 58 | const unk2 = @truncate(u32, gregs[std.os.REG.R8]); 59 | const unk3 = @truncate(u32, gregs[std.os.REG.R9]); 60 | logger("DebugPrint('{s}', 0x{X}, 0x{X}, 0x{X})", .{ 61 | std.fmt.fmtSliceEscapeUpper(unk0), unk1, unk2, unk3 62 | }); 63 | }, 64 | 2 => { 65 | const unk0 = gregs[std.os.REG.RCX]; 66 | const unk1 = @truncate(u16, gregs[std.os.REG.RDX]); 67 | const unk2 = gregs[std.os.REG.R8]; 68 | const unk3 = @truncate(u16, gregs[std.os.REG.R9]); 69 | logger("DebugPrompt(0x{X}, 0x{X}, 0x{X}, 0x{X})", .{ 70 | unk0, unk1, unk2, unk3 71 | }); 72 | }, 73 | else => logger("Unknown debug call 0x{X}", .{eax}), 74 | } 75 | std.os.abort(); 76 | } 77 | 78 | pub fn main() !void { 79 | try rt.init(&smss_path, &smss_command_line); 80 | 81 | var sa = std.os.Sigaction{ 82 | .handler = .{ .sigaction = trapHandler }, 83 | .flags = 0, 84 | .mask = std.mem.zeroes([32]u32), 85 | }; 86 | 87 | try std.os.sigaction(std.os.SIG.TRAP, &sa, null); 88 | 89 | var ntdll_file = try std.fs.cwd().openFile("test/Windows/System32/ntdll.dll", .{}); 90 | defer ntdll_file.close(); 91 | 92 | const ntdll_entry = try PE.load(ntdll_file, ResolveContext); 93 | _ = ntdll_entry; 94 | 95 | // launch Smss.exe 96 | var smss = try std.fs.cwd().openFile("test/Windows/System32/smss.exe", .{}); 97 | defer smss.close(); 98 | 99 | try doVfsInit(); 100 | 101 | const smss_entry = try PE.load(smss, ResolveContext); 102 | logger("Calling smss.exe entry @ 0x{X}", .{smss_entry}); 103 | _ = rt.call_entry(smss_entry); 104 | } 105 | -------------------------------------------------------------------------------- /src/common/tp.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | var tp_alloc = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = std.heap.page_allocator }; 4 | var work_alloc = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = std.heap.page_allocator }; 5 | 6 | pub const Work = *const fn( 7 | Environment, 8 | Context, 9 | *anyopaque, 10 | ) callconv(.Win64) void; 11 | 12 | pub const Context = u64; 13 | pub const Environment = *extern struct { 14 | version: u32, 15 | pool: ?*ThreadPool, 16 | // ... 17 | }; 18 | 19 | pub const TPWork = struct { 20 | queue_node: std.TailQueue(void).Node, 21 | env: Environment, 22 | context: Context, 23 | work: ?Work, 24 | finish_sema: std.Thread.Semaphore = .{}, 25 | }; 26 | 27 | const WorkQueue = struct { 28 | sema: std.Thread.Semaphore = .{}, 29 | pool_mutex: std.Thread.Mutex = .{}, 30 | queue: std.TailQueue(void) = .{}, 31 | 32 | pub fn pop(self: *@This()) *TPWork { 33 | self.sema.wait(); 34 | 35 | self.pool_mutex.lock(); 36 | defer self.pool_mutex.unlock(); 37 | 38 | return @fieldParentPtr(TPWork, "queue_node", self.queue.pop() orelse unreachable); 39 | } 40 | 41 | pub fn push(self: *@This(), w: *TPWork) void { 42 | self.pool_mutex.lock(); 43 | defer self.pool_mutex.unlock(); 44 | 45 | self.queue.append(&w.queue_node); 46 | self.sema.post(); 47 | } 48 | }; 49 | 50 | pub fn allocWork(work: ?Work, context: Context, env: Environment) !*TPWork { 51 | const ptr = try work_alloc.allocator().create(TPWork); 52 | ptr.* = .{ 53 | .queue_node = undefined, 54 | .work = work, 55 | .context = context, 56 | .env = env, 57 | }; 58 | return ptr; 59 | } 60 | 61 | pub fn releaseWork(work: *TPWork) void { 62 | work_alloc.allocator().destroy(work); 63 | } 64 | 65 | pub fn allocPool() !*ThreadPool { 66 | const p = try tp_alloc.allocator().create(ThreadPool); 67 | p.* = .{}; 68 | return p; 69 | } 70 | 71 | pub const ThreadPool = struct { 72 | running_threads: usize = 0, 73 | queue: WorkQueue = .{}, 74 | 75 | pub fn removeThreads(self: *@This(), num: usize) !void { 76 | while(true) { 77 | const old_val = @atomicLoad(usize, &self.running_threads, .Acquire); 78 | if(old_val < num) return error.NotEnoughThreadsToExit; 79 | if(@cmpxchgWeak(usize, &self.running_threads, old_val, old_val - num, .AcqRel, .Acquire)) |_| { 80 | return doRemoveThreads(num); 81 | } 82 | } 83 | } 84 | 85 | pub fn addThreads(self: *@This(), num: usize) !void { 86 | while(true) { 87 | @atomicRmw(usize, &self.running_threads, .Add, num, .AcqRel); 88 | return doAddThreads(num); 89 | } 90 | } 91 | 92 | pub fn setNumThreads(self: *@This(), num: usize) !void { 93 | const old_running_threads = @atomicRmw(usize, &self.running_threads, .Xchg, num, .AcqRel); 94 | if(old_running_threads < num) { 95 | return self.doAddThreads(num - old_running_threads); 96 | } else { 97 | return self.doRemoveThreads(old_running_threads - num); 98 | } 99 | } 100 | 101 | pub fn addWork(self: *@This(), work: *TPWork) !void { 102 | self.queue.push(work); 103 | } 104 | 105 | fn killOneThread(self: *@This()) !void { 106 | self.queue.push(try allocWork( 107 | null, 108 | undefined, 109 | undefined, 110 | )); 111 | } 112 | 113 | fn doRemoveThreads(self: *@This(), num: usize) !void { 114 | var i: usize = 0; 115 | while(i < num) : (i += 1) { 116 | try self.killOneThread(); 117 | } 118 | } 119 | 120 | fn threadWorker(self: *@This()) void { 121 | while(true) { 122 | const work = self.queue.pop(); 123 | if(work.work) |f| { 124 | f( 125 | work.env, 126 | work.context, 127 | work, 128 | ); 129 | work.finish_sema.post(); 130 | } else { 131 | releaseWork(work); 132 | return; 133 | } 134 | } 135 | } 136 | 137 | fn startOneThread(self: *@This()) !void { 138 | const t = try std.Thread.spawn(.{}, threadWorker, .{self}); 139 | t.detach(); 140 | } 141 | 142 | fn doAddThreads(self: *@This(), num: usize) !void { 143 | var i: usize = 0; 144 | while(i < num) : (i += 1) { 145 | try self.startOneThread(); 146 | } 147 | } 148 | }; 149 | -------------------------------------------------------------------------------- /src/common/rt.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub const BOOL = i32; 4 | pub const LOGICAL = ULONG; 5 | pub const FALSE = 0; 6 | pub const TRUE = 1; 7 | 8 | pub const UCHAR = u8; 9 | pub const WORD = u16; 10 | pub const USHORT = u16; 11 | pub const DWORD = u32; 12 | pub const ULONG = u32; 13 | pub const SIZE_T = u32; 14 | pub const ULONGLONG = u64; 15 | pub const KAFFINITY = u64; 16 | pub const LARGEINT = i64; 17 | 18 | pub const WCHAR = u16; 19 | 20 | pub const PVOID = ?*anyopaque; 21 | pub const HINSTANCE = ?*anyopaque; 22 | pub const HANDLE = usize; 23 | 24 | pub const LPCSTR = ?[*:0]const u8; 25 | 26 | pub const PWSTR = ?[*:0]WCHAR; 27 | pub const PCWSTR = ?[*:0]const WCHAR; 28 | pub const LPCWSTR = ?[*:0]const WCHAR; 29 | 30 | const log = @import("log.zig").scoped(.rt); 31 | 32 | export fn c_log_impl(function: ?[*:0]u8, file: ?[*:0]u8, line: c_int, msg: ?[*:0]WCHAR) callconv(.Win64) void { 33 | log("{any}: {any}:{d}: {}", .{ function, file, line, fmt(msg) }); 34 | } 35 | 36 | export fn c_panic_impl(function: ?[*:0]u8, file: ?[*:0]u8, line: c_int, msg: ?[*:0]WCHAR) callconv(.Win64) void { 37 | log("{any}: {any}:{d}: {}", .{ function, file, line, fmt(msg) }); 38 | @panic(""); 39 | } 40 | 41 | pub fn alignPageUp(value: usize) usize { 42 | return (value + 0xFFF) & ~@as(usize, 0xFFF); 43 | } 44 | 45 | pub fn Fmt(comptime T: type) type { 46 | return struct { 47 | v: T, 48 | 49 | pub fn format( 50 | self: @This(), 51 | comptime layout: []const u8, 52 | opts: std.fmt.FormatOptions, 53 | writer: anytype, 54 | ) !void { 55 | _ = layout; 56 | _ = opts; 57 | switch (T) { 58 | LPCSTR, PWSTR, LPCWSTR => { 59 | if (self.v) |v| { 60 | const span = std.mem.span(v); 61 | try writer.print("(0x{X}) '", .{@ptrToInt(span.ptr)}); 62 | for (span) |chr| { 63 | if (chr > 0x7F) { 64 | try writer.print("\\x{X:0>2}", .{chr}); 65 | } else { 66 | try writer.print("{c}", .{@truncate(u8, chr)}); 67 | } 68 | } 69 | try writer.print("'", .{}); 70 | } else { 71 | try writer.print("(null)", .{}); 72 | } 73 | }, 74 | BOOL => { 75 | if (self.v != FALSE) { 76 | try writer.print("TRUE", .{}); 77 | } else { 78 | try writer.print("FALSE", .{}); 79 | } 80 | }, 81 | else => @compileError("rt.fmt not implemented for type " ++ @typeName(T) ++ " yet!"), 82 | } 83 | } 84 | }; 85 | } 86 | 87 | pub fn pad(comptime v: anytype, comptime len: usize) [len]@TypeOf(v[0]) { 88 | return v ++ ([1]@TypeOf(v[0]){0} ** (len - v.len)); 89 | } 90 | 91 | pub fn fmt(val: anytype) Fmt(@TypeOf(val)) { 92 | return Fmt(@TypeOf(val)){ .v = val }; 93 | } 94 | 95 | pub const GUID = @import("guids.zig").GUID; 96 | pub const LPCGUID = ?*const GUID; 97 | 98 | pub const EventFilterDescriptor = extern struct { 99 | ptr: ULONGLONG, 100 | size: ULONG, 101 | type: ULONG, 102 | }; 103 | 104 | pub const EnableCallback = *const fn ( 105 | source: LPCGUID, 106 | is_enabled: ULONG, 107 | level: UCHAR, 108 | match_any_keyword: ULONGLONG, 109 | match_all_keyword: ULONGLONG, 110 | filter_data: ?*EventFilterDescriptor, 111 | callback_context: PVOID, 112 | ) callconv(.Win64) void; 113 | 114 | pub const UnicodeString = extern struct { 115 | length: USHORT, 116 | capacity: USHORT, 117 | buffer: ?[*]WCHAR, 118 | 119 | pub fn initFromBuffer(buf: []WCHAR) UnicodeString { 120 | return .{ 121 | .length = @intCast(USHORT, buf.len << 1), 122 | .capacity = @intCast(USHORT, buf.len << 1), 123 | .buffer = buf.ptr, 124 | }; 125 | } 126 | 127 | pub fn freeCapacity(self: @This()) usize { 128 | return (self.capacity - self.length) >> 1; 129 | } 130 | 131 | pub fn makeSpaceFor(self: *@This(), num_chars: usize, alloc: std.mem.Allocator) !void { 132 | if (self.freeCapacity() < num_chars) { 133 | const new_capacity = std.math.max( 134 | (num_chars << 1) + self.length, // new length 135 | self.capacity << 1, // double capacity 136 | ); 137 | self.buffer = (try alloc.realloc(self.buffer.?[0 .. self.capacity >> 1], new_capacity >> 1)).ptr; 138 | self.capacity = @intCast(USHORT, new_capacity); 139 | } 140 | } 141 | 142 | pub fn appendAssumeCapacity(self: *@This(), appendage: []const WCHAR) void { 143 | std.mem.copy(WCHAR, self.buffer.?[self.length >> 1 .. (self.length >> 1) + appendage.len], appendage); 144 | self.length += @intCast(USHORT, appendage.len << 1); 145 | } 146 | 147 | pub fn append(self: *@This(), appendage: []const WCHAR, alloc: std.mem.Allocator) !void { 148 | try self.makeSpaceFor(appendage.len, alloc); 149 | self.appendAssumeCapacity(appendage); 150 | } 151 | 152 | pub fn chars(self: @This()) ?[]const WCHAR { 153 | return (self.buffer orelse return null)[0 .. self.length >> 1]; 154 | } 155 | 156 | pub fn format( 157 | self: @This(), 158 | comptime layout: []const u8, 159 | opts: std.fmt.FormatOptions, 160 | writer: anytype, 161 | ) !void { 162 | _ = layout; 163 | _ = opts; 164 | if (self.buffer) |buf| { 165 | const span = buf[0 .. self.length >> 1]; 166 | try writer.print("'", .{}); 167 | for (span) |chr| { 168 | if (chr > 0x7F) { 169 | try writer.print("\\x{X:0>2}", .{chr}); 170 | } else { 171 | try writer.print("{c}", .{@truncate(u8, chr)}); 172 | } 173 | } 174 | try writer.print("'", .{}); 175 | } else { 176 | try writer.print("{{ null buf }}", .{}); 177 | } 178 | } 179 | }; 180 | 181 | pub const ProcessParameters = extern struct { 182 | reserved1: [16]u8, 183 | reserved2: [10]PVOID, 184 | image_path_name: UnicodeString, 185 | command_line: UnicodeString, 186 | }; 187 | 188 | pub const PEB = extern struct { 189 | reserved1: [2]u8 = std.mem.zeroes([2]u8), 190 | being_debugged: u8 = 0, 191 | reserved2: [1]u8 = std.mem.zeroes([1]u8), 192 | reserved3: [2]PVOID = std.mem.zeroes([2]PVOID), 193 | ldr: PVOID = null, // PPEB_LDR_DATA 194 | process_parameters: ?*ProcessParameters = null, 195 | reserved4: [3]PVOID = std.mem.zeroes([3]PVOID), 196 | atl_thunk_s_list_ptr: PVOID = null, 197 | reserved5: PVOID = null, 198 | reserved6: ULONG = 0, 199 | reserved7: PVOID = null, 200 | reserved8: ULONG = 0, 201 | atl_think_s_list_ptr32: ULONG = 0, 202 | reserved9: [45]PVOID = std.mem.zeroes([45]PVOID), 203 | reserved10: [96]u8 = std.mem.zeroes([96]u8), 204 | post_process_init_routine: PVOID = null, // PPS_POST_PROCESS_INIT_ROUTINE 205 | reserved11: [128]u8 = std.mem.zeroes([128]u8), 206 | reserved12: [1]PVOID = std.mem.zeroes([1]PVOID), 207 | session_id: ULONG = 0, 208 | }; 209 | 210 | comptime { 211 | std.debug.assert(@offsetOf(PEB, "process_parameters") == 0x20); 212 | } 213 | 214 | const KSystemTime = extern struct { 215 | idk0: u32 = 0x51515151, 216 | idk1: u32 = 0x53535353, 217 | wtf: u32 = 0x52525252, 218 | }; 219 | 220 | const KUserSharedData = extern struct { 221 | // zig fmt: off 222 | tick_count_low: u32 = 0x40404040, // 0x0000 223 | tick_count_multiplier: u32 = 0x40404041, // 0x0004 224 | interrupt_time: KSystemTime = .{}, // 0x0008 225 | system_time: KSystemTime = .{}, // 0x0014 226 | time_zone_bias: KSystemTime = .{}, // 0x0020 227 | image_number_low: USHORT = 0, // 0x002C 228 | image_number_high: USHORT = 42, // 0x002E 229 | nt_system_root: [0x104]WCHAR = pad(std.unicode.utf8ToUtf16LeStringLiteral("C:\\Windows").*, 0x104), // 0x30 230 | max_stack_trace_depth: ULONG = 20, // 0x0238 231 | crypto_exponent: ULONG = 0x10001, // 0x023C 232 | time_zone_id: ULONG = 0, // 0x0240 233 | large_page_minimum: ULONG = 0x1000 << 9, // 0x0244 234 | // zig fmt: on 235 | }; 236 | 237 | pub var pparam: ProcessParameters = undefined; 238 | pub var peb: PEB = undefined; 239 | 240 | const TEB = extern struct { 241 | // zig fmt: off 242 | unk0: [0x30]u8 = undefined, // 0x0000 243 | self: *TEB, // 0x0030 244 | unk1: [0x8]u8 = undefined, // 0x0038 245 | process_id: u32 = 0x5, // 0x0040 246 | unk2: [0x1C]u8 = undefined, // 0x0044 247 | peb: ?*PEB = undefined, // 0x0060 248 | // zig fmt: on 249 | }; 250 | 251 | var teb: TEB = .{ 252 | .self = undefined, 253 | }; 254 | 255 | const kuser_shared_data_addr = 0x7ffe0000; 256 | 257 | pub fn init(image_path_name: [:0]WCHAR, command_line: [:0]WCHAR) !void { 258 | _ = try std.os.mmap( 259 | @intToPtr([*]align(0x1000) u8, kuser_shared_data_addr), 260 | 0x1000, 261 | std.os.PROT.READ | std.os.PROT.WRITE, 262 | std.os.MAP.FIXED | std.os.MAP.ANONYMOUS | std.os.MAP.PRIVATE, 263 | 0, 264 | 0, 265 | ); 266 | var kusd = @intToPtr(*KUserSharedData, kuser_shared_data_addr); 267 | kusd.* = .{}; 268 | 269 | teb.peb = &peb; 270 | teb.self = &teb; 271 | 272 | asm volatile ("WRGSBASE %[teb]" 273 | : 274 | : [teb] "r" (@ptrToInt(&teb)), 275 | ); 276 | 277 | pparam.image_path_name = UnicodeString.initFromBuffer(image_path_name); 278 | pparam.command_line = UnicodeString.initFromBuffer(command_line); 279 | peb.process_parameters = &pparam; 280 | } 281 | 282 | pub fn call_entry(entry_point: usize) c_int { 283 | return @intToPtr(*const fn (*PEB) callconv(.Win64) c_int, entry_point)(&peb); 284 | } 285 | -------------------------------------------------------------------------------- /src/common/vfs.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const rt = @import("rt.zig"); 3 | 4 | const log = @import("log.zig").scoped(.vfs); 5 | 6 | pub var dirents: std.ArrayListUnmanaged(DirectoryEntry) = .{}; 7 | var curr_free: i32 = -1; 8 | var dirents_mutex = std.Thread.Mutex{}; 9 | var vfs_alloc = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = std.heap.page_allocator }; 10 | 11 | fn deref(idx: i32) *DirectoryEntry { 12 | std.debug.assert(idx >= 0); 13 | return &dirents.items[@intCast(usize, idx)]; 14 | } 15 | 16 | fn allocIdx() !i32 { 17 | if(curr_free != -1) { 18 | const result = curr_free; 19 | curr_free = deref(curr_free).next; 20 | return result; 21 | } 22 | 23 | const result = @intCast(i32, dirents.items.len); 24 | _ = dirents.addOneAssumeCapacity(); 25 | return result; 26 | } 27 | 28 | var symdyn_alloc = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = std.heap.page_allocator }; 29 | var dynstring_alloc = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = std.heap.page_allocator }; 30 | 31 | pub const DirectoryEntry = struct { 32 | name: []u8, 33 | next: i32 = -1, 34 | value: Value, 35 | 36 | const Value = union(enum) { 37 | newly_created, 38 | dir: i32, // First dirent 39 | symlink: []const u16, 40 | symdyn: []const u16, 41 | string: []const u16, 42 | dynstring: []const u16, 43 | mutex: std.Thread.Mutex, 44 | }; 45 | 46 | const ValueKind = @typeInfo(Value).Union.tag_type.?; 47 | 48 | pub fn get(self: *@This(), comptime kind: ValueKind) ?*@TypeOf(@field(self.value, @tagName(kind))) { 49 | if(self.value == .newly_created) { 50 | switch(comptime kind) { 51 | .dir => { 52 | self.value = .{ .dir = -1 }; 53 | return &self.value.dir; 54 | }, 55 | .mutex => { 56 | self.value = .{ .mutex = .{} }; 57 | return &self.value.mutex; 58 | }, 59 | .symlink => { 60 | self.value = .{ .symlink = &[_]u16{} }; 61 | return &self.value.symlink; 62 | }, 63 | .string => { 64 | self.value = .{ .string = &[_]u16{} }; 65 | return &self.value.string; 66 | }, 67 | else => @compileError("Bad value kind for get()"), 68 | } 69 | } 70 | if(comptime (kind == .symlink) and self.value == .symdyn) 71 | return &self.value.symdyn; 72 | 73 | if(comptime (kind == .string) and self.value == .dynstring) 74 | return &self.value.dynstring; 75 | 76 | if(self.value == kind) { 77 | return &@field(self.value, @tagName(kind)); 78 | } 79 | return null; 80 | } 81 | 82 | pub fn setSymlinkDyn(self: *@This(), value: []const u16) !void { 83 | const new_mem = try symdyn_alloc.allocator().dupe(u16, value); 84 | switch(self.value) { 85 | .newly_created, .symlink => self.value = .{ .symdyn = new_mem }, 86 | .symdyn => |*d| { 87 | symdyn_alloc.allocator().free(d.*); 88 | d.* = new_mem; 89 | }, 90 | else => @panic("bad value type"), 91 | } 92 | } 93 | 94 | pub fn setStringDyn(self: *@This(), value: []const u16) !void { 95 | const new_mem = try dynstring_alloc.allocator().dupe(u16, value); 96 | switch(self.value) { 97 | .newly_created, .string => self.value = .{ .dynstring = new_mem }, 98 | .dynstring => |*d| { 99 | dynstring_alloc.allocator().free(d.*); 100 | d.* = new_mem; 101 | }, 102 | else => @panic("bad value type"), 103 | } 104 | } 105 | }; 106 | 107 | pub var fs_root: i32 = -1; 108 | pub var object_root: i32 = -1; 109 | pub var registry_root: i32 = -1; 110 | 111 | pub fn caseInsensitiveEq(lhs: u21, rhs: u21) bool { 112 | if(lhs <= 0x7F and rhs <= 0x7F) { 113 | return std.ascii.toLower(@intCast(u8, lhs)) == std.ascii.toLower(@intCast(u8, rhs)); 114 | } 115 | return lhs == rhs; 116 | } 117 | 118 | fn compareNames(path: *[]const u8, name: []const u8) bool { 119 | var path_idx: usize = 0; 120 | var name_idx: usize = 0; 121 | while(true) { 122 | const curr_path = path.*[path_idx..]; 123 | const curr_name = name[name_idx..]; 124 | 125 | if(curr_path.len == 0 or curr_path[0] == '\\') { 126 | if(curr_name.len == 0) { 127 | path.* = curr_path; 128 | return true; 129 | } else { 130 | return false; 131 | } 132 | } 133 | if(curr_name.len == 0) return false; 134 | 135 | const path_len = std.unicode.utf8ByteSequenceLength(curr_path[0]) catch @panic("aaa"); 136 | const name_len = std.unicode.utf8ByteSequenceLength(curr_name[0]) catch @panic("aaa"); 137 | 138 | if(path_len > curr_path.len) @panic("aaa"); 139 | if(name_len > curr_name.len) @panic("aaa"); 140 | 141 | const path_cp = std.unicode.utf8Decode(curr_path[0..path_len]) catch @panic("aaa"); 142 | const name_cp = std.unicode.utf8Decode(curr_name[0..name_len]) catch @panic("aaa"); 143 | 144 | if(!caseInsensitiveEq(path_cp, name_cp)) 145 | return false; 146 | 147 | path_idx += path_len; 148 | name_idx += name_len; 149 | } 150 | } 151 | 152 | // If the entry is found or created, the chars are consumed 153 | pub fn resolveSingleStep(current_dir: *i32, buf: *[]const u8, create: bool) !*DirectoryEntry { 154 | var dirent_tail = current_dir; 155 | while(dirent_tail.* != -1) { 156 | const dirent = deref(dirent_tail.*); 157 | dirent_tail = &dirent.next; 158 | 159 | if(!compareNames(buf, dirent.name)) 160 | continue; 161 | 162 | return dirent; 163 | } 164 | 165 | if(create) { 166 | const name = try vfs_alloc.allocator().dupe(u8, split(buf, '\\')); 167 | //log("-> Could not find it, creating new dirent with name '{s}'", .{name}); 168 | //log(" -> Remaining search string '{s}'", .{buf.*}); 169 | const next = try allocIdx(); 170 | dirent_tail.* = next; 171 | const result = deref(next); 172 | result.* = .{ 173 | .name = name, 174 | .value = .newly_created, 175 | }; 176 | return result; 177 | } else { 178 | return error.DoesNotExist; 179 | } 180 | } 181 | 182 | pub fn resolveInDir(current_dir_c: *i32, buffer: *[]const u8, create_deep: bool) !*DirectoryEntry { 183 | var current_dir = current_dir_c; 184 | while(true) { 185 | //log("Resolving: '{s}'", .{buffer.*}); 186 | const res = try resolveSingleStep(current_dir, buffer, create_deep); 187 | if(takeStr(buffer, "\\")) { 188 | current_dir = res.get(.dir) orelse @panic("wtf"); 189 | if(buffer.len == 0) return res; 190 | continue; 191 | } 192 | if(buffer.len > 0) { 193 | log("Remaining: '{s}'", .{buffer.*}); 194 | @panic("resolveInDir char not consumed"); 195 | } 196 | return res; 197 | } 198 | } 199 | 200 | fn takeStr(buffer: *[]const u8, str: []const u8) bool { 201 | if(std.mem.startsWith(u8, buffer.*, str)) { 202 | buffer.* = buffer.*[str.len..]; 203 | return true; 204 | } 205 | return false; 206 | } 207 | 208 | fn split(buffer: *[]const u8, delim: u8) []const u8 { 209 | const idx = std.mem.indexOfScalar(u8, buffer.*, delim) orelse buffer.len; 210 | const retval = buffer.*[0..idx]; 211 | buffer.* = buffer.*[idx..]; 212 | return retval; 213 | } 214 | 215 | pub fn resolve(buffer: *[]const u8, create_deep: bool) !*DirectoryEntry { 216 | dirents_mutex.lock(); 217 | errdefer dirents_mutex.unlock(); 218 | 219 | try dirents.ensureUnusedCapacity(vfs_alloc.allocator(), 100); // Ought to be enough for anybody 220 | 221 | _ = takeStr(buffer, "\\??\\"); 222 | _ = takeStr(buffer, "\\??"); 223 | if(takeStr(buffer, "\\Registry\\")) { 224 | return resolveInDir(®istry_root, buffer, create_deep); 225 | } 226 | if(takeStr(buffer, "C:\\")) { 227 | return resolveInDir(&fs_root, buffer, create_deep); 228 | } 229 | if(takeStr(buffer, "\\")) { 230 | return resolveInDir(&object_root, buffer, create_deep); 231 | } 232 | return resolveInDir(&fs_root, buffer, create_deep); 233 | } 234 | 235 | pub fn close(dirent: *DirectoryEntry) void { 236 | _ = dirent; 237 | dirents_mutex.unlock(); 238 | } 239 | 240 | const VALID_HANDLE: rt.HANDLE = 0xFF000000; 241 | 242 | pub fn handle(dirent: *DirectoryEntry) rt.HANDLE { 243 | // Calculate offset from start of dirent array 244 | const offset = @ptrToInt(dirent) - @ptrToInt(dirents.items.ptr); 245 | const idx = offset / @sizeOf(DirectoryEntry); 246 | return idx | VALID_HANDLE; 247 | } 248 | 249 | pub fn openHandle(h: rt.HANDLE) *DirectoryEntry { 250 | if((h & VALID_HANDLE) != VALID_HANDLE) { 251 | @panic("Invalid handle"); 252 | } 253 | const handle_idx = h & ~VALID_HANDLE; 254 | dirents_mutex.lock(); 255 | return &dirents.items[handle_idx]; 256 | } 257 | 258 | var resolve_utf8_buffer: [4096]u8 = undefined; 259 | 260 | fn transcode(path: []const u16) []const u8 { 261 | const len = std.unicode.utf16leToUtf8(&resolve_utf8_buffer, path) catch @panic("aaa"); 262 | return resolve_utf8_buffer[0..len]; 263 | } 264 | 265 | pub fn resolve16In(dir: *i32, path: []const u16, create: bool) !*DirectoryEntry { 266 | var buf = transcode(path); 267 | return resolveSingleStep(dir, &buf, create); 268 | } 269 | 270 | pub fn resolve16(path: []const u16, create_deep: bool) !*DirectoryEntry { 271 | var buf = transcode(path); 272 | return resolve(&buf, create_deep); 273 | } 274 | 275 | pub fn resolve8(path: []const u8, create_deep: bool) !*DirectoryEntry { 276 | var buf = path; 277 | return resolve(&buf, create_deep); 278 | } 279 | 280 | const writer = std.io.getStdErr().writer(); 281 | 282 | fn dumpDir(dirent_c: i32, depth: usize) @TypeOf(writer).Error!void { 283 | var dirent = dirent_c; 284 | while(dirent != -1) { 285 | var ent = &dirents.items[@intCast(usize, dirent)]; 286 | try writer.writeByteNTimes(' ', depth); 287 | try writer.writeAll("> "); 288 | for(ent.name) |b| { 289 | try writer.writeByte(@truncate(u8, b)); 290 | } 291 | try writer.writeByte('\n'); 292 | 293 | if(ent.value == .dir) { 294 | try dumpDir(ent.value.dir, depth + 1); 295 | } 296 | dirent = ent.next; 297 | } 298 | } 299 | 300 | pub fn dump() !void { 301 | try writer.writeAll("fs:\n"); 302 | try dumpDir(fs_root, 0); 303 | try writer.writeAll("objects:\n"); 304 | try dumpDir(object_root, 0); 305 | try writer.writeAll("registry:\n"); 306 | try dumpDir(registry_root, 0); 307 | } 308 | -------------------------------------------------------------------------------- /src/common/PE.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const log = @import("log.zig").scoped(.PE); 4 | 5 | const IMAGE_DIRECTORY_ENTRY_EXPORT = 0; // Export directory 6 | const IMAGE_DIRECTORY_ENTRY_IMPORT = 1; // Import directory 7 | const IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; // Resource directory 8 | const IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3; // Exception directory 9 | const IMAGE_DIRECTORY_ENTRY_SECURITY = 4; // Security directory 10 | const IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; // Base relocation table 11 | const IMAGE_DIRECTORY_ENTRY_DEBUG = 6; // Debug directory 12 | const IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7; // Architecture-specific data 13 | const IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; // The relative virtual address of global pointer 14 | const IMAGE_DIRECTORY_ENTRY_TLS = 9; // Thread local storage directory 15 | const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10; // Load configuration directory 16 | const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11; // Bound import directory 17 | const IMAGE_DIRECTORY_ENTRY_IAT = 12; // Import address table 18 | const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; // Delay import table 19 | const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14; // COM descriptor table 20 | 21 | pub fn load(file: std.fs.File, comptime ResolveContext: type) !usize { 22 | var resolve_context = ResolveContext{}; 23 | 24 | const file_size = try file.getEndPos(); 25 | const file_data = try file.readToEndAllocOptions(std.heap.page_allocator, file_size, file_size, 1, null); 26 | var coff_file = std.coff.Coff{.allocator = undefined}; 27 | try coff_file.parse(file_data); 28 | 29 | var min_addr: usize = std.math.maxInt(usize); 30 | var max_addr: usize = std.math.minInt(usize); 31 | 32 | for (coff_file.getSectionHeaders()) |header| { 33 | if (header.virtual_address < min_addr) { 34 | min_addr = header.virtual_address; 35 | } 36 | 37 | const top_addr = header.virtual_address + header.virtual_size; 38 | 39 | if (max_addr < top_addr) { 40 | max_addr = top_addr; 41 | } 42 | 43 | if (header.number_of_relocations != 0) { 44 | @panic("Section header relocations!"); 45 | } 46 | log("Name: '{s}', vaddr = 0x{X}, size = 0x{}", .{ header.name[0..std.mem.indexOfScalar(u8, &header.name, 0).?], header.virtual_address, header.virtual_size }); 47 | } 48 | 49 | const virt_size = ((max_addr - min_addr) + 0xFFF) & ~@as(usize, 0xFFF); 50 | const vmem = try std.os.mmap( 51 | @intToPtr([*]align(4096) u8, min_addr + coff_file.getImageBase()), 52 | virt_size, 53 | std.os.PROT.NONE, 54 | std.os.MAP.ANONYMOUS | std.os.MAP.PRIVATE, 55 | 0, 56 | 0, 57 | ); 58 | errdefer std.os.munmap(vmem); 59 | 60 | const load_delta = @ptrToInt(vmem.ptr) -% (min_addr + coff_file.getImageBase()); 61 | log("Allocated executable space at 0x{X} (delta 0x{X})", .{ @ptrToInt(vmem.ptr), load_delta }); 62 | 63 | for (coff_file.getSectionHeaders()) |header| { 64 | const section_mem = blk: { 65 | var result = vmem[header.virtual_address - min_addr ..][0..header.virtual_size]; 66 | result.len += 0xFFF; 67 | result.len &= ~@as(usize, 0xFFF); 68 | break :blk @alignCast(4096, result); 69 | }; 70 | 71 | try std.os.mprotect(section_mem, std.os.PROT.READ | std.os.PROT.WRITE); 72 | 73 | //if(header.characteristics & 0x00000040 != 0) { // Section contains initialized data 74 | const read = try file.preadAll( 75 | section_mem[0..header.size_of_raw_data], 76 | header.pointer_to_raw_data, 77 | ); 78 | if (read != header.size_of_raw_data) { 79 | log("Read 0x{X} but expected to read 0x{X}", .{ read, header.size_of_raw_data }); 80 | return error.EndOfFile; 81 | } 82 | //} 83 | //if(header.characteristics & 0x00000080 != 0) { // Section contains uninitialized data 84 | std.mem.set(u8, section_mem[header.size_of_raw_data..], 0); 85 | //} 86 | } 87 | 88 | log("File loaded", .{}); 89 | 90 | if (@ptrToInt(vmem.ptr) != min_addr) { 91 | log("File was loaded at an offset, doing relocations", .{}); 92 | 93 | const relocs_entry = coff_file.getDataDirectories()[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 94 | var reloc_block_bytes = vmem[relocs_entry.virtual_address - min_addr ..][0..relocs_entry.size]; 95 | 96 | while (reloc_block_bytes.len >= 8) { 97 | const current_block_base_addr = @as(usize, std.mem.readIntNative(u32, reloc_block_bytes[0..4])); 98 | const num_block_bytes = std.mem.readIntNative(u32, reloc_block_bytes[4..8]); 99 | 100 | for (std.mem.bytesAsSlice(u16, reloc_block_bytes[8..num_block_bytes])) |reloc| { 101 | const block_offset = @as(usize, @truncate(u12, reloc)); 102 | const reloc_type = @truncate(u4, reloc >> 12); 103 | 104 | const reloc_addr = current_block_base_addr + block_offset; 105 | const reloc_bytes = vmem[reloc_addr - min_addr ..]; 106 | 107 | //log.debug("Relocation of type {d} at addr 0x{X} (offset 0x{X})", .{reloc_type, reloc_addr, block_offset}); 108 | 109 | switch (reloc_type) { 110 | // IMAGE_REL_BASED_ABSOLUTE 111 | // The base relocation is skipped. This type can be used to pad a block. 112 | 0 => {}, 113 | 114 | // IMAGE_REL_BASED_HIGH 115 | // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. 116 | // The 16-bit field represents the high value of a 32-bit word. 117 | // 1 => std.mem.bytesAsSlice(u16, reloc_bytes)[0] +%= @truncate(u16, load_delta >> 16), 118 | 119 | // IMAGE_REL_BASED_LOW 120 | // The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. 121 | // The 16-bit field represents the low half of a 32-bit word. 122 | // 2 => std.mem.bytesAsSlice(u16, reloc_bytes)[0] +%= @truncate(u16, load_delta), 123 | 124 | // IMAGE_REL_BASED_HIGHLOW 125 | // The base relocation applies all 32 bits of the difference to the 32-bit field at offset. 126 | // 3 => std.mem.bytesAsSlice(u32, reloc_bytes)[0] +%= @intCast(u32, load_delta), 127 | 128 | // IMAGE_REL_BASED_HIGHADJ 129 | // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. 130 | // The 16-bit field represents the high value of a 32-bit word. The low 16 bits of the 32-bit 131 | // value are stored in the 16-bit word that follows this base relocation. 132 | // This means that this base relocation occupies two slots. 133 | // 4 => , 134 | 135 | // IMAGE_REL_BASED_MIPS_JMPADDR 136 | // The relocation interpretation is dependent on the machine type. 137 | // When the machine type is MIPS, the base relocation applies to a MIPS jump instruction. 138 | // 5 => , 139 | 140 | // IMAGE_REL_BASED_ARM_MOV32 141 | // This relocation is meaningful only when the machine type is ARM or Thumb. 142 | // The base relocation applies the 32-bit address of a symbol across a consecutive 143 | // MOVW/MOVT instruction pair. 144 | // 5 => , 145 | 146 | // IMAGE_REL_BASED_RISCV_HIGH20 147 | // This relocation is only meaningful when the machine type is RISC-V. 148 | // The base relocation applies to the high 20 bits of a 32-bit absolute address. 149 | // 5 => , 150 | 151 | // Reserved, must be zero. 152 | // 6 => , 153 | 154 | // IMAGE_REL_BASED_THUMB_MOV32 155 | // This relocation is meaningful only when the machine type is Thumb. 156 | // The base relocation applies the 32-bit address of a symbol to a consecutive MOVW/MOVT 157 | // instruction pair. 158 | // 7 => , 159 | 160 | // IMAGE_REL_BASED_RISCV_LOW12I 161 | // This relocation is only meaningful when the machine type is RISC-V. 162 | // The base relocation applies to the low 12 bits of a 32-bit absolute address formed 163 | // in RISC-V I-type instruction format. 164 | // 7 => , 165 | 166 | // IMAGE_REL_BASED_RISCV_LOW12S 167 | // This relocation is only meaningful when the machine type is RISC-V. 168 | // The base relocation applies to the low 12 bits of a 32-bit absolute address formed 169 | // in RISC-V S-type instruction format. 170 | // 8 => , 171 | 172 | // IMAGE_REL_BASED_LOONGARCH32_MARK_LA 173 | // This relocation is only meaningful when the machine type is LoongArch 32-bit. 174 | // The base relocation applies to a 32-bit absolute address formed in two consecutive instructions. 175 | // 8 => , 176 | 177 | // IMAGE_REL_BASED_LOONGARCH64_MARK_LA 178 | // This relocation is only meaningful when the machine type is LoongArch 64-bit. 179 | // The base relocation applies to a 64-bit absolute address formed in four consecutive instructions. 180 | // 8 => , 181 | 182 | // IMAGE_REL_BASED_MIPS_JMPADDR16 183 | // The relocation is only meaningful when the machine type is MIPS. 184 | // The base relocation applies to a MIPS16 jump instruction. 185 | // 9 => , 186 | 187 | // IMAGE_REL_BASED_DIR64 188 | // The base relocation applies the difference to the 64-bit field at offset. 189 | 10 => std.mem.bytesAsSlice(u64, reloc_bytes)[0] +%= load_delta, 190 | 191 | else => { 192 | log("Relocation of type {d} at addr 0x{X} (offset 0x{X})", .{ reloc_type, reloc_addr, block_offset }); 193 | @panic("Unknown relocation!"); 194 | }, 195 | } 196 | } 197 | 198 | reloc_block_bytes = reloc_block_bytes[num_block_bytes..]; 199 | } 200 | 201 | log("Relocations done", .{}); 202 | } 203 | 204 | // Imports? 205 | blk: { 206 | const imports_entry = coff_file.getDataDirectories()[IMAGE_DIRECTORY_ENTRY_IMPORT]; 207 | if (imports_entry.size == 0) 208 | break :blk; 209 | const import_descriptor_bytes = vmem[imports_entry.virtual_address - min_addr ..][0..imports_entry.size]; 210 | for (std.mem.bytesAsSlice(extern struct { 211 | import_name_table: u32, 212 | time_stamp: u32, 213 | forwarder_chain: u32, 214 | dll_name_addr: u32, 215 | import_addr_table_addr: u32, 216 | }, import_descriptor_bytes)) |desc| { 217 | if (desc.dll_name_addr == 0 or desc.import_addr_table_addr == 0) { 218 | break; 219 | } 220 | const dll_name = std.mem.span(@ptrCast([*:0]u8, &vmem[desc.dll_name_addr - min_addr])); 221 | const import_name_table = std.mem.span(@ptrCast([*:0]u64, @alignCast(8, &vmem[desc.import_name_table - min_addr]))); 222 | const import_addr_table = @ptrCast([*]u64, @alignCast(8, &vmem[desc.import_addr_table_addr - min_addr])); 223 | for (import_name_table) |import_name_base, i| { 224 | const import_name = std.mem.span(@ptrCast([*:0]u8, &vmem[import_name_base + 2 - min_addr])); 225 | const sym = resolve_context.resolve(dll_name, import_name) orelse { 226 | log("Unresolved import '{s}' from '{s}'", .{import_name, dll_name}); 227 | return error.UnresolvedImport; 228 | }; 229 | import_addr_table[i] = @ptrToInt(sym); 230 | } 231 | } 232 | log("Imports done", .{}); 233 | } 234 | 235 | // Exports? 236 | blk: { 237 | const exports_entry = coff_file.getDataDirectories()[IMAGE_DIRECTORY_ENTRY_EXPORT]; 238 | if (exports_entry.size == 0) 239 | break :blk; 240 | const export_descriptor_bytes = vmem[exports_entry.virtual_address - min_addr ..][0..exports_entry.size]; 241 | 242 | const num_functions = std.mem.readIntNative(u32, export_descriptor_bytes[0x14..0x18]); 243 | const num_names = std.mem.readIntNative(u32, export_descriptor_bytes[0x18..0x1C]); 244 | const addrs_base = std.mem.readIntNative(u32, export_descriptor_bytes[0x1C..0x20]); 245 | const addrs = std.mem.bytesAsSlice(u32, vmem[addrs_base - min_addr..][0..num_functions*4]); 246 | const names_base = std.mem.readIntNative(u32, export_descriptor_bytes[0x20..0x24]); 247 | const names = std.mem.bytesAsSlice(u32, vmem[names_base - min_addr..][0..num_names*4]); 248 | const ordinals_base = std.mem.readIntNative(u32, export_descriptor_bytes[0x24..0x28]); 249 | const ordinals = std.mem.bytesAsSlice(u16, vmem[ordinals_base - min_addr..][0..num_names*2]); 250 | 251 | // Literally who thought this was a good structure???? 252 | for(names) |name_rva, name_idx| { 253 | const ordinal = ordinals[name_idx]; 254 | const name = std.mem.span(@ptrCast([*:0]u8, &vmem[name_rva - min_addr])); 255 | const addr = @ptrCast(*anyopaque, &vmem[addrs[ordinal] - min_addr]); 256 | resolve_context.provide("ntdll.dll", name, addr); 257 | } 258 | } 259 | 260 | for (coff_file.getSectionHeaders()) |header| { 261 | const section_mem = blk: { 262 | var result = vmem[header.virtual_address - min_addr ..][0..header.virtual_size]; 263 | result.len += 0xFFF; 264 | result.len &= ~@as(usize, 0xFFF); 265 | break :blk @alignCast(4096, result); 266 | }; 267 | 268 | if (header.flags.MEM_DISCARDABLE != 0) { // Section can be discarded after loading 269 | log("Unmapping section at 0x{X} with size 0x{X}", .{ @ptrToInt(section_mem.ptr), section_mem.len }); 270 | std.os.munmap(section_mem); 271 | continue; 272 | } 273 | 274 | const prot_flags = blk: { 275 | var result: u32 = std.os.PROT.READ; 276 | if (header.flags.MEM_EXECUTE != 0) 277 | result |= std.os.PROT.EXEC; 278 | if (header.flags.MEM_WRITE != 0) 279 | result |= std.os.PROT.WRITE; 280 | break :blk result; 281 | }; 282 | 283 | log("Keeping section at 0x{X} with size 0x{X}, new prot flags: 0x{X}", .{ @ptrToInt(section_mem.ptr), section_mem.len, prot_flags }); 284 | 285 | try std.os.mprotect( 286 | section_mem, 287 | prot_flags, 288 | ); 289 | } 290 | log("Section permissions set", .{}); 291 | 292 | return coff_file.getOptionalHeader().address_of_entry_point +% load_delta +% coff_file.getImageBase(); 293 | } 294 | -------------------------------------------------------------------------------- /src/common/ntdll.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const rt = @import("rt.zig"); 3 | const guids = @import("guids.zig"); 4 | const vfs = @import("vfs.zig"); 5 | const tp = @import("tp.zig"); 6 | 7 | const log = @import("log.zig").scoped(.ntdll); 8 | 9 | var rtl_global_heap = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = std.heap.page_allocator }; 10 | 11 | pub fn RtlAllocateHeap(heap_handle: ?*anyopaque, flags: rt.ULONG, size: rt.SIZE_T) callconv(.Win64) ?*anyopaque { 12 | log("RtlAllocateHeap(handle=0x{X}, flags=0x{X}, size=0x{X})", .{ @ptrToInt(heap_handle), flags, size }); 13 | if (heap_handle) |_| { 14 | @panic("RtlAllocateHeap with handle"); 15 | } 16 | 17 | const retval = (rtl_global_heap.allocator().alloc(u8, size) catch |err| { 18 | log("RtlAllocateHeap failed (error.{s})!", .{@errorName(err)}); 19 | return null; 20 | }).ptr; 21 | 22 | log("RtlAllocateHeap -> 0x{X}", .{@ptrToInt(retval)}); 23 | return retval; 24 | } 25 | 26 | pub fn RtlFreeHeap(heap_handle: ?*anyopaque, flags: rt.ULONG, base_addr: ?[*]u8) callconv(.Win64) rt.LOGICAL { 27 | // TODO: Don't just leak memory here 28 | log("RtlFreeHeap(handle=0x{X}, flags = 0x{X}, ptr=0x{X})", .{ @ptrToInt(heap_handle), flags, @ptrToInt(base_addr) }); 29 | return rt.TRUE; 30 | } 31 | 32 | pub fn NtSetInformationProcess( 33 | process_handle: rt.HANDLE, 34 | process_information_class: ProcessInfoClass, 35 | process_information: rt.PVOID, 36 | process_information_length: rt.ULONG, 37 | ) callconv(.Win64) NTSTATUS { 38 | log("NtSetInformationProcess(handle=0x{X}, class={s}, info=0x{x}, length={d})", .{ process_handle, @tagName(process_information_class), @ptrToInt(process_information), process_information_length }); 39 | return .SUCCESS; 40 | } 41 | 42 | pub fn RtlSetHeapInformation( 43 | heap_handle: rt.PVOID, 44 | heap_information_class: HeapInformationClass, 45 | heap_information: rt.PVOID, 46 | heap_information_length: rt.SIZE_T, 47 | ) callconv(.Win64) NTSTATUS { 48 | log("RtlSetHeapInformation(handle=0x{X}, class={s}, info=0x{x}, length={d})", .{ @ptrToInt(heap_handle), @tagName(heap_information_class), @ptrToInt(heap_information), heap_information_length }); 49 | return .SUCCESS; 50 | } 51 | 52 | const REGHANDLE = u64; 53 | 54 | pub fn EtwEventRegister( 55 | provider_id: rt.LPCGUID, 56 | callback: rt.EnableCallback, 57 | callback_context: rt.PVOID, 58 | result_handle: ?*REGHANDLE, 59 | ) callconv(.Win64) Error { 60 | log("EtwEventRegister(guid={any}, callback=0x{X}, context=0x{x}, result_out=0x{X})", .{ provider_id, @ptrToInt(callback), @ptrToInt(callback_context), @ptrToInt(result_handle) }); 61 | return .SUCCESS; 62 | } 63 | 64 | const WmidPRequestCode = enum(u32) { 65 | GetAllData = 0, 66 | GetSingleInstance = 1, 67 | SetSingleInstance = 2, 68 | SetSingleItem = 3, 69 | EnableEvents = 4, 70 | DisableEvents = 5, 71 | EnableCollection = 6, 72 | DisableCollection = 7, 73 | RegInfo = 8, 74 | ExecuteMethod = 9, 75 | }; 76 | 77 | const WMidPRequest = *const fn ( 78 | request_code: WmidPRequestCode, 79 | request_context: rt.PVOID, 80 | buffer_size: ?*rt.ULONG, 81 | buffer: rt.PVOID, 82 | ) callconv(.Win64) rt.ULONG; 83 | 84 | const TraceGuidRegistration = extern struct { 85 | guid: rt.LPCGUID, 86 | handle: rt.HANDLE, 87 | }; 88 | 89 | const TraceHandle = rt.HANDLE; 90 | 91 | pub fn EtwRegisterTraceGuidsW( 92 | request_address: WMidPRequest, 93 | request_context: rt.PVOID, 94 | control_guid: rt.LPCGUID, 95 | guid_count: rt.ULONG, 96 | trace_guid_registration: ?*TraceGuidRegistration, 97 | m_of_image_path: rt.LPCWSTR, 98 | m_of_resource_name: rt.LPCWSTR, 99 | registration_handle: ?*TraceHandle, 100 | ) callconv(.Win64) Error { 101 | log("EtwRegisterTraceGuidsW(req_addr=0x{X}, req_cont=0x{X}, cguid={any}, guidcnt={}, tguid={any}, imgp={}, mrname={}, rhandle=0x{X})", .{ 102 | @ptrToInt(request_address), 103 | @ptrToInt(request_context), 104 | control_guid, 105 | guid_count, 106 | trace_guid_registration, 107 | rt.fmt(m_of_image_path), 108 | rt.fmt(m_of_resource_name), 109 | @ptrToInt(registration_handle), 110 | }); 111 | return .SUCCESS; 112 | } 113 | 114 | pub fn TpAllocPool( 115 | opt_result: ?**tp.ThreadPool, 116 | reserved: rt.PVOID, 117 | ) callconv(.Win64) NTSTATUS { 118 | const result = opt_result orelse return .INVALID_PARAMETER; 119 | result.* = tp.allocPool() catch return .NO_MEMORY; 120 | log("TpAllocPool(0x{X}) -> 0x{X}", .{@ptrToInt(result), @ptrToInt(result.*)}); 121 | _ = reserved; 122 | return .SUCCESS; 123 | } 124 | 125 | pub fn TpAllocWork( 126 | out_opt: ?**tp.TPWork, 127 | work_opt: ?tp.Work, 128 | context: tp.Context, 129 | env: tp.Environment, 130 | ) callconv(.Win64) NTSTATUS { 131 | log("TpAllocWork(0x{X}, 0x{X})", .{@ptrToInt(out_opt), @ptrToInt(work_opt)}); 132 | const out = out_opt orelse return .INVALID_PARAMETER; 133 | const work = work_opt orelse return .INVALID_PARAMETER; 134 | out.* = tp.allocWork(work, context, env) catch return .NO_MEMORY; 135 | return .SUCCESS; 136 | } 137 | 138 | pub fn TpPostWork( 139 | work_opt: ?*tp.TPWork, 140 | ) callconv(.Win64) NTSTATUS { 141 | const work = work_opt orelse return .INVALID_PARAMETER; 142 | const env = work.env; 143 | const pool = env.pool.?; 144 | pool.addWork(work) catch return .NO_MEMORY; 145 | return .SUCCESS; 146 | } 147 | 148 | pub fn TpWaitForWork( 149 | work_opt: ?*tp.TPWork, 150 | ) callconv(.Win64) NTSTATUS { 151 | log("TpWaitForWork(0x{X})", .{@ptrToInt(work_opt)}); 152 | (work_opt orelse return .INVALID_PARAMETER).finish_sema.wait(); 153 | return .SUCCESS; 154 | } 155 | 156 | pub fn TpReleaseWork( 157 | work_opt: ?*tp.TPWork, 158 | ) callconv(.Win64) NTSTATUS { 159 | log("TpReleaseWork(0x{X})", .{@ptrToInt(work_opt)}); 160 | if(false) tp.releaseWork(work_opt orelse return .INVALID_PARAMETER); 161 | return .SUCCESS; 162 | } 163 | 164 | pub fn TpSetPoolMinThreads( 165 | pool: ?*tp.ThreadPool, 166 | min_threads: rt.ULONG, 167 | ) callconv(.Win64) NTSTATUS { 168 | const p = pool orelse return .INVALID_PARAMETER; 169 | const num_threads = std.math.max(min_threads, 1); 170 | log("TpSetPoolMinThreads(0x{X}, {d} (treated as {d}))", .{ 171 | @ptrToInt(p), 172 | min_threads, 173 | num_threads, 174 | }); 175 | p.setNumThreads(num_threads) catch return .NO_MEMORY; 176 | return .SUCCESS; 177 | } 178 | 179 | const JobObjectInfoClass = enum(u32) { 180 | BasicAccountingInformation = 1, 181 | BasicLimitInformation = 2, 182 | BasicProcessIdList = 3, 183 | BasicUIRestrictions = 4, 184 | SecurityLimitInformation = 5, 185 | EndOfJobTimeInformation = 6, 186 | AssociateCompletionPortInformation = 7, 187 | BasicAndIoAccountingInformation = 8, 188 | ExtendedLimitInformation = 9, 189 | JobSetInformation = 10, 190 | GroupInformation = 11, 191 | NotificationLimitInformation = 12, 192 | LimitViolationInformation = 13, 193 | GroupInformationEx = 14, 194 | CpuRateControlInformation = 15, 195 | CompletionFilter = 16, 196 | CompletionCounter = 17, 197 | 198 | NetRateControlInformation = 32, 199 | JobObjectNotificationLimitInformation2 = 33, 200 | JobObjectLimitViolationInformation2 = 34, 201 | JobObjectCreateSilo = 35, 202 | JobObjectSiloBasicInformation = 36, 203 | 204 | Unk_39 = 39, 205 | }; 206 | 207 | pub fn NtQueryInformationJobObject( 208 | handle: rt.HANDLE, 209 | class: JobObjectInfoClass, 210 | len: rt.ULONG, 211 | ret_len: ?*rt.ULONG, 212 | ) callconv(.Win64) NTSTATUS { 213 | log("NtQueryInformationJobObject(handle=0x{X}, class={s}, len=0x{x}, ret_len={any})", .{ handle, @tagName(class), len, ret_len }); 214 | return .SUCCESS; 215 | } 216 | 217 | var rtl_unicode_string_heap = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = std.heap.page_allocator }; 218 | 219 | pub fn RtlInitUnicodeStringEx( 220 | dest: ?*rt.UnicodeString, 221 | src: rt.PCWSTR, 222 | ) callconv(.Win64) NTSTATUS { 223 | log("RtlInitUnicodeStringEx({})", .{rt.fmt(src)}); 224 | const str = src orelse { 225 | var buf = [_]u16{}; 226 | (dest orelse return .INVALID_PARAMETER).* = rt.UnicodeString.initFromBuffer(&buf); 227 | return .SUCCESS; 228 | }; 229 | (dest orelse return .INVALID_PARAMETER).* = 230 | rt.UnicodeString.initFromBuffer(rtl_unicode_string_heap.allocator().dupeZ(u16, std.mem.span(str)) catch return .NO_MEMORY); 231 | return .SUCCESS; 232 | } 233 | 234 | pub fn RtlInitUnicodeString( 235 | dest: ?*rt.UnicodeString, 236 | src: rt.PCWSTR, 237 | ) callconv(.Win64) void { 238 | if (RtlInitUnicodeStringEx(dest, src) != .SUCCESS) { 239 | log("RtlInitUnicodeString: RtlInitUnicodeStringEx failed!", .{}); 240 | } 241 | } 242 | 243 | pub fn RtlGetNtSystemRoot( 244 | ) callconv(.Win64) [*:0]const u16 { 245 | return std.unicode.utf8ToUtf16LeStringLiteral("C:\\"); 246 | } 247 | 248 | pub fn RtlSetThreadIsCritical( 249 | new_value: rt.BOOL, 250 | old_value: ?*rt.BOOL, 251 | check_flag: rt.BOOL, 252 | ) callconv(.Win64) NTSTATUS { 253 | if (old_value) |o| o.* = rt.FALSE; 254 | log("RtlSetThreadIsCritical({},check_flag={})", .{ rt.fmt(new_value), rt.fmt(check_flag) }); 255 | return .SUCCESS; 256 | } 257 | 258 | pub fn RtlCreateTagHeap( 259 | heap_handle: rt.HANDLE, 260 | flags: rt.ULONG, 261 | tag_name: rt.PWSTR, 262 | tag_sub_name: rt.PWSTR, 263 | ) callconv(.Win64) Error { 264 | log("RtlCreateTagHeap(handle=0x{X}, flags=0x{X}, tag_name={}, tag_sub_name={})", .{ heap_handle, flags, rt.fmt(tag_name), rt.fmt(tag_sub_name) }); 265 | return .SUCCESS; 266 | } 267 | 268 | fn giveSystemInfo(ret_ptr: rt.PVOID, ret_max_size: rt.ULONG, ret_out_size: ?*rt.ULONG, comptime T: type) NTSTATUS { 269 | const copy_size = std.math.min(@sizeOf(T), ret_max_size); 270 | if (ret_out_size) |out| 271 | out.* = @intCast(rt.ULONG, @sizeOf(T)); 272 | 273 | if (ret_ptr) |p| { 274 | @memcpy(@ptrCast([*]u8, p), @intToPtr([*]const u8, @ptrToInt(&T{})), copy_size); 275 | } 276 | 277 | if (ret_max_size < @sizeOf(T)) { 278 | return .INFO_LENGTH_MISMATCH; 279 | } else { 280 | return .SUCCESS; 281 | } 282 | } 283 | 284 | var manufacturer_profile_name = std.unicode.utf8ToUtf16LeStringLiteral("Champagne-SYSTEM").*; 285 | 286 | pub fn NtQuerySystemInformation( 287 | class: SystemInformationClass, 288 | ret_ptr: rt.PVOID, 289 | ret_max_size: rt.ULONG, 290 | ret_out_size: ?*rt.ULONG, 291 | ) callconv(.Win64) NTSTATUS { 292 | log("NtQuerySystemInformation(class=0x{X})", .{@enumToInt(class)}); 293 | log("NtQuerySystemInformation(class=0x{X} ('{s}'), max_size=0x{X})", .{ @enumToInt(class), @tagName(class), ret_max_size }); 294 | return switch (class) { 295 | .Basic => giveSystemInfo(ret_ptr, ret_max_size, ret_out_size, extern struct { 296 | reserved: rt.ULONG = 0, 297 | timer_resolution: rt.ULONG = 1_000_000_000, 298 | page_size: rt.ULONG = 0x1000, 299 | number_of_physical_pages: rt.ULONG = 1729, 300 | lowest_physical_page_number: rt.ULONG = 1, 301 | highest_physical_page_number: rt.ULONG = 1729, 302 | allocation_granularity: rt.ULONG = 8, 303 | minimum_user_mode_address: usize = 0x10000, 304 | maximum_user_mode_address: usize = 0x7ff80000, 305 | active_processors_affinity_mask: usize = 1 << 0, 306 | number_of_processors: usize = 1, 307 | }), 308 | .Processor => giveSystemInfo(ret_ptr, ret_max_size, ret_out_size, extern struct { 309 | architecture: enum(u16) { 310 | intel = 0, 311 | i286 = 2, 312 | i386 = 3, 313 | i486 = 4, 314 | i586_pentium = 5, 315 | 316 | amd = 9, 317 | } = .i586_pentium, 318 | 319 | level: u16 = 0xD0, 320 | revision: u16 = 5, 321 | maximum_processors: u16 = 1, 322 | feature_bits: u32 = 0, 323 | }), 324 | .NumaProcessorMap => giveSystemInfo(ret_ptr, ret_max_size, ret_out_size, extern struct { 325 | const MAXIMUM_NODE_COUNT = 0x40; 326 | 327 | const GroupAffinity = extern struct { 328 | mask: rt.KAFFINITY = 1, 329 | group: rt.WORD = 0, 330 | reserved: [3]rt.WORD = undefined, 331 | }; 332 | 333 | highest_node_number: rt.ULONG = 1, 334 | reserved: rt.ULONG = undefined, 335 | aff: [MAXIMUM_NODE_COUNT]GroupAffinity = [1]GroupAffinity{.{}} ++ ([1]GroupAffinity{undefined} ** (MAXIMUM_NODE_COUNT - 1)), 336 | 337 | comptime { 338 | if (@sizeOf(@This()) != 0x408) @compileError("wtf"); 339 | } 340 | }), 341 | .FirmwareTableInformation => giveSystemInfo(ret_ptr, ret_max_size, ret_out_size, extern struct { 342 | provider: [4]u8 = "CHMP".*, // Champagne 343 | action: u32 = 0, 344 | table_id: [4]u8 = "XSDT".*, 345 | table_buffer_len: rt.ULONG = 4, 346 | table_buffer: [4]u8 = "XSDT".*, 347 | }), 348 | .SystemManufacturingInformation => giveSystemInfo(ret_ptr, ret_max_size, ret_out_size, extern struct { 349 | options: rt.ULONG = 0, 350 | profile_name: rt.UnicodeString = rt.UnicodeString.initFromBuffer(&manufacturer_profile_name), 351 | }), 352 | }; 353 | } 354 | 355 | const ConditionVariable = std.Thread.Condition; 356 | const Mutex = std.Thread.Mutex; 357 | 358 | comptime { 359 | std.debug.assert(@sizeOf(Mutex) <= 8); 360 | std.debug.assert(@sizeOf(ConditionVariable) <= 8); 361 | } 362 | 363 | pub fn RtlInitializeSRWLock( 364 | lock: ?*Mutex, 365 | ) callconv(.Win64) void { 366 | //log("RtlInitializeSRWLock(0x{X})", .{@ptrToInt(lock)}); 367 | lock.?.* = .{}; 368 | } 369 | 370 | pub fn RtlAcquireSRWLockExclusive( 371 | lock: ?*Mutex, 372 | ) callconv(.Win64) void { 373 | log("RtlAcquireSRWLockExclusive(0x{X})", .{@ptrToInt(lock)}); 374 | lock.?.lock(); 375 | } 376 | 377 | pub fn RtlReleaseSRWLockExclusive( 378 | lock: ?*Mutex, 379 | ) callconv(.Win64) void { 380 | log("RtlReleaseSRWLockExclusive(0x{X})", .{@ptrToInt(lock)}); 381 | lock.?.unlock(); 382 | } 383 | 384 | pub fn RtlAcquireSRWLockShared( 385 | lock: ?*Mutex, 386 | ) callconv(.Win64) void { 387 | log("RtlAcquireSRWLockShared(0x{X})", .{@ptrToInt(lock)}); 388 | lock.?.lock(); 389 | } 390 | 391 | pub fn RtlReleaseSRWLockShared( 392 | lock: ?*Mutex, 393 | ) callconv(.Win64) void { 394 | log("RtlReleaseSRWLockShared(0x{X})", .{@ptrToInt(lock)}); 395 | lock.?.unlock(); 396 | } 397 | 398 | pub fn RtlInitializeConditionVariable( 399 | out_cvar: ?*ConditionVariable, 400 | ) callconv(.Win64) void { 401 | log("RtlInitializeConditionVariable(0x{X})", .{@ptrToInt(out_cvar)}); 402 | out_cvar.?.* = .{}; 403 | } 404 | 405 | pub fn RtlSleepConditionVariableSRW( 406 | condvar: ?*ConditionVariable, 407 | lock: ?*Mutex, 408 | timeout: rt.LARGEINT, 409 | flags: rt.ULONG, 410 | ) callconv(.Win64) NTSTATUS { 411 | log("RtlSleepConditionVariableSRW({d})", .{timeout}); 412 | _ = flags; 413 | if(timeout == 0) { 414 | condvar.?.timedWait(lock.?, ~@as(usize, 0)) catch return .INVALID_PARAMETER; 415 | } else { 416 | condvar.?.timedWait(lock.?, @intCast(usize, timeout)) catch return .INVALID_PARAMETER; 417 | } 418 | return .SUCCESS; 419 | } 420 | 421 | pub fn RtlWakeAllConditionVariable( 422 | condvar: ?*ConditionVariable, 423 | ) callconv(.Win64) NTSTATUS { 424 | (condvar orelse return .INVALID_PARAMETER).broadcast(); 425 | return .SUCCESS; 426 | } 427 | 428 | pub fn RtlAdjustPrivilege( 429 | priv: Privilege, 430 | enable: rt.BOOL, 431 | current_thread: rt.BOOL, 432 | enabled: ?*rt.BOOL, 433 | ) callconv(.Win64) NTSTATUS { 434 | log("RtlAdjustPrivilege(priv={s}, enable=0x{X})", .{ @tagName(priv), enable }); 435 | _ = current_thread; 436 | if (enabled) |e| e.* = rt.TRUE; 437 | switch (priv) { 438 | .Shutdown => return .SUCCESS, 439 | else => return .INVALID_PARAMETER, 440 | } 441 | } 442 | 443 | pub fn NtRaiseHardError( 444 | error_status: NTSTATUS, 445 | num_params: rt.ULONG, 446 | unicode_string_parameter_mask: ?*rt.UnicodeString, 447 | params: rt.PVOID, 448 | response_option: HardErrorResponseOption, 449 | response: ?*HardErrorResponse, 450 | ) callconv(.Win64) NTSTATUS { 451 | _ = params; 452 | _ = unicode_string_parameter_mask; 453 | log("NtRaiseHardError(status=0x{X}, ropt=0x{X})", .{ @enumToInt(error_status), @enumToInt(response_option) }); 454 | log("NtRaiseHardError(status={s}, params={d}, ropt={s})", .{ @tagName(error_status), num_params, @tagName(response_option) }); 455 | if (response) |r| r.* = .NotHandled; 456 | return .SUCCESS; 457 | } 458 | 459 | pub fn NtTerminateProcess( 460 | process_handle: rt.HANDLE, 461 | exit_status: NTSTATUS, 462 | ) callconv(.Win64) NTSTATUS { 463 | log("NtTerminateProcess(handle=0x{X}, status='{s}')", .{ process_handle, @tagName(exit_status) }); 464 | std.os.exit(0); 465 | } 466 | 467 | pub fn RtlNormalizeProcessParams( 468 | ) callconv(.Win64) NTSTATUS { 469 | log("RtlNormalizeProcessParams: Nothing to do under champagne", .{}); 470 | return .SUCCESS; 471 | } 472 | 473 | pub fn NtAlpcCreatePort( 474 | opt_port_handle: ?*rt.HANDLE, 475 | opt_object_attributes: ?*ObjectAttributes, 476 | opt_port_attributes: rt.PVOID, // ?*PortAttributes, 477 | ) callconv(.Win64) NTSTATUS { 478 | log("STUB: NtAlpcCreatePort({any})", .{opt_object_attributes}); 479 | _ = opt_port_attributes; 480 | const port_handle = opt_port_handle orelse return .INVALID_PARAMETER; 481 | _ = port_handle; 482 | return .SUCCESS; 483 | } 484 | 485 | pub fn NtOpenDirectoryObject( 486 | opt_dir_handle: ?*rt.HANDLE, 487 | desired_access: AccessMask, 488 | opt_object_attributes: ?*ObjectAttributes, 489 | ) callconv(.Win64) NTSTATUS { 490 | log("NtOpenDirectoryObject({any})", .{opt_object_attributes}); 491 | const n = resovleAttrs(opt_object_attributes, true) orelse return .INVALID_PARAMETER; 492 | defer vfs.close(n); 493 | if(opt_dir_handle) |handle_out| { 494 | handle_out.* = vfs.handle(n); 495 | } 496 | _ = desired_access; 497 | return .SUCCESS; 498 | } 499 | 500 | pub fn NtCreateMutant( 501 | opt_handle: ?*rt.HANDLE, 502 | desired_access: AccessMask, 503 | opt_object_attributes: ?*ObjectAttributes, 504 | initial_owner: rt.BOOL, 505 | ) callconv(.Win64) NTSTATUS { 506 | const n = resovleAttrs(opt_object_attributes, true) orelse return .INVALID_PARAMETER; 507 | defer vfs.close(n); 508 | const mutex = n.get(.mutex) orelse return .INVALID_PARAMETER; 509 | if(initial_owner != 0) { 510 | mutex.lock(); 511 | } 512 | if(opt_handle) |out| { 513 | out.* = vfs.handle(n); 514 | } 515 | _ = desired_access; 516 | return .SUCCESS; 517 | } 518 | 519 | pub fn NtOpenKey( 520 | opt_handle: ?*rt.HANDLE, 521 | desired_access: AccessMask, 522 | opt_object_attributes: ?*ObjectAttributes, 523 | ) callconv(.Win64) NTSTATUS { 524 | log("STUB: NtOpenKey({any})", .{opt_object_attributes}); 525 | const n = resovleAttrs(opt_object_attributes, true) orelse return .INVALID_PARAMETER; 526 | defer vfs.close(n); 527 | _ = n.get(.dir); 528 | if(opt_handle) |out| { 529 | out.* = vfs.handle(n); 530 | } 531 | _ = desired_access; 532 | return .SUCCESS; 533 | } 534 | 535 | pub fn NtCreateKey( 536 | opt_handle: ?*rt.HANDLE, 537 | desired_access: AccessMask, 538 | opt_object_attributes: ?*ObjectAttributes, 539 | title_index: rt.ULONG, 540 | class: ?*rt.UnicodeString, 541 | create_options: rt.ULONG, 542 | disposition: ?*rt.ULONG, 543 | ) callconv(.Win64) NTSTATUS { 544 | log("STUB: NtCreateKey({any})", .{opt_object_attributes}); 545 | const n = resovleAttrs(opt_object_attributes, true) orelse return .INVALID_PARAMETER; 546 | defer vfs.close(n); 547 | _ = n.get(.dir); 548 | if(opt_handle) |out| { 549 | out.* = vfs.handle(n); 550 | } 551 | _ = desired_access; 552 | _ = title_index; 553 | _ = class; 554 | _ = create_options; 555 | _ = disposition; 556 | return .SUCCESS; 557 | } 558 | 559 | pub fn NtCreateDirectoryObject( 560 | opt_handle: ?*rt.HANDLE, 561 | desired_access: AccessMask, 562 | opt_object_attributes: ?*ObjectAttributes, 563 | ) callconv(.Win64) NTSTATUS { 564 | log("STUB: NtCreateDirectoryObject({any})", .{opt_object_attributes}); 565 | const n = resovleAttrs(opt_object_attributes, true) orelse return .INVALID_PARAMETER; 566 | defer vfs.close(n); 567 | _ = n.get(.dir); 568 | if(opt_handle) |out| { 569 | out.* = vfs.handle(n); 570 | } 571 | _ = desired_access; 572 | return .SUCCESS; 573 | } 574 | 575 | pub fn NtCreateFile( 576 | opt_handle: ?*rt.HANDLE, 577 | desired_access: AccessMask, 578 | opt_object_attributes: ?*ObjectAttributes, 579 | io_status_block: rt.PVOID, 580 | allocation_size: ?*rt.LARGEINT, 581 | file_attrs: rt.ULONG, 582 | share_access: rt.ULONG, 583 | create_disposition: rt.ULONG, 584 | create_options: rt.ULONG, 585 | ea_buffer: rt.PVOID, 586 | ea_length: rt.ULONG, 587 | ) callconv(.Win64) NTSTATUS { 588 | _ = opt_handle; 589 | _ = desired_access; 590 | log("STUB: NtCreateFile({any})", .{opt_object_attributes}); 591 | _ = io_status_block; 592 | _ = allocation_size; 593 | _ = file_attrs; 594 | _ = share_access; 595 | _ = create_disposition; 596 | _ = create_options; 597 | _ = ea_buffer; 598 | _ = ea_length; 599 | return .SUCCESS; 600 | } 601 | 602 | pub fn NtOpenFile( 603 | opt_handle: ?*rt.HANDLE, 604 | desired_access: AccessMask, 605 | opt_object_attributes: ?*ObjectAttributes, 606 | io_status_block: rt.PVOID, 607 | share_access: rt.ULONG, 608 | open_options: rt.ULONG, 609 | ) callconv(.Win64) NTSTATUS { 610 | _ = opt_handle; 611 | _ = desired_access; 612 | log("STUB: NtOpenFile({any})", .{opt_object_attributes}); 613 | _ = io_status_block; 614 | _ = share_access; 615 | _ = open_options; 616 | return .SUCCESS; 617 | } 618 | 619 | pub fn NtCreateSection( 620 | opt_handle: ?*rt.HANDLE, 621 | desired_access: AccessMask, 622 | opt_object_attributes: ?*ObjectAttributes, 623 | max_size: ?*rt.LARGEINT, 624 | section_page_protection: rt.ULONG, 625 | allocation_attributes: rt.ULONG, 626 | file_handle: rt.ULONG, 627 | ) callconv(.Win64) NTSTATUS { 628 | const size = @intCast(usize, (max_size orelse return .INVALID_PARAMETER).*); 629 | _ = desired_access; 630 | _ = section_page_protection; 631 | _ = allocation_attributes; 632 | log("STUB: NtCreateSection({any}, 0x{X}, 0x{X})", .{opt_object_attributes, file_handle, size}); 633 | std.debug.assert(opt_object_attributes == null or opt_object_attributes.?.name == null); 634 | std.debug.assert(file_handle == 0); 635 | if(opt_handle) |h| { 636 | h.* = @intCast(rt.HANDLE, std.os.memfd_createZ("NtCreateSection", 0) catch return .NO_MEMORY); 637 | log("-> Returning linux memfd {d} with size 0x{X}", .{h.*, size}); 638 | std.os.ftruncate(@intCast(i32, h.*), size) catch unreachable; 639 | h.* |= @intCast(rt.HANDLE, size << 32); 640 | } else { 641 | unreachable; 642 | } 643 | return .SUCCESS; 644 | } 645 | 646 | var section_view_map: std.AutoHashMapUnmanaged(usize, usize) = .{}; 647 | var section_view_alloc = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = std.heap.page_allocator }; 648 | 649 | pub fn NtAllocateVirtualMemory( 650 | process_handle: rt.HANDLE, 651 | base_addr: *usize, 652 | zero_bits: usize, 653 | region_size: *usize, 654 | allocation_type: rt.ULONG, 655 | protection: rt.ULONG, 656 | ) callconv(.Win64) NTSTATUS { 657 | _ = process_handle; 658 | _ = allocation_type; 659 | _ = protection; 660 | log("NtAllocateVirtualMemory(baddr=0x{X}, zero_bits={d}, region_size=0x{X})", .{ 661 | base_addr.*, 662 | zero_bits, 663 | region_size.*, 664 | }); 665 | std.debug.assert(zero_bits == 0); 666 | 667 | base_addr.* = rt.alignPageUp(base_addr.*); 668 | 669 | const result = std.os.mmap( 670 | @intToPtr(?[*]align(0x1000) u8, base_addr.*), 671 | region_size.*, 672 | std.os.PROT.READ | std.os.PROT.WRITE, 673 | std.os.MAP.ANONYMOUS | std.os.MAP.PRIVATE, 674 | -1, 675 | 0, 676 | ) catch return .NO_MEMORY; 677 | 678 | region_size.* = result.len; 679 | base_addr.* = @ptrToInt(result.ptr); 680 | 681 | log("NtAllocateVirtualMemory -> 0x{}", .{base_addr.*}); 682 | 683 | return .SUCCESS; 684 | } 685 | 686 | pub fn NtMapViewOfSection( 687 | section_handle: rt.HANDLE, 688 | process_handle: rt.HANDLE, 689 | base_addr_opt: ?*?[*]align(0x1000) u8, 690 | zero_bits: rt.ULONG, 691 | commit_size: rt.ULONG, 692 | section_offset_opt: ?*rt.LARGEINT, 693 | view_size_opt: ?*rt.ULONG, 694 | inherit_dispotision: c_int, 695 | allocation_type: rt.ULONG, 696 | protect: rt.ULONG, 697 | ) callconv(.Win64) NTSTATUS { 698 | const base_addr = base_addr_opt orelse return .INVALID_PARAMETER; 699 | const section_offset_value = if(section_offset_opt) |so| so.* else 0; 700 | 701 | _ = process_handle; 702 | 703 | const fd = @truncate(u32, section_handle); 704 | const view_size_value = rt.alignPageUp(@truncate(u32, section_handle >> 32)); 705 | 706 | log("NtMapViewOfSection(fd=0x{X}, base=0x{X}, size=0x{X}, offset=0x{X})", .{ 707 | fd, 708 | @ptrToInt(base_addr.*), 709 | view_size_value, 710 | section_offset_value, 711 | }); 712 | 713 | const mem = std.os.mmap( 714 | base_addr.*, 715 | view_size_value, 716 | std.os.PROT.READ | std.os.PROT.WRITE, 717 | std.os.MAP.SHARED, 718 | @intCast(i32, fd), 719 | @intCast(usize, section_offset_value), 720 | ) catch return .NO_MEMORY; 721 | 722 | section_view_map.putNoClobber( 723 | section_view_alloc.allocator(), 724 | @ptrToInt(mem.ptr), 725 | view_size_value, 726 | ) catch { 727 | std.os.munmap(mem); 728 | return .NO_MEMORY; 729 | }; 730 | 731 | log("-> returning mmap ptr 0x{x}", .{@ptrToInt(mem.ptr)}); 732 | base_addr.* = mem.ptr; 733 | if(section_offset_opt) |so| { 734 | so.* = section_offset_value; 735 | } 736 | if(view_size_opt) |sz| { 737 | sz.* = @intCast(u32, view_size_value); 738 | } 739 | 740 | _ = protect; 741 | _ = allocation_type; 742 | _ = inherit_dispotision; 743 | _ = commit_size; 744 | _ = zero_bits; 745 | 746 | return .SUCCESS; 747 | } 748 | 749 | pub fn NtUnmapViewOfSection( 750 | process_handle: rt.HANDLE, 751 | base_addr: usize, 752 | ) callconv(.Win64) NTSTATUS { 753 | _ = process_handle; 754 | log("NtUnmapViewOfSection(0x{X})", .{base_addr}); 755 | if(section_view_map.get(base_addr)) |size| { 756 | log("-> Mapping of size 0x{X} found", .{size}); 757 | std.debug.assert(section_view_map.remove(base_addr)); 758 | std.os.munmap(@intToPtr([*]align(0x1000)u8, base_addr)[0..size]); 759 | return .SUCCESS; 760 | } 761 | log("-> No mapping found!!", .{}); 762 | return .INVALID_PARAMETER; 763 | } 764 | 765 | pub fn NtDeleteValueKey( 766 | key_handle: rt.HANDLE, 767 | value_name: ?*rt.UnicodeString, 768 | ) callconv(.Win64) NTSTATUS { 769 | log("STUB: NtDeleteValueKey(0x{X}, {any})", .{key_handle, value_name}); 770 | return .SUCCESS; 771 | } 772 | 773 | pub fn NtSetValueKey( 774 | key_handle: rt.HANDLE, 775 | value_name_opt: ?*rt.UnicodeString, 776 | index: rt.ULONG, 777 | kind: RegistryValueKind, 778 | data: rt.PVOID, 779 | data_size: rt.ULONG, 780 | ) callconv(.Win64) NTSTATUS { 781 | log("STUB: NtSetValueKey(0x{X}, {any}, {s})", .{key_handle, value_name_opt, @tagName(kind)}); 782 | const key = vfs.openHandle(key_handle); 783 | defer vfs.close(key); 784 | const dir = key.get(.dir) orelse return .INVALID_PARAMETER; 785 | const value_name = value_name_opt orelse return .INVALID_PARAMETER; 786 | const value = vfs.resolve16In(dir, value_name.chars() orelse return .INVALID_PARAMETER, true) catch return .NO_MEMORY; 787 | var u8dbgbuf: [4096]u8 = undefined; 788 | _ = u8dbgbuf; 789 | 790 | switch(kind) { 791 | .Symlink => { 792 | const data16 = @ptrCast([*]const u16, @alignCast(2, data))[0..@divExact(data_size, 2)]; 793 | //log("-> Link value: '{s}'", .{u8dbgbuf[0..std.unicode.utf16leToUtf8(&u8dbgbuf, data16) catch unreachable]}); 794 | value.setSymlinkDyn(data16) catch return .NO_MEMORY; 795 | }, 796 | .String => { 797 | const data16 = @ptrCast([*]const u16, @alignCast(2, data))[0..@divExact(data_size, 2)]; 798 | //log("-> String value: '{s}'", .{u8dbgbuf[0..std.unicode.utf16leToUtf8(&u8dbgbuf, data16) catch unreachable]}); 799 | value.setStringDyn(data16) catch return .NO_MEMORY; 800 | }, 801 | else => @panic("Bad key type!"), 802 | } 803 | _ = index; 804 | return .SUCCESS; 805 | } 806 | 807 | pub fn NtQueryValueKey( 808 | key_handle: rt.HANDLE, 809 | value_name_opt: ?*rt.UnicodeString, 810 | information_class: ValueInformationClass, 811 | info: rt.PVOID, 812 | info_capacity: rt.ULONG, 813 | result_len: *rt.ULONG, 814 | ) callconv(.Win64) NTSTATUS { 815 | _ = info; 816 | _ = info_capacity; 817 | _ = result_len; 818 | log("STUB: NtQueryValueKey(0x{X}, {any}, {s})", .{key_handle, value_name_opt, @tagName(information_class)}); 819 | return .SUCCESS; 820 | } 821 | 822 | fn resovleAttrs(attrs_opt: ?*ObjectAttributes, create_deep: bool) ?*vfs.DirectoryEntry { 823 | const attrs = attrs_opt orelse return null; 824 | const name = attrs.name orelse return null; 825 | const path = name.chars() orelse return null; 826 | if(attrs.root_dir == 0) { 827 | return vfs.resolve16(path, create_deep) catch return null; 828 | } else { 829 | const root = vfs.openHandle(attrs.root_dir); 830 | const root_dir = root.get(.dir) orelse { 831 | vfs.close(root); 832 | return null; 833 | }; 834 | return vfs.resolve16In(root_dir, path, create_deep) catch { 835 | vfs.close(root); 836 | return null; 837 | }; 838 | } 839 | } 840 | 841 | pub fn NtOpenSymbolicLinkObject( 842 | opt_handle: ?*rt.HANDLE, 843 | desired_access: AccessMask, 844 | opt_object_attributes: ?*ObjectAttributes, 845 | ) callconv(.Win64) NTSTATUS { 846 | log("STUB: NtOpenSymbolicLinkObject({any})", .{opt_object_attributes}); 847 | const link = resovleAttrs(opt_object_attributes, true) orelse return .INVALID_PARAMETER; 848 | defer vfs.close(link); 849 | _ = link.get(.symlink); 850 | if(opt_handle) |oh| { 851 | oh.* = vfs.handle(link); 852 | } 853 | _ = desired_access; 854 | return .SUCCESS; 855 | } 856 | 857 | pub fn NtQuerySymbolicLinkObject( 858 | link_handle: rt.HANDLE, 859 | link_target_opt: ?*rt.UnicodeString, 860 | out_length: ?*rt.ULONG, 861 | ) callconv(.Win64) NTSTATUS { 862 | log("NtQuerySymbolicLinkObject(0x{X})", .{link_handle}); 863 | const link_dirent = vfs.openHandle(link_handle); 864 | defer vfs.close(link_dirent); 865 | const link = link_dirent.get(.symlink) orelse @panic("Not a symlink!"); 866 | const buf_len = if(link_target_opt) |target| target.capacity else 0; 867 | 868 | log("-> Valid symlink of length {d}, buffer size is {d}", .{link.len, buf_len}); 869 | 870 | if(out_length) |ol| ol.* = @intCast(rt.ULONG, link.len); 871 | if(link.len > buf_len) return .BUFFER_TOO_SMALL; 872 | 873 | const link_target = link_target_opt orelse return .INVALID_PARAMETER; 874 | const data_ptr = link_target.buffer orelse return .INVALID_PARAMETER; 875 | std.mem.copy(u16, data_ptr[0..link.len], link.*); 876 | link_target.length = @intCast(u16, link.len); 877 | return .SUCCESS; 878 | } 879 | 880 | var utf16_buffer: [2048]u16 = undefined; 881 | 882 | pub fn NtQueryDirectoryObject( 883 | dir_handle: rt.HANDLE, 884 | buffer: ?*u16, 885 | buf_len: rt.ULONG, 886 | return_single_entry: rt.BOOL, 887 | restart_scan: rt.BOOL, 888 | context_opt: ?*rt.ULONG, 889 | return_length: ?*rt.ULONG, 890 | ) callconv(.Win64) NTSTATUS { 891 | std.debug.assert(return_single_entry != 0); 892 | const context = context_opt orelse return .INVALID_PARAMETER; 893 | 894 | log("NtQueryDirectoryObject(0x{X}, 0x{X})", .{dir_handle, @ptrToInt(return_length)}); 895 | 896 | const dh = vfs.openHandle(dir_handle); 897 | defer vfs.close(dh); 898 | 899 | if(restart_scan != 0) context.* = 0; 900 | var idx = context.*; 901 | 902 | var dirent = dh.next; 903 | while(idx != 0) : (idx -= 1) { 904 | std.debug.assert(dirent != -1); 905 | dirent = vfs.dirents.items[@intCast(usize, dirent)].next; 906 | } 907 | 908 | if(dirent == -1) { 909 | return .INFO_NO_MORE_ENTRIES; 910 | } 911 | 912 | if(true) @panic("TODO: NtQueryDirectoryObject ents"); 913 | 914 | _ = buffer; 915 | _ = buf_len; 916 | 917 | context.* += 1; 918 | return .MORE_ENTRIES; 919 | } 920 | 921 | pub fn NtOpenEvent( 922 | opt_handle: ?*rt.HANDLE, 923 | desired_access: AccessMask, 924 | opt_object_attributes: ?*ObjectAttributes, 925 | ) callconv(.Win64) NTSTATUS { 926 | log("STUB: NtOpenEvent({any})", .{opt_object_attributes}); 927 | _ = opt_handle; 928 | _ = desired_access; 929 | return .SUCCESS; 930 | } 931 | 932 | pub fn NtCreateEvent( 933 | opt_handle: ?*rt.HANDLE, 934 | desired_access: AccessMask, 935 | opt_object_attributes: ?*ObjectAttributes, 936 | event_type: rt.ULONG, 937 | initial_state: rt.BOOL, 938 | ) callconv(.Win64) NTSTATUS { 939 | log("STUB: NtCreateEvent({any})", .{opt_object_attributes}); 940 | _ = opt_handle; 941 | _ = desired_access; 942 | _ = event_type; 943 | _ = initial_state; 944 | return .SUCCESS; 945 | } 946 | 947 | pub fn NtClose( 948 | handle: rt.HANDLE, 949 | ) callconv(.Win64) NTSTATUS { 950 | log("STUB: NtClose(0x{X})", .{handle}); 951 | return .SUCCESS; 952 | } 953 | 954 | pub fn NtDuplicateObject( 955 | source_process: rt.HANDLE, 956 | source_handle: rt.HANDLE, 957 | target_process: rt.HANDLE, 958 | target_handle_opt: ?*rt.HANDLE, 959 | desired_access: AccessMask, 960 | inherit_handle: rt.BOOL, 961 | options: rt.ULONG, 962 | ) callconv(.Win64) NTSTATUS { 963 | log("STUB: NtDuplicateObject(0x{X})", .{source_handle}); 964 | _ = source_process; 965 | _ = target_process; 966 | 967 | _ = desired_access; 968 | _ = inherit_handle; 969 | _ = options; 970 | 971 | const target_handle = target_handle_opt orelse return .INVALID_PARAMETER; 972 | target_handle.* = source_handle; 973 | return .SUCCESS; 974 | } 975 | 976 | pub fn RtlCreateEnvironment( 977 | inherit: rt.BOOL, 978 | env: ?*rt.PCWSTR, 979 | ) callconv(.Win64) NTSTATUS { 980 | _ = inherit; 981 | _ = env; 982 | // log("STUB: RtlCreateEnvironment({}, {s})", .{inherit != 0, env}); 983 | return .SUCCESS; 984 | } 985 | 986 | const ObjectAttributes = extern struct { 987 | length: rt.ULONG, 988 | root_dir: rt.HANDLE, 989 | name: ?*rt.UnicodeString, 990 | attributes: rt.ULONG, 991 | security_descriptor: ?*SecurityDescriptor, 992 | security_qos: rt.PVOID, 993 | 994 | pub fn format( 995 | self: @This(), 996 | comptime layout: []const u8, 997 | opts: std.fmt.FormatOptions, 998 | writer: anytype, 999 | ) !void { 1000 | _ = layout; 1001 | _ = opts; 1002 | try writer.print("Attribs{{ .root_dir=0x{X}, name={any} }}", .{ 1003 | self.root_dir, 1004 | self.name, 1005 | }); 1006 | } 1007 | }; 1008 | 1009 | const Error = enum(rt.ULONG) { 1010 | SUCCESS = 0x00000000, 1011 | }; 1012 | 1013 | pub const NTSTATUS = enum(u32) { 1014 | SUCCESS = 0x00000000, 1015 | MORE_ENTRIES = 0x00000105, 1016 | 1017 | INFO_NO_MORE_ENTRIES = 0x8000001A, 1018 | 1019 | INFO_LENGTH_MISMATCH = 0xC0000004, 1020 | INVALID_PARAMETER = 0xC000000D, 1021 | NO_MEMORY = 0xC0000017, 1022 | BUFFER_TOO_SMALL = 0xC0000023, 1023 | SYSTEM_PROCESS_TERMINATED = 0xC000021A, 1024 | }; 1025 | 1026 | const AccessMask = rt.DWORD; 1027 | 1028 | const SecurityDescriptor = extern struct { 1029 | revision: u8, 1030 | sbz1: u8 = 0, 1031 | control: SecurityDescriptorControl = 0, 1032 | owner: ?*SecurityIdentifier = null, 1033 | group: ?*SecurityIdentifier = null, 1034 | sacl: ?*AccessControlList = null, 1035 | dacl: ?*AccessControlList = null, 1036 | }; 1037 | 1038 | const SecurityDescriptorControl = rt.WORD; 1039 | 1040 | const SecurityIdentifier = extern struct { 1041 | revision: u8, 1042 | sub_authority_count: u8 = 0, 1043 | identifier_authority: SecurityIdentifierAuthority = undefined, 1044 | sub_authorities: [8]rt.ULONG = undefined, 1045 | 1046 | pub fn size(self: @This()) u8 { 1047 | return @offsetOf(@This(), "sub_authorities") + @sizeOf(rt.ULONG) * self.sub_authority_count; 1048 | } 1049 | 1050 | pub fn format( 1051 | self: @This(), 1052 | comptime layout: []const u8, 1053 | opts: std.fmt.FormatOptions, 1054 | writer: anytype, 1055 | ) !void { 1056 | _ = layout; 1057 | _ = opts; 1058 | try writer.print("SecurityIdentifier{{ .revision = {d}, .identifier_authority = {any}, .sub = {any}", .{ 1059 | self.revision, 1060 | self.identifier_authority, 1061 | self.sub_authorities[0..self.sub_authority_count], 1062 | }); 1063 | } 1064 | }; 1065 | 1066 | const SecurityIdentifierAuthority = [6]u8; 1067 | 1068 | const AccessControlList = extern struct { 1069 | revision: u8, 1070 | sbz1: u8, 1071 | acl_size: rt.WORD, 1072 | ace_count: rt.WORD, 1073 | sbz2: rt.WORD, 1074 | }; 1075 | 1076 | const AccessControlListEntry = extern struct { 1077 | const Type = enum(u8) { 1078 | allowed = 0, 1079 | // denied = 1, 1080 | // system_audit = 2, 1081 | // system_alarm = 3, 1082 | // allowed_compound = 4, 1083 | // allowed_object = 5, 1084 | // denied_object = 6, 1085 | // system_audit_object = 7, 1086 | // system_alarm_object = 8, 1087 | allowed_callback = 9, 1088 | // denied_callback = 10, 1089 | allowed_callback_object = 11, 1090 | // denied_callback_object = 12, 1091 | // system_audit_callback = 13, 1092 | // system_alarm_callback = 14, 1093 | // system_audit_callback_object = 15, 1094 | // system_alarm_callback_object = 16, 1095 | }; 1096 | 1097 | type: Type, 1098 | num_bytes: u8, 1099 | flags: rt.DWORD, 1100 | 1101 | u: extern union { 1102 | allowed: extern struct { 1103 | mask: AccessMask, 1104 | sid: SecurityIdentifier, 1105 | }, 1106 | allowed_callback: extern struct { 1107 | mask: AccessMask, 1108 | sid: SecurityIdentifier, 1109 | }, 1110 | allowed_callback_object: extern struct { 1111 | mask: AccessMask, 1112 | flags: rt.DWORD, 1113 | object_type: rt.GUID, 1114 | inherited_object_type: rt.GUID, 1115 | sid: SecurityIdentifier, 1116 | }, 1117 | }, 1118 | 1119 | pub fn size(self: *@This()) u8 { 1120 | inline for (@typeInfo(Type).Enum.fields) |f| { 1121 | if (@enumToInt(self.type) == f.value) { 1122 | return @offsetOf(@This(), "u") + @sizeOf(@TypeOf(@field(self.u, f.name))) - @sizeOf(SecurityIdentifier) + @field(self.u, f.name).sid.size(); 1123 | } 1124 | unreachable; 1125 | } 1126 | } 1127 | 1128 | pub fn format( 1129 | self: @This(), 1130 | comptime layout: []const u8, 1131 | opts: std.fmt.FormatOptions, 1132 | writer: anytype, 1133 | ) !void { 1134 | _ = layout; 1135 | _ = opts; 1136 | try writer.print("AccessControlListEntry{{ .flags = 0x{X}, .type = {d} }}", .{ self.flags, @enumToInt(self.type) }); 1137 | } 1138 | }; 1139 | 1140 | const HardErrorResponseOption = enum(u32) { 1141 | AbortRetryIgnore, 1142 | Ok, 1143 | OkCancel, 1144 | RetryCancel, 1145 | YesNo, 1146 | YesNoCancel, 1147 | ShutdownSystem, 1148 | }; 1149 | 1150 | const HardErrorResponse = enum(u32) { 1151 | ReturnToCaller, 1152 | NotHandled, 1153 | Abort, 1154 | Cancel, 1155 | Ignore, 1156 | No, 1157 | Ok, 1158 | Retry, 1159 | Yes, 1160 | }; 1161 | 1162 | const RegistryValueKind = enum(rt.ULONG) { 1163 | Unknown = 0, 1164 | String = 1, 1165 | ExpandString = 2, 1166 | Binary = 3, 1167 | DWord = 4, 1168 | DWordBigEndian = 5, 1169 | Symlink = 6, 1170 | MultiString = 7, 1171 | ResourceList = 8, 1172 | FullResourceDescription = 9, 1173 | ResourceRequirementsList = 10, 1174 | QWord = 11, 1175 | None = ~@as(rt.ULONG, 0), 1176 | }; 1177 | 1178 | const ValueInformationClass = enum(rt.ULONG) { 1179 | Basic = 0, 1180 | Full = 1, 1181 | Partial = 2, 1182 | FullAlign64 = 3, 1183 | PartialAlign64 = 4, 1184 | Layer = 5, 1185 | }; 1186 | 1187 | // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/class.htm 1188 | // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/basic.htm?ts=0,200 1189 | const SystemInformationClass = enum(u32) { 1190 | Basic = 0x00, 1191 | Processor = 0x01, 1192 | //Performance = 2, 1193 | NumaProcessorMap = 0x37, 1194 | FirmwareTableInformation = 0x4C, 1195 | SystemManufacturingInformation = 0x9D, 1196 | }; 1197 | 1198 | const Privilege = enum(rt.ULONG) { 1199 | CreateToken = 1, 1200 | AssignPrimaryToken = 2, 1201 | LockMemory = 3, 1202 | IncreaseQuota = 4, 1203 | UnsolicitedInput = 5, 1204 | MachineAccount = 6, 1205 | Tcb = 7, 1206 | Security = 8, 1207 | TakeOwnership = 9, 1208 | LoadDriver = 10, 1209 | SystemProfile = 11, 1210 | Systemtime = 12, 1211 | ProfileSingleProcess = 13, 1212 | IncreaseBasePriority = 14, 1213 | CreatePagefile = 15, 1214 | CreatePermanent = 16, 1215 | Backup = 17, 1216 | Restore = 18, 1217 | Shutdown = 19, 1218 | Debug = 20, 1219 | Audit = 21, 1220 | SystemEnvironment = 22, 1221 | ChangeNotify = 23, 1222 | RemoteShutdown = 24, 1223 | Undock = 25, 1224 | SyncAgent = 26, 1225 | EnableDelegation = 27, 1226 | ManageVolume = 28, 1227 | Impersonate = 29, 1228 | CreateGlobal = 30, 1229 | TrustedCredManAccess = 31, 1230 | Relabel = 32, 1231 | IncreaseWorkingSet = 33, 1232 | TimeZone = 34, 1233 | CreateSymbolicLink = 35, 1234 | }; 1235 | 1236 | const HeapInformationClass = enum(u32) { HeapCompatibilityInformation = 0, HeapEnableTerminationOnCorruption = 1, HeapOptimizeResources = 3, HeapTag }; 1237 | 1238 | const ProcessInfoClass = enum(i32) { 1239 | ProcessBasicInformation = 0x00, 1240 | ProcessQuotaLimits = 0x01, 1241 | ProcessIoCounters = 0x02, 1242 | ProcessVmCounters = 0x03, 1243 | ProcessTimes = 0x04, 1244 | ProcessBasePriority = 0x05, 1245 | ProcessRaisePriority = 0x06, 1246 | ProcessDebugPort = 0x07, 1247 | ProcessExceptionPort = 0x08, 1248 | ProcessAccessToken = 0x09, 1249 | ProcessLdtInformation = 0x0A, 1250 | ProcessLdtSize = 0x0B, 1251 | ProcessDefaultHardErrorMode = 0x0C, 1252 | ProcessIoPortHandlers = 0x0D, 1253 | ProcessPooledUsageAndLimits = 0x0E, 1254 | ProcessWorkingSetWatch = 0x0F, 1255 | ProcessUserModeIOPL = 0x10, 1256 | ProcessEnableAlignmentFaultFixup = 0x11, 1257 | ProcessPriorityClass = 0x12, 1258 | ProcessWx86Information = 0x13, 1259 | ProcessHandleCount = 0x14, 1260 | ProcessAffinityMask = 0x15, 1261 | ProcessPriorityBoost = 0x16, 1262 | ProcessDeviceMap = 0x17, 1263 | ProcessSessionInformation = 0x18, 1264 | ProcessForegroundInformation = 0x19, 1265 | ProcessWow64Information = 0x1A, 1266 | ProcessImageFileName = 0x1B, 1267 | ProcessLUIDDeviceMapsEnabled = 0x1C, 1268 | ProcessBreakOnTermination = 0x1D, 1269 | ProcessDebugObjectHandle = 0x1E, 1270 | ProcessDebugFlags = 0x1F, 1271 | ProcessHandleTracing = 0x20, 1272 | ProcessIoPriority = 0x21, 1273 | ProcessExecuteFlags = 0x22, 1274 | ProcessResourceManagement = 0x23, 1275 | ProcessCookie = 0x24, 1276 | ProcessImageInformation = 0x25, 1277 | ProcessCycleTime = 0x26, 1278 | ProcessPagePriority = 0x27, 1279 | ProcessInstrumentationCallback = 0x28, 1280 | ProcessThreadStackAllocation = 0x29, 1281 | ProcessWorkingSetWatchEx = 0x2A, 1282 | ProcessImageFileNameWin32 = 0x2B, 1283 | ProcessImageFileMapping = 0x2C, 1284 | ProcessAffinityUpdateMode = 0x2D, 1285 | ProcessMemoryAllocationMode = 0x2E, 1286 | ProcessGroupInformation = 0x2F, 1287 | ProcessTokenVirtualizationEnabled = 0x30, 1288 | ProcessConsoleHostProcess = 0x31, 1289 | ProcessWindowInformation = 0x32, 1290 | ProcessHandleInformation = 0x33, 1291 | ProcessMitigationPolicy = 0x34, 1292 | ProcessDynamicFunctionTableInformation = 0x35, 1293 | ProcessHandleCheckingMode = 0x36, 1294 | ProcessKeepAliveCount = 0x37, 1295 | ProcessRevokeFileHandles = 0x38, 1296 | ProcessWorkingSetControl = 0x39, 1297 | ProcessHandleTable = 0x3A, 1298 | ProcessCheckStackExtentsMode = 0x3B, 1299 | ProcessCommandLineInformation = 0x3C, 1300 | ProcessProtectionInformation = 0x3D, 1301 | ProcessMemoryExhaustion = 0x3E, 1302 | ProcessFaultInformation = 0x3F, 1303 | ProcessTelemetryIdInformation = 0x40, 1304 | ProcessCommitReleaseInformation = 0x41, 1305 | ProcessDefaultCpuSetsInformation = 0x42, 1306 | ProcessAllowedCpuSetsInformation = 0x43, 1307 | ProcessSubsystemProcess = 0x44, 1308 | ProcessJobMemoryInformation = 0x45, 1309 | ProcessInPrivate = 0x46, 1310 | ProcessRaiseUMExceptionOnInvalidHandleClose = 0x47, 1311 | ProcessIumChallengeResponse = 0x48, 1312 | ProcessChildProcessInformation = 0x49, 1313 | ProcessHighGraphicsPriorityInformation = 0x4A, 1314 | ProcessSubsystemInformation = 0x4B, 1315 | ProcessEnergyValues = 0x4C, 1316 | ProcessActivityThrottleState = 0x4D, 1317 | ProcessActivityThrottlePolicy = 0x4E, 1318 | ProcessWin32kSyscallFilterInformation = 0x4F, 1319 | ProcessDisableSystemAllowedCpuSets = 0x50, 1320 | ProcessWakeInformation = 0x51, 1321 | ProcessEnergyTrackingState = 0x52, 1322 | ProcessManageWritesToExecutableMemory = 0x53, 1323 | ProcessCaptureTrustletLiveDump = 0x54, 1324 | ProcessTelemetryCoverage = 0x55, 1325 | ProcessEnclaveInformation = 0x56, 1326 | ProcessEnableReadWriteVmLogging = 0x57, 1327 | ProcessUptimeInformation = 0x58, 1328 | ProcessImageSection = 0x59, 1329 | ProcessDebugAuthInformation = 0x5A, 1330 | ProcessSystemResourceManagement = 0x5B, 1331 | ProcessSequenceNumber = 0x5C, 1332 | ProcessLoaderDetour = 0x5D, 1333 | ProcessSecurityDomainInformation = 0x5E, 1334 | ProcessCombineSecurityDomainsInformation = 0x5F, 1335 | ProcessEnableLogging = 0x60, 1336 | ProcessLeapSecondInformation = 0x61, 1337 | ProcessFiberShadowStackAllocation = 0x62, 1338 | ProcessFreeFiberShadowStackAllocation = 0x63, 1339 | MaxProcessInfoClass = 0x64, 1340 | }; 1341 | -------------------------------------------------------------------------------- /src/common/symbols.zig: -------------------------------------------------------------------------------- 1 | const symbols = .{ 2 | .@"ntdll.dll" = .{ 3 | .hooks = .{ 4 | .EtwEventRegister = ntdll.EtwEventRegister, 5 | .EtwRegisterTraceGuidsW = ntdll.EtwRegisterTraceGuidsW, 6 | .NtAllocateVirtualMemory = ntdll.NtAllocateVirtualMemory, 7 | .NtAlpcCreatePort = ntdll.NtAlpcCreatePort, 8 | .NtClose = ntdll.NtClose, 9 | .NtCreateDirectoryObject = ntdll.NtCreateDirectoryObject, 10 | .NtCreateEvent = ntdll.NtCreateEvent, 11 | .NtCreateFile = ntdll.NtCreateFile, 12 | .NtCreateKey = ntdll.NtCreateKey, 13 | .NtCreateMutant = ntdll.NtCreateMutant, 14 | .NtCreateSection = ntdll.NtCreateSection, 15 | .NtDeleteValueKey = ntdll.NtDeleteValueKey, 16 | .NtDuplicateObject = ntdll.NtDuplicateObject, 17 | .NtMapViewOfSection = ntdll.NtMapViewOfSection, 18 | .NtOpenDirectoryObject = ntdll.NtOpenDirectoryObject, 19 | .NtOpenEvent = ntdll.NtOpenEvent, 20 | .NtOpenFile = ntdll.NtOpenFile, 21 | .NtOpenKey = ntdll.NtOpenKey, 22 | .NtOpenSymbolicLinkObject = ntdll.NtOpenSymbolicLinkObject, 23 | .NtQueryDirectoryObject = ntdll.NtQueryDirectoryObject, 24 | .NtQueryInformationJobObject = ntdll.NtQueryInformationJobObject, 25 | .NtQuerySymbolicLinkObject = ntdll.NtQuerySymbolicLinkObject, 26 | .NtQuerySystemInformation = ntdll.NtQuerySystemInformation, 27 | .NtQueryValueKey = ntdll.NtQueryValueKey, 28 | .NtRaiseHardError = ntdll.NtRaiseHardError, 29 | .NtSetInformationProcess = ntdll.NtSetInformationProcess, 30 | .NtSetValueKey = ntdll.NtSetValueKey, 31 | .NtTerminateProcess = ntdll.NtTerminateProcess, 32 | .NtUnmapViewOfSection = ntdll.NtUnmapViewOfSection, 33 | .RtlAcquireSRWLockExclusive = ntdll.RtlAcquireSRWLockExclusive, 34 | .RtlAcquireSRWLockShared = ntdll.RtlAcquireSRWLockShared, 35 | .RtlAdjustPrivilege = ntdll.RtlAdjustPrivilege, 36 | .RtlAllocateHeap = ntdll.RtlAllocateHeap, 37 | .RtlCreateEnvironment = ntdll.RtlCreateEnvironment, 38 | .RtlCreateTagHeap = ntdll.RtlCreateTagHeap, 39 | .RtlFreeHeap = ntdll.RtlFreeHeap, 40 | .RtlGetNtSystemRoot = ntdll.RtlGetNtSystemRoot, 41 | .RtlInitializeConditionVariable = ntdll.RtlInitializeConditionVariable, 42 | .RtlWakeAllConditionVariable = ntdll.RtlWakeAllConditionVariable, 43 | .RtlInitializeSRWLock = ntdll.RtlInitializeSRWLock, 44 | .RtlInitUnicodeString = ntdll.RtlInitUnicodeString, 45 | .RtlInitUnicodeStringEx = ntdll.RtlInitUnicodeStringEx, 46 | .RtlNormalizeProcessParams = ntdll.RtlNormalizeProcessParams, 47 | .RtlReleaseSRWLockExclusive = ntdll.RtlReleaseSRWLockExclusive, 48 | .RtlReleaseSRWLockShared = ntdll.RtlReleaseSRWLockShared, 49 | .RtlSetHeapInformation = ntdll.RtlSetHeapInformation, 50 | .RtlSetThreadIsCritical = ntdll.RtlSetThreadIsCritical, 51 | .RtlSleepConditionVariableSRW = ntdll.RtlSleepConditionVariableSRW, 52 | .TpAllocPool = ntdll.TpAllocPool, 53 | .TpAllocWork = ntdll.TpAllocWork, 54 | .TpPostWork = ntdll.TpPostWork, 55 | .TpReleaseWork = ntdll.TpReleaseWork, 56 | .TpSetPoolMinThreads = ntdll.TpSetPoolMinThreads, 57 | .TpWaitForWork = ntdll.TpWaitForWork, 58 | }, 59 | 60 | .real = .{ 61 | // Math, strings and memory 62 | .NlsAnsiCodePage, 63 | .NlsMbCodePageTag, 64 | .NlsMbOemCodePageTag, 65 | .RtlCharToInteger, 66 | .RtlAnsiCharToUnicodeChar, 67 | .RtlAnsiStringToUnicodeSize, 68 | .RtlAnsiStringToUnicodeString, 69 | .RtlAppendAsciizToString, 70 | .RtlAppendPathElement, 71 | .RtlAppendStringToString, 72 | .RtlAppendUnicodeStringToString, 73 | .RtlAppendUnicodeToString, 74 | .RtlCanonicalizeDomainName, 75 | .RtlCompareMemory, 76 | .RtlCompareMemoryUlong, 77 | .RtlCompareString, 78 | .RtlCompareUnicodeString, 79 | .RtlCompareUnicodeStrings, 80 | .RtlConsoleMultiByteToUnicodeN, 81 | .RtlCopyLuid, 82 | .RtlCopyLuidAndAttributesArray, 83 | .RtlCopyMappedMemory, 84 | .RtlCopyMemory, 85 | .RtlCopyMemoryNonTemporal, 86 | .RtlCopyString, 87 | .RtlCopyUnicodeString, 88 | .RtlCreateUnicodeString, 89 | .RtlCreateUnicodeStringFromAsciiz, 90 | .RtlCustomCPToUnicodeN, 91 | .RtlDosPathNameToNtPathName_U, 92 | .RtlDosPathNameToNtPathName_U_WithStatus, 93 | .RtlEqualString, 94 | .RtlEqualUnicodeString, 95 | .RtlExpandEnvironmentStrings_U, 96 | .RtlFindCharInUnicodeString, 97 | .RtlFreeUnicodeString, 98 | .RtlInitAnsiString, 99 | .RtlMoveMemory, 100 | .RtlPrefixString, 101 | .RtlPrefixUnicodeString, 102 | .RtlUnicodeStringToInteger, 103 | .RtlUnicodeStringToAnsiSize, 104 | .RtlUnicodeStringToAnsiString, 105 | .RtlUnicodeStringToUTF8String, 106 | .RtlUpcaseUnicodeChar, 107 | .RtlUTF8ToUnicodeN, 108 | .LdrVerifyImageMatchesChecksumEx, // Nt 109 | .__C_specific_handler, 110 | .__chkstk, 111 | .__isascii, 112 | .__iscsym, 113 | .__iscsymf, 114 | .__misaligned_access, 115 | .__toascii, 116 | ._atoi64, 117 | ._errno, 118 | ._fltused, 119 | ._i64toa, 120 | ._i64toa_s, 121 | ._i64tow, 122 | ._i64tow_s, 123 | ._itoa, 124 | ._itoa_s, 125 | ._itow, 126 | ._itow_s, 127 | ._lfind, 128 | ._local_unwind, 129 | ._ltoa, 130 | ._ltoa_s, 131 | ._ltow, 132 | ._ltow_s, 133 | ._makepath_s, 134 | ._memccpy, 135 | ._memicmp, 136 | ._setjmp, 137 | ._setjmpex, 138 | ._snprintf, 139 | ._snprintf_s, 140 | ._snscanf_s, 141 | ._snwprintf, 142 | ._snwprintf_s, 143 | ._snwscanf_s, 144 | ._splitpath, 145 | ._splitpath_s, 146 | ._strcmpi, 147 | ._stricmp, 148 | ._strlwr, 149 | ._strlwr_s, 150 | ._strnicmp, 151 | ._strnset_s, 152 | ._strset_s, 153 | ._strupr, 154 | ._strupr_s, 155 | ._swprintf, 156 | ._ui64toa, 157 | ._ui64toa_s, 158 | ._ui64tow, 159 | ._ui64tow_s, 160 | ._ultoa, 161 | ._ultoa_s, 162 | ._ultow, 163 | ._ultow_s, 164 | ._vscprintf, 165 | ._vscwprintf, 166 | ._vsnprintf, 167 | ._vsnprintf_s, 168 | ._vsnwprintf, 169 | ._vsnwprintf_s, 170 | ._vswprintf, 171 | ._wcsicmp, 172 | ._wcslwr, 173 | ._wcslwr_s, 174 | ._wcsnicmp, 175 | ._wcsnset_s, 176 | ._wcsset_s, 177 | ._wcstoi64, 178 | ._wcstoui64, 179 | ._wcsupr, 180 | ._wcsupr_s, 181 | ._wmakepath_s, 182 | ._wsplitpath_s, 183 | ._wtoi, 184 | ._wtoi64, 185 | ._wtol, 186 | .abs, 187 | .atan, 188 | .atan2, 189 | .atoi, 190 | .atol, 191 | .bsearch, 192 | .bsearch_s, 193 | .ceil, 194 | .cos, 195 | .fabs, 196 | .floor, 197 | .isalnum, 198 | .isalpha, 199 | .iscntrl, 200 | .isdigit, 201 | .isgraph, 202 | .islower, 203 | .isprint, 204 | .ispunct, 205 | .isspace, 206 | .isupper, 207 | .iswalnum, 208 | .iswalpha, 209 | .iswascii, 210 | .iswctype, 211 | .iswdigit, 212 | .iswgraph, 213 | .iswlower, 214 | .iswprint, 215 | .iswspace, 216 | .iswxdigit, 217 | .isxdigit, 218 | .labs, 219 | .log, 220 | .mbstowcs, 221 | .memchr, 222 | .memcmp, 223 | .memcpy, 224 | .memcpy_s, 225 | .memmove, 226 | .memmove_s, 227 | .memset, 228 | .pow, 229 | .qsort, 230 | .qsort_s, 231 | .sin, 232 | .sprintf, 233 | .sprintf_s, 234 | .sqrt, 235 | .sscanf, 236 | .sscanf_s, 237 | .strcat, 238 | .strcat_s, 239 | .strchr, 240 | .strcmp, 241 | .strcpy, 242 | .strcpy_s, 243 | .strcspn, 244 | .strlen, 245 | .strncat, 246 | .strncat_s, 247 | .strncmp, 248 | .strncpy, 249 | .strncpy_s, 250 | .strnlen, 251 | .strpbrk, 252 | .strrchr, 253 | .strspn, 254 | .strstr, 255 | .strtok_s, 256 | .strtol, 257 | .strtoul, 258 | .swprintf, 259 | .swprintf_s, 260 | .swscanf_s, 261 | .tan, 262 | .tolower, 263 | .toupper, 264 | .towlower, 265 | .towupper, 266 | .vsprintf, 267 | .vsprintf_s, 268 | .vswprintf_s, 269 | .wcscat, 270 | .wcscat_s, 271 | .wcschr, 272 | .wcscmp, 273 | .wcscpy, 274 | .wcscpy_s, 275 | .wcscspn, 276 | .wcslen, 277 | .wcsncat, 278 | .wcsncat_s, 279 | .wcsncmp, 280 | .wcsncpy, 281 | .wcsncpy_s, 282 | .wcsnlen, 283 | .wcspbrk, 284 | .wcsrchr, 285 | .wcsspn, 286 | .wcsstr, 287 | .wcstok_s, 288 | .wcstol, 289 | .wcstombs, 290 | .wcstoul, 291 | 292 | // Hashing 293 | .A_SHAFinal, 294 | .A_SHAInit, 295 | .A_SHAUpdate, 296 | .MD4Final, 297 | .MD4Init, 298 | .MD4Update, 299 | .MD5Final, 300 | .MD5Init, 301 | .MD5Update, 302 | .RtlComputeCrc32, 303 | .RtlCrc32, 304 | .RtlCrc64, 305 | 306 | // Prefix tables 307 | .PfxFindPrefix, 308 | .PfxInitialize, 309 | .PfxInsertPrefix, 310 | .PfxRemovePrefix, 311 | 312 | 313 | // Needs more investigating into what lock functions we want to pass through 314 | // .RtlAcquirePebLock, 315 | // .RtlAcquirePrivilege, heap and Nt 316 | // .RtlAcquireReleaseSRWLockExclusive, 317 | // .RtlAcquireResourceExclusive, Nt 318 | // .RtlAcquireResourceShared, Nt 319 | // .RtlConvertExclusiveToShared, (Only NtReleaseSemaphore) 320 | // .RtlConvertSRWLockExclusiveToShared (Only NtAlertThreadByThreadId) 321 | // .RtlConvertSharedToExclusive, 322 | 323 | // Heap and other things 324 | // .RtlActivateActivationContext 325 | // .RtlActivateActivationContextEx 326 | // .RtlActivateActivationContextUnsafeFast 327 | 328 | // ACL memes 329 | .RtlAddAccessAllowedAce, 330 | .RtlAddAccessAllowedAceEx, 331 | .RtlAddAccessAllowedObjectAce, 332 | .RtlAddAccessDeniedAce, 333 | .RtlAddAccessDeniedAceEx, 334 | .RtlAddAccessDeniedObjectAce, 335 | .RtlAddAccessFilterAce, 336 | .RtlAddAce, 337 | .RtlAddAuditAccessAce, 338 | .RtlAddAuditAccessAceEx, 339 | .RtlAddAuditAccessObjectAce, 340 | .RtlAddCompoundAce, 341 | .RtlAddIntegrityLabelToBoundaryDescriptor, 342 | .RtlAddMandatoryAce, 343 | .RtlAddProcessTrustLabelAce, 344 | .RtlAddRefActivationContext, 345 | .RtlAddResourceAttributeAce, 346 | .RtlAddSIDToBoundaryDescriptor, 347 | .RtlAddScopedPolicyIDAce, 348 | .RtlAllocateAndInitializeSid, 349 | .RtlConvertSidToUnicodeString, 350 | .RtlConvertToAutoInheritSecurityObject, 351 | .RtlCopySecurityDescriptor, 352 | .RtlCopySid, 353 | .RtlCopySidAndAttributesArray, 354 | .RtlCreateAcl, 355 | .RtlCreateSecurityDescriptor, 356 | .RtlCreateServiceSid, 357 | // .RtlCreateUserSecurityObject, AAAAAAA 358 | .RtlCreateVirtualAccountSid, 359 | // .RtlDefaultNpAcl, Nt 360 | .RtlDeleteAce, 361 | .RtlDeleteBoundaryDescriptor, 362 | .RtlDeleteSecurityObject, 363 | .RtlFirstFreeAce, 364 | .RtlFreeSid, 365 | .RtlGetAce, 366 | .RtlIsValidProcessTrustLabelSid, 367 | .RtlLengthSid, 368 | .RtlLengthSidAsUnicodeString, 369 | .RtlSetDaclSecurityDescriptor, 370 | .RtlSetOwnerSecurityDescriptor, 371 | .RtlSetSaclSecurityDescriptor, 372 | .RtlValidAcl, 373 | .RtlValidRelativeSecurityDescriptor, 374 | .RtlValidSecurityDescriptor, 375 | .RtlValidSid, 376 | 377 | // PE (?) 378 | .RtlAddressInSectionTable, 379 | // .RtlComputeImportTableHash, Nt 380 | .RtlComputePrivatizedDllName_U, 381 | 382 | // ? 383 | .RtlApplicationVerifierStop, 384 | .RtlAreAllAccessesGranted, 385 | .RtlAreAnyAccessesGranted, 386 | // RtlCheckBootStatusIntegrity, fs calls 387 | .RtlAreLongPathsEnabled, 388 | // .RtlCheckTokenCapability, fs calls 389 | // .RtlCheckTokenMembership, fs calls 390 | // .RtlCheckTokenMembershipEx, fs calls 391 | // .RtlCleanUpTEBLangLists, heap 392 | .RtlCmDecodeMemIoResource, 393 | .RtlCmEncodeMemIoResource, 394 | // .RtlCommitDebugInfo, heap 395 | // .RtlCompactHeap, heap 396 | .RtlCompareAltitudes, 397 | // .RtlCompleteProcessCloning, 398 | .RtlCompressBuffer, 399 | // .RtlConstructCrossVmEventPath, heap 400 | // .RtlConstructCrossVmMutexPath, 401 | // .RtlContractHashTable, heap 402 | .RtlConvertDeviceFamilyInfoToString, 403 | .RtlConvertLCIDToString, 404 | .RtlCopyContext, 405 | .RtlCopyExtendedContext, 406 | // .RtlCreateActivationContext, heap 407 | // .RtlCreateAndSetSD, heap 408 | // .RtlCreateAtomTable, heap 409 | // .RtlCreateBoundaryDescriptor, heap 410 | // .RtlCreateEnvironment, heap, critical sections and shit 411 | // .RtlCreateEnvironmentEx, -||- 412 | // .RtlCreateMemoryBlockLookaside, ?? 413 | .RtlCreateMemoryZone, 414 | // .RtlCreateProcessParameters, heap 415 | // .RtlCreateProcessParametersEx, 416 | // .RtlCreateProcessParametersWithTemplate, 417 | // .RtlCreateProcessReflection, Nt 418 | // .RtlCreateQueryDebugBuffer, Nt 419 | // .RtlCreateSystemVolumeInformationFolder, Nt and heap 420 | // .RtlCultureNameToLCID, Registry 421 | // .RtlCutoverTimeToSystemTime, AAAA 422 | .RtlDeCommitDebugInfo, 423 | .RtlDeNormalizeProcessParams, 424 | // .RtlDecodePointer, NtQueryInformationProcess 425 | // .RtlDecodeRemotePointer, NtQueryInformationProcess 426 | .RtlDecodeSystemPointer, 427 | .RtlDecompressBuffer, 428 | .RtlDecompressBufferEx, 429 | .RtlDecompressFragment, 430 | // .RtlDeleteElementGenericTable, heap 431 | // .RtlDeleteElementGenericTableAvl, heap 432 | // .RtlDeleteElementGenericTableAvlEx, heap 433 | // .RtlDeleteFunctionTable, AAAA 434 | // .RtlDeleteGrowableFunctionTable, AAAA 435 | // .RtlDeleteResource, heap and Nt 436 | // .RtlDeleteUmsCompletionList, heap and Nt 437 | // .RtlDeleteUmsThreadContext, heap 438 | // .RtlDequeueUmsCompletionListItems, NtWaitForSingleObject 439 | // .RtlDeregisterSecureMemoryCacheCallback, heap and lock 440 | .RtlConnectToSm, 441 | .RtlSendMsgToSm, 442 | 443 | // Splay trees 444 | .RtlDelete, 445 | .RtlDeleteNoSplay, 446 | 447 | // Hash table 448 | .RtlCreateHashTable, 449 | .RtlCreateHashTableEx, 450 | .RtlDeleteHashTable, 451 | 452 | // Registry Nt 453 | .RtlApplyRXact, 454 | .RtlApplyRXactNoFlush, 455 | .RtlCapabilityCheck, 456 | .RtlCapabilityCheckForSingleSessionSku, 457 | .RtlCheckPortableOperatingSystem, 458 | .RtlCheckRegistryKey, 459 | .RtlCreateBootStatusDataFile, 460 | .RtlCreateRegistryKey, 461 | .RtlWriteRegistryValue, 462 | .RtlAppxIsFileOwnedByTrustedInstaller, 463 | .RtlQueryRegistryValuesEx, 464 | 465 | // .RtlCheckSandboxedToken, NtQueryInformationToken 466 | // .RtlCheckSystemBootStatusIntegrity, NtPowerInformation 467 | 468 | // Bitset functions 469 | .RtlAreBitsClear, 470 | .RtlAreBitsClearEx, 471 | .RtlAreBitsSet, 472 | .RtlClearAllBits, 473 | .RtlClearAllBitsEx, 474 | .RtlClearBit, 475 | .RtlClearBitEx, 476 | .RtlClearBits, 477 | .RtlClearBitsEx, 478 | .RtlCopyBitMap, 479 | .RtlFindClearBits, 480 | .RtlFindClearBitsAndSet, 481 | .RtlFindClearBitsEx, 482 | .RtlFindSetBits, 483 | .RtlInitializeBitMap, 484 | .RtlInitializeBitMapEx, 485 | .RtlNumberOfClearBits, 486 | .RtlNumberOfClearBitsEx, 487 | .RtlNumberOfClearBitsInRange, 488 | .RtlNumberOfSetBits, 489 | .RtlNumberOfSetBitsEx, 490 | .RtlNumberOfSetBitsInRange, 491 | .RtlSetAllBits, 492 | .RtlSetAllBitsEx, 493 | .RtlSetBit, 494 | .RtlSetBitEx, 495 | .RtlSetBits, 496 | .RtlSetBitsEx, 497 | .RtlTestBit, 498 | 499 | // AVL trees 500 | .RtlAvlInsertNodeEx, 501 | .RtlAvlRemoveNode, 502 | 503 | // Needs proper thread memes 504 | // .RtlBarrier, 505 | // .RtlBarrierForDelete 506 | // .RtlCancelTimer 507 | // .RtlCheckForOrphanedCriticalSections, 508 | // .RtlClearThreadWorkOnBehalfTicket, 509 | // .RtlCreateTimer, heap 510 | // .RtlCreateTimerQueue, heap 511 | // .RtlCreateUmsCompletionList, heap 512 | // .RtlCreateUmsThreadContext, heap 513 | // .RtlDeactivateActivationContext, 514 | // .RtlDeactivateActivationContextUnsafeFast, 515 | // .RtlDeleteAtomFromAtomTable, heap 516 | // .RtlDeleteBarrier, 517 | // .RtlDeleteCriticalSection, 518 | // .RtlDeleteTimer, 519 | // .RtlDeleteTimerQueue, 520 | // .RtlDeleteTimerQueueEx, 521 | .RtlRandomEx, // This uses once so may die if contended 522 | 523 | // Stack memes 524 | .RtlCaptureContext, 525 | .RtlCaptureContext2, 526 | .RtlCallEnclaveReturn, 527 | // .RtlCaptureStackBackTrace, NtQueryVirtualMemory 528 | 529 | // Processes 530 | .RtlCreateUserProcess, 531 | .RtlCreateUserProcessEx, 532 | // .RtlCreateUserFiberShadowStack, // AAAA 533 | // .RtlCreateUserStack, // AAAA 534 | // .RtlCreateUserThread, 535 | .RtlAcquirePrivilege, 536 | .RtlReleasePrivilege, 537 | .LdrQueryImageFileExecutionOptions, 538 | .RtlDestroyProcessParameters, 539 | 540 | // Time 541 | .RtlSecondsSince1970ToTime, 542 | .RtlSecondsSince1980ToTime, 543 | .RtlTimeFieldsToTime, 544 | .RtlTimeToElapsedTimeFields, 545 | .RtlTimeToSecondsSince1970, 546 | .RtlTimeToSecondsSince1980, 547 | .RtlTimeToTimeFields, 548 | 549 | // Exceptions 550 | .RtlLookupFunctionEntry, 551 | .RtlUnhandledExceptionFilter, 552 | .RtlUnhandledExceptionFilter2, 553 | .RtlVirtualUnwind, 554 | 555 | // Tracing 556 | .EtwGetTraceLoggerHandle, 557 | .EtwGetTraceEnableLevel, 558 | .EtwGetTraceEnableFlags, 559 | 560 | // ALPC 561 | .AlpcGetMessageAttribute, 562 | .AlpcInitializeMessageAttribute, 563 | .TpAllocAlpcCompletion, 564 | }, 565 | 566 | .kill = .{ 567 | .DbgBreakPoint, 568 | .DbgPrompt, 569 | .RtlDeregisterWait, 570 | .RtlDeregisterWaitEx, 571 | .RtlDeriveCapabilitySidsFromName, 572 | .RtlDestroyAtomTable, 573 | .RtlDestroyEnvironment, 574 | .RtlDestroyHandleTable, 575 | .RtlDestroyHeap, 576 | .RtlDestroyMemoryBlockLookaside, 577 | .RtlDestroyMemoryZone, 578 | .RtlDestroyQueryDebugBuffer, 579 | .RtlDetectHeapLeaks, 580 | .RtlDetermineDosPathNameType_U, 581 | .RtlDisableThreadProfiling, 582 | .RtlDisownModuleHeapAllocation, 583 | .RtlDllShutdownInProgress, 584 | .RtlDnsHostNameToComputerName, 585 | .RtlDoesFileExists_U, 586 | .RtlDoesNameContainWildCards, 587 | .RtlDosApplyFileIsolationRedirection_Ustr, 588 | .RtlDosLongPathNameToNtPathName_U_WithStatus, 589 | .RtlDosLongPathNameToRelativeNtPathName_U_WithStatus, 590 | .RtlDosPathNameToNtPathName_U, 591 | .RtlDosPathNameToNtPathName_U_WithStatus, 592 | .RtlDosPathNameToRelativeNtPathName_U, 593 | .RtlDosPathNameToRelativeNtPathName_U_WithStatus, 594 | .RtlDosSearchPath_U, 595 | .RtlDosSearchPath_Ustr, 596 | .RtlDowncaseUnicodeChar, 597 | .RtlDowncaseUnicodeString, 598 | .RtlDrainNonVolatileFlush, 599 | .RtlDumpResource, 600 | .RtlDuplicateUnicodeString, 601 | .RtlEmptyAtomTable, 602 | .RtlEnableEarlyCriticalSectionEventCreation, 603 | .RtlEnableThreadProfiling, 604 | .RtlEnclaveCallDispatch, 605 | .RtlEnclaveCallDispatchReturn, 606 | .RtlEncodePointer, 607 | .RtlEncodeRemotePointer, 608 | .RtlEncodeSystemPointer, 609 | .RtlEndEnumerationHashTable, 610 | .RtlEndStrongEnumerationHashTable, 611 | .RtlEndWeakEnumerationHashTable, 612 | .RtlEnterCriticalSection, 613 | .RtlEnterUmsSchedulingMode, 614 | .RtlEnumProcessHeaps, 615 | .RtlEnumerateEntryHashTable, 616 | .RtlEnumerateGenericTable, 617 | .RtlEnumerateGenericTableAvl, 618 | .RtlEnumerateGenericTableLikeADirectory, 619 | .RtlEnumerateGenericTableWithoutSplaying, 620 | .RtlEnumerateGenericTableWithoutSplayingAvl, 621 | .RtlEqualComputerName, 622 | .RtlEqualDomainName, 623 | .RtlEqualLuid, 624 | .RtlEqualPrefixSid, 625 | .RtlEqualSid, 626 | .RtlEqualWnfChangeStamps, 627 | .RtlEraseUnicodeString, 628 | .RtlEthernetAddressToStringA, 629 | .RtlEthernetAddressToStringW, 630 | .RtlEthernetStringToAddressA, 631 | .RtlEthernetStringToAddressW, 632 | .RtlExecuteUmsThread, 633 | .RtlExitUserProcess, 634 | .RtlExitUserThread, 635 | .RtlExpandEnvironmentStrings, 636 | .RtlExpandEnvironmentStrings_U, 637 | .RtlExpandHashTable, 638 | .RtlExtendCorrelationVector, 639 | .RtlExtendMemoryBlockLookaside, 640 | .RtlExtendMemoryZone, 641 | .RtlExtractBitMap, 642 | .RtlFillMemory, 643 | .RtlFillMemoryNonTemporal, 644 | .RtlFillNonVolatileMemory, 645 | .RtlFinalReleaseOutOfProcessMemoryStream, 646 | .RtlFindAceByType, 647 | .RtlFindActivationContextSectionGuid, 648 | .RtlFindActivationContextSectionString, 649 | .RtlFindClearRuns, 650 | .RtlFindClosestEncodableLength, 651 | .RtlFindExportedRoutineByName, 652 | .RtlFindLastBackwardRunClear, 653 | .RtlFindLeastSignificantBit, 654 | .RtlFindLongestRunClear, 655 | .RtlFindMessage, 656 | .RtlFindMostSignificantBit, 657 | .RtlFindNextForwardRunClear, 658 | .RtlFindSetBits, 659 | .RtlFindSetBitsAndClear, 660 | .RtlFindSetBitsAndClearEx, 661 | .RtlFindSetBitsEx, 662 | .RtlFindUnicodeSubstring, 663 | .RtlFirstEntrySList, 664 | .RtlFlsAlloc, 665 | .RtlFlsFree, 666 | .RtlFlsGetValue, 667 | .RtlFlsSetValue, 668 | .RtlFlushHeaps, 669 | .RtlFlushNonVolatileMemory, 670 | .RtlFlushNonVolatileMemoryRanges, 671 | .RtlFlushSecureMemoryCache, 672 | .RtlFormatCurrentUserKeyPath, 673 | .RtlFormatMessage, 674 | .RtlFormatMessageEx, 675 | .RtlFreeActivationContextStack, 676 | .RtlFreeAnsiString, 677 | .RtlFreeHandle, 678 | .RtlFreeMemoryBlockLookaside, 679 | .RtlFreeNonVolatileToken, 680 | .RtlFreeOemString, 681 | .RtlFreeThreadActivationContextStack, 682 | .RtlFreeUTF8String, 683 | .RtlFreeUserFiberShadowStack, 684 | .RtlFreeUserStack, 685 | .RtlGUIDFromString, 686 | .RtlGenerate8dot3Name, 687 | .RtlGetActiveActivationContext, 688 | .RtlGetActiveConsoleId, 689 | .RtlGetAppContainerNamedObjectPath, 690 | .RtlGetAppContainerParent, 691 | .RtlGetAppContainerSidType, 692 | .RtlGetCallersAddress, 693 | .RtlGetCompressionWorkSpaceSize, 694 | .RtlGetConsoleSessionForegroundProcessId, 695 | .RtlGetControlSecurityDescriptor, 696 | .RtlGetCriticalSectionRecursionCount, 697 | .RtlGetCurrentDirectory_U, 698 | .RtlGetCurrentPeb, 699 | .RtlGetCurrentProcessorNumber, 700 | .RtlGetCurrentProcessorNumberEx, 701 | .RtlGetCurrentServiceSessionId, 702 | .RtlGetCurrentTransaction, 703 | .RtlGetCurrentUmsThread, 704 | .RtlGetDaclSecurityDescriptor, 705 | .RtlGetDeviceFamilyInfoEnum, 706 | .RtlGetElementGenericTable, 707 | .RtlGetElementGenericTableAvl, 708 | .RtlGetEnabledExtendedFeatures, 709 | .RtlGetExePath, 710 | .RtlGetExtendedContextLength, 711 | .RtlGetExtendedContextLength2, 712 | .RtlGetExtendedFeaturesMask, 713 | .RtlGetFileMUIPath, 714 | .RtlGetFrame, 715 | .RtlGetFullPathName_U, 716 | .RtlGetFullPathName_UEx, 717 | .RtlGetFullPathName_UstrEx, 718 | .RtlGetFunctionTableListHead, 719 | .RtlGetGroupSecurityDescriptor, 720 | .RtlGetIntegerAtom, 721 | .RtlGetInterruptTimePrecise, 722 | .RtlGetLastNtStatus, 723 | .RtlGetLastWin32Error, 724 | .RtlGetLengthWithoutLastFullDosOrNtPathElement, 725 | .RtlGetLengthWithoutTrailingPathSeperators, 726 | .RtlGetLocaleFileMappingAddress, 727 | .RtlGetLongestNtPathLength, 728 | .RtlGetMultiTimePrecise, 729 | .RtlGetNativeSystemInformation, 730 | .RtlGetNextEntryHashTable, 731 | .RtlGetNextUmsListItem, 732 | .RtlGetNonVolatileToken, 733 | .RtlGetNtGlobalFlags, 734 | .RtlGetNtProductType, 735 | .RtlGetNtSystemRoot, 736 | .RtlGetNtVersionNumbers, 737 | .RtlGetOwnerSecurityDescriptor, 738 | .RtlGetParentLocaleName, 739 | .RtlGetPersistedStateLocation, 740 | .RtlGetProcessHeaps, 741 | .RtlGetProcessPreferredUILanguages, 742 | .RtlGetProductInfo, 743 | .RtlGetReturnAddressHijackTarget, 744 | .RtlGetSaclSecurityDescriptor, 745 | .RtlGetSearchPath, 746 | .RtlGetSecurityDescriptorRMControl, 747 | .RtlGetSessionProperties, 748 | .RtlGetSetBootStatusData, 749 | .RtlGetSuiteMask, 750 | .RtlGetSystemBootStatus, 751 | .RtlGetSystemBootStatusEx, 752 | .RtlGetSystemPreferredUILanguages, 753 | .RtlGetSystemTimeAndBias, 754 | .RtlGetSystemTimePrecise, 755 | .RtlGetThreadErrorMode, 756 | .RtlGetThreadLangIdByIndex, 757 | .RtlGetThreadPreferredUILanguages, 758 | .RtlGetThreadWorkOnBehalfTicket, 759 | .RtlGetTokenNamedObjectPath, 760 | .RtlGetUILanguageInfo, 761 | .RtlGetUmsCompletionListEvent, 762 | .RtlGetUnloadEventTrace, 763 | .RtlGetUnloadEventTraceEx, 764 | .RtlGetUserInfoHeap, 765 | .RtlGetUserPreferredUILanguages, 766 | .RtlGetVersion, 767 | .RtlGrowFunctionTable, 768 | .RtlGuardCheckLongJumpTarget, 769 | .RtlHashUnicodeString, 770 | .RtlHeapTrkInitialize, 771 | .RtlIdentifierAuthoritySid, 772 | .RtlIdnToAscii, 773 | .RtlIdnToNameprepUnicode, 774 | .RtlIdnToUnicode, 775 | .RtlImageDirectoryEntryToData, 776 | .RtlImageNtHeader, 777 | .RtlImageNtHeaderEx, 778 | .RtlImageRvaToSection, 779 | .RtlImageRvaToVa, 780 | .RtlImpersonateSelf, 781 | .RtlImpersonateSelfEx, 782 | .RtlIncrementCorrelationVector, 783 | .RtlInitAnsiStringEx, 784 | .RtlInitBarrier, 785 | .RtlInitCodePageTable, 786 | .RtlInitEnumerationHashTable, 787 | .RtlInitMemoryStream, 788 | .RtlInitNlsTables, 789 | .RtlInitOutOfProcessMemoryStream, 790 | .RtlInitString, 791 | .RtlInitStringEx, 792 | .RtlInitStrongEnumerationHashTable, 793 | .RtlInitUTF8String, 794 | .RtlInitUTF8StringEx, 795 | .RtlInitUnicodeString, 796 | .RtlInitUnicodeStringEx, 797 | .RtlInitWeakEnumerationHashTable, 798 | .RtlInitializeAtomPackage, 799 | .RtlInitializeConditionVariable, 800 | .RtlInitializeContext, 801 | .RtlInitializeCorrelationVector, 802 | .RtlInitializeCriticalSection, 803 | .RtlInitializeCriticalSectionAndSpinCount, 804 | .RtlInitializeCriticalSectionEx, 805 | .RtlInitializeExtendedContext, 806 | .RtlInitializeExtendedContext2, 807 | .RtlInitializeGenericTable, 808 | .RtlInitializeGenericTableAvl, 809 | .RtlInitializeHandleTable, 810 | .RtlInitializeNtUserPfn, 811 | .RtlInitializeRXact, 812 | .RtlInitializeResource, 813 | .RtlInitializeSListHead, 814 | .RtlInitializeSid, 815 | .RtlInitializeSidEx, 816 | .RtlInsertElementGenericTable, 817 | .RtlInsertElementGenericTableAvl, 818 | .RtlInsertElementGenericTableFull, 819 | .RtlInsertElementGenericTableFullAvl, 820 | .RtlInsertEntryHashTable, 821 | .RtlInstallFunctionTableCallback, 822 | .RtlInt64ToUnicodeString, 823 | .RtlIntegerToChar, 824 | .RtlIntegerToUnicodeString, 825 | .RtlInterlockedClearBitRun, 826 | .RtlInterlockedFlushSList, 827 | .RtlInterlockedPopEntrySList, 828 | .RtlInterlockedPushEntrySList, 829 | .RtlInterlockedPushListSList, 830 | .RtlInterlockedPushListSListEx, 831 | .RtlInterlockedSetBitRun, 832 | .RtlIoDecodeMemIoResource, 833 | .RtlIoEncodeMemIoResource, 834 | .RtlIpv4AddressToStringA, 835 | .RtlIpv4AddressToStringExA, 836 | .RtlIpv4AddressToStringExW, 837 | .RtlIpv4AddressToStringW, 838 | .RtlIpv4StringToAddressA, 839 | .RtlIpv4StringToAddressExA, 840 | .RtlIpv4StringToAddressExW, 841 | .RtlIpv4StringToAddressW, 842 | .RtlIpv6AddressToStringA, 843 | .RtlIpv6AddressToStringExA, 844 | .RtlIpv6AddressToStringExW, 845 | .RtlIpv6AddressToStringW, 846 | .RtlIpv6StringToAddressA, 847 | .RtlIpv6StringToAddressExA, 848 | .RtlIpv6StringToAddressExW, 849 | .RtlIpv6StringToAddressW, 850 | .RtlIsActivationContextActive, 851 | .RtlIsCapabilitySid, 852 | .RtlIsCloudFilesPlaceholder, 853 | .RtlIsCriticalSectionLocked, 854 | .RtlIsCriticalSectionLockedByThread, 855 | .RtlIsCurrentProcess, 856 | .RtlIsCurrentThread, 857 | .RtlIsCurrentThreadAttachExempt, 858 | .RtlIsDosDeviceName_U, 859 | .RtlIsElevatedRid, 860 | .RtlIsGenericTableEmpty, 861 | .RtlIsGenericTableEmptyAvl, 862 | .RtlIsMultiSessionSku, 863 | .RtlIsMultiUsersInSessionSku, 864 | .RtlIsNameInExpression, 865 | .RtlIsNameInUnUpcasedExpression, 866 | .RtlIsNameLegalDOS8Dot3, 867 | .RtlIsNonEmptyDirectoryReparsePointAllowed, 868 | .RtlIsNormalizedString, 869 | .RtlIsPackageSid, 870 | .RtlIsParentOfChildAppContainer, 871 | .RtlIsPartialPlaceholder, 872 | .RtlIsPartialPlaceholderFileHandle, 873 | .RtlIsPartialPlaceholderFileInfo, 874 | .RtlIsProcessorFeaturePresent, 875 | .RtlIsStateSeparationEnabled, 876 | .RtlIsTextUnicode, 877 | .RtlIsThreadWithinLoaderCallout, 878 | .RtlIsUntrustedObject, 879 | .RtlIsValidHandle, 880 | .RtlIsValidIndexHandle, 881 | .RtlIsValidLocaleName, 882 | .RtlIsZeroMemory, 883 | .RtlKnownExceptionFilter, 884 | .RtlLCIDToCultureName, 885 | .RtlLargeIntegerToChar, 886 | .RtlLcidToLocaleName, 887 | .RtlLeaveCriticalSection, 888 | .RtlLengthRequiredSid, 889 | .RtlLengthSecurityDescriptor, 890 | .RtlLoadString, 891 | .RtlLocalTimeToSystemTime, 892 | .RtlLocaleNameToLcid, 893 | .RtlLocateExtendedFeature, 894 | .RtlLocateExtendedFeature2, 895 | .RtlLocateLegacyContext, 896 | .RtlLockBootStatusData, 897 | .RtlLockCurrentThread, 898 | .RtlLockHeap, 899 | .RtlLockMemoryBlockLookaside, 900 | .RtlLockMemoryStreamRegion, 901 | .RtlLockMemoryZone, 902 | .RtlLockModuleSection, 903 | .RtlLogStackBackTrace, 904 | .RtlLookupAtomInAtomTable, 905 | .RtlLookupElementGenericTable, 906 | .RtlLookupElementGenericTableAvl, 907 | .RtlLookupElementGenericTableFull, 908 | .RtlLookupElementGenericTableFullAvl, 909 | .RtlLookupEntryHashTable, 910 | .RtlLookupFirstMatchingElementGenericTableAvl, 911 | .RtlLookupFunctionEntry, 912 | .RtlLookupFunctionTable, 913 | .RtlMakeSelfRelativeSD, 914 | .RtlMapGenericMask, 915 | .RtlMapSecurityErrorToNtStatus, 916 | .RtlMultiAppendUnicodeStringBuffer, 917 | .RtlMultiByteToUnicodeN, 918 | .RtlMultiByteToUnicodeSize, 919 | .RtlMultipleAllocateHeap, 920 | .RtlMultipleFreeHeap, 921 | .RtlNewInstanceSecurityObject, 922 | .RtlNewSecurityGrantedAccess, 923 | .RtlNewSecurityObject, 924 | .RtlNewSecurityObjectEx, 925 | .RtlNewSecurityObjectWithMultipleInheritance, 926 | .RtlNormalizeSecurityDescriptor, 927 | .RtlNormalizeString, 928 | .RtlNotifyFeatureUsage, 929 | .RtlNtPathNameToDosPathName, 930 | .RtlNtStatusToDosError, 931 | .RtlNtStatusToDosErrorNoTeb, 932 | .RtlNtdllName, 933 | .RtlNumberGenericTableElements, 934 | .RtlNumberGenericTableElementsAvl, 935 | .RtlNumberOfSetBitsUlongPtr, 936 | .RtlOemStringToUnicodeSize, 937 | .RtlOemStringToUnicodeString, 938 | .RtlOemToUnicodeN, 939 | .RtlOpenCurrentUser, 940 | .RtlOsDeploymentState, 941 | .RtlOwnerAcesPresent, 942 | .RtlPcToFileHeader, 943 | .RtlPinAtomInAtomTable, 944 | .RtlPopFrame, 945 | .RtlPrepareForProcessCloning, 946 | .RtlProcessFlsData, 947 | .RtlProtectHeap, 948 | .RtlPublishWnfStateData, 949 | .RtlPushFrame, 950 | .RtlQueryActivationContextApplicationSettings, 951 | .RtlQueryAllFeatureConfigurations, 952 | .RtlQueryAtomInAtomTable, 953 | .RtlQueryCriticalSectionOwner, 954 | .RtlQueryDepthSList, 955 | .RtlQueryDynamicTimeZoneInformation, 956 | .RtlQueryElevationFlags, 957 | .RtlQueryEnvironmentVariable, 958 | .RtlQueryEnvironmentVariable_U, 959 | .RtlQueryFeatureConfiguration, 960 | .RtlQueryFeatureConfigurationChangeStamp, 961 | .RtlQueryFeatureUsageNotificationSubscriptions, 962 | .RtlQueryHeapInformation, 963 | .RtlQueryImageMitigationPolicy, 964 | .RtlQueryInformationAcl, 965 | .RtlQueryInformationActivationContext, 966 | .RtlQueryInformationActiveActivationContext, 967 | .RtlQueryInterfaceMemoryStream, 968 | .RtlQueryModuleInformation, 969 | .RtlQueryPackageClaims, 970 | .RtlQueryPackageIdentity, 971 | .RtlQueryPackageIdentityEx, 972 | .RtlQueryPerformanceCounter, 973 | .RtlQueryPerformanceFrequency, 974 | .RtlQueryProcessBackTraceInformation, 975 | .RtlQueryProcessDebugInformation, 976 | .RtlQueryProcessHeapInformation, 977 | .RtlQueryProcessLockInformation, 978 | .RtlQueryProcessPlaceholderCompatibilityMode, 979 | .RtlQueryProtectedPolicy, 980 | .RtlQueryRegistryValueWithFallback, 981 | .RtlQueryRegistryValues, 982 | .RtlQueryRegistryValuesEx, 983 | .RtlQueryResourcePolicy, 984 | .RtlQuerySecurityObject, 985 | .RtlQueryTagHeap, 986 | .RtlQueryThreadPlaceholderCompatibilityMode, 987 | .RtlQueryThreadProfiling, 988 | .RtlQueryTimeZoneInformation, 989 | .RtlQueryTokenHostIdAsUlong64, 990 | .RtlQueryUmsThreadInformation, 991 | .RtlQueryUnbiasedInterruptTime, 992 | .RtlQueryValidationRunlevel, 993 | .RtlQueryWnfMetaNotification, 994 | .RtlQueryWnfStateData, 995 | .RtlQueryWnfStateDataWithExplicitScope, 996 | .RtlQueueApcWow64Thread, 997 | .RtlQueueWorkItem, 998 | .RtlRaiseCustomSystemEventTrigger, 999 | .RtlRaiseException, 1000 | .RtlRaiseExceptionForReturnAddressHijack, 1001 | .RtlRaiseNoncontinuableException, 1002 | .RtlRaiseStatus, 1003 | .RtlRandom, 1004 | .RtlRbInsertNodeEx, 1005 | .RtlRbRemoveNode, 1006 | .RtlReAllocateHeap, 1007 | .RtlReadMemoryStream, 1008 | .RtlReadOutOfProcessMemoryStream, 1009 | .RtlReadThreadProfilingData, 1010 | .RtlRealPredecessor, 1011 | .RtlRealSuccessor, 1012 | .RtlRegisterFeatureConfigurationChangeNotification, 1013 | .RtlRegisterForWnfMetaNotification, 1014 | .RtlRegisterSecureMemoryCacheCallback, 1015 | .RtlRegisterThreadWithCsrss, 1016 | .RtlRegisterWait, 1017 | .RtlReleaseActivationContext, 1018 | .RtlReleaseMemoryStream, 1019 | .RtlReleasePath, 1020 | .RtlReleasePebLock, 1021 | .RtlReleasePrivilege, 1022 | .RtlReleaseRelativeName, 1023 | .RtlReleaseResource, 1024 | .RtlReleaseSRWLockExclusive, 1025 | .RtlRemoteCall, 1026 | .RtlRemoveEntryHashTable, 1027 | .RtlRemovePrivileges, 1028 | .RtlRemoveVectoredContinueHandler, 1029 | .RtlRemoveVectoredExceptionHandler, 1030 | .RtlReplaceSidInSd, 1031 | .RtlReplaceSystemDirectoryInPath, 1032 | .RtlReportException, 1033 | .RtlReportExceptionEx, 1034 | .RtlReportSilentProcessExit, 1035 | .RtlReportSqmEscalation, 1036 | .RtlResetMemoryBlockLookaside, 1037 | .RtlResetMemoryZone, 1038 | .RtlResetNtUserPfn, 1039 | .RtlResetRtlTranslations, 1040 | .RtlRestoreBootStatusDefaults, 1041 | .RtlRestoreContext, 1042 | .RtlRestoreLastWin32Error, 1043 | .RtlRestoreSystemBootStatusDefaults, 1044 | .RtlRestoreThreadPreferredUILanguages, 1045 | .RtlRetrieveNtUserPfn, 1046 | .RtlRevertMemoryStream, 1047 | .RtlRunDecodeUnicodeString, 1048 | .RtlRunEncodeUnicodeString, 1049 | .RtlRunOnceBeginInitialize, 1050 | .RtlRunOnceComplete, 1051 | .RtlRunOnceExecuteOnce, 1052 | .RtlRunOnceInitialize, 1053 | .RtlSeekMemoryStream, 1054 | .RtlSelfRelativeToAbsoluteSD, 1055 | .RtlSelfRelativeToAbsoluteSD2, 1056 | .RtlSetAttributesSecurityDescriptor, 1057 | .RtlSetControlSecurityDescriptor, 1058 | .RtlSetCriticalSectionSpinCount, 1059 | .RtlSetCurrentDirectory_U, 1060 | .RtlSetCurrentTransaction, 1061 | .RtlSetDynamicTimeZoneInformation, 1062 | .RtlSetEnvironmentStrings, 1063 | .RtlSetEnvironmentVar, 1064 | .RtlSetEnvironmentVariable, 1065 | .RtlSetExtendedFeaturesMask, 1066 | .RtlSetFeatureConfigurations, 1067 | .RtlSetGroupSecurityDescriptor, 1068 | .RtlSetHeapInformation, 1069 | .RtlSetImageMitigationPolicy, 1070 | .RtlSetInformationAcl, 1071 | .RtlSetIoCompletionCallback, 1072 | .RtlSetLastWin32Error, 1073 | .RtlSetLastWin32ErrorAndNtStatusFromNtStatus, 1074 | .RtlSetMemoryStreamSize, 1075 | .RtlSetPortableOperatingSystem, 1076 | .RtlSetProcessDebugInformation, 1077 | .RtlSetProcessIsCritical, 1078 | .RtlSetProcessPlaceholderCompatibilityMode, 1079 | .RtlSetProcessPreferredUILanguages, 1080 | .RtlSetProtectedPolicy, 1081 | .RtlSetProxiedProcessId, 1082 | .RtlSetSearchPathMode, 1083 | .RtlSetSecurityDescriptorRMControl, 1084 | .RtlSetSecurityObject, 1085 | .RtlSetSecurityObjectEx, 1086 | .RtlSetSystemBootStatus, 1087 | .RtlSetSystemBootStatusEx, 1088 | .RtlSetThreadErrorMode, 1089 | .RtlSetThreadIsCritical, 1090 | .RtlSetThreadPlaceholderCompatibilityMode, 1091 | .RtlSetThreadPoolStartFunc, 1092 | .RtlSetThreadPreferredUILanguages, 1093 | .RtlSetThreadPreferredUILanguages2, 1094 | .RtlSetThreadSubProcessTag, 1095 | .RtlSetThreadWorkOnBehalfTicket, 1096 | .RtlSetTimeZoneInformation, 1097 | .RtlSetTimer, 1098 | .RtlSetUmsThreadInformation, 1099 | .RtlSetUnhandledExceptionFilter, 1100 | .RtlSetUserFlagsHeap, 1101 | .RtlSetUserValueHeap, 1102 | .RtlSidDominates, 1103 | .RtlSidDominatesForTrust, 1104 | .RtlSidEqualLevel, 1105 | .RtlSidHashInitialize, 1106 | .RtlSidHashLookup, 1107 | .RtlSidIsHigherLevel, 1108 | .RtlSizeHeap, 1109 | .RtlSleepConditionVariableCS, 1110 | .RtlSleepConditionVariableSRW, 1111 | .RtlSplay, 1112 | .RtlStartRXact, 1113 | .RtlStatMemoryStream, 1114 | .RtlStringFromGUID, 1115 | .RtlStringFromGUIDEx, 1116 | .RtlStronglyEnumerateEntryHashTable, 1117 | .RtlSubAuthorityCountSid, 1118 | .RtlSubAuthoritySid, 1119 | .RtlSubscribeForFeatureUsageNotification, 1120 | .RtlSubscribeWnfStateChangeNotification, 1121 | .RtlSubtreePredecessor, 1122 | .RtlSubtreeSuccessor, 1123 | .RtlSwitchedVVI, 1124 | .RtlSystemTimeToLocalTime, 1125 | .RtlTestAndPublishWnfStateData, 1126 | .RtlTestBit, 1127 | .RtlTestBitEx, 1128 | .RtlTestProtectedAccess, 1129 | .RtlTraceDatabaseAdd, 1130 | .RtlTraceDatabaseCreate, 1131 | .RtlTraceDatabaseDestroy, 1132 | .RtlTraceDatabaseEnumerate, 1133 | .RtlTraceDatabaseFind, 1134 | .RtlTraceDatabaseLock, 1135 | .RtlTraceDatabaseUnlock, 1136 | .RtlTraceDatabaseValidate, 1137 | .RtlTryAcquirePebLock, 1138 | .RtlTryAcquireSRWLockExclusive, 1139 | .RtlTryAcquireSRWLockShared, 1140 | .RtlTryConvertSRWLockSharedToExclusiveOrRelease, 1141 | .RtlTryEnterCriticalSection, 1142 | .RtlUTF8StringToUnicodeString, 1143 | .RtlUdiv128, 1144 | .RtlUmsThreadYield, 1145 | .RtlUnicodeStringToCountedOemString, 1146 | .RtlUnicodeStringToOemSize, 1147 | .RtlUnicodeStringToOemString, 1148 | .RtlUnicodeToCustomCPN, 1149 | .RtlUnicodeToMultiByteN, 1150 | .RtlUnicodeToMultiByteSize, 1151 | .RtlUnicodeToOemN, 1152 | .RtlUnicodeToUTF8N, 1153 | .RtlUniform, 1154 | .RtlUnlockBootStatusData, 1155 | .RtlUnlockCurrentThread, 1156 | .RtlUnlockHeap, 1157 | .RtlUnlockMemoryBlockLookaside, 1158 | .RtlUnlockMemoryStreamRegion, 1159 | .RtlUnlockMemoryZone, 1160 | .RtlUnlockModuleSection, 1161 | .RtlUnregisterFeatureConfigurationChangeNotification, 1162 | .RtlUnsubscribeFromFeatureUsageNotifications, 1163 | .RtlUnsubscribeWnfNotificationWaitForCompletion, 1164 | .RtlUnsubscribeWnfNotificationWithCompletionCallback, 1165 | .RtlUnsubscribeWnfStateChangeNotification, 1166 | .RtlUnwind, 1167 | .RtlUnwindEx, 1168 | .RtlUpcaseUnicodeString, 1169 | .RtlUpcaseUnicodeStringToAnsiString, 1170 | .RtlUpcaseUnicodeStringToCountedOemString, 1171 | .RtlUpcaseUnicodeStringToOemString, 1172 | .RtlUpcaseUnicodeToCustomCPN, 1173 | .RtlUpcaseUnicodeToMultiByteN, 1174 | .RtlUpcaseUnicodeToOemN, 1175 | .RtlUpdateClonedCriticalSection, 1176 | .RtlUpdateClonedSRWLock, 1177 | .RtlUpdateTimer, 1178 | .RtlUpperChar, 1179 | .RtlUpperString, 1180 | .RtlUserFiberStart, 1181 | .RtlUserThreadStart, 1182 | .RtlValidProcessProtection, 1183 | .RtlValidateCorrelationVector, 1184 | .RtlValidateHeap, 1185 | .RtlValidateProcessHeaps, 1186 | .RtlValidateUnicodeString, 1187 | .RtlVerifyVersionInfo, 1188 | .RtlVirtualUnwind, 1189 | .RtlWaitForWnfMetaNotification, 1190 | .RtlWaitOnAddress, 1191 | .RtlWakeAddressAll, 1192 | .RtlWakeAddressAllNoFence, 1193 | .RtlWakeAddressSingle, 1194 | .RtlWakeAddressSingleNoFence, 1195 | .RtlWakeConditionVariable, 1196 | .RtlWalkFrameChain, 1197 | .RtlWalkHeap, 1198 | .RtlWeaklyEnumerateEntryHashTable, 1199 | .RtlWerpReportException, 1200 | .RtlWnfCompareChangeStamp, 1201 | .RtlWnfDllUnloadCallback, 1202 | .RtlWow64CallFunction64, 1203 | .RtlWow64EnableFsRedirection, 1204 | .RtlWow64EnableFsRedirectionEx, 1205 | .RtlWow64GetCpuAreaInfo, 1206 | .RtlWow64GetCurrentCpuArea, 1207 | .RtlWow64GetCurrentMachine, 1208 | .RtlWow64GetEquivalentMachineCHPE, 1209 | .RtlWow64GetProcessMachines, 1210 | .RtlWow64GetSharedInfoProcess, 1211 | .RtlWow64GetThreadContext, 1212 | .RtlWow64GetThreadSelectorEntry, 1213 | .RtlWow64IsWowGuestMachineSupported, 1214 | .RtlWow64LogMessageInEventLogger, 1215 | .RtlWow64PopAllCrossProcessWorkFromWorkList, 1216 | .RtlWow64PopCrossProcessWorkFromFreeList, 1217 | .RtlWow64PushCrossProcessWorkOntoFreeList, 1218 | .RtlWow64PushCrossProcessWorkOntoWorkList, 1219 | .RtlWow64RequestCrossProcessHeavyFlush, 1220 | .RtlWow64SetThreadContext, 1221 | .RtlWow64SuspendProcess, 1222 | .RtlWow64SuspendThread, 1223 | .RtlWriteMemoryStream, 1224 | .RtlWriteNonVolatileMemory, 1225 | .RtlZeroHeap, 1226 | .RtlZeroMemory, 1227 | .RtlZombifyActivationContext, 1228 | .RtlpApplyLengthFunction, 1229 | .RtlpCheckDynamicTimeZoneInformation, 1230 | .RtlpCleanupRegistryKeys, 1231 | .RtlpConvertAbsoluteToRelativeSecurityAttribute, 1232 | .RtlpConvertCultureNamesToLCIDs, 1233 | .RtlpConvertLCIDsToCultureNames, 1234 | .RtlpConvertRelativeToAbsoluteSecurityAttribute, 1235 | .RtlpCreateProcessRegistryInfo, 1236 | .RtlpEnsureBufferSize, 1237 | .RtlpExecuteUmsThread, 1238 | .RtlpFreezeTimeBias, 1239 | .RtlpGetDeviceFamilyInfoEnum, 1240 | .RtlpGetLCIDFromLangInfoNode, 1241 | .RtlpGetNameFromLangInfoNode, 1242 | .RtlpGetSystemDefaultUILanguage, 1243 | .RtlpGetUserOrMachineUILanguage4NLS, 1244 | .RtlpInitializeLangRegistryInfo, 1245 | .RtlpIsQualifiedLanguage, 1246 | .RtlpLoadMachineUIByPolicy, 1247 | .RtlpLoadUserUIByPolicy, 1248 | .RtlpMergeSecurityAttributeInformation, 1249 | .RtlpMuiFreeLangRegistryInfo, 1250 | .RtlpMuiRegCreateRegistryInfo, 1251 | .RtlpMuiRegFreeRegistryInfo, 1252 | .RtlpMuiRegLoadRegistryInfo, 1253 | .RtlpNotOwnerCriticalSection, 1254 | .RtlpNtCreateKey, 1255 | .RtlpNtEnumerateSubKey, 1256 | .RtlpNtMakeTemporaryKey, 1257 | .RtlpNtOpenKey, 1258 | .RtlpNtQueryValueKey, 1259 | .RtlpNtSetValueKey, 1260 | .RtlpQueryDefaultUILanguage, 1261 | .RtlpQueryProcessDebugInformationFromWow64, 1262 | .RtlpQueryProcessDebugInformationRemote, 1263 | .RtlpRefreshCachedUILanguage, 1264 | .RtlpSetInstallLanguage, 1265 | .RtlpSetPreferredUILanguages, 1266 | .RtlpSetUserPreferredUILanguages, 1267 | .RtlpTimeFieldsToTime, 1268 | .RtlpTimeToTimeFields, 1269 | .RtlpUmsExecuteYieldThreadEnd, 1270 | .RtlpUmsThreadYield, 1271 | .RtlpUnWaitCriticalSection, 1272 | .RtlpVerifyAndCommitUILanguageSettings, 1273 | .RtlpWaitForCriticalSection, 1274 | .RtlpWow64CtxFromAmd64, 1275 | .RtlpWow64GetContextOnAmd64, 1276 | .RtlpWow64SetContextOnAmd64, 1277 | .RtlxAnsiStringToUnicodeSize, 1278 | .RtlxOemStringToUnicodeSize, 1279 | .RtlxUnicodeStringToAnsiSize, 1280 | .RtlxUnicodeStringToOemSize, 1281 | .SbExecuteProcedure, 1282 | .SbSelectProcedure, 1283 | .ShipAssert, 1284 | .ShipAssertGetBufferInfo, 1285 | .ShipAssertMsgA, 1286 | .ShipAssertMsgW, 1287 | .TpAllocAlpcCompletionEx, 1288 | .TpAllocCleanupGroup, 1289 | .TpAllocIoCompletion, 1290 | .TpAllocJobNotification, 1291 | .TpAllocPool, 1292 | .TpAllocTimer, 1293 | .TpAllocWait, 1294 | .TpAllocWork, 1295 | .TpAlpcRegisterCompletionList, 1296 | .TpAlpcUnregisterCompletionList, 1297 | .TpCallbackDetectedUnrecoverableError, 1298 | .TpCallbackIndependent, 1299 | .TpCallbackLeaveCriticalSectionOnCompletion, 1300 | .TpCallbackMayRunLong, 1301 | .TpCallbackReleaseMutexOnCompletion, 1302 | .TpCallbackReleaseSemaphoreOnCompletion, 1303 | .TpCallbackSendAlpcMessageOnCompletion, 1304 | .TpCallbackSendPendingAlpcMessage, 1305 | .TpCallbackSetEventOnCompletion, 1306 | .TpCallbackUnloadDllOnCompletion, 1307 | .TpCancelAsyncIoOperation, 1308 | .TpCaptureCaller, 1309 | .TpCheckTerminateWorker, 1310 | .TpDbgDumpHeapUsage, 1311 | .TpDbgSetLogRoutine, 1312 | .TpDisablePoolCallbackChecks, 1313 | .TpDisassociateCallback, 1314 | .TpIsTimerSet, 1315 | .TpPostWork, 1316 | .TpQueryPoolStackInformation, 1317 | .TpReleaseAlpcCompletion, 1318 | .TpReleaseCleanupGroup, 1319 | .TpReleaseCleanupGroupMembers, 1320 | .TpReleaseIoCompletion, 1321 | .TpReleaseJobNotification, 1322 | .TpReleasePool, 1323 | .TpReleaseTimer, 1324 | .TpReleaseWait, 1325 | .TpReleaseWork, 1326 | .TpSetDefaultPoolMaxThreads, 1327 | .TpSetDefaultPoolStackInformation, 1328 | .TpSetPoolMaxThreads, 1329 | .TpSetPoolMaxThreadsSoftLimit, 1330 | .TpSetPoolMinThreads, 1331 | .TpSetPoolStackInformation, 1332 | .TpSetPoolThreadBasePriority, 1333 | .TpSetPoolThreadCpuSets, 1334 | .TpSetPoolWorkerThreadIdleTimeout, 1335 | .TpSetTimer, 1336 | .TpSetTimerEx, 1337 | .TpSetWait, 1338 | .TpSetWaitEx, 1339 | .TpSimpleTryPost, 1340 | .TpStartAsyncIoOperation, 1341 | .TpTimerOutstandingCallbackCount, 1342 | .TpTrimPools, 1343 | .TpWaitForAlpcCompletion, 1344 | .TpWaitForIoCompletion, 1345 | .TpWaitForJobNotification, 1346 | .TpWaitForTimer, 1347 | .TpWaitForWait, 1348 | .TpWaitForWork, 1349 | .VerSetConditionMask, 1350 | .WerReportExceptionWorker, 1351 | .WerReportSQMEvent, 1352 | .WinSqmAddToAverageDWORD, 1353 | .WinSqmAddToStream, 1354 | .WinSqmAddToStreamEx, 1355 | .WinSqmCheckEscalationAddToStreamEx, 1356 | .WinSqmCheckEscalationSetDWORD, 1357 | .WinSqmCheckEscalationSetDWORD64, 1358 | .WinSqmCheckEscalationSetString, 1359 | .WinSqmCommonDatapointDelete, 1360 | .WinSqmCommonDatapointSetDWORD, 1361 | .WinSqmCommonDatapointSetDWORD64, 1362 | .WinSqmCommonDatapointSetStreamEx, 1363 | .WinSqmCommonDatapointSetString, 1364 | .WinSqmEndSession, 1365 | .WinSqmEventEnabled, 1366 | .WinSqmEventWrite, 1367 | .WinSqmGetEscalationRuleStatus, 1368 | .WinSqmGetInstrumentationProperty, 1369 | .WinSqmIncrementDWORD, 1370 | .WinSqmIsOptedIn, 1371 | .WinSqmIsOptedInEx, 1372 | .WinSqmIsSessionDisabled, 1373 | .WinSqmSetDWORD, 1374 | .WinSqmSetDWORD64, 1375 | .WinSqmSetEscalationInfo, 1376 | .WinSqmSetIfMaxDWORD, 1377 | .WinSqmSetIfMinDWORD, 1378 | .WinSqmSetString, 1379 | .WinSqmStartSession, 1380 | .WinSqmStartSessionForPartner, 1381 | .WinSqmStartSqmOptinListener, 1382 | .longjmp, 1383 | .vDbgPrintEx, 1384 | .vDbgPrintExWithPrefix, 1385 | .NtAcceptConnectPort, 1386 | .NtAccessCheck, 1387 | .NtAccessCheckAndAuditAlarm, 1388 | .NtAccessCheckByType, 1389 | .NtAccessCheckByTypeAndAuditAlarm, 1390 | .NtAccessCheckByTypeResultList, 1391 | .NtAccessCheckByTypeResultListAndAuditAlarm, 1392 | .NtAccessCheckByTypeResultListAndAuditAlarmByHandle, 1393 | .NtAcquireCrossVmMutant, 1394 | .NtAcquireProcessActivityReference, 1395 | .NtAddAtom, 1396 | .NtAddAtomEx, 1397 | .NtAddBootEntry, 1398 | .NtAddDriverEntry, 1399 | .NtAdjustGroupsToken, 1400 | .NtAdjustPrivilegesToken, 1401 | .NtAdjustTokenClaimsAndDeviceGroups, 1402 | .NtAlertResumeThread, 1403 | .NtAlertThread, 1404 | .NtAlertThreadByThreadId, 1405 | .NtAllocateLocallyUniqueId, 1406 | .NtAllocateReserveObject, 1407 | .NtAllocateUserPhysicalPages, 1408 | .NtAllocateUserPhysicalPagesEx, 1409 | .NtAllocateUuids, 1410 | .NtAllocateVirtualMemoryEx, 1411 | .NtAlpcAcceptConnectPort, 1412 | .NtAlpcCancelMessage, 1413 | .NtAlpcConnectPort, 1414 | .NtAlpcConnectPortEx, 1415 | .NtAlpcCreatePortSection, 1416 | .NtAlpcCreateResourceReserve, 1417 | .NtAlpcCreateSectionView, 1418 | .NtAlpcCreateSecurityContext, 1419 | .NtAlpcDeletePortSection, 1420 | .NtAlpcDeleteResourceReserve, 1421 | .NtAlpcDeleteSectionView, 1422 | .NtAlpcDeleteSecurityContext, 1423 | .NtAlpcDisconnectPort, 1424 | .NtAlpcImpersonateClientContainerOfPort, 1425 | .NtAlpcImpersonateClientOfPort, 1426 | .NtAlpcOpenSenderProcess, 1427 | .NtAlpcOpenSenderThread, 1428 | .NtAlpcQueryInformation, 1429 | .NtAlpcQueryInformationMessage, 1430 | .NtAlpcRevokeSecurityContext, 1431 | .NtAlpcSendWaitReceivePort, 1432 | .NtAlpcSetInformation, 1433 | .NtApphelpCacheControl, 1434 | .NtAreMappedFilesTheSame, 1435 | .NtAssignProcessToJobObject, 1436 | .NtAssociateWaitCompletionPacket, 1437 | .NtCallEnclave, 1438 | .NtCallbackReturn, 1439 | .NtCancelIoFile, 1440 | .NtCancelIoFileEx, 1441 | .NtCancelSynchronousIoFile, 1442 | .NtCancelTimer, 1443 | .NtCancelTimer2, 1444 | .NtCancelWaitCompletionPacket, 1445 | .NtClearEvent, 1446 | .NtCloseObjectAuditAlarm, 1447 | .NtCommitComplete, 1448 | .NtCommitEnlistment, 1449 | .NtCommitRegistryTransaction, 1450 | .NtCommitTransaction, 1451 | .NtCompactKeys, 1452 | .NtCompareObjects, 1453 | .NtCompareSigningLevels, 1454 | .NtCompareTokens, 1455 | .NtCompleteConnectPort, 1456 | .NtCompressKey, 1457 | .NtConnectPort, 1458 | .NtContinue, 1459 | .NtContinueEx, 1460 | .NtConvertBetweenAuxiliaryCounterAndPerformanceCounter, 1461 | .NtCreateCrossVmEvent, 1462 | .NtCreateCrossVmMutant, 1463 | .NtCreateDebugObject, 1464 | .NtCreateDirectoryObjectEx, 1465 | .NtCreateEnclave, 1466 | .NtCreateEnlistment, 1467 | .NtCreateEventPair, 1468 | .NtCreateIRTimer, 1469 | .NtCreateIoCompletion, 1470 | .NtCreateJobObject, 1471 | .NtCreateJobSet, 1472 | .NtCreateKeyTransacted, 1473 | .NtCreateKeyedEvent, 1474 | .NtCreateLowBoxToken, 1475 | .NtCreateMailslotFile, 1476 | .NtCreateNamedPipeFile, 1477 | .NtCreatePagingFile, 1478 | .NtCreatePartition, 1479 | .NtCreatePort, 1480 | .NtCreatePrivateNamespace, 1481 | .NtCreateProcess, 1482 | .NtCreateProcessEx, 1483 | .NtCreateProfile, 1484 | .NtCreateProfileEx, 1485 | .NtCreateRegistryTransaction, 1486 | .NtCreateResourceManager, 1487 | .NtCreateSectionEx, 1488 | .NtCreateSemaphore, 1489 | .NtCreateSymbolicLinkObject, 1490 | .NtCreateThread, 1491 | .NtCreateThreadEx, 1492 | .NtCreateTimer, 1493 | .NtCreateTimer2, 1494 | .NtCreateToken, 1495 | .NtCreateTokenEx, 1496 | .NtCreateTransaction, 1497 | .NtCreateTransactionManager, 1498 | .NtCreateUserProcess, 1499 | .NtCreateWaitCompletionPacket, 1500 | .NtCreateWaitablePort, 1501 | .NtCreateWnfStateName, 1502 | .NtCreateWorkerFactory, 1503 | .NtDebugActiveProcess, 1504 | .NtDebugContinue, 1505 | .NtDelayExecution, 1506 | .NtDeleteAtom, 1507 | .NtDeleteBootEntry, 1508 | .NtDeleteDriverEntry, 1509 | .NtDeleteFile, 1510 | .NtDeleteKey, 1511 | .NtDeleteObjectAuditAlarm, 1512 | .NtDeletePrivateNamespace, 1513 | .NtDeleteWnfStateData, 1514 | .NtDeleteWnfStateName, 1515 | .NtDeviceIoControlFile, 1516 | .NtDirectGraphicsCall, 1517 | .NtDisableLastKnownGood, 1518 | .NtDisplayString, 1519 | .NtDrawText, 1520 | .NtDuplicateToken, 1521 | .NtEnableLastKnownGood, 1522 | .NtEnumerateBootEntries, 1523 | .NtEnumerateDriverEntries, 1524 | .NtEnumerateKey, 1525 | .NtEnumerateSystemEnvironmentValuesEx, 1526 | .NtEnumerateTransactionObject, 1527 | .NtEnumerateValueKey, 1528 | .NtExtendSection, 1529 | .NtFilterBootOption, 1530 | .NtFilterToken, 1531 | .NtFilterTokenEx, 1532 | .NtFindAtom, 1533 | .NtFlushBuffersFile, 1534 | .NtFlushBuffersFileEx, 1535 | .NtFlushInstallUILanguage, 1536 | .NtFlushInstructionCache, 1537 | .NtFlushKey, 1538 | .NtFlushProcessWriteBuffers, 1539 | .NtFlushVirtualMemory, 1540 | .NtFlushWriteBuffer, 1541 | .NtFreeUserPhysicalPages, 1542 | .NtFreeVirtualMemory, 1543 | .NtFreezeRegistry, 1544 | .NtFreezeTransactions, 1545 | .NtFsControlFile, 1546 | .NtGetCachedSigningLevel, 1547 | .NtGetCompleteWnfStateSubscription, 1548 | .NtGetContextThread, 1549 | .NtGetCurrentProcessorNumber, 1550 | .NtGetCurrentProcessorNumberEx, 1551 | .NtGetDevicePowerState, 1552 | .NtGetMUIRegistryInfo, 1553 | .NtGetNextProcess, 1554 | .NtGetNextThread, 1555 | .NtGetNlsSectionPtr, 1556 | .NtGetNotificationResourceManager, 1557 | .NtGetWriteWatch, 1558 | .NtImpersonateAnonymousToken, 1559 | .NtImpersonateClientOfPort, 1560 | .NtImpersonateThread, 1561 | .NtInitializeEnclave, 1562 | .NtInitializeNlsFiles, 1563 | .NtInitializeRegistry, 1564 | .NtInitiatePowerAction, 1565 | .NtIsProcessInJob, 1566 | .NtIsSystemResumeAutomatic, 1567 | .NtIsUILanguageComitted, 1568 | .NtListenPort, 1569 | .NtLoadDriver, 1570 | .NtLoadEnclaveData, 1571 | .NtLoadKey, 1572 | .NtLoadKey2, 1573 | .NtLoadKey3, 1574 | .NtLoadKeyEx, 1575 | .NtLockFile, 1576 | .NtLockProductActivationKeys, 1577 | .NtLockRegistryKey, 1578 | .NtLockVirtualMemory, 1579 | .NtMakePermanentObject, 1580 | .NtMakeTemporaryObject, 1581 | .NtManageHotPatch, 1582 | .NtManagePartition, 1583 | .NtMapCMFModule, 1584 | .NtMapUserPhysicalPages, 1585 | .NtMapUserPhysicalPagesScatter, 1586 | .NtMapViewOfSectionEx, 1587 | .NtModifyBootEntry, 1588 | .NtModifyDriverEntry, 1589 | .NtNotifyChangeDirectoryFile, 1590 | .NtNotifyChangeDirectoryFileEx, 1591 | .NtNotifyChangeKey, 1592 | .NtNotifyChangeMultipleKeys, 1593 | .NtNotifyChangeSession, 1594 | .NtOpenEnlistment, 1595 | .NtOpenEventPair, 1596 | .NtOpenIoCompletion, 1597 | .NtOpenJobObject, 1598 | .NtOpenKeyEx, 1599 | .NtOpenKeyTransacted, 1600 | .NtOpenKeyTransactedEx, 1601 | .NtOpenKeyedEvent, 1602 | .NtOpenMutant, 1603 | .NtOpenObjectAuditAlarm, 1604 | .NtOpenPartition, 1605 | .NtOpenPrivateNamespace, 1606 | .NtOpenProcess, 1607 | .NtOpenProcessToken, 1608 | .NtOpenProcessTokenEx, 1609 | .NtOpenRegistryTransaction, 1610 | .NtOpenResourceManager, 1611 | .NtOpenSection, 1612 | .NtOpenSemaphore, 1613 | .NtOpenSession, 1614 | .NtOpenThread, 1615 | .NtOpenThreadToken, 1616 | .NtOpenThreadTokenEx, 1617 | .NtOpenTimer, 1618 | .NtOpenTransaction, 1619 | .NtOpenTransactionManager, 1620 | .NtPlugPlayControl, 1621 | .NtPowerInformation, 1622 | .NtPrePrepareComplete, 1623 | .NtPrePrepareEnlistment, 1624 | .NtPrepareComplete, 1625 | .NtPrepareEnlistment, 1626 | .NtPrivilegeCheck, 1627 | .NtPrivilegeObjectAuditAlarm, 1628 | .NtPrivilegedServiceAuditAlarm, 1629 | .NtPropagationComplete, 1630 | .NtPropagationFailed, 1631 | .NtProtectVirtualMemory, 1632 | .NtPssCaptureVaSpaceBulk, 1633 | .NtPulseEvent, 1634 | .NtQueryAttributesFile, 1635 | .NtQueryAuxiliaryCounterFrequency, 1636 | .NtQueryBootEntryOrder, 1637 | .NtQueryBootOptions, 1638 | .NtQueryDebugFilterState, 1639 | .NtQueryDefaultLocale, 1640 | .NtQueryDefaultUILanguage, 1641 | .NtQueryDirectoryFile, 1642 | .NtQueryDirectoryFileEx, 1643 | .NtQueryDriverEntryOrder, 1644 | .NtQueryEaFile, 1645 | .NtQueryEvent, 1646 | .NtQueryFullAttributesFile, 1647 | .NtQueryInformationAtom, 1648 | .NtQueryInformationByName, 1649 | .NtQueryInformationEnlistment, 1650 | .NtQueryInformationFile, 1651 | .NtQueryInformationPort, 1652 | .NtQueryInformationProcess, 1653 | .NtQueryInformationResourceManager, 1654 | .NtQueryInformationThread, 1655 | .NtQueryInformationToken, 1656 | .NtQueryInformationTransaction, 1657 | .NtQueryInformationTransactionManager, 1658 | .NtQueryInformationWorkerFactory, 1659 | .NtQueryInstallUILanguage, 1660 | .NtQueryIntervalProfile, 1661 | .NtQueryIoCompletion, 1662 | .NtQueryKey, 1663 | .NtQueryLicenseValue, 1664 | .NtQueryMultipleValueKey, 1665 | .NtQueryMutant, 1666 | .NtQueryObject, 1667 | .NtQueryOpenSubKeys, 1668 | .NtQueryOpenSubKeysEx, 1669 | .NtQueryPerformanceCounter, 1670 | .NtQueryPortInformationProcess, 1671 | .NtQueryQuotaInformationFile, 1672 | .NtQuerySection, 1673 | .NtQuerySecurityAttributesToken, 1674 | .NtQuerySecurityObject, 1675 | .NtQuerySecurityPolicy, 1676 | .NtQuerySemaphore, 1677 | .NtQuerySystemEnvironmentValue, 1678 | .NtQuerySystemEnvironmentValueEx, 1679 | .NtQuerySystemInformationEx, 1680 | .NtQuerySystemTime, 1681 | .NtQueryTimer, 1682 | .NtQueryTimerResolution, 1683 | .NtQueryVirtualMemory, 1684 | .NtQueryVolumeInformationFile, 1685 | .NtQueryWnfStateData, 1686 | .NtQueryWnfStateNameInformation, 1687 | .NtQueueApcThread, 1688 | .NtQueueApcThreadEx, 1689 | .NtRaiseException, 1690 | .NtReadFile, 1691 | .NtReadFileScatter, 1692 | .NtReadOnlyEnlistment, 1693 | .NtReadRequestData, 1694 | .NtReadVirtualMemory, 1695 | .NtRecoverEnlistment, 1696 | .NtRecoverResourceManager, 1697 | .NtRecoverTransactionManager, 1698 | .NtRegisterProtocolAddressInformation, 1699 | .NtRegisterThreadTerminatePort, 1700 | .NtReleaseKeyedEvent, 1701 | .NtReleaseMutant, 1702 | .NtReleaseSemaphore, 1703 | .NtReleaseWorkerFactoryWorker, 1704 | .NtRemoveIoCompletion, 1705 | .NtRemoveIoCompletionEx, 1706 | .NtRemoveProcessDebug, 1707 | .NtRenameKey, 1708 | .NtRenameTransactionManager, 1709 | .NtReplaceKey, 1710 | .NtReplacePartitionUnit, 1711 | .NtReplyPort, 1712 | .NtReplyWaitReceivePort, 1713 | .NtReplyWaitReceivePortEx, 1714 | .NtReplyWaitReplyPort, 1715 | .NtRequestPort, 1716 | .NtRequestWaitReplyPort, 1717 | .NtResetEvent, 1718 | .NtResetWriteWatch, 1719 | .NtRestoreKey, 1720 | .NtResumeProcess, 1721 | .NtResumeThread, 1722 | .NtRevertContainerImpersonation, 1723 | .NtRollbackComplete, 1724 | .NtRollbackEnlistment, 1725 | .NtRollbackRegistryTransaction, 1726 | .NtRollbackTransaction, 1727 | .NtRollforwardTransactionManager, 1728 | .NtSaveKey, 1729 | .NtSaveKeyEx, 1730 | .NtSaveMergedKeys, 1731 | .NtSecureConnectPort, 1732 | .NtSerializeBoot, 1733 | .NtSetBootEntryOrder, 1734 | .NtSetBootOptions, 1735 | .NtSetCachedSigningLevel, 1736 | .NtSetCachedSigningLevel2, 1737 | .NtSetContextThread, 1738 | .NtSetDebugFilterState, 1739 | .NtSetDefaultHardErrorPort, 1740 | .NtSetDefaultLocale, 1741 | .NtSetDefaultUILanguage, 1742 | .NtSetDriverEntryOrder, 1743 | .NtSetEaFile, 1744 | .NtSetEvent, 1745 | .NtSetEventBoostPriority, 1746 | .NtSetHighEventPair, 1747 | .NtSetHighWaitLowEventPair, 1748 | .NtSetIRTimer, 1749 | .NtSetInformationDebugObject, 1750 | .NtSetInformationEnlistment, 1751 | .NtSetInformationFile, 1752 | .NtSetInformationJobObject, 1753 | .NtSetInformationKey, 1754 | .NtSetInformationObject, 1755 | .NtSetInformationResourceManager, 1756 | .NtSetInformationSymbolicLink, 1757 | .NtSetInformationThread, 1758 | .NtSetInformationToken, 1759 | .NtSetInformationTransaction, 1760 | .NtSetInformationTransactionManager, 1761 | .NtSetInformationVirtualMemory, 1762 | .NtSetInformationWorkerFactory, 1763 | .NtSetIntervalProfile, 1764 | .NtSetIoCompletion, 1765 | .NtSetIoCompletionEx, 1766 | .NtSetLdtEntries, 1767 | .NtSetLowEventPair, 1768 | .NtSetLowWaitHighEventPair, 1769 | .NtSetQuotaInformationFile, 1770 | .NtSetSecurityObject, 1771 | .NtSetSystemEnvironmentValue, 1772 | .NtSetSystemEnvironmentValueEx, 1773 | .NtSetSystemInformation, 1774 | .NtSetSystemPowerState, 1775 | .NtSetSystemTime, 1776 | .NtSetThreadExecutionState, 1777 | .NtSetTimer, 1778 | .NtSetTimer2, 1779 | .NtSetTimerEx, 1780 | .NtSetTimerResolution, 1781 | .NtSetUuidSeed, 1782 | .NtSetVolumeInformationFile, 1783 | .NtSetWnfProcessNotificationEvent, 1784 | .NtShutdownSystem, 1785 | .NtShutdownWorkerFactory, 1786 | .NtSignalAndWaitForSingleObject, 1787 | .NtSinglePhaseReject, 1788 | .NtStartProfile, 1789 | .NtStopProfile, 1790 | .NtSubscribeWnfStateChange, 1791 | .NtSuspendProcess, 1792 | .NtSuspendThread, 1793 | .NtSystemDebugControl, 1794 | .NtTerminateEnclave, 1795 | .NtTerminateJobObject, 1796 | .NtTerminateThread, 1797 | .NtTestAlert, 1798 | .NtThawRegistry, 1799 | .NtThawTransactions, 1800 | .NtTraceControl, 1801 | .NtTraceEvent, 1802 | .NtTranslateFilePath, 1803 | .NtUmsThreadYield, 1804 | .NtUnloadDriver, 1805 | .NtUnloadKey, 1806 | .NtUnloadKey2, 1807 | .NtUnloadKeyEx, 1808 | .NtUnlockFile, 1809 | .NtUnlockVirtualMemory, 1810 | .NtUnmapViewOfSectionEx, 1811 | .NtUnsubscribeWnfStateChange, 1812 | .NtUpdateWnfStateData, 1813 | .NtVdmControl, 1814 | .NtWaitForAlertByThreadId, 1815 | .NtWaitForDebugEvent, 1816 | .NtWaitForKeyedEvent, 1817 | .NtWaitForMultipleObjects, 1818 | .NtWaitForMultipleObjects32, 1819 | .NtWaitForSingleObject, 1820 | .NtWaitForWorkViaWorkerFactory, 1821 | .NtWaitHighEventPair, 1822 | .NtWaitLowEventPair, 1823 | .NtWorkerFactoryWorkerReady, 1824 | .NtWriteFile, 1825 | .NtWriteFileGather, 1826 | .NtWriteRequestData, 1827 | .NtWriteVirtualMemory, 1828 | .NtYieldExecution, 1829 | 1830 | .RtlGetVersion, 1831 | 1832 | .TpAllocTimer, 1833 | .TpSetTimer, 1834 | 1835 | .EtwEventWrite, // Nt calls 1836 | .EtwEventEnabled, // Nt calls 1837 | .RtlQueryRegistryValuesEx, 1838 | 1839 | .RtlSetEnvironmentVariable, 1840 | .RtlQueryEnvironmentVariable_U, 1841 | .RtlDosSearchPath_U, 1842 | .RtlInterlockedSetBitRun, 1843 | .RtlCreateProcessParametersEx, 1844 | }, 1845 | 1846 | .success_stubs = .{ 1847 | .RtlDeleteRegistryValue, 1848 | .RtlSetCurrentEnvironment, 1849 | }, 1850 | }, 1851 | }; 1852 | 1853 | comptime { 1854 | // Verify symbols don't have duplicates 1855 | for(@typeInfo(@TypeOf(symbols)).Struct.fields) |dll_field| { 1856 | const dll_name = dll_field.name; 1857 | const dll_value = @field(symbols, dll_name); 1858 | var dll_symbols: []const []const u8 = &[_][]const u8 {}; 1859 | 1860 | @setEvalBranchQuota(5 * @typeInfo(@TypeOf(dll_value.hooks)).Struct.fields.len); 1861 | for(@typeInfo(@TypeOf(dll_value.hooks)).Struct.fields) |hook_field| { 1862 | dll_symbols = dll_symbols ++ &[1][]const u8{hook_field.name}; 1863 | } 1864 | 1865 | @setEvalBranchQuota(5 * dll_value.real.len); 1866 | for(dll_value.real) |real_symbol| { 1867 | dll_symbols = dll_symbols ++ &[1][]const u8{@tagName(real_symbol)}; 1868 | } 1869 | 1870 | @setEvalBranchQuota(5 * dll_value.kill.len); 1871 | for(dll_value.kill) |kill_symbol| { 1872 | dll_symbols = dll_symbols ++ &[1][]const u8{@tagName(kill_symbol)}; 1873 | } 1874 | 1875 | @setEvalBranchQuota(5 * dll_value.success_stubs.len); 1876 | for(dll_value.success_stubs) |success_symbol| { 1877 | dll_symbols = dll_symbols ++ &[1][]const u8{@tagName(success_symbol)}; 1878 | } 1879 | 1880 | @setEvalBranchQuota(1000 * dll_symbols.len); 1881 | var sorted_symbols = dll_symbols[0..dll_symbols.len].*; 1882 | std.sort.sort([]const u8, &sorted_symbols, {}, struct { 1883 | fn f(_: void, lhs: []const u8, rhs: []const u8) bool { 1884 | return std.mem.lessThan(u8, lhs, rhs); 1885 | } 1886 | }.f 1887 | ); 1888 | 1889 | @setEvalBranchQuota(10 * dll_symbols.len); 1890 | for(dll_symbols) |first_sym, i| { 1891 | if(i + 1 < dll_symbols.len) { 1892 | const second_sym = dll_symbols[i + 1]; 1893 | if(std.mem.eql(u8, first_sym, second_sym)) { 1894 | @compileError(std.fmt.comptimePrint("Symbol for {s} found at least twice: {s}", .{dll_name, first_sym})); 1895 | } 1896 | } 1897 | } 1898 | } 1899 | } 1900 | 1901 | fn RealAddrHolder(comptime symname: []const u8) type { 1902 | _ = symname; 1903 | return struct { var value: ?*const anyopaque = null; }; 1904 | } 1905 | 1906 | fn KillStub(comptime symname: []const u8) type { 1907 | return struct { 1908 | fn f() callconv(.Win64) ntdll.NTSTATUS { 1909 | @panic("Reached kill function " ++ symname); 1910 | } 1911 | }; 1912 | } 1913 | 1914 | fn SuccessStub(comptime symname: []const u8) type { 1915 | return struct { 1916 | fn f() callconv(.Win64) ntdll.NTSTATUS { 1917 | log("WARNING: STUB: " ++ symname, .{}); 1918 | return .SUCCESS; 1919 | } 1920 | }; 1921 | } 1922 | 1923 | pub const ResolveContext = struct { 1924 | const ResolveResult = union(enum) { 1925 | unknown_dll, 1926 | dll_known_symbol_unknown, 1927 | hook: *const anyopaque, 1928 | real: *?*const anyopaque, 1929 | }; 1930 | 1931 | fn findEntry(self: *@This(), dll_name: []const u8, symbol_name: []const u8) ResolveResult { 1932 | _ = self; 1933 | inline for(@typeInfo(@TypeOf(symbols)).Struct.fields) |dll_field| { 1934 | if(std.mem.eql(u8, dll_name, dll_field.name)) { 1935 | const dll_value = @field(symbols, dll_field.name); 1936 | 1937 | @setEvalBranchQuota(5 * @typeInfo(@TypeOf(dll_value.hooks)).Struct.fields.len); 1938 | inline for(@typeInfo(@TypeOf(dll_value.hooks)).Struct.fields) |hook_field| { 1939 | if(std.mem.eql(u8, hook_field.name, symbol_name)) { 1940 | return .{ .hook = @field(dll_value.hooks, hook_field.name) }; 1941 | } 1942 | } 1943 | 1944 | @setEvalBranchQuota(5 * dll_value.real.len); 1945 | inline for(dll_value.real) |real_sym| { 1946 | if(std.mem.eql(u8, @tagName(real_sym), symbol_name)) { 1947 | return .{ 1948 | .real = &RealAddrHolder(@tagName(real_sym)).value 1949 | }; 1950 | } 1951 | } 1952 | 1953 | @setEvalBranchQuota(5 * dll_value.kill.len); 1954 | inline for(dll_value.kill) |kill_sym| { 1955 | if(std.mem.eql(u8, @tagName(kill_sym), symbol_name)) { 1956 | return .{ 1957 | .hook = @ptrCast(*const anyopaque, &KillStub(@tagName(kill_sym)).f) 1958 | }; 1959 | } 1960 | } 1961 | 1962 | @setEvalBranchQuota(5 * dll_value.success_stubs.len); 1963 | inline for(dll_value.success_stubs) |stub_sym| { 1964 | if(std.mem.eql(u8, @tagName(stub_sym), symbol_name)) { 1965 | return .{ 1966 | .hook = @ptrCast(*const anyopaque, &SuccessStub(@tagName(stub_sym)).f) 1967 | }; 1968 | } 1969 | } 1970 | 1971 | return .{ .dll_known_symbol_unknown = {} }; 1972 | } 1973 | } 1974 | 1975 | return .{ .unknown_dll = {} }; 1976 | } 1977 | 1978 | pub fn resolve(self: *@This(), dll_name: []const u8, symbol_name: []const u8) ?*const anyopaque { 1979 | const entry = self.findEntry(dll_name, symbol_name); 1980 | return switch(entry) { 1981 | .unknown_dll, .dll_known_symbol_unknown => null, 1982 | .hook => |h| h, 1983 | .real => |r| r.*, 1984 | }; 1985 | } 1986 | 1987 | pub fn provide(self: *@This(), dll_name: []const u8, symbol_name: []const u8, addr: *anyopaque) void { 1988 | const entry = self.findEntry(dll_name, symbol_name); 1989 | return switch(entry) { 1990 | .unknown_dll => @panic("Unknown dll, TODO runtime resolving"), 1991 | .dll_known_symbol_unknown => { 1992 | //log("WARNING: Unknown symbol for dll {s}: {s}", .{dll_name, symbol_name}); 1993 | }, 1994 | .hook => |hook_target| { 1995 | const delta = @ptrToInt(hook_target) -% (@ptrToInt(addr) + 5); 1996 | if(delta < 0x80000000 or delta >= 0xFFFFFFFF80000000) { 1997 | var instr_bytes: [5]u8 = undefined; 1998 | instr_bytes[0] = 0xE9; // jmp imm32 1999 | std.mem.writeIntLittle(u32, instr_bytes[1..], @truncate(u32, delta)); 2000 | std.mem.copy(u8, @ptrCast([*]u8, addr)[0..instr_bytes.len], &instr_bytes); 2001 | } else if(@ptrToInt(hook_target) < 0x100000000) { 2002 | var instr_bytes: [6]u8 = undefined; 2003 | instr_bytes[0] = 0x68; // push imm32 2004 | std.mem.writeIntLittle(u32, instr_bytes[1..5], @truncate(u32, @ptrToInt(hook_target))); 2005 | instr_bytes[5] = 0xC3; // ret 2006 | std.mem.copy(u8, @ptrCast([*]u8, addr)[0..instr_bytes.len], &instr_bytes); 2007 | } else { 2008 | var instr_bytes: [12]u8 = undefined; 2009 | std.mem.copy(u8, &instr_bytes, "\x48\xB8XXXXXXXX\xFF\xE0"); // movabs rax, hook_target; jmp rax 2010 | std.mem.writeIntLittle(u64, instr_bytes[2..10], @ptrToInt(hook_target)); 2011 | std.mem.copy(u8, @ptrCast([*]u8, addr)[0..instr_bytes.len], &instr_bytes); 2012 | } 2013 | }, 2014 | .real => |real_target| { 2015 | real_target.* = addr; 2016 | }, 2017 | }; 2018 | } 2019 | }; 2020 | 2021 | const std = @import("std"); 2022 | const log = @import("log.zig").scoped(.ntdll); 2023 | 2024 | const WrappedFunction = struct { 2025 | hooked: ?bool, 2026 | fptr: *const anyopaque, 2027 | }; 2028 | 2029 | const RealFunction = struct { 2030 | fptr: ?*const anyopaque = null, 2031 | }; 2032 | 2033 | fn wrapped(fptr: anytype, hook: bool) WrappedFunction { 2034 | const f = @typeInfo(@TypeOf(fptr.*)).Fn; 2035 | std.debug.assert(f.calling_convention == .Win64); 2036 | return .{ 2037 | .hooked = if(hook) false else null, 2038 | .fptr = @ptrCast(*const anyopaque, f), 2039 | }; 2040 | } 2041 | 2042 | const ntdll = @import("ntdll.zig"); 2043 | 2044 | fn stub(comptime str: []const u8) *const anyopaque { 2045 | return @ptrCast(*const anyopaque, struct { 2046 | fn f() callconv(.Win64) ntdll.NTSTATUS { 2047 | log("Undefined, stub: " ++ str, .{}); 2048 | return .SUCCESS; 2049 | } 2050 | }.f); 2051 | } 2052 | --------------------------------------------------------------------------------