Solved

WriteProcessMemory in Windows7

Posted on 2010-11-09
9
1,786 Views
Last Modified: 2012-05-10
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
Comment
Question by:MelissaCG
  • 4
  • 3
  • 2
9 Comments
 
LVL 26

Expert Comment

by:Russell Libby
ID: 34096454
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
 
LVL 24

Expert Comment

by:jimyX
ID: 34097114
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
 

Author Comment

by:MelissaCG
ID: 34098700
@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
 
LVL 26

Accepted Solution

by:
Russell Libby earned 500 total points
ID: 34099193
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
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 24

Expert Comment

by:jimyX
ID: 34105454
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
 

Author Comment

by:MelissaCG
ID: 34106284
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
 
LVL 26

Expert Comment

by:Russell Libby
ID: 34107053
Sad and very true. I hardly touch Delphi any more because of x64 requirements in the work I do.
0
 

Author Comment

by:MelissaCG
ID: 34107839
Does C++ have these requirements?? I mean, is it easier to work with memory in x64 with it??
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 34107883
Yes, Visual C++ makes 64 bit development extremely simple, provided your familiar with C++ development to begin with.

Russell
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now