Avatar of MelissaCG
MelissaCG
 asked on

WriteProcessMemory in Windows7

Hello Experts,

I was just looking at some posts in a forum and saw one interesting about manipulating a listview of another app. Actually the listviw is from the taskmgr in this code, but that's just for learning purposes i guess, since it's such an ugly code that noone could actually use it for bad things... Well, anyway, i tried it in my Windows 7 x64 Home Premium with UAC and DEP off and its not working... The string with the processes names are blank. I think it's something with write/readprocessmemory because i tested the handles and they arent nil... My friend tested in a windows XP and it worked... What might be wrong here??


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, commctrl, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{Função para pegar o texto do Item da ListView}
function PegaTexto(s: string): string;
var
c: Char;
i: integer;
Src,Dst: PChar;
begin
i:=length(s);
SetLength(Result,i);
Src:=pointer(s);
Dst:=pointer(Result);
While i <> 0 do
  begin
  c:=Src^;
  if (c>='A') and (c<='Z') then
    Inc(c,32);
  Dst^:=c;
  Inc(Src);
  Inc(Dst);
  Dec(i);
  end;
end;

procedure Esconde(proc: string);
var
dwSize,dwNumBytes,PID,hProc: Cardinal;
PLocalShared,PSysShared: PlvItem;
h: THandle;
iCount,i: integer;
szTemp: string;
begin
{Pega o Handle da ListView}
h:=FindWindow('#32770',nil);
h:=FindWindowEx(h,0,'#32770',nil);
h:=FindWindowEx(h,0,'SysListView32',nil);

{Pega o número de itens da ListView}
iCount:=SendMessage(h, LVM_GETITEMCOUNT,0,0);
for i:=0 to iCount-1 do
  begin
  {Define o tamanho de cada item da ListView}
  dwSize:=sizeof(LV_ITEM) + sizeof(CHAR) * MAX_PATH;

  {Abre um espaço na memória do NOSSO programa para o PLocalShared}
  PLocalShared:=VirtualAlloc(nil, dwSize, MEM_RESERVE + MEM_COMMIT, PAGE_READWRITE);

  {Pega o PID do processo taskmgr}
  GetWindowThreadProcessId(h,@PID);

  {Abre o processo taskmgr}
  hProc:=OpenProcess(PROCESS_ALL_ACCESS,false,PID);

  {Abre um espaço na memória do taskmgr para o PSysShared}
  PSysShared:=VirtualAllocEx(hProc, nil, dwSize, MEM_RESERVE OR MEM_COMMIT, PAGE_READWRITE);

  {Define as propriedades do PLocalShared}
  PLocalShared.mask:=LVIF_TEXT;
  PLocalShared.iItem:=0;
  PLocalShared.iSubItem:=0;
  PLocalShared.pszText:=LPTSTR(dword(PSysShared) + sizeof(LV_ITEM));
  PLocalShared.cchTextMax:=100;

  {Escreve PLocalShared no espaço de memória que abriu no taskmgr}
  WriteProcessMemory(hProc,PSysShared,PLocalShared,1024,dwNumBytes);

  {Pega o texto to item i e passa pro PSysShared}
  SendMessage(h,LVM_GETITEMTEXT,i,LPARAM(PSysShared));

  {Passa o PSysShared para o PLocalShared}
  ReadProcessMemory(hProc,PSysShared,PLocalShared,1024,dwNumBytes);

  {Passa o texto do Item para szTemp}
  szTemp:=pchar(dword(PLocalShared)+sizeof(LV_ITEM));

  {Se esse texto contiver a string proc deleta o item}
  if pos(proc,PegaTexto(szTemp)) > 0 then
    ListView_DeleteItem(h,i);

  {Libera os espaços de memória utilizados}
  VirtualFree(pLocalShared, 0, MEM_RELEASE);
  VirtualFreeEx(hProc, pSysShared, 0, MEM_RELEASE);

  {Fecha o handle do processo}
  CloseHandle(hProc);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
esconde('notepad.exe');
end;

end.

Open in new window

Delphi

Avatar of undefined
Last Comment
Russell Libby

8/22/2022 - Mon
Russell Libby

The problem is that your app is 32 bit, and the remote process is 64 bit (Windows 7 64 bit task manager). The LVITEM structure is defined as follows:

  {$EXTERNALSYM tagLVITEMA}
  tagLVITEMA = packed record
    mask: UINT;
    iItem: Integer;
    iSubItem: Integer;
    state: UINT;
    stateMask: UINT;
    pszText: PAnsiChar;
    cchTextMax: Integer;
    iImage: Integer;
    lParam: LPARAM;
    iIndent: Integer;
  end;

The two items to note are:

pszText: PAnsiChar;

and

lParam: LPARAM;

In your application a pointer/LPARAM is 4 bytes in size. In the remote (64 bit process), these are 8 byte values. You could try re-defining this structure so the 2 fields are Int64, and then casting the pszText(Int64) to/from PChar. Can't test myself, as I don't have Delphi loaded on my Win7 64 bit system. It would look something like this though:

type
 tagLVITEM64A    = packed record
     mask:       UINT;
     iItem:      Integer;
     iSubItem:   Integer;
     state:      UINT;
     stateMask:  UINT;
     pszText:    Int64;
     cchTextMax: Integer;
     iImage:     Integer;
     lParam:     Int64;
     iIndent:    Integer;
  end;
  LV_ITEM64A     =  tagLVITEM64A;
  PLVITEM64      =  ^LV_ITEM64A;

var
  Form1: TForm1;

implementation
{$R *.DFM}

function PegaTexto(s: string): string;
var
c: Char;
i: integer;
Src,Dst: PChar;
begin
i:=length(s);
SetLength(Result,i);
Src:=pointer(s);
Dst:=pointer(Result);
While i <> 0 do
  begin
  c:=Src^;
  if (c>='A') and (c<='Z') then
    Inc(c,32);
  Dst^:=c;
  Inc(Src);
  Inc(Dst);
  Dec(i);
  end;
end;

procedure Esconde(proc: string);
var
dwSize,dwNumBytes,PID,hProc: Cardinal;
PLocalShared,PSysShared: PLVITEM64;
h: THandle;
iCount,i: integer;
szTemp: string;
begin
{Pega o Handle da ListView}
h:=FindWindow('#32770',nil);
h:=FindWindowEx(h,0,'#32770',nil);
h:=FindWindowEx(h,0,'SysListView32',nil);

{Pega o número de itens da ListView}
iCount:=SendMessage(h, LVM_GETITEMCOUNT,0,0);
for i:=0 to iCount-1 do
  begin
  {Define o tamanho de cada item da ListView}
  dwSize:=sizeof(LV_ITEM64A) + sizeof(CHAR) * MAX_PATH;

  {Abre um espaço na memória do NOSSO programa para o PLocalShared}
  PLocalShared:=VirtualAlloc(nil, dwSize, MEM_RESERVE + MEM_COMMIT, PAGE_READWRITE);

  {Pega o PID do processo taskmgr}
  GetWindowThreadProcessId(h,@PID);

  {Abre o processo taskmgr}
  hProc:=OpenProcess(PROCESS_ALL_ACCESS,false,PID);

  {Abre um espaço na memória do taskmgr para o PSysShared}
  PSysShared:=VirtualAllocEx(hProc, nil, dwSize, MEM_RESERVE OR MEM_COMMIT, PAGE_READWRITE);

  {Define as propriedades do PLocalShared}
  PLocalShared.mask:=LVIF_TEXT;
  PLocalShared.iItem:=0;
  PLocalShared.iSubItem:=0;
  PLocalShared.pszText:=Int64(PSysShared) + sizeof(LV_ITEM64A);
  PLocalShared.cchTextMax:=100;

  {Escreve PLocalShared no espaço de memória que abriu no taskmgr}
  WriteProcessMemory(hProc,PSysShared,PLocalShared,1024,dwNumBytes);

  {Pega o texto to item i e passa pro PSysShared}
  SendMessage(h,LVM_GETITEMTEXT,i,LPARAM(PSysShared));

  {Passa o PSysShared para o PLocalShared}
  ReadProcessMemory(hProc,PSysShared,PLocalShared,1024,dwNumBytes);

  {Passa o texto do Item para szTemp}
  szTemp:=pchar(dword(PLocalShared)+sizeof(LV_ITEM64A));

  {Se esse texto contiver a string proc deleta o item}
  if pos(proc,PegaTexto(szTemp)) > 0 then
    ListView_DeleteItem(h,i);

  {Libera os espaços de memória utilizados}
  VirtualFree(pLocalShared, 0, MEM_RELEASE);
  VirtualFreeEx(hProc, pSysShared, 0, MEM_RELEASE);

  {Fecha o handle do processo}
  CloseHandle(hProc);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
esconde('notepad.exe');
end;

-----

Regards,
Russell

jimyX

Hi MelissaCG,

I have tried your code in Win xp and Win 7 but seems your code does not really do what you are expecting it to do.

In Win xp the item is deleted but it comes back to it's place instantly (maybe because I am using low specification Laptop so the task flashes before the windows recovers the line). In Win 7 (high spesification) the function looks like it has no effect, but it gets the handle correctly, even you will get the correct number of lines (i.e.: you can try showmessage(inttostr(iCount)); it will get you the right number of lines in the listview, even you can try to maximize the listview (ShowWindow(h, SW_MAXIMIZE);) it will work too.
So your code actually works in Win xp and Win 7 but it does not do what you were told it does (according to the test that I did). You can try one thing, which is: delete all the items by removing the condition which is for matching and finding the intended task in the listview so it will enable the function to delete all the items and then you will see the items are deleted and recovered instantly (in both Win xp & Win 7).

{Funça~o para pegar o texto do Item da ListView}
function PegaTexto(s: string): string;
var
c: Char;
i: integer;
Src,Dst: PChar;
begin
i:=length(s);
SetLength(Result,i);
Src:=pointer(s);
Dst:=pointer(Result);
While i <> 0 do
  begin
  c:=Src^;
  if (c>='A') and (c<='Z') then
    Inc(c,32);
  Dst^:=c;
  Inc(Src);
  Inc(Dst);
  Dec(i);
  end;
end;

procedure Esconde(proc: string);
var
dwSize,dwNumBytes,PID,hProc: Cardinal;
PLocalShared,PSysShared: PlvItem;
h: THandle;
iCount,i: integer;
szTemp: string;
begin
{Pega o Handle da ListView}
h:=FindWindow('#32770',nil);
h:=FindWindowEx(h,0,'#32770',nil);
h:=FindWindowEx(h,0,'SysListView32',nil);

{Pega o nu'mero de itens da ListView}
iCount:=SendMessage(h, LVM_GETITEMCOUNT,0,0);
showmessage(InttoStr(iCount));
for i:=0 to iCount-1 do
  begin
  {Define o tamanho de cada item da ListView}
  dwSize:=sizeof(LV_ITEM) + sizeof(CHAR) * MAX_PATH;

  {Abre um espaço na memo'ria do NOSSO programa para o PLocalShared}
  PLocalShared:=VirtualAlloc(nil, dwSize, MEM_RESERVE + MEM_COMMIT, PAGE_READWRITE);

  {Pega o PID do processo taskmgr}
  GetWindowThreadProcessId(h,@PID);

  {Abre o processo taskmgr}
  hProc:=OpenProcess(PROCESS_ALL_ACCESS,false,PID);

  {Abre um espaço na memo'ria do taskmgr para o PSysShared}
  PSysShared:=VirtualAllocEx(hProc, nil, dwSize, MEM_RESERVE OR MEM_COMMIT, PAGE_READWRITE);

  {Define as propriedades do PLocalShared}
  PLocalShared.mask:=LVIF_TEXT;
  PLocalShared.iItem:=0;
  PLocalShared.iSubItem:=0;
  PLocalShared.pszText:=LPTSTR(dword(PSysShared) + sizeof(LV_ITEM));
  PLocalShared.cchTextMax:=100;

  {Escreve PLocalShared no espaço de memo'ria que abriu no taskmgr}
  WriteProcessMemory(hProc,PSysShared,PLocalShared,1024,dwNumBytes);

  {Pega o texto to item i e passa pro PSysShared}
  SendMessage(h,LVM_GETITEMTEXT,i,LPARAM(PSysShared));

  {Passa o PSysShared para o PLocalShared}
  ReadProcessMemory(hProc,PSysShared,PLocalShared,1024,dwNumBytes);

  {Passa o texto do Item para szTemp}
  szTemp:=pchar(dword(PLocalShared)+sizeof(LV_ITEM));

  {Se esse texto contiver a string proc deleta o item}
  // disable this condition so it deletes all tasks and here you will notice it works but Windows recovers the list quickly
  //if pos(proc,PegaTexto(szTemp)) > 0 then
    ListView_DeleteItem(h,i);

  {Libera os espaços de memo'ria utilizados}
  VirtualFree(pLocalShared, 0, MEM_RELEASE);
  VirtualFreeEx(hProc, pSysShared, 0, MEM_RELEASE);

  {Fecha o handle do processo}
  CloseHandle(hProc);
  end;
end;

Open in new window

MelissaCG

ASKER
@rllibby:
The VirtualAllocEx returns the right length pointer for my system?? And the first function im using pchar, which is 4 bytes too, should i change it to 8 bytes, i tested the way you told but something is missing i guess...


@jimyX:
Actually thats a normal behavior, it should go into a timer and all... As i said, im just using this code for learning purposes ;D
I had removed the condition and made it list the processes names but they are coming blank strings...
Your help has saved me hundreds of hours of internet surfing.
fblack61
ASKER CERTIFIED SOLUTION
Russell Libby

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
jimyX

I just came to know that Windows Task Manager refreshes the processes list view every 500 ms, from:
http://www.codeproject.com/KB/system/Hack_Windows_Task_Manager.aspx

The program from the above link clears the task manager list, it works on my Win 7, you can try it on yours to find out.

Also you can imitate that program by adding Timer to your form and set the interval to 50 and add this line to your procedure Esconde. As follows:

ListView_DeleteAllItems(h);   // remove all lines

procedure Esconde(proc: string);
var
dwSize,dwNumBytes,PID,hProc: Cardinal;
PLocalShared,PSysShared: PlvItem;
h: THandle;
iCount,i: integer;
szTemp: string;
begin
{Pega o Handle da ListView}
h:=FindWindow('#32770',nil);
h:=FindWindowEx(h,0,'#32770',nil);
h:=FindWindowEx(h,0,'SysListView32',nil);

{Pega o nu'mero de itens da ListView}
iCount:=SendMessage(h, LVM_GETITEMCOUNT,0,0);
for i:=0 to iCount-1 do
  begin
  {Define o tamanho de cada item da ListView}
  dwSize:=sizeof(LV_ITEM) + sizeof(CHAR) * MAX_PATH;

  {Abre um espaço na memo'ria do NOSSO programa para o PLocalShared}
  PLocalShared:=VirtualAlloc(nil, dwSize, MEM_RESERVE + MEM_COMMIT, PAGE_READWRITE);

  {Pega o PID do processo taskmgr}
  GetWindowThreadProcessId(h,@PID);

  {Abre o processo taskmgr}
  hProc:=OpenProcess(PROCESS_ALL_ACCESS,false,PID);

  {Abre um espaço na memo'ria do taskmgr para o PSysShared}
  PSysShared:=VirtualAllocEx(hProc, nil, dwSize, MEM_RESERVE OR MEM_COMMIT, PAGE_READWRITE);

  {Define as propriedades do PLocalShared}
  PLocalShared.mask:=LVIF_TEXT;
  PLocalShared.iItem:=0;
  PLocalShared.iSubItem:=0;
  PLocalShared.pszText:=LPTSTR(dword(PSysShared) + sizeof(LV_ITEM));
  PLocalShared.cchTextMax:=100;

  {Escreve PLocalShared no espaço de memo'ria que abriu no taskmgr}
  WriteProcessMemory(hProc,PSysShared,PLocalShared,1024,dwNumBytes);

  {Pega o texto to item i e passa pro PSysShared}
  SendMessage(h,LVM_GETITEMTEXT,i,LPARAM(PSysShared));

  {Passa o PSysShared para o PLocalShared}
  ReadProcessMemory(hProc,PSysShared,PLocalShared,1024,dwNumBytes);

  {Passa o texto do Item para szTemp}
  szTemp:=pchar(dword(PLocalShared)+sizeof(LV_ITEM));

  ListView_DeleteAllItems(h);   // remove all lines

  {Libera os espaços de memo'ria utilizados}
  VirtualFree(pLocalShared, 0, MEM_RELEASE);
  VirtualFreeEx(hProc, pSysShared, 0, MEM_RELEASE);

  {Fecha o handle do processo}
  CloseHandle(hProc);
  end;
end;

Open in new window

MelissaCG

ASKER
Well, I've told you this code would go in a timer in the last post... The ideia of this question was not to accomplish the source objective, but to understand the process. Since I've just been told that it cant be done because of incompatibilities in 64bits and 32bits I guess there's no point carrying this on anymore.

I guess Borland should make a Delphi for 64bit OS, many people must have this problem with much more important things...

Thank you for the reply though.
Russell Libby

Sad and very true. I hardly touch Delphi any more because of x64 requirements in the work I do.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
MelissaCG

ASKER
Does C++ have these requirements?? I mean, is it easier to work with memory in x64 with it??
Russell Libby

Yes, Visual C++ makes 64 bit development extremely simple, provided your familiar with C++ development to begin with.

Russell