Search code examples
stringdelphinotepadreadprocessmemory

Delphi ReadProcessMemory From Notepad


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.

Solution

  • 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.