Jump to content
Tuts 4 You

How Can I Read Memory From Another Process?


Externalist

Recommended Posts

First of all, sorry for my poor english since it's not my first language :( , but I'll try my best to make the content understandable.

I was making a simple program that would read another process's memory Via the most popular

FindWindow -> GetWindowThreadProcessId -> OpenProcess -> ReadProcessMemory

method and all worked fine while assembling insinde WinAsm IDE and running "inside" the IDE.

But once I started to run the program outside the IDA, in other words when I double clicked on the produced .exe then the program wouldn't function as expected so I went on debugging the program in OllyDbg to find out which API failed.

But the strange thing is, even in OllyDbg, if I press the RUN button the program would run exactly the way it was supposed to(and even read the right values from memory thus, no API failing) but after closing Olly and running the program indepently through double clicking it, it fails again. So I assumed the program which I want to read memory from uses some Anti-Readmemory tricks and indeed, after a little testing I found out that the OpenProcess API returns False.

So my question is, is there any other way to read another process's memory other than the above method? I've searched & looked at other people's code but over 70% use the same method and the other 30% use a programming language I have no knowledge in :( . Thanks in advance.

Edited by scmmaker
Link to comment
Guest Pickled

Yes of course!

One of the most popular methods is called DLL Injection whereby you can directly access the contents of image you have hooked.

For example:

In the .exe you are hooking, say you want to read data from the location 0x400123 which is say a game of some sorts, 0x400123 = NumberOfLives.

You could inject a dll and create a new thread which scans that process.

/*
Search google for DLL injection, it's very straighforward You can trick windows into loading your DLL into the image of another app,
then create a new thread which you can then utilise to play inside the other process directly.See basic outline example below for hacking a game of some sort :)
*/BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH: /*
When the DLL is injected, this code is called, which
creates a new Thread which then calls back to your Function (MyThreadProc) (callback)
*/ CreateThread(MyThreadProc, ... /*see MSDN for CreateThread*/);
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}DWORD WINAPI MyThreadProc(LPVOID lParam)
{ //Read the contents of lives in our application
int* NumberOfLives = (int*)NumberOfLives; //Display Results
printf("NumberOfLives left: %d\n", *NumberOfLives); /*
Now do Whatever you like here in your
own thread with direct access to the process!!
No more need for Read/WriteProcessMemory! Use DIRECT access! :)
If you need to write new opcodes etc.
then use VirtualProtect(/*see MSDN*/PAGE_EXECUTE_READWRITE...)
to disable page security attributes for the specified region
*/ return 0;
}
Edited by Pickled
Link to comment

It's been a veeery long time since I've written something like that but it sounds to me like some exceptions are going on of which you didn't take care. When you open an application in debugger, it catches exceptions and decides if it should handle them itself or pass them to program.

It would be good if you can paste that specific piece of code where you open/attach to process and read from it.

Link to comment

dll injection indeed! :D Until now, I did practicly everything I can like trying to change the token privilege or the process privilege reading the MSDN debugging reference but since I'm so much of a newbie, soon enough I ran into a deadend. :angry: I must read those dll injection documents and get this over with! Thanks for the advice. ;)

and as for the code, there really is nothing in there. only this

Readmem procinvoke FindWindow, NULL, addr ProgName
mov windhand,eax
invoke GetWindowThreadProcessId, windhand, addr pid
invoke OpenProcess,PROCESS_VM_READ, 0, pid
mov phandle,eax
invoke ReadProcessMemory,phandle, ReadStart, addr Buffer, 20, NULLReadmem Endp

and in the DlgProc, a wsprintf for conversion, SetDlgItemText to output the result and that's all there is. I don't know why the program's behaving that way but all I could guess is because the SE_DEBUG_PRIVILEGE flag for the process(or process token?) is disabled(which was enabled when the program was run through the debugger/assembler IDE). If only there was a way to enable it...

Link to comment

Still... Win32.hlp says VirtualProtectEx needs a handle that has PROCESS_VM_OPRATION access but when I try to open the process with OpenProcess API passing PROCESS_VM_OPERATION flag, It would simply fail to open the process.

I just wonder how on earth the debugger/IDE sets their privileges to highest. If only there was a way to imitate the same routine, then everything would be solved... but that just a theory. :( Thanks for the help.

Edited by scmmaker
Link to comment

If You loke read only virtual memory of other processes You don't need set SeDebugPrivilege. Only if You need open process like system service (winlogon, ...) You'll need this privilege. This is example try to get process handle by pid and then read data from process PEB block. By calling VirtualProtect You can change page privileges from Read, Execute to CopyWrite or CopyWriteExecute.

/* Adjusting Process Token Privileges */
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
fprintf(stderr, "OpenProcessToken - GetLastError: 0x%.8d\n", GetLastError());
return 1;
}
if(!LookupPrivilegavalue("", SE_DEBUG_NAME, &luidDebug))
{
fprintf(stderr, "LookupPrivilegavalue - GetLastError: 0x%.8d\n", GetLastError());
return 1;
} tok.PrivilegeCount = 1;
tok.Privileges[0].Luid = luidDebug;
tok.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if(!AdjustTokenPrivileges(hToken, FALSE, &tok, sizeof(tok), NULL, NULL))
{
fprintf(stderr, "AdjustTokenPrivileges - GetLastError: 0x%.8d\n", GetLastError());
return 1;
}
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); for(ProcessId=1; ProcessId<4095; ProcessId++)
{
if(!(ProcessId % 4))
{
ClientId.UniqueThread = 0;
ClientId.UniqueProcess = (HANDLE)ProcessId; NtStatus = NtOpenProcess(
&ProcessHandle,
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
&ObjectAttributes,
&ClientId); if(!NtStatus)
{
printf("%.2d PID: %.4d ", i, ProcessId); hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE,
ProcessId); if(!hProcess)
printf("State: H ");
else
printf("State: - "); i++; NtStatus = NtQueryInformationProcess(
ProcessHandle,
0,
(PVOID) &ProcessInformation,
sizeof(PROCESS_BASIC_INFORMATION),
&ReturnLength); if(NtStatus)
{
fprintf(stderr, "NtQueryInformationProcess - NtStatus: 0x%.8X\n", NtStatus);
return 1;
} NtStatus = NtReadVirtualMemory(
ProcessHandle,
ProcessInformation.PebBaseAddress,
&Peb,
sizeof(Peb),
&dwSize);
...
Link to comment

Wow, that is absolutely awesome!!! That might be just the answer I was looking for!

I would have never been able to figure that out with MSDN Debugging Reference, seeing that there are some undocumented NTDLL functions and for my lack of knowledge... I wish I could try that out right away but the army makes it hard to let me use my freetime on things I really want to do... Anyway, thanks a bunch for helping me out!

But I still have a few questions about some places that confuses me;

First of all, under the if(!NtStatus), I see a variable 'i' where I can't find anywhere. :( Where is it coming from?

And the for(ProcessId=1; ProcessId<4095; ProcessId++) loop, because of my lack of knowledge I don't know why it has to perform the routine for 4096 Processes and moreover, the processes that has an ID number dividible by 4? :dunno:

Just a side question, but if I could get the process's (which I want to read memory) ID, then can I omit the for loop?

Thanks in advance!

Edited by scmmaker
Link to comment

Hi scmmaker

These undocumented functions are native version of well-known functions exported by kernel32.dll. For example NtReadVirtualMemory is native version of ReadProcessMemory. Native functions don't have body like other functions. They use int 2eh or sysenter (syscall) to jump to kernel mode. I used it because my program look for all running processes. But many of trojan horses hook kernel32 and ntdll exports like WriteProcessMemory, OpenProcess, NtQuerySystemInformation, ... So I called native functions directly:

_declspec(naked)
NTSTATUS NTAPI NtQueryInformationProcess(
IN PHANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL)
{
__asm
{
mov eax, 0x86
lea edx, [esp+0x04]
int 0x2E
ret 0x14
}
}

It works only on Windows 2k SP2! 'i' was just counter for listed processes. Look at Your task manager... All processes has pids which can divide by 4! 4095 it was max number of pid. But I'm not sure this is true. If You like read more about undocumented functions look for book "Native API" by Gary Nebbett. This is link to complete source code: http://vixen03.info/fl3a/ProcId.rar pass: lot5ProcId7

// how to call native api in Asm ;)

	xor edx, edx
push edx ; EaLength
push edx ; EaBuffer
push 60h ; CreateOptions
push edx ; CreateDisposition
push edx ; ShareAccess
push edx ; FileAttributes
push edx ; AllocationSize
push edx ; IoStatusBlock
push edi ; ObjectAttributes
push 40100000h ; DesiredAccess
lea eax, handle
push eax ; FileHandle mov eax, 20h
lea edx, [esp]
int 2eh
add esp, 2ch

// And description of NtCreateFile:

http://undocumented.ntinternals.net/UserMo...CreateFile.html

Edited by fl3a
Link to comment

Wow, I never knew native functions would be that simple... and I thought they were something huge and never even bothered to look into them! That's very new stuff(at least for me), thanks for the info!

And finally I made a success! :D and I never knew it would be that simple. Couldn't have done it without you. :P I thank you very much for all the help/advice you gave me and hope you have a very pleasant day!

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...