Exetools

Exetools (https://forum.exetools.com/index.php)
-   General Discussion (https://forum.exetools.com/forumdisplay.php?f=2)
-   -   Reading process memory (https://forum.exetools.com/showthread.php?t=6465)

FEARHQ 01-19-2005 09:06

Reading process memory
 
While writing a tiny library to read/write process memory I came across a rather unusual problem. While I can write to the process memory without a hitch, I have discovered a wierd bug that would crash the process of which you are reading the memory and I'm not sure why this happens. What I have actually done is use the ToolHelp32 library to traverse the module list and wait until a certain module is loaded (sleeping 10 milliseconds if not found), get it's base address and base size and then proceed to read it's memory with what I have written below. The problem is that the module fails in really odd manners after I try to read it with the code below. My write routine is very similar and produces no faults.

Code:


;GetProcessMemory proc uses ecx dwProcessId:DWORD, lpAddress:DWORD, dwSize:DWORD, lpBuffer:DWORD
;        LOCAL hProcess:DWORD
;        LOCAL oldProt:DWORD
;        LOCAL dummyProt:DWORD
;       
;        ; Attempt to open the process for write operations
;        invoke OpenProcess, PROCESS_VM_OPERATION+ PROCESS_VM_READ, FALSE, dwProcessId
;        .IF eax == 0
;                ret
;        .endif
;        mov hProcess, eax
;       
;        ; Set the page protection to allow read, write and execute status
;        invoke VirtualProtectEx, hProcess, lpAddress, dwSize, PAGE_EXECUTE_READWRITE, addr oldProt
;        or eax, eax
;        jz Failed
;       
;        ; Read the target process's memory
;        invoke ReadProcessMemory, hProcess, lpAddress, lpBuffer, dwSize, NULL
;        or eax, eax
;        jz Failed
;       
;        ; Restore the old page protection
;        invoke VirtualProtectEx, hProcess, lpAddress, dwSize, oldProt, addr dummyProt
;        or eax, eax
;        jz Failed
;       
;        invoke CloseHandle, hProcess
;        ret
;       
;Failed:
;        invoke CloseHandle, hProcess
;        xor eax, eax
;        ret
;GetProcessMemory endp


Innocent 01-19-2005 14:36

Hmmm. I would suggest using OllyDbg on your program to see where the problem is. Watch the registers as you step through your code. Pay attention to the LastErr flag. My guess is one of your invoke statements is producing an error. Use Olly to find which one and troubleshoot.

JuneMouse 01-19-2005 20:10

you must have read access to entire area that you trying to read
that means if a byte is straddling on other page than you need Read access
to both the pages

use IsBadReadPtr() and also intersperse your Calls with GetLastError()
or set a seh to trap failures that way you can easily pinpoint the failures to certain areas rathere than looking from scratch

upb 01-20-2005 16:20

umm but isnt he setting read access on the entire area of pages covered by the buf?!

Shub-Nigurrath 01-20-2005 21:43

here's a code snippet form a tool I'm writing. it's in C++ but might help.
The concept is to wrap the real ReadProcessMemory and use the new one. The code I wrote in C++ is useful because for classes derived from the one here attached there's nothing to change, and you might write the code as before.

I hope it helps: despite you are programming in ASM the concepts are the same and also the code structure doesn't change that much.

AccessMemory.h
Code:

#include <windows.h>

typedef BOOL (__stdcall *ACCESS_PROCESS_MEMORY_FCN)(HANDLE, LPVOID, LPVOID, DWORD, LPDWORD );

class CAccessMemory 
{
public:
        CAccessMemory();
        virtual ~CAccessMemory();

        BOOL ReadProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer,
                DWORD nSize, LPDWORD lpNumberOfBytesRead);
        BOOL WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer,
                DWORD nSize, LPDWORD lpNumberOfBytesWritten);

private:
        BOOL _accessProcessMemory(
                ACCESS_PROCESS_MEMORY_FCN fcn,
                HANDLE hProcess,
                LPVOID lpBaseAddress, LPVOID lpBuffer,
                DWORD nSize, LPDWORD lpNumberOfBytesWritten);

};

AccessMemory.cpp
Code:

CAccessMemory::CAccessMemory()
{

}

CAccessMemory::~CAccessMemory()
{

}

//A wrapper for the ::ReadProcessMemory which set also the memory
//access right properly
BOOL CAccessMemory::ReadProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer,
                DWORD nSize, LPDWORD lpNumberOfBytesRead) {
       
        ACCESS_PROCESS_MEMORY_FCN fcn;
       
        //There's a little difference between the two function pointers or
        //::ReadProcessMemory and ::WriteProcessMemory, because the two prototypes are different
        //This trick cast the pointer of the function pointer of ::ReadProcessMemory to a
        //void* then cast it back to an ACCESS_PROCESS_MEMORY_FCN function pointer.
        //The differences between these two prototypes are not important and
        //everything works excellently.
        fcn=(ACCESS_PROCESS_MEMORY_FCN)((void*)&(::ReadProcessMemory));
       
        return _accessProcessMemory(fcn, hProcess, lpBaseAddress, lpBuffer,
                nSize, lpNumberOfBytesRead);
}

//A wrapper for the ::WriteProcessMemory which set also the memory
//access right properly
BOOL CAccessMemory::WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer,
                DWORD nSize, LPDWORD lpNumberOfBytesWritten)
{
        ACCESS_PROCESS_MEMORY_FCN fcn;

        //Assign the function pointer, this time there are no problems,
        //because ACCESS_PROCESS_MEMORY_FCN is the prototype of ::WriteProcessMemory
        fcn=::WriteProcessMemory;
       
        return _accessProcessMemory(fcn, hProcess, lpBaseAddress, lpBuffer,
                nSize, lpNumberOfBytesWritten);
}

//It is used by the WriteProcessMemory and ReadProcessMemory methods.
//It worry to grant access to memory.
BOOL CAccessMemory::_accessProcessMemory(
                ACCESS_PROCESS_MEMORY_FCN fcn,
                HANDLE hProcess,
                LPVOID lpBaseAddress, LPVOID lpBuffer,
                DWORD nSize, LPDWORD lpNumberOfBytes)
{
        DWORD OldProtection=0;
        //It is not really used because the VirtualProtectEx function always requires a valid
        //variable to hold the old page protection values, otherwise fails. When restoring the
        //protection values of the page, on the existing of this program, the old values are not
        //important of course.
        DWORD dummyProtection=0;

        BOOL bVal=FALSE;

        int tries=0;
       
        //Do 3 tries loop, so as not the block forever..
        while(tries<3) {
                __try {
                        tries++;
                        bVal=fcn(hProcess, lpBaseAddress, lpBuffer,nSize, lpNumberOfBytes);
                        if(!bVal)
                                //The RaiseException function raises an exception in the calling thread.
                                RaiseException(1, // exception code
                0,                // continuable exception (non death exception)
                0, NULL);        // no arguments
                }
                __except(TRUE) {
                        if(IsBadReadPtr(lpBaseAddress, nSize) || IsBadWritePtr(lpBaseAddress, nSize))
                                VirtualProtectEx(hProcess, lpBaseAddress, nSize,
                                        PAGE_EXECUTE_READWRITE, &OldProtection);
                        continue;
                }
                break;
        }
       
        //Restore the previous protections of the patched address.
        //OlProtection is !=0 if the previous VirtualProtectEx has been done.
        if(OldProtection!=0)
                VirtualProtectEx(hProcess, lpBaseAddress, nSize,
                        OldProtection, &dummyProtection);

        return bVal;

}


FEARHQ 01-21-2005 15:42

Thanks for all the replies guys :)

My function does succeed in reading the entire block and copying it, that's not really the problem. The problem is the module not playing so nicely with me afterwards :/ I did set the protection to read/write/execute in any case to allow all acces... Perhaps this is deadly when code is actually executing in there, heh.

Shub-Nigurrath, I love the idea to use IsBadReadPtr/IsBadWritePtr to check the memory range for desired access, but wouldn't this simply give you the access rights for YOUR process's pages in that range? I don't see those functions taking in a handle to the target process, but then again I never used them before.

Innocent: Olly is MY debugger of choice, for all debugging and 'other' tasks. There is no direct problem with my code, but aparently the target code doesn't like to be read, or have it's protections changed (haven't really looked at that). The point is that this generic write routine fails by all means with my current target, and so would Shub-Nigurrath's. My workaround was to map the target file to memory and get whatever info I need for there.

On a side note, is there any way to pause execution of the target process? I would probably need to stop all of it's threads, then later resume them... Best would be to save the thread's run state (some may be paused and if they were, they should be paused when I'm done)

Shub-Nigurrath 01-21-2005 16:38

2 FEARHQ

not really using that permissions you can gain access right for any process, even external processes: I used it for a loader which launches an external program and everything works fine.

TQN 01-21-2005 19:04

Hi Shub-Nigurrath !
Sorry first if I have a wrong idea. I think the IsBadReadPtr and IsBadWritePtr can not be used to check memory access right for a memory range of another process. In your code, you really call them to check read/write right for a memory range in your virtual memory process with the addess value is same as lpAddress (of beging loaded process).
FEARHQ, if one of a call to ReadProcessMemory failed, the protection flag of those memory pages will be not restored to original flag (je Failed). Some coders/programs uses PAGE_NOACCESS to allocate memory when need.
Regards,
TQN

Shub-Nigurrath 01-22-2005 08:29

humm. You are right: I got the wrong point because I used since now it for loaders, so the target process, even if external, is launched by my loader, a "child", works also for protected memory sections of the target..but a process of this type is different than an external already running process.

Effectively for opened processes it doesn't work, or better, works the reading but not the writing: it returns a casual value (negative also) and do not write anything.

JuneMouse 01-22-2005 15:57

TQN so if isBadReadPtr() wont work for processes opened by OpenProcess
then what do we use is it VirtualQuery() ??
how does one ascertain if one really has access to that process for read write etc
without getting the code in debugger and looking for every return values

TQN 01-22-2005 21:24

Hi JuneMouse !
Sorry if I wrong. In my experience, the safe way is call VirtualQueryEx to detect read/write right of a virtual memory page of a external process. Call GetSystemInfo to get page size, scan one page one.


All times are GMT +8. The time now is 15:34.

Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX