diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-03-30 17:04:50 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-03-30 21:08:31 +0200 |
| commit | 423b9f11144cc7f7f027db9a091174e9c752c511 (patch) | |
| tree | d982e96c0df8c8e347d010e778b5801e79130990 /src/link | |
| parent | d2f013085523436b51023f7d28d52a859b70a4b3 (diff) | |
| download | zig-423b9f11144cc7f7f027db9a091174e9c752c511.tar.gz zig-423b9f11144cc7f7f027db9a091174e9c752c511.zip | |
coff: reimplement Read/WriteProcessMemory using our own ntdll wrappers
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/Coff.zig | 117 |
1 files changed, 53 insertions, 64 deletions
diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 8337d69088..2dd29d8022 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -793,28 +793,60 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { log.debug("page not mapped for write access; re-mapping...", .{}); try writeMemProtected(handle, vaddr, code); } else { - try writeMem(handle, vaddr, code); + if (WriteProcessMemory(handle, vaddr, code)) |amt| { + if (amt != code.len) return error.InputOutput; + } else |err| { + log.warn("writing to process memory failed with error: {s}", .{@errorName(err)}); + } } } try self.base.file.?.pwriteAll(code, file_offset); } -extern "kernel32" fn ReadProcessMemory( - hProcess: std.os.windows.HANDLE, - lpBaseAddress: std.os.windows.LPCVOID, - lpBuffer: std.os.windows.LPVOID, - nSize: std.os.windows.SIZE_T, - lpNumberOfBytesRead: *std.os.windows.SIZE_T, -) std.os.windows.BOOL; +extern "ntdll" fn NtReadVirtualMemory( + ProcessHandle: std.os.windows.HANDLE, + BaseAddress: std.os.windows.PVOID, + Buffer: std.os.windows.LPVOID, + NumberOfBytesToRead: std.os.windows.SIZE_T, + NumberOfBytesRead: ?*std.os.windows.SIZE_T, +) std.os.windows.NTSTATUS; -extern "kernel32" fn WriteProcessMemory( - hProcess: std.os.windows.HANDLE, - lpBaseAddress: std.os.windows.LPVOID, - lpBuffer: std.os.windows.LPCVOID, - nSize: std.os.windows.SIZE_T, - lpNumberOfBytesWritten: *std.os.windows.SIZE_T, -) std.os.windows.BOOL; +extern "ntdll" fn NtWriteVirtualMemory( + ProcessHandle: std.os.windows.HANDLE, + BaseAddress: std.os.windows.PVOID, + Buffer: std.os.windows.LPCVOID, + NumberOfBytesToWrite: std.os.windows.SIZE_T, + NumberOfBytesWritten: ?*std.os.windows.SIZE_T, +) std.os.windows.NTSTATUS; + +fn ReadProcessMemory(handle: std.os.windows.HANDLE, base_addr: usize, buffer: []u8) ![]u8 { + var nread: usize = 0; + switch (NtReadVirtualMemory( + handle, + @intToPtr(*anyopaque, base_addr), + buffer.ptr, + buffer.len, + &nread, + )) { + .SUCCESS => return buffer[0..nread], + else => |rc| return std.os.windows.unexpectedStatus(rc), + } +} + +fn WriteProcessMemory(handle: std.os.windows.HANDLE, base_addr: usize, buffer: []const u8) !usize { + var nwritten: usize = 0; + switch (NtWriteVirtualMemory( + handle, + @intToPtr(*anyopaque, base_addr), + @ptrCast(*const anyopaque, buffer.ptr), + buffer.len, + &nwritten, + )) { + .SUCCESS => return nwritten, + else => |rc| return std.os.windows.unexpectedStatus(rc), + } +} extern "kernel32" fn VirtualProtectEx( hProcess: std.os.windows.HANDLE, @@ -849,43 +881,16 @@ fn getProcessBaseAddress(handle: std.ChildProcess.Id) !u64 { } var peb_buf: [@sizeOf(std.os.windows.PEB)]u8 align(@alignOf(std.os.windows.PEB)) = undefined; - var peb_nread: usize = 0; - if (ReadProcessMemory( - handle, - info.PebBaseAddress, - &peb_buf, - @sizeOf(std.os.windows.PEB), - &peb_nread, - ) == 0) { - const err = std.os.windows.kernel32.GetLastError(); - log.warn("reading from process memory failed with err: {s}({x})", .{ @tagName(err), @enumToInt(err) }); - return error.FailedToReadPebForProcess; - } - if (peb_nread != @sizeOf(std.os.windows.PEB)) return error.InputOutput; - - const peb = @ptrCast(*const std.os.windows.PEB, &peb_buf); + const pebout = try ReadProcessMemory(handle, @ptrToInt(info.PebBaseAddress), &peb_buf); + const peb = @ptrCast(*const std.os.windows.PEB, @alignCast(@alignOf(std.os.windows.PEB), pebout.ptr)); return @ptrToInt(peb.ImageBaseAddress); } fn debugMem(allocator: Allocator, handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) !void { var buffer = try allocator.alloc(u8, code.len); defer allocator.free(buffer); - var nread: usize = 0; - if (ReadProcessMemory( - handle, - @intToPtr(*anyopaque, vaddr), - buffer.ptr, - code.len, - &nread, - ) == 0) { - const err = std.os.windows.kernel32.GetLastError(); - log.warn("reading from process memory failed with err: {s}({x})", .{ @tagName(err), @enumToInt(err) }); - } - if (nread != code.len) { - log.warn("reading from process memory InputOutput error: read != requested: {x} != {x}", .{ nread, code.len }); - } - - log.debug("in memory: {x}", .{std.fmt.fmtSliceHexLower(buffer)}); + const memread = try ReadProcessMemory(handle, vaddr, buffer); + log.debug("in memory: {x}", .{std.fmt.fmtSliceHexLower(memread)}); log.debug("to write: {x}", .{std.fmt.fmtSliceHexLower(code)}); } @@ -898,7 +903,8 @@ fn writeMemProtected(handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) log.warn("making page(s) writeable failed with error: {s}({x})", .{ @tagName(err), @enumToInt(err) }); return; } - try writeMem(handle, vaddr, code); + const amt = try WriteProcessMemory(handle, vaddr, code); + if (amt != code.len) return error.InputOutput; // TODO: We can probably just set the pages writeable and leave it at that without having to restore the attributes. // For that though, we want to track which page has already been modified. if (VirtualProtectEx(handle, pvaddr, code.len, old_prot, &new_prot) == 0) { @@ -907,23 +913,6 @@ fn writeMemProtected(handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) } } -fn writeMem(handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) !void { - var nwritten: usize = 0; - if (WriteProcessMemory( - handle, - @intToPtr(*anyopaque, vaddr), - code.ptr, - code.len, - &nwritten, - ) == 0) { - const err = std.os.windows.kernel32.GetLastError(); - log.warn("writing to process memory failed with err: {s}({x})", .{ @tagName(err), @enumToInt(err) }); - } - if (nwritten != code.len) { - log.warn("writing to process memory InputOutput error: written != requested: {x} != {x}", .{ nwritten, code.len }); - } -} - fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void { switch (self.ptr_width) { .p32 => { |
