Delphi ReadProcessMemory From Notepad

4.3k views Asked by At

I want to extract the full process memory of notepad process and write it to a text file. The problem is that i do not find what i type in notepad in the textfile. For example, if i type "test123" in notepad, i cannot find the string in the textfile that the program creates. Here is the code:

{$APPTYPE CONSOLE}

uses
  Windows,
  TLHelp32,
  SysUtils;

var
  Snap, err: dword;
  sysinfo: TSystemInfo;
  Process: TPROCESSENTRY32;
  Handle: THandle;
  Mbi: TMemoryBasicInformation;
  Addr, BytesRead: dword;
  Buf: PChar;
  f: TextFile;
begin
  GetSystemInfo(sysinfo);
        Handle := OpenProcess(PROCESS_ALL_ACCESS, false, 2928);
        if Handle <> 0 then
        begin
          writeln(Process.szExeFile);
          Addr := dword(sysinfo.lpMinimumApplicationAddress);
          while (Addr < $80000000) do
          begin
            if VirtualQueryEx(Handle, Ptr(Addr), Mbi, SizeOf(Mbi)) = 0 then
            begin
              err := GetLastError;
              inc(Addr, sysinfo.dwPageSize);
              continue;
            end;
             Buf := AllocMem(Mbi.RegionSize);
             ReadProcessMemory(Handle, Mbi.BaseAddress, Buf, Mbi.RegionSize, BytesRead);
             AssignFile(f, 'Test.txt');
             Append(f);
             WriteLn(f, Buf);
             CloseFile(f);
             FreeMem(Buf);
            if Addr + Mbi.RegionSize < Addr then
              break;
            Addr := Addr + Mbi.RegionSize;
          end;
          CloseHandle(Handle)
        end;
  Readln;
end.
2

There are 2 answers

1
Remy Lebeau On BEST ANSWER

The correct way to retrieve notepad's text content is to locate the HWND of notepad's edit field, using FindWindowEx() or EnumChildWindows() or similar, and then send it a WM_GETTEXT message.

But if you must dump Notepad's allocated memory, then you need to fix your code. It is ignoring errors, and not writing the retrieved data to your file correctly. Try something more like this instead:

uses
  Windows,
  TLHelp32,
  SysUtils;

var
  err: DWORD;
  sysinfo: TSystemInfo;
  Handle: THandle;
  Mbi: TMemoryBasicInformation;
  Addr: DWORD_PTR;
  BytesRead: DWORD;
  Buf: array of Byte;
  f: TFileStream;
begin
  GetSystemInfo(sysinfo);
  Handle := OpenProcess(PROCESS_ALL_ACCESS, FALSE, 2928);
  if Handle = 0 then
  begin
    err := GetLastError;
    // do something...
  end else
  try
    f := TFileStream.Create('Test.txt', fmCreate);
    try
      Addr := DWORD_PTR(SysInfo.lpMinimumApplicationAddress);
      while (Addr < $80000000) do
      begin
        if VirtualQueryEx(Handle, Pointer(Addr), Mbi, SizeOf(Mbi)) = 0 then
        begin
          err := GetLastError;
          Inc(Addr, sysinfo.dwPageSize);
          Continue;
        end;
        if Mbi.RegionSize > Length(Buf) then
          SetLength(Buf, Mbi.RegionSize);
        if not ReadProcessMemory(Handle, Mbi.BaseAddress, @Buf[0], Mbi.RegionSize, BytesRead) then
        begin
            err := GetLastError;
            // do something...
        end else
          f.WriteBuffer(Buf[0], BytesRead);
        if Addr + Mbi.RegionSize < Addr then
          break;
        Addr := Addr + Mbi.RegionSize;
      end;
    finally
      f.Free;
    end;
  finally
    CloseHandle(Handle);
  end;
  Readln;
end.
7
David Heffernan On

Notepad presumably stores its text encoded in the Windows native UTF-16. So look for that text as a wide string.

I guess the other problem is that you are writing binary data to a text file. Any null characters in your memory blocks will terminate the output. You really want to stop using Pascal I/O and just dump this memory to a file stream. Or if you have to use Pascal I/O at least to it in binary mode.

Wouldn't it just be easier to use the automation API or send WM_GETTEXT?