| ... | @@ -793,28 +793,60 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { | ... | @@ -793,28 +793,60 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { |
| 793 | log.debug("page not mapped for write access; re-mapping...", .{}); | 793 | log.debug("page not mapped for write access; re-mapping...", .{}); |
| 794 | try writeMemProtected(handle, vaddr, code); | 794 | try writeMemProtected(handle, vaddr, code); |
| 795 | } else { | 795 | } else { |
| 796 | try writeMem(handle, vaddr, code); | 796 | if (WriteProcessMemory(handle, vaddr, code)) |amt| { |
| | 797 | if (amt != code.len) return error.InputOutput; |
| | 798 | } else |err| { |
| | 799 | log.warn("writing to process memory failed with error: {s}", .{@errorName(err)}); |
| | 800 | } |
| 797 | } | 801 | } |
| 798 | } | 802 | } |
| 799 | | 803 | |
| 800 | try self.base.file.?.pwriteAll(code, file_offset); | 804 | try self.base.file.?.pwriteAll(code, file_offset); |
| 801 | } | 805 | } |
| 802 | | 806 | |
| 803 | extern "kernel32" fn ReadProcessMemory( | 807 | extern "ntdll" fn NtReadVirtualMemory( |
| 804 | hProcess: std.os.windows.HANDLE, | 808 | ProcessHandle: std.os.windows.HANDLE, |
| 805 | lpBaseAddress: std.os.windows.LPCVOID, | 809 | BaseAddress: std.os.windows.PVOID, |
| 806 | lpBuffer: std.os.windows.LPVOID, | 810 | Buffer: std.os.windows.LPVOID, |
| 807 | nSize: std.os.windows.SIZE_T, | 811 | NumberOfBytesToRead: std.os.windows.SIZE_T, |
| 808 | lpNumberOfBytesRead: *std.os.windows.SIZE_T, | 812 | NumberOfBytesRead: ?*std.os.windows.SIZE_T, |
| 809 | ) std.os.windows.BOOL; | 813 | ) std.os.windows.NTSTATUS; |
| 810 | | 814 | |
| 811 | extern "kernel32" fn WriteProcessMemory( | 815 | extern "ntdll" fn NtWriteVirtualMemory( |
| 812 | hProcess: std.os.windows.HANDLE, | 816 | ProcessHandle: std.os.windows.HANDLE, |
| 813 | lpBaseAddress: std.os.windows.LPVOID, | 817 | BaseAddress: std.os.windows.PVOID, |
| 814 | lpBuffer: std.os.windows.LPCVOID, | 818 | Buffer: std.os.windows.LPCVOID, |
| 815 | nSize: std.os.windows.SIZE_T, | 819 | NumberOfBytesToWrite: std.os.windows.SIZE_T, |
| 816 | lpNumberOfBytesWritten: *std.os.windows.SIZE_T, | 820 | NumberOfBytesWritten: ?*std.os.windows.SIZE_T, |
| 817 | ) std.os.windows.BOOL; | 821 | ) std.os.windows.NTSTATUS; |
| | 822 | |
| | 823 | fn ReadProcessMemory(handle: std.os.windows.HANDLE, base_addr: usize, buffer: []u8) ![]u8 { |
| | 824 | var nread: usize = 0; |
| | 825 | switch (NtReadVirtualMemory( |
| | 826 | handle, |
| | 827 | @intToPtr(*anyopaque, base_addr), |
| | 828 | buffer.ptr, |
| | 829 | buffer.len, |
| | 830 | &nread, |
| | 831 | )) { |
| | 832 | .SUCCESS => return buffer[0..nread], |
| | 833 | else => |rc| return std.os.windows.unexpectedStatus(rc), |
| | 834 | } |
| | 835 | } |
| | 836 | |
| | 837 | fn WriteProcessMemory(handle: std.os.windows.HANDLE, base_addr: usize, buffer: []const u8) !usize { |
| | 838 | var nwritten: usize = 0; |
| | 839 | switch (NtWriteVirtualMemory( |
| | 840 | handle, |
| | 841 | @intToPtr(*anyopaque, base_addr), |
| | 842 | @ptrCast(*const anyopaque, buffer.ptr), |
| | 843 | buffer.len, |
| | 844 | &nwritten, |
| | 845 | )) { |
| | 846 | .SUCCESS => return nwritten, |
| | 847 | else => |rc| return std.os.windows.unexpectedStatus(rc), |
| | 848 | } |
| | 849 | } |
| 818 | | 850 | |
| 819 | extern "kernel32" fn VirtualProtectEx( | 851 | extern "kernel32" fn VirtualProtectEx( |
| 820 | hProcess: std.os.windows.HANDLE, | 852 | hProcess: std.os.windows.HANDLE, |
| ... | @@ -849,43 +881,16 @@ fn getProcessBaseAddress(handle: std.ChildProcess.Id) !u64 { | ... | @@ -849,43 +881,16 @@ fn getProcessBaseAddress(handle: std.ChildProcess.Id) !u64 { |
| 849 | } | 881 | } |
| 850 | | 882 | |
| 851 | var peb_buf: [@sizeOf(std.os.windows.PEB)]u8 align(@alignOf(std.os.windows.PEB)) = undefined; | 883 | var peb_buf: [@sizeOf(std.os.windows.PEB)]u8 align(@alignOf(std.os.windows.PEB)) = undefined; |
| 852 | var peb_nread: usize = 0; | 884 | const pebout = try ReadProcessMemory(handle, @ptrToInt(info.PebBaseAddress), &peb_buf); |
| 853 | if (ReadProcessMemory( | 885 | const peb = @ptrCast(*const std.os.windows.PEB, @alignCast(@alignOf(std.os.windows.PEB), pebout.ptr)); |
| 854 | handle, | | |
| 855 | info.PebBaseAddress, | | |
| 856 | &peb_buf, | | |
| 857 | @sizeOf(std.os.windows.PEB), | | |
| 858 | &peb_nread, | | |
| 859 | ) == 0) { | | |
| 860 | const err = std.os.windows.kernel32.GetLastError(); | | |
| 861 | log.warn("reading from process memory failed with err: {s}({x})", .{ @tagName(err), @enumToInt(err) }); | | |
| 862 | return error.FailedToReadPebForProcess; | | |
| 863 | } | | |
| 864 | if (peb_nread != @sizeOf(std.os.windows.PEB)) return error.InputOutput; | | |
| 865 | | | |
| 866 | const peb = @ptrCast(*const std.os.windows.PEB, &peb_buf); | | |
| 867 | return @ptrToInt(peb.ImageBaseAddress); | 886 | return @ptrToInt(peb.ImageBaseAddress); |
| 868 | } | 887 | } |
| 869 | | 888 | |
| 870 | fn debugMem(allocator: Allocator, handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) !void { | 889 | fn debugMem(allocator: Allocator, handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) !void { |
| 871 | var buffer = try allocator.alloc(u8, code.len); | 890 | var buffer = try allocator.alloc(u8, code.len); |
| 872 | defer allocator.free(buffer); | 891 | defer allocator.free(buffer); |
| 873 | var nread: usize = 0; | 892 | const memread = try ReadProcessMemory(handle, vaddr, buffer); |
| 874 | if (ReadProcessMemory( | 893 | log.debug("in memory: {x}", .{std.fmt.fmtSliceHexLower(memread)}); |
| 875 | handle, | | |
| 876 | @intToPtr(*anyopaque, vaddr), | | |
| 877 | buffer.ptr, | | |
| 878 | code.len, | | |
| 879 | &nread, | | |
| 880 | ) == 0) { | | |
| 881 | const err = std.os.windows.kernel32.GetLastError(); | | |
| 882 | log.warn("reading from process memory failed with err: {s}({x})", .{ @tagName(err), @enumToInt(err) }); | | |
| 883 | } | | |
| 884 | if (nread != code.len) { | | |
| 885 | log.warn("reading from process memory InputOutput error: read != requested: {x} != {x}", .{ nread, code.len }); | | |
| 886 | } | | |
| 887 | | | |
| 888 | log.debug("in memory: {x}", .{std.fmt.fmtSliceHexLower(buffer)}); | | |
| 889 | log.debug("to write: {x}", .{std.fmt.fmtSliceHexLower(code)}); | 894 | log.debug("to write: {x}", .{std.fmt.fmtSliceHexLower(code)}); |
| 890 | } | 895 | } |
| 891 | | 896 | |
| ... | @@ -898,7 +903,8 @@ fn writeMemProtected(handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) | ... | @@ -898,7 +903,8 @@ fn writeMemProtected(handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) |
| 898 | log.warn("making page(s) writeable failed with error: {s}({x})", .{ @tagName(err), @enumToInt(err) }); | 903 | log.warn("making page(s) writeable failed with error: {s}({x})", .{ @tagName(err), @enumToInt(err) }); |
| 899 | return; | 904 | return; |
| 900 | } | 905 | } |
| 901 | try writeMem(handle, vaddr, code); | 906 | const amt = try WriteProcessMemory(handle, vaddr, code); |
| | 907 | if (amt != code.len) return error.InputOutput; |
| 902 | // TODO: We can probably just set the pages writeable and leave it at that without having to restore the attributes. | 908 | // TODO: We can probably just set the pages writeable and leave it at that without having to restore the attributes. |
| 903 | // For that though, we want to track which page has already been modified. | 909 | // For that though, we want to track which page has already been modified. |
| 904 | if (VirtualProtectEx(handle, pvaddr, code.len, old_prot, &new_prot) == 0) { | 910 | 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) | ... | @@ -907,23 +913,6 @@ fn writeMemProtected(handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) |
| 907 | } | 913 | } |
| 908 | } | 914 | } |
| 909 | | 915 | |
| 910 | fn writeMem(handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) !void { | | |
| 911 | var nwritten: usize = 0; | | |
| 912 | if (WriteProcessMemory( | | |
| 913 | handle, | | |
| 914 | @intToPtr(*anyopaque, vaddr), | | |
| 915 | code.ptr, | | |
| 916 | code.len, | | |
| 917 | &nwritten, | | |
| 918 | ) == 0) { | | |
| 919 | const err = std.os.windows.kernel32.GetLastError(); | | |
| 920 | log.warn("writing to process memory failed with err: {s}({x})", .{ @tagName(err), @enumToInt(err) }); | | |
| 921 | } | | |
| 922 | if (nwritten != code.len) { | | |
| 923 | log.warn("writing to process memory InputOutput error: written != requested: {x} != {x}", .{ nwritten, code.len }); | | |
| 924 | } | | |
| 925 | } | | |
| 926 | | | |
| 927 | fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void { | 916 | fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void { |
| 928 | switch (self.ptr_width) { | 917 | switch (self.ptr_width) { |
| 929 | .p32 => { | 918 | .p32 => { |