Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Accessing other programs' memory

Posted on 2004-10-27
19
Medium Priority
?
278 Views
Last Modified: 2010-04-05
Hello. I have been trying to find a way to read a few bytes from another program's memory. Basically I'm trying to read values from other programs by using the memory adress, no luck so far. So what I'm looking for is basically working code that reads a given amount of bytes from a given adress in a given program, basically like a standard memory viewer.
0
Comment
Question by:Rohan32
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 6
  • 3
  • +1
19 Comments
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 12429340
I use a SharedMemoryMap unit I made to share memory across applications

but it basically does

        HMapping := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE,
        0, SHAREDMAPFILESIZE, pchar(MAPNAME));

MapViewOfFile(HMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);

then use mutexes for "locking" so you don't get update issues

        HMapMutex := CreateMutex(nil, false, pchar('LOCK' + MapName));
//  if HMixMutex = 0 then we were not able to lock, try again, or wait

0
 
LVL 20

Expert Comment

by:Madshi
ID: 12430946
ReadProcessMemory is the way to go. It's actually quite easy to use.

You can check which memory areas are allocated by using VirtualAllocEx.

Both APIs want a process handle, which you can get by using OpenProcess.
0
 

Author Comment

by:Rohan32
ID: 12431406
Thank you for the suggestions, I will give it a try later today and see if it works.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 2

Expert Comment

by:DeNavigator
ID: 12434576
Maybe it would be easier to use Memory Mapped Files. If you need a example just shout and I'll post some sample code
0
 
LVL 2

Expert Comment

by:DeNavigator
ID: 12434614
Oeps. Just noticed TheRealLoki says the same. :( Still if you need a more worked out example. :)
0
 

Author Comment

by:Rohan32
ID: 12436154
I was able to read the bytes with FileMapping but only the beginning (I assume that's a static part). When I tried to read the points of interest all I got from the program was 00 bytes (even though a mem viewer showed plenty of non-zero bytes there). I assume that has something to do with that the points of interest are initialised as empty bytes and then changed during runtime? If so then I need the filemapper to update somehow.
0
 
LVL 2

Expert Comment

by:DeNavigator
ID: 12436426
type
  TMijnData = record
    Naam: String[30];
    Meldingsdatum: TDateTime;
    Straat: String[30];
    Huisnummer: Integer;
    Postcode: String[7];
    Plaats: String[25];
  end;
  PMijnData = ^TMijnData;

procedure TForm1.ButtonReadClick(Sender: TObject);
var
  MijnData: PMijnData;
begin
  WaitForSingleObject(MijnMutex, INFINITE);
  try
    MijnData := MapViewOfFile(MijnMemBestand, FILE_MAP_READ, 0, 0, SizeOf(TMijnData));
    try
      LabeledEditNaam.Text := MijnData^.Naam;
      LabeledEditStraat.Text := MijnData^.Straat;
      LabeledEditNummer.Text := IntToStr(MijnData^.Huisnummer);
      LabeledEditPostcode.Text := MijnData^.Postcode;
      LabeledEditPlaats.Text := MijnData^.Plaats;
      DateTimePicker1.Date := MijnData^.Meldingsdatum;
    finally
      UnmapViewOfFile(MijnData);
    end;
  finally
    ReleaseMutex(MijnMutex);
  end;
end;

procedure TForm1.ButtonWriteClick(Sender: TObject);
var
  MijnData: PMijnData;
begin
  WaitForSingleObject(MijnMutex, INFINITE);
  try
    MijnData := MapViewOfFile(MijnMemBestand, FILE_MAP_WRITE, 0, 0, SizeOf(TMijnData));
    try
      MijnData^.Naam := LabeledEditNaam.Text;
      MijnData^.Straat := LabeledEditStraat.Text;
      MijnData^.Huisnummer := StrToInt(LabeledEditNummer.Text);
      MijnData^.Postcode := LabeledEditPostcode.Text;
      MijnData^.Plaats := LabeledEditPlaats.Text;
      MijnData^.Meldingsdatum := DateTimePicker1.Date;
    finally
      UnmapViewOfFile(MijnData);
    end;
  finally
    ReleaseMutex(MijnMutex);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MijnMemBestand := CreateFileMapping($FFFFFFFF, nil,
                       PAGE_READWRITE, 0, SizeOf(TMijnData), MMF_Naam);
  if MijnMemBestand <> 0 then begin
    if GetLastError = ERROR_ALREADY_EXISTS then begin
      CloseHandle(MijnMemBestand);
      MijnMemBestand := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, MMF_Naam);
    end;
  end;
  MijnMutex := CreateMutex(nil, False, Mutex_Naam);
  if (MijnMemBestand = 0) or (MijnMutex = 0) then begin
    ButtonSchrijf.Enabled := False;
    ButtonLees.Enabled := False;
    ShowMessage('MMF of Mutex konden niet worden gemaakt.');
  end;
end;

This is what I use!
0
 

Author Comment

by:Rohan32
ID: 12447341
ReadProcessMemory seems to partially work. I was able to read some memory from one process but then when I tried it on the desired process the OpenProcess command failed. I'm guessing this is because it couldn't get the desired access (PROCESS_VM_READ). Is there any way to go around this? I figured I would try SetSecurityInfo() but it doesn't seem to be defined in Delphi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 12450733
Which is the desired process? Is it a normal application/game, or is it a system process or service? Do you have admin rights? SetSecurityInfo won't help.
0
 

Author Comment

by:Rohan32
ID: 12450836
It's a normal application that runs as a process, not a system process or anything like that. And yes I have admin rights. OpenProcess just returns zero instead of an ID so I would assume that means that it failed.
0
 

Author Comment

by:Rohan32
ID: 12450941
Here's the code I got so far (in case I made any mistakes in it):

procedure TForm1.Button1Click(Sender: TObject);
var
  ProcessID:Integer;
begin
  ProcessID:=GetProcessID('desiredprocess');                  //This step works fine
  ProcessID:=OpenProcess(PROCESS_VM_READ,False,ProcessId);  //This stage returns 0 even though it works for other processes
  if ProcessID=0 then
    Exit;
  Caption:=IntToStr(ReadAddress(ReadAddress($848A18,ProcessID)+$0aac,ProcessID));
end;

function TForm1.ReadAddress(Address,ProcessID:Integer):Integer;
var
  Contents:Int64;
  BytesRead:Cardinal;
begin
  Contents:=0;
  if not ReadProcessMemory(ProcessID,Ptr(Address),@Contents,4,BytesRead) then
    Application.MessageBox('Error reading the process memory.','Error',MB_OK);
  Result:=Contents;
end;

function GetProcessID(ProcessName:String):Integer;
var
  ContinueLoop:BOOL;
  FSnapshotHandle:THandle;
  FProcessEntry32:TProcessEntry32;
begin
  Result:=0;
  FSnapshotHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
  FProcessEntry32.dwSize:=Sizeof(FProcessEntry32);
  ContinueLoop:=Process32First(FSnapshotHandle, FProcessEntry32);
  while Integer(ContinueLoop)<>0 do
  begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile))=UpperCase(ProcessName))
     or (UpperCase(FProcessEntry32.szExeFile)=UpperCase(ProcessName))) then
    begin
      Result:=FProcessEntry32.th32ProcessID;
      Break;
    end;
    ContinueLoop:=Process32Next(FSnapshotHandle,FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;
0
 
LVL 20

Expert Comment

by:Madshi
ID: 12451042
Please check what "ProcessID" contains before calling OpenProcess. If OpenProcess returns 0, please check what GetLastError sais afterwards.

Btw, please don't forget to call CloseHandle on the process handle you got from OpenProcess (only, if it returned something <> 0, of course). Otherwise your code has a handle leak.
0
 

Author Comment

by:Rohan32
ID: 12451101
It contains a non-zero value before calling OpenProcess. This is the error that I receive:

EAccessViolation with message 'Access violation at adress 77D5E176 in module 'user32.dll'. Read of adress 00000005'
0
 
LVL 20

Expert Comment

by:Madshi
ID: 12453880
First you said OpenProcess returned 0. Now you speak about an access violation. That are 2 different thing. Could you please clarify?
0
 

Author Comment

by:Rohan32
ID: 12453924
OpenProcess does indeed return 0 and from GetLastError I get the error about access violation (which probably results in the zero being returned).

  ProcessID:=OpenProcess(PROCESS_VM_READ,False,ProcessId);  //This stage gives ProcessID the value 0.
  if ProcessID=0 then
  begin
    Application.MessageBox(PChar(GetLastError()),'Error',MB_OK);  //This gives the access violation message.
    Exit;
  end;
0
 
LVL 20

Expert Comment

by:Madshi
ID: 12454016
You can't use GetLastError like that. It returns an integer value, not a string. You need to use IntToStr(GetLastError).
0
 

Author Comment

by:Rohan32
ID: 12456155
Replaced it with

ShowMessage(SysErrorMessage(GetlastError()));

And got "Access denied".
0
 
LVL 20

Accepted Solution

by:
Madshi earned 500 total points
ID: 12456295
Are you sure that it is a normal application and that you have admin rights?

Eventually calling this in the initialization of  your program helps:

procedure EnableAllPrivileges;
type TTokenPrivileges = record
       PrivilegeCount : dword;
       Privileges     : array [0..maxInt shr 4 - 1] of TLUIDAndAttributes;
     end;
var c1, c2 : dword;
    i1     : integer;
    ptp    : ^TTokenPrivileges;
    backup, restore : int64;
begin
  if OpenProcessToken(windows.GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, c1) then
    try
      c2 := 0;
      GetTokenInformation(c1, TokenPrivileges, nil, 0, c2);
      if c2 <> 0 then begin
        ptp := pointer(LocalAlloc(LPTR, c2 * 2));
        if GetTokenInformation(c1, TokenPrivileges, ptp, c2 * 2, c2) then begin
          // enabling backup/restore privileges breaks Explorer's Samba support
          if not LookupPrivilegeValue(nil, pchar(DecryptStr(CSeBackupPrivilege )), backup ) then backup  := 0;
          if not LookupPrivilegeValue(nil, pchar(DecryptStr(CSeRestorePrivilege)), restore) then restore := 0;
          for i1 := 0 to integer(ptp^.PrivilegeCount) - 1 do
            if (ptp^.Privileges[i1].Luid <> backup ) and
               (ptp^.Privileges[i1].Luid <> restore) then
              ptp^.Privileges[i1].Attributes := ptp^.Privileges[i1].Attributes or SE_PRIVILEGE_ENABLED;
          AdjustTokenPrivileges(c1, false, PTokenPrivileges(ptp)^, c2, PTokenPrivileges(nil)^, cardinal(pointer(nil)^));
        end;
        LocalFree(dword(ptp));
      end;
    finally CloseHandle(c1) end;
end;
0
 

Author Comment

by:Rohan32
ID: 12456625
Thank you, that bit of code fixed it :)
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Please read the paragraph below before following the instructions in the video — there are important caveats in the paragraph that I did not mention in the video. If your PaperPort 12 or PaperPort 14 is failing to start, or crashing, or hanging, …
This lesson discusses how to use a Mainform + Subforms in Microsoft Access to find and enter data for payments on orders. The sample data comes from a custom shop that builds and sells movable storage structures that are delivered to your property. …
Suggested Courses

610 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