Thread: Reading Process Memory

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    16

    Reading Process Memory

    For one of my current projects, I'm using ReadProcessMemory() to search through a program's memory (0x00400000 -> 0x7FFFFFFF). This method is obviously obscure somehow as it takes hours to finish.

    Some premade memory editors I've used have completed the same search in under 5 seconds, and I've searched for the more efficient method with no luck.

    Would anybody happen to know, or have any ideas, on how to speed up my search?

    For reference, this is the process I'm using:

    My read function:
    Code:
    public byte[] ReadProcessMemory(IntPtr MemoryAddress, uint bytesToRead, out int bytesReaded)
            {
                byte[] buffer = new byte[bytesToRead];
    
                IntPtr ptrBytesReaded;
                ProcessMemoryReaderApi.ReadProcessMemory(m_hProcess, MemoryAddress, buffer, bytesToRead, out ptrBytesReaded);
    
                bytesReaded = ptrBytesReaded.ToInt32();
    
                return buffer;
            }

    And my calls:
    Code:
    for (int i = 0x00400000; i < 0x7FFFFFFF; i++)
                {
                    tempRead = pReader.ReadProcessMemory((IntPtr)i, 5, out bytesRead);
                    //All my if statements, etc
                }
    So it's grabbing 5 bytes, 1 byte at a time. For each address. It grabs 5 because the array of bytes I'm looking for (an unchanging marker) is 5 bytes long.

    My question, reiterated: Would anybody happen to know, or have any ideas, how the entire scope can be searched in < 10 seconds?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Maybe try and use a fixed sized buffer of say 64K, rather than keep allocating a tiny block of 5 bytes each time. There is an awful lot of overhead when allocating such small blocks, and you have so many of them.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Took that advice, but it still has to search through the 64k buffer byte by byte. It runs much faster, but nowhere near 10 seconds.

    Code:
            public bool CheckBytes(int position, byte[] signature)
            {
                byte[] Validator = new byte[signature.Length];
                for (int j = 0; j < signature.Length; j++)
                    Validator[j] = Buffer[j];
                if(Validator == signature)
                    return true;
                return false;
            }
    
            public bool CheckBytes(int position, string signature)
            {
                byte[] Validator = new byte[signature.Length];
                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                for (int j = 0; j < signature.Length; j++)
                    Validator[j] = Buffer[j];
                if (enc.GetString(Validator) == signature)
                    return true;
                return false;
            }
    
            public int GetAddresses()
            {
                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                int bytesRead;
                byte[] RawSigOne = {0x10, 0x41, 0xC4, 0x17, 0x14};
                byte[] RawSigTwo = {0xEC, 0x0C, 0xCA, 0x00, 0x08};
    
                for (int i = 0x00400000; i < 0x7FFFFFFF; i += 65536)
                {
                    counter++;
                    Buffer = pReader.ReadProcessMemory((IntPtr)i, 65536, out bytesRead);
                    for (int j = 0; j < 65536; j++)
                    {
                        if (CheckBytes(j, RawSigOne))
                            AddressOne = i + j;
                        else if (CheckBytes(j, RawSigTwo))
                            AddressTwo = i + j;
                        else if (CheckBytes(j, "lueScreen"))
                            AddressThree = i + j;
                    }
                }
    
                return 0;
            }
    This ends up running through 32767 loops of 64k buffers, and it processes about 16 loops per second.


    Edit: Oops. Wised up a bit. It was running the process 3 times when it only needed to run it once. The code is now:

    Code:
            public byte[] CheckBytes(int position)
            {
                byte[] Validator = new byte[5];
                for (int j = 0; j < 5; j++)
                    Validator[j] = Buffer[j];
                return Validator;
            }
    
            public int GetAddresses()
            {
                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                int bytesRead;
                byte[] RawSigOne = {0x10, 0x41, 0xC4, 0x17, 0x14};
                byte[] RawSigTwo = {0xEC, 0x0C, 0xCA, 0x00, 0x08};
    
                for (int i = 0x00400000; i < 0x7FFFFFFF; i += 65536)
                {
                    Buffer = pReader.ReadProcessMemory((IntPtr)i, 65536, out bytesRead);
                    for (int j = 0; j < 65536; j++)
                    {
                        byte[] CurrentArray = CheckBytes(j);
                        if (CurrentArray == RawSigOne)
                            TheAddress = i + j;
                        else if (CurrentArray == RawSigTwo)
                            AddressTwo = i + j;
                        else if (enc.GetString(CurrentArray) == "lueSc")
                            AddressThree = i + j;
                    }
                }
                return 0;
            }
    So now it runs 3 times faster, but still nowhere near 10 seconds.
    Last edited by Llam4; 04-15-2007 at 02:46 PM.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    STOP allocating memory for every bit of work you're trying to do.

    I mean, how many blocks of memory get allocated and freed with this single line?
    byte[] CurrentArray = CheckBytes(j);

    And that's for EVERY iteration of the loop.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    I don't understand how I'd be able to find a 5 byte array within a much larger array without saving and comparing 5 bytes at a time.

    I'd stop allocating memory where I do if I knew how to achieve the same result doing so.

    Edit: Wow, sped it up a lot. It's now more along the lines of 30 seconds and I'm almost down to my goal of 10~15.

    Code:
            public byte[] CheckBytes(uint position)
            {
                for (int j = 0; j < 5; j++)
                    Validator[j] = Buffer[j];
                return Validator;
            }
    
            public int GetAddresses()
            {
                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                int bytesRead;
                byte[] RawSigOne = {0x10, 0x41, 0xC4, 0x17, 0x14};
                byte[] RawSigTwo = {0xEC, 0x0C, 0xCA, 0x00, 0x08};
    
                for (uint i = 0x00400000; i < 0x7FFFFFFF; i += 65536)
                {
                    Buffer = pReader.ReadProcessMemory((IntPtr)i, 65536, out bytesRead);
                    for (uint j = 0; j < 65536; j++)
                    {
                        if (RawSigOne[0] == Buffer[j] || RawSigTwo[0] == Buffer[j] || Buffer[j] == 0x6C)
                        {
                            byte[] CurrentArray = CheckBytes(j);
                            if (CurrentArray == RawSigOne)
                                TheAddress = i + j;
                            else if (CurrentArray == RawSigTwo)
                                AddressTwo = i + j;
                            else if (enc.GetString(CurrentArray) == "lueSc")
                                AddressThree = i + j;
                        }
                    }
                }
                return 0;
            }
    Now it checks only the first byte to see if it could even possibly match before running the function.
    Last edited by Llam4; 04-15-2007 at 03:28 PM.

  6. #6
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    A lot of work on the program has been done, now I find myself at my wits end. There MUST be a logical error here that I can't figure out, as I've been trying to fix this problem for almost 8 hours now.

    Code:
    public bool GetSpec()
            {
                int bytesRead;
                byte[] RawSig = { 0x50, 0x65, 0x6F, 0x70, 0x6C, 0x65, 0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64 };
    
                for (uint i = 0x10000000; i < 0x2A000000; i += 65524)
                {
                    Buffer = new byte[65536];
                    Buffer = pReader.ReadProcessMemory((IntPtr)i, 65536, out bytesRead);
                    for (uint j = 0; j < 65524; j++)
                    {
                        if (Buffer[j] == RawSig[0] && Buffer[j+1] == RawSig[1]) //Point A
                        {
                                  //Unimportant code. Further inspects the Buffer for the rest of my signature (RawSig).
                        }
                    }
                    return true;
                }
    Explaining the function: The string I'm looking for is a marker for a dynamic value I want. They both move around in the range specified in my code, and they're always the same distance in bytes apart.

    The problem: Most of the time, the function will fail the if statement at "Point A" while i + j = the address it's currently at. I know this because I'm running a memory editor on the process and I'm looking at that specific address. Sometimes, though, it will correctly identify the marker and give me the right address.

    I'm thinking it has to be some logical error in the way I'm searching the memory. I'm grabbing x to x+64k, and then searching it. It makes logical sense to me.

    I'm pulling my hair out over this, please help if you know where I'm going wrong.
    Last edited by Llam4; 04-19-2007 at 04:13 PM.

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Llam4 View Post
    Code:
    Buffer = new byte[65536];
    Buffer = pReader.ReadProcessMemory((IntPtr)i, 65536, out bytesRead);
    for (uint j = 0; j < 65524; j++)
    You read 65536 bytes, but only examine 65524 of them. If the pattern occurs in the 12 bytes you aren't checking, you're going to miss it.

    What if the pattern spans between two of these blocks? You're never going to find it.

  8. #8
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Quote Originally Posted by brewbuck View Post
    You read 65536 bytes, but only examine 65524 of them. If the pattern occurs in the 12 bytes you aren't checking, you're going to miss it.

    What if the pattern spans between two of these blocks? You're never going to find it.
    I buffer 0-65535.

    I only search 1-65524 for the first byte of my 12 byte array, so I'm actually getting 0-11 to 65523-65535.

    Then the next search starts 12 bytes into the previous search (65536 - 12 = 65524) to make sure I don't have any gaps.

  9. #9
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    I'm converting this project from console -> GUI windows application right now. I'm not familiar at all with programming GUI in C#. The program is designed to contine looping forever, and it's always doing the heavy loops I've described in this thread, which leads it to be permanently "Not Responding". I added frequent Refresh() commands, which updates the information, but the program is still unusable and reports as not responding.

    All the mainstream programs I use are still very usable while under heavy load. How would I be able to process heavy loads without lagging my form? All of the processes are running in my Main class, not my form class and it still lags my form.

    Edit: After a few Refresh() or Update() commands it stop updatng altogether. The rest of the functions run, but my Refresh() and Update() commands are seemingly ignored by the program.
    Last edited by Llam4; 04-19-2007 at 11:14 PM.

  10. #10
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Take a look at BackgroundWorker.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  11. #11
    Registered User
    Join Date
    Apr 2007
    Posts
    16
    Yeah I threaded it. It's almost ready for a public beta release now.
    Last edited by Llam4; 04-20-2007 at 01:27 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. init adopts zombie process?
    By password636 in forum Linux Programming
    Replies: 4
    Last Post: 07-01-2009, 10:05 AM
  2. Replies: 4
    Last Post: 01-13-2008, 02:14 AM
  3. Question regarding Memory Leak
    By clegs in forum C++ Programming
    Replies: 29
    Last Post: 12-07-2007, 01:57 AM
  4. Pointer's
    By xlordt in forum C Programming
    Replies: 13
    Last Post: 10-14-2003, 02:15 PM
  5. Reading from file into memory
    By GaPe in forum C Programming
    Replies: 15
    Last Post: 12-17-2001, 04:19 PM