如何在 Delphi 中使用 WriteProcessMemory

How to use WriteProcessMemory in Delphi

我无法编译这段代码。我能帮忙吗?谢谢

procedure ChangeOutsideDateTime(h: HWND; dt: TDateTime);
var
  st: TSystemTime;
  pst: Pointer;
  hDTP: Cardinal;
  hProc: THandle;
  dwWrote: DWORD;
begin
  DateTimeToSystemTime(dt, st);
  pst:= VirtualAllocEx(h, nil, SizeOf(st), MEM_COMMIT, 0);
  if pst <> nil then begin
    if GetWindowThreadProcessId(h, hDTP) > 0 then begin
      hProc:= OpenProcess(PROCESS_VM_OPERATION, false, hDTP);
      if WriteProcessMemory(hProc, pst, @st, SizeOf(st), dwWrote) > 0 then begin
        SendMessage(h, DTM_SETSYSTEMTIME, GDT_VALID, hDTP);
        CloseHandle(hProc);
      end;
    end;
    VirtualFreeEx(h, pst, 0, MEM_RELEASE);
  end;
end;

它在使用 "WriteProcessMemory" 的行显示 "Types of actual and formal var parameters must be identical"。

Types of actual and formal var parameters must be identical

这是编译器错误 E2003。如果遇到不理解的编译错误,首先要做的是阅读documentation。它说:

For a variable parameter, the actual argument must be of the exact type of the formal parameter.

导致此错误的函数调用是WriteProcessMemory。让我们看看它的声明:

function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; 
  lpBuffer: Pointer; nSize: SIZE_T; var lpNumberOfBytesWritten: SIZE_T): BOOL; stdcall;

这里只有一个var参数,最后一个参数。您传递的变量必须是 SIZE_T 类型,但您传递的是 DWORD 类型的变量。那就是不匹配。

其他一些评论:

  • VirtualAllocEx 的调用必然会失败,因为您传递的是window 句柄而不是进程句柄。
  • 从语义上讲,测试正线程 ID 毫无意义。测试不等于零是否成功。
  • 您没有检查 OpenProcess return 值。那很容易失败。
  • 您没有打开具有 PROCESS_VM_WRITE 访问权限的进程,这是 WriteProcessMemory 所必需的。
  • 如果对 WriteProcessMemory 的调用失败,您将泄漏句柄。
  • WriteProcessMemory的return类型是BOOL
  • hDTP 是一个奇怪的进程 ID 名称。该名称表明您认为它是日期时间选择器控件的句柄。不是。这是进程ID。
  • 您在 SendMessage 调用中传递了该进程 ID,而不是您刚刚写入的系统时间地址。

您的代码中有几个错误。

  • 您正在将 HWND 传递给 VirtualAllocEx(),但它期望将 THandle 传递给打开的进程。在打开进程句柄之前,您正在调用 VirtualAllocEx()。而且您没有请求对分配的内存的写入权限。

  • 调用 OpenProcess() 时,您没有请求 PROCESS_VM_WRITE 许可,而 WriteProcessMemory() 需要。

  • 您对 WriteProcessMemory() 的使用与其声明不符。这就是您收到编译器错误的原因。

  • 您将 HWND 的进程 ID 作为 DTM_SETSYSTEMTIMELPARAM 传递,但它需要分配的 TSystemTime 指针。

试试这样的东西:

procedure ChangeOutsideDateTime(h: HWND; dt: TDateTime);
var
  st: TSystemTime;
  PID: DWORD;
  hProc: THandle;
  pst: Pointer;
  NumWrote: SIZE_T;
begin
  GetWindowThreadProcessId(h, PID);
  hProc := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_WRITE, false, PID);
  if hProc <> 0 then
  try
    pst := VirtualAllocEx(hProc, nil, SizeOf(st), MEM_COMMIT, PAGE_READWRITE);
    if pst <> nil then
    try
      DateTimeToSystemTime(dt, st);
      if WriteProcessMemory(hProc, pst, @st, SizeOf(st), NumWrote) then begin
        SendMessage(h, DTM_SETSYSTEMTIME, GDT_VALID, LPARAM(pst));
      end;
    finally
      VirtualFreeEx(hProc, pst, 0, MEM_RELEASE);
    end;
  finally
    CloseHandle(hProc);
  end;
end;