• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1959
  • Last Modified:

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

0
MelissaCG
Asked:
MelissaCG
  • 4
  • 3
  • 2
1 Solution
 
Russell LibbySoftware Engineer, Advisory Commented:
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

0
 
jimyXCommented:
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

0
 
MelissaCGAuthor Commented:
@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...
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
Russell LibbySoftware Engineer, Advisory Commented:
VirtualAllocEx is not your issue, pointers in your process are 32 bit. Your issue is getting the struct in the format expected by the receiving 64 bit process. That part is correct. Plus getting that struct passed to the task manager (this is where it fails) What I missed the first time around was the call to SendMessage passing the pointer of the struct in the lParam of the message. This, according to MS, will NOT fly:

•Pointer Truncation—Although a 32-bit application can use the LONGLONG data type to store a 64-bit value, there are instances where no Windows API element exists that would enable the 32-bit application to receive a 64-bit value from a 64-bit process, or to send a 64-bit value to a 64-bit process. For example, the GetWindowLongPtr and SendMessage functions truncate all pointer values, leaving the 32-bit application with a useless value.

In short, this call:

 SendMessage(h,LVM_GETITEMTEXT,i,LPARAM(PSysShared));

is not sending a 64bit pointer (8 bytes) in the lParam of the message, and there is no way to keep it from truncating to 32 bits (leaving the other 32 bits undefined). Simply put, your app is not going to work on 64 bit processes, period.

Russell





0
 
jimyXCommented:
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

0
 
MelissaCGAuthor Commented:
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.
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Sad and very true. I hardly touch Delphi any more because of x64 requirements in the work I do.
0
 
MelissaCGAuthor Commented:
Does C++ have these requirements?? I mean, is it easier to work with memory in x64 with it??
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Yes, Visual C++ makes 64 bit development extremely simple, provided your familiar with C++ development to begin with.

Russell
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

  • 4
  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now