| ... | ... | @@ -793,28 +793,60 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void { |
| 793 | 793 | log.debug("page not mapped for write access; re-mapping...", .{}); |
| 794 | 794 | try writeMemProtected(handle, vaddr, code); |
| 795 | 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 | 804 | try self.base.file.?.pwriteAll(code, file_offset); |
| 801 | 805 | } |
| 802 | 806 | |
| 803 | | extern "kernel32" fn ReadProcessMemory( |
| 804 | | hProcess: std.os.windows.HANDLE, |
| 805 | | lpBaseAddress: std.os.windows.LPCVOID, |
| 806 | | lpBuffer: std.os.windows.LPVOID, |
| 807 | | nSize: std.os.windows.SIZE_T, |
| 808 | | lpNumberOfBytesRead: *std.os.windows.SIZE_T, |
| 809 | | ) std.os.windows.BOOL; |
| 807 | extern "ntdll" fn NtReadVirtualMemory( |
| 808 | ProcessHandle: std.os.windows.HANDLE, |
| 809 | BaseAddress: std.os.windows.PVOID, |
| 810 | Buffer: std.os.windows.LPVOID, |
| 811 | NumberOfBytesToRead: std.os.windows.SIZE_T, |
| 812 | NumberOfBytesRead: ?*std.os.windows.SIZE_T, |
| 813 | ) std.os.windows.NTSTATUS; |
| 810 | 814 | |
| 811 | | extern "kernel32" fn WriteProcessMemory( |
| 812 | | hProcess: std.os.windows.HANDLE, |
| 813 | | lpBaseAddress: std.os.windows.LPVOID, |
| 814 | | lpBuffer: std.os.windows.LPCVOID, |
| 815 | | nSize: std.os.windows.SIZE_T, |
| 816 | | lpNumberOfBytesWritten: *std.os.windows.SIZE_T, |
| 817 | | ) std.os.windows.BOOL; |
| 815 | extern "ntdll" fn NtWriteVirtualMemory( |
| 816 | ProcessHandle: std.os.windows.HANDLE, |
| 817 | BaseAddress: std.os.windows.PVOID, |
| 818 | Buffer: std.os.windows.LPCVOID, |
| 819 | NumberOfBytesToWrite: std.os.windows.SIZE_T, |
| 820 | NumberOfBytesWritten: ?*std.os.windows.SIZE_T, |
| 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 | 851 | extern "kernel32" fn VirtualProtectEx( |
| 820 | 852 | hProcess: std.os.windows.HANDLE, |
| ... | ... | @@ -849,43 +881,16 @@ fn getProcessBaseAddress(handle: std.ChildProcess.Id) !u64 { |
| 849 | 881 | } |
| 850 | 882 | |
| 851 | 883 | var peb_buf: [@sizeOf(std.os.windows.PEB)]u8 align(@alignOf(std.os.windows.PEB)) = undefined; |
| 852 | | var peb_nread: usize = 0; |
| 853 | | if (ReadProcessMemory( |
| 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); |
| 884 | const pebout = try ReadProcessMemory(handle, @ptrToInt(info.PebBaseAddress), &peb_buf); |
| 885 | const peb = @ptrCast(*const std.os.windows.PEB, @alignCast(@alignOf(std.os.windows.PEB), pebout.ptr)); |
| 867 | 886 | return @ptrToInt(peb.ImageBaseAddress); |
| 868 | 887 | } |
| 869 | 888 | |
| 870 | 889 | fn debugMem(allocator: Allocator, handle: std.ChildProcess.Id, vaddr: u64, code: []const u8) !void { |
| 871 | 890 | var buffer = try allocator.alloc(u8, code.len); |
| 872 | 891 | defer allocator.free(buffer); |
| 873 | | var nread: usize = 0; |
| 874 | | if (ReadProcessMemory( |
| 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)}); |
| 892 | const memread = try ReadProcessMemory(handle, vaddr, buffer); |
| 893 | log.debug("in memory: {x}", .{std.fmt.fmtSliceHexLower(memread)}); |
| 889 | 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 | 903 | log.warn("making page(s) writeable failed with error: {s}({x})", .{ @tagName(err), @enumToInt(err) }); |
| 899 | 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 | 908 | // TODO: We can probably just set the pages writeable and leave it at that without having to restore the attributes. |
| 903 | 909 | // For that though, we want to track which page has already been modified. |
| 904 | 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 | 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 | 916 | fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void { |
| 928 | 917 | switch (self.ptr_width) { |
| 929 | 918 | .p32 => { |