Page 1 of 2 12 LastLast
Results 1 to 15 of 16

Thread: Getting ReadProcessMemory to work

  1. #1
    Eddie
    Guest

    Getting ReadProcessMemory to work

    Ok, I'm a newb in both using API calls and reverse engineering who is attempting to build his own patch. What I'm trying to do is a program to read a string from another program. This has to be really easy and I already got the memory address of the string.

    The hardest part for me is that I use Ada to write my programs, which is a great language until you have to interact with other things such the API calls. It is very strict on variable types and it can be really hard to convert from one type to another if you don't have the functions to do so, but well, I thing I got over this.

    I based my first testing program in this guide: http://www.woodmann.com/fravia/natz_mp2.htm

    And simplifying this is what I do:

    - Calling FindWindow to get the window handle from the program which I want to read from. Works fine.

    - Getting the process ID with the GetWindowThreadProcessId function. Works fine.

    - Open a thread to that process using the OpenProcess function. Either by using the PROCESS_VM_READ or PROCESS_ALL_ACCESS flags it works fine.

    - Using the ReadProcessMemory with the following parameters:

    hProcess: The handle provided by the previous function.
    lpBaseAddress: 16#0C38DF8C# The Hex value that points at the start of the string.
    lpBuffer: String which I'm saving the returning value in.
    nSize: 8 bytes. The string is longer, but I just want to get this to work atm.
    lpNumberOfBytesRead: Null. I don't really need to know how many bytes I am reading atm because the function is not even working for me yet.

    Guess what I get... It returns the value 0! Ok, then I try to use the GetLastError and FormatMessage functions attempting to have an idea of what is not working. What I get in my win would mean "Invalid controller", I don't know the exact error message in english as I'm not running an english version of windows. I don't remember the error code but I think it was 6.

    I think I said almost everything... Oh, I tried this only in Win XP Home with admin rights.

    Thanks a lot to whoever who could help me.

    Regards~
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  2. #2
    <script>alert(0)</script> disavowed's Avatar
    Join Date
    Apr 2002
    Posts
    1,281
    lpNumberOfBytesRead can't be null. It has to be a pointer to a writable DWORD.

  3. #3
    Eddie
    Guest
    Really? >,<
    I didn't understand that from msdn:

    Parameters

    hProcess
    [in] A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process.
    lpBaseAddress
    [in] A pointer to the base address in the specified process from which to read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access, and if it is not accessible the function fails.
    lpBuffer
    [out] A pointer to a buffer that receives the contents from the address space of the specified process.
    nSize
    [in] The number of bytes to be read from the specified process.
    lpNumberOfBytesRead
    [out] A pointer to a variable that receives the number of bytes transferred into the specified buffer. If lpNumberOfBytesRead is NULL, the parameter is ignored.


    I'll give it a try. Thanks for the reply.
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  4. #4
    Super Moderator
    Join Date
    Dec 2004
    Posts
    1,487
    Blog Entries
    15
    no need it can be null
    Code:
    ReadProcessMemory(debproc,status,&dlah,4,NULL);
    works for me
    probably your # blah is throwing some errors
    is it raw value ??
    i mean how did you get it if it is raw value from file you need to convert it to
    virtual offset
    other than that try using virtualquery() and based on result try adding virtualprotect(page_read) before calling Readprocessmemory

    Code:
    some thing like this
    
    pid = Plugingetvalue(VAL_PROCESSID);
    debproc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
    ntdll_NtQueryInformationProcess(debproc,ProcessBasicInformation,&pbi,sizeof(pbi),NULL);
    status = pbi.PebBaseAddress;
    (byte *)status += 0x68;
    VirtualQueryEx(debproc,status,&mbi,sizeof(mbi));
    VirtualProtectEx(debproc,mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&lpOld);
    ReadProcessMemory(debproc,status,&dlah,4,NULL);
    elah = (long)dlah;
    elah |= 0x02;
    WriteProcessMemory(debproc,status,&elah,4,NULL);
    Last edited by blabberer; July 20th, 2005 at 11:52.

  5. #5
    Eddie
    Guest
    I think I'll have to forget about using Ada on doing this and get a C++ developing envoirment... I'm tired of type conversions.

    Theorically I have read access to the page, but I don't get it to work... >,<
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  6. #6
    : Code Injector : nikolatesla20's Avatar
    Join Date
    Apr 2002
    Location
    :ether:
    Posts
    815
    Hi Eddie, the only thing I could think of is that lpString that you are passing. This must be a memory address..it could be that the string buffer you are passing is malfunctioning. Can't you walk thru the debugger and see what the value is right before and right after the readprocessmemory call?

    Ada is kind of like Python in the sense that everything is an object I believe...so a "pointer to a string" might have to be handled a special way. VB is the same way, it does strings stuff behind the scenes. For example, the string's length is actually the first characters in the string in VB. But VB sees this when you call API's and gives the correct address (2 bytes into the string). Maybe Ada is doing something similar to you.

    -niko

  7. #7
    Eddie
    Guest
    Hi niko,
    My head hurts because of not getting this to work...

    Here is an example of how I define the buffer and its pointer. Ada is very transparent in its way of working, it doesn't have hidden characters in the strings, so you have to add the markers for yourself .

    Code:
      type buffer_type is new string(1..8);
      type buffer_pointer_type is access all buffer_type;
      Buff: aliased buffer_type;
      Buff_pointer: constant buffer_pointer_type:= Buff'access;
    
      function buffer_pointer_type_to_address is new
        Ada.unchecked_conversion
          (source => buffer_pointer_type,
           target => System.Address);
    I checked if the buffer pointer address value was correct with the debugger and it was, so the pointers that I'm using really contain the memory addresses...

    I'm messed up...

    Thanks to everyone for your help.
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  8. #8
    Super Moderator
    Join Date
    Dec 2004
    Posts
    1,487
    Blog Entries
    15
    does it produce 32 bit pe executable loadable in ollydbg if yes post a prototype non working compiled binary here let me take a look at it

  9. #9
    Things that come to mind (including some reiterations of other posts):

    I'm fairly sure lpNumberOfBytesRead can be NULL. I had it working so yesterday. However, VirtualProtectEx's equivalent parameter can't be NULL. Perhaps that's where the confusion comes in.

    You'll want to make sure you send the base address by value. I know Visual Basic tends to create a new variable equal to that base address and passes it by reference. Hence in order to get the desired stack construction, it requires an explicit ByVal in the function call:

    ReadProcessMemory(hProcess, ByVal &H77D40000, ByVal Buffer, 7, NumBytes)
    as opposed to
    ReadProcessMemory(hProcess, &H77D40000, ByVal Buffer, 7, NumBytes)

    It's quite possible that Ada uses its own array and string classes, which may clash with the lpAddress required by ReadProcessMemory. Try using a byte array (passing the first entry by reference) first. If that doesn't work, see if passing a string is any better. Of course, the whole process will be easier to oversee if you monitor the stack at the point of the call. If you have OllyDbg, use it. If you don't, get it.

    Good luck
    Admiral

  10. #10
    Eddie
    Guest
    First of all, thanks to everyone for your replies, I really appreciate it.

    I tried to do this in C# but I never used anything but Ada before so it took me a while to realize how to do some things and some other things should be done better, but well, I think I got close to my Ada version, the funny thing is that I'm getting the same error: #6: Invalid controller.

    Ok, so if you are willing to help (thanks a lot again) I'll post this file, Read.zip.

    It contains the following:

    readme.txt - Exactly what I'm writing here.
    ReadAda/read.htm - The formatted sourcecode written in Ada (highly comented to be easy to understand even not familiarized with the language). Html format.
    ReadAda/read.rtf - The formatted sourcecode written in Ada (highly comented to be easy to understand even not familiarized with the language). Rich text format.
    ReadAda/read.exe - The executable binary file compiled with the Ada GNAT compiler.
    ReadAda/read.adb - The original sourcecode file(highly comented to be easy to understand even not familiarized with the language).
    ReadAdaUncomented/read.htm - The formatted sourcecode written in Ada (not comented to have a clean version). Html format.
    ReadAdaUncomented/read.rtf - The formatted sourcecode written in Ada (not comented to have a clean version). Rich text format.
    ReadAdaUncomented/read.exe - The executable binary file compiled with the Ada GNAT compiler.
    ReadAdaUncomented/read.adb - The original sourcecode file (not comented to have a clean version).
    ReadC#/Read.htm - The formatted sourcecode written in C#. Html format.
    ReadC#/Read.rtf - The formatted sourcecode written in C#. Rich text format.
    ReadC#/Read.exe - The executable binary file compiled with the Microsoft Visual C# compiler.
    ReadC#/Program.cs - The original sourcecode file.


    Notes:
    The coment flag in Ada is --, in C# is comonly //.
    Ada is not case sensitive, C# is.
    The executables built with the Ada compiler are large, I don't really know why but I think that it is because it adds lots of error handling functions.
    You may need Microsoft .NET Framework to run the C# executable.


    Should I learn assembly language? >_<

    Kind regards,

    Eddie~
    Attached Files Attached Files
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  11. #11
    Super Moderator
    Join Date
    Dec 2004
    Posts
    1,487
    Blog Entries
    15
    Code:
    0244FA7C   00260262  |hWnd = 00260262 ('Iczelion's tutorial no.2',class='#32770')
    0244FA80   00000000  \pProcessID = NULL  <-- you should probably fill this with an address and try
    as from help

    it says

    pdwProcessId

    Points to a 32-bit value that receives the process identifier. If this parameter is not NULL, GetWindowThreadProcessId copies the identifier of the process to the 32-bit value; otherwise, it does not.

    Code:
    the return value for me atm is is 588 :(
    
    Unnamed window, item 6
     Process=00000584
     Name=msgbox
     Window=Iczelion's tutorial no.2
     Path=D:\borland\tut02\msgbox.exe
    
    
    D:\borland\windbg>tlist -p msgbox.exe
    1412 == 584 not 588



    tlist -1416 retns no info
    its neither on takmanger
    not on tlsit dunno from where it returns this value
    probably some thread identifier

    may be its because i was running this one some too much crapped non admin account dunno have to investigate

    or probably this function is crap
    may be it returns explorers pid saying explorers created it

    as the return values help is kinda ambigous to understand for me at the moment
    from help
    The return value is the identifier of the thread that created the window.
    lets look at it in detail now to find what the heck is 588

    ok its the thread identifier not process identifier

    take a look at tlist -v
    Code:
     NumberOfThreads: 1
     1416 Win32StartAddr:0x00401000 LastErr:0x00000000 State:Waiting
    
    
    D:\borland\windbg>tlist 1412
    1412 msgbox.exe        Iczelion's tutorial no.2
       CWD:     D:\borland\tut02\
       CmdLine: "D:\borland\tut02\msgbox.exe"
       VirtualSize:    17596 KB   PeakVirtualSize:    17596 KB
       WorkingSetSize:  1852 KB   PeakWorkingSetSize:  1852 KB
       NumberOfThreads: 1
       1416 Win32StartAddr:0x00401000 LastErr:0x00000000 State:Waiting
                         0x00400000  D:\borland\tut02\msgbox.exe
      5.0.2195.6899 shp  0x77F80000  C:\WINNT\system32\ntdll.dll
      5.0.2195.6946 shp  0x7C570000  C:\WINNT\system32\KERNEL32.dll
      5.0.2195.7032 shp  0x77E10000  C:\WINNT\system32\USER32.dll
      5.0.2195.6945 shp  0x77F40000  C:\WINNT\system32\GDI32.dll
         5.1.2409.7 shp  0x60000000  C:\WINNT\system32\MSCTF.dll
      5.0.2195.6876 shp  0x7C2D0000  C:\WINNT\system32\ADVAPI32.dll
      5.0.2195.6904 shp  0x77D30000  C:\WINNT\system32\RPCRT4.DLL
        2.40.4522.0 shp  0x779B0000  C:\WINNT\system32\OLEAUT32.DLL
      5.0.2195.7021 shp  0x77A50000  C:\WINNT\system32\ole32.dll
           9.50.0.0 shp  0x10000000  C:\PROGRA~1\Logitech\MOUSEW~1\SYSTEM\LgMousHk.d
    ll
    ok one doubt out of way to get pid you should probably provide an address

    ok ill mcgyver some thing without recompiling

    Code:
    0244FA7C   00260262  |hWnd = 00260262 ('Iczelion's tutorial no.2',class='#32770')
    0244FA80   00424E90  \pProcessID = read.00424E90
    
    ok that works 
    
    00424E90  84 05 00 00                                      ..
    
    see 584 there :)
    ok spleunking continues

    Code:
    your original open process
    0244FA78   001F0FFF  |Access = PROCESS_ALL_ACCESS
    0244FA7C   00000000  |Inheritable = FALSE
    0244FA80   00000588  \ProcessId = 588
    
    spleunked
    
    0244FA78   001F0FFF  |Access = PROCESS_ALL_ACCESS
    0244FA7C   00000000  |Inheritable = FALSE
    0244FA80   00000584  \ProcessId = 584
    Write the window name from the program to identify and press ENTER:
    Iczelion's tutorial no.2
    The window "Iczelion's tutorial no.2" was found.
    Access to the process granted.

    as i said in the first post your address is probably wrong
    atleast it is wrong for the window i am using

    Code:
    |hProcess = 00000048
    |pBaseAddress = 18D20E0  <----- what the heck is this from where did you get it did you verify if it exists are you sure about this address ??????????????
    |Buffer = 0244FDC4
    |BytesToRead = 6
    \pBytesRead = NULL
    lets just press on without spleuking and see what happenss


    opps it errs
    ERROR_PARTIAL_COPY (0000012B)
    Code:
    ok restart and spleunk 
    
    |hProcess = 00000048
    |pBaseAddress = 403000
    |Buffer = 0244FDC4
    |BytesToRead = 6
    \pBytesRead = NULL
    
    
    before execution 
    0244FDC4  00 00 00 00 21 21 F8 77 24 00 00 00 FC FD 44 02  ....!!w$...D
    
    after execution 
    0244FDC4  49 63 7A 65 6C 69 F8 77 24 00 00 00 FC FD 44 02  Iczeliw$...D
    do you see it has read all the 6 bytes "Iczeli"

    not satisified ok we will fetch a big string

    now spleunked to fetch 40 bytes
    Code:
    |hProcess = 00000048
    |pBaseAddress = 403000
    |Buffer = 0244FDC4
    |BytesToRead = 40 (64.)
    \pBytesRead = NULL
    
    
    before execution
    
    0244FDC4  00 00 00 00 21 21 F8 77 24 00 00 00 FC FD 44 02  ....!!w$...D
    0244FDD4  FC FD 44 02 24 00 00 00 07 00 00 00 00 00 00 00  D$..........
    0244FDE4  9C FE 44 02 4D AB 5A 7C 00 00 00 00 00 00 00 00  DMZ|........
    0244FDF4  23 02 02 00 0C 00 00 00 1C 00 34 00 02 00 00 00  #......4....
    
    after execution 
    
    0244FDC4  49 63 7A 65 6C 69 6F 6E 27 73 20 74 75 74 6F 72  Iczelion's tutor
    0244FDD4  69 61 6C 20 6E 6F 2E 32 00 57 69 6E 33 32 20 41  ial no.2.Win32 A
    0244FDE4  73 73 65 6D 62 6C 79 20 69 73 20 47 72 65 61 74  ssembly is Great
    0244FDF4  21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  !...............
    hoooooray pat myself on my back

    opps my paste some how didnt get th final result
    Buffer address: 16#244FDC4#
    Buffer value: 0 0 0 0 33 33
    Target address: 16#18D20E0#
    Write the window name from the program to identify and press ENTER:
    Iczelion's tutorial no.2
    The window "Iczelion's tutorial no.2" was found.
    Access to the process granted.
    The process memory was read successfuly.
    Buffer address: 16#244FDC4#
    Buffer value: 73 99 122 101 108 105
    Target address: 16#18D20E0#
    Program finished. Press any key to exit.
    Last edited by blabberer; July 24th, 2005 at 08:01.

  12. #12
    Eddie
    Guest
    OMFG
    Thank you!
    Thank you!!
    THANK YOU!!!

    I realized what I did wrong and also realized how ignorant I am in API calls... I didn't realize by myself that the problem wasn't in ReadProcessMemory, it was in the previous functions...

    0244FA80 00000000 \pProcessID = NULL <-- you should probably fill this with an address and try
    That was it... the two null value in GetWindowThreadProcessId and a wrong parameter in OpenProcess... I was calling it like this...

    Code:
    AccessHandle := Win32.Winbase.OpenProcess(
                        Win32.Winnt.PROCESS_ALL_ACCESS,
                        Win32.FALSE,
                        ProcHandle);
    Where ProcHandle was the value returned by GetWindowThreadProcessId and I should had used the ProcID provided also in that function...

    I'm feeling silly because I don't get what is different from the dwProcessId and the process handle that GetWindowThreadProcessId returns.

    Sorry for having you wasting your time >_<

    Thank you again!



    Regards,

    Eddie~
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  13. #13
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,084
    Blog Entries
    5
    See, that's what's great about this community. If someone asks a reasonable question in a reasonable manner and shows they're doing the work, not just looking for a crack request, people fall all over themselves to try to help. That's the way it should be. It seems like a simple equation...

    I don't think anyone wasted their time Eddie, these are the kind of detailed posts people can learn from. Nice to see.

    Cheers,
    Kayaker

  14. #14
    Super Moderator
    Join Date
    Dec 2004
    Posts
    1,487
    Blog Entries
    15
    well it wasnt time wasted i ve never used the
    GetWindowProcess whatever api so i wont forget how to use it if ever i need to use it now

    any way i suggest you to get ollydbg and play with it debugging the program
    any program it just is an amazingly wonderful tool and saves you lot of troubles like this

    any way for me it was just few clicks to find this out
    ctrl+n on the module
    set log breakpoint log arguments to always on all those apis from findWindowOnwards till ReadProcessMemory and just looked through them to
    understand it may be took three minutes flat

    Code:
    Log data
    Address    Message
    0040B133   CALL to FindWindowA
                 Class = 0
                 Title = "Iczelion's tutorial no.2"
    0040EAE0   CALL to FindWindowA from read.0040B133
                 Class = 0
                 Title = "Iczelion's tutorial no.2"
    0040B32D   CALL to GetWindowThreadProcessId
                 hWnd = 000804B0 ('Iczelion's tutorial no.2',class='#32770')
                 pProcessID = NULL
    0040EAA8   CALL to GetWindowThreadProcessId from read.0040B32D
                 hWnd = 000804B0 ('Iczelion's tutorial no.2',class='#32770')
                 pProcessID = NULL
    0040B348   CALL to OpenProcess
                 Access = PROCESS_ALL_ACCESS
                 Inheritable = FALSE
                 ProcessId = 3BC  <--- when see this just hit file attach and see whats the actual pid and does it match nope so investigate why ?? :)
    004239AC   CALL to OpenProcess from read.0040B348
                 Access = PROCESS_ALL_ACCESS
                 Inheritable = FALSE
                 ProcessId = 3BC  open process has all required params so why did it fail ?????
    0040B3B0   CALL to ReadProcessMemory
                 hProcess = NULL
                 pBaseAddress = 18D20E0
                 Buffer = 0244FDC4
                 BytesToRead = 6
                 pBytesRead = NULL
    004239B4   CALL to ReadProcessMemory from read.0040B3B0
                 hProcess = NULL   <--- cannot be null so open process failed 
                 pBaseAddress = 18D20E0
                 Buffer = 0244FDC4
                 BytesToRead = 6
                 pBytesRead = NULL
    writing it up in step by step actually took more than 30 minutes

    thats it

  15. #15

    Lightbulb

    Just adding my two cents after the show: Error code 6 means "invalid handle". Why it was invalid has been explained above.

    BTW, you don't have to use C#, an older Visual C++ 6 will be sufficient for almost any case. Just make sure to apply the latest processor pack and service pack, otherwise you may end up in funny messes

    For doing small experiments, you can just do the following:

    Fire up Visual C++ (Visual Studio, whatever), use the wizard to create a new project. Select the MFC category, and select creating a new MFC application. Configure it to be dialog-based and leave all the other settings alone. The wizard will now create a new application project which will compile fine, involving 2 classes (CMyProg and CMyProgDlg). Open up the resource view, select the pre-created dialog and double-click the OK button. The class wizard will create a new member function for you which will execute when you push the OK button.
    Now write your code inside the OnOK-Function that has been created. (Make sure to put all of your code before the Call to ::OnOK, this call ends the application).

    Finally, hit F5 to compile and run. Default will be debug mode so you can step through your code easily and see what's happening.

    For lazy people like me (otherwise I'd just write up everything in asm), this is a very nice and easy testbed

    If you have any questions about this, just let me know.
    Double the killers!

Similar Threads

  1. RE work
    By Carlos in forum Off Topic
    Replies: 0
    Last Post: October 22nd, 2013, 17:03
  2. ODbgScript does not work
    By anthrazius in forum The Newbie Forum
    Replies: 2
    Last Post: March 27th, 2013, 06:25
  3. how to get it to work
    By jeremy in forum The Newbie Forum
    Replies: 2
    Last Post: July 6th, 2006, 05:02
  4. ReadProcessMemory vs. WinXP
    By tazmanian in forum The Newbie Forum
    Replies: 5
    Last Post: March 18th, 2003, 21:43
  5. RV tracer seems not work on...
    By spiderman in forum Malware Analysis and Unpacking Forum
    Replies: 7
    Last Post: October 17th, 2002, 21:04

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •