authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-30 17:18:34+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-30 21:08:31+02:00
log5d387742fd0f9e5c2072a2a527ccbf22044d4513
treefda426408a81c580afbb1cd79e269d8124eb08e9
parent423b9f11144cc7f7f027db9a091174e9c752c511

coff: reimplement VirtualProtectEx using our own ntdll wrapper


2 files changed, 26 insertions(+), 20 deletions(-)

lib/std/os/windows/ntdll.zig+1-1
......@@ -367,7 +367,7 @@ pub extern "ntdll" fn RtlQueryRegistryValues(
367367pub extern "ntdll" fn NtProtectVirtualMemory(
368368 ProcessHandle: HANDLE,
369369 BaseAddress: *PVOID,
370 NumberOfBytesToProtect: *ULONG,
370 NumberOfBytesToProtect: *SIZE_T,
371371 NewAccessProtection: ULONG,
372372 OldAccessProtection: *ULONG,
373373) callconv(WINAPI) NTSTATUS;
src/link/Coff.zig+25-19
......@@ -820,6 +820,14 @@ extern "ntdll" fn NtWriteVirtualMemory(
820820 NumberOfBytesWritten: ?*std.os.windows.SIZE_T,
821821) std.os.windows.NTSTATUS;
822822
823extern "ntdll" fn NtProtectVirtualMemory(
824 ProcessHandle: std.os.windows.HANDLE,
825 BaseAddress: *std.os.windows.PVOID,
826 NumberOfBytesToProtect: *std.os.windows.SIZE_T,
827 NewAccessProtection: std.os.windows.ULONG,
828 OldAccessProtection: *std.os.windows.ULONG,
829) std.os.windows.NTSTATUS;
830
823831fn ReadProcessMemory(handle: std.os.windows.HANDLE, base_addr: usize, buffer: []u8) ![]u8 {
824832 var nread: usize = 0;
825833 switch (NtReadVirtualMemory(
......@@ -848,13 +856,21 @@ fn WriteProcessMemory(handle: std.os.windows.HANDLE, base_addr: usize, buffer: [
848856 }
849857}
850858
851extern "kernel32" fn VirtualProtectEx(
852 hProcess: std.os.windows.HANDLE,
853 lpAddress: std.os.windows.LPVOID,
854 dwSize: std.os.windows.SIZE_T,
855 flNewProtect: std.os.windows.DWORD,
856 lpflOldProtect: *std.os.windows.DWORD,
857) std.os.windows.BOOL;
859fn VirtualProtectEx(handle: std.os.windows.HANDLE, base_addr: usize, size: usize, new_prot: u32) !u32 {
860 var out_paddr = @intToPtr(*anyopaque, base_addr);
861 var out_size = size;
862 var old_prot: u32 = undefined;
863 switch (NtProtectVirtualMemory(
864 handle,
865 &out_paddr,
866 &out_size,
867 new_prot,
868 &old_prot,
869 )) {
870 .SUCCESS => return old_prot,
871 else => |rc| return std.os.windows.unexpectedStatus(rc),
872 }
873}
858874
859875const PROCESS_BASIC_INFORMATION = extern struct {
860876 ExitStatus: std.os.windows.NTSTATUS,
......@@ -895,22 +911,12 @@ fn debugMem(allocator: Allocator, handle: std.ChildProcess.Id, vaddr: u64, code:
895911}
896912
897913fn writeMemProtected(handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) !void {
898 const pvaddr = @intToPtr(*anyopaque, vaddr);
899 var new_prot: std.os.windows.DWORD = std.os.windows.PAGE_EXECUTE_WRITECOPY;
900 var old_prot: std.os.windows.DWORD = undefined;
901 if (VirtualProtectEx(handle, pvaddr, code.len, new_prot, &old_prot) == 0) {
902 const err = std.os.windows.kernel32.GetLastError();
903 log.warn("making page(s) writeable failed with error: {s}({x})", .{ @tagName(err), @enumToInt(err) });
904 return;
905 }
914 const old_prot = try VirtualProtectEx(handle, vaddr, code.len, std.os.windows.PAGE_EXECUTE_WRITECOPY);
906915 const amt = try WriteProcessMemory(handle, vaddr, code);
907916 if (amt != code.len) return error.InputOutput;
908917 // TODO: We can probably just set the pages writeable and leave it at that without having to restore the attributes.
909918 // For that though, we want to track which page has already been modified.
910 if (VirtualProtectEx(handle, pvaddr, code.len, old_prot, &new_prot) == 0) {
911 const err = std.os.windows.kernel32.GetLastError();
912 log.warn("restoring page(s) attributes failed with error: {s}({x})", .{ @tagName(err), @enumToInt(err) });
913 }
919 _ = try VirtualProtectEx(handle, vaddr, code.len, old_prot);
914920}
915921
916922fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {