0

I'm working on a video game cheat engine with utilizes simple memory manipulation to achieve its goal. I have successfully been able to write a piece of code that dumps a process' memory into a byte[] and iterates over these arrays in search of the desired string. The piece of code that searches is thus:

    public bool FindString(byte[] bytes, string pName, long offset)
    {
        string s = System.Text.Encoding.UTF8.GetString(bytes);
        var match = Regex.Match(s, "test");
        if (match.Success)
            return true;
        return false;
    }

I then open up a 32-bit version of notepad (since that is what my dumping method is conditioned for) and type the word "test" in it and run my program in debug mode to see if the condition is ever hit. It does not.

Upon further inspect I check out the 's' string's contents on one of the iterations, it is thus:

\0\0\0\0\0\0\0\0���\f\0\u0001����\u0001\0\0\0 \u0001�\0\0\0\0\0          \u0001�\0\0\0\0\0\0\0�\0\0\0\0\0\0\0�\0\0\0\0\0\u0010\0\0\0\0\0\0\0 \a�\0\0\0\0\0\0\0�\0\0\0\0\0\u000f\0\0\0\u0001\0\0\0\0\0\0\0\0\0\0\0�\u000f�\0\0\0\0\0�\u000f�\0\0\0\0\0\0�\0\0\0\0\0\0\0\0\0\0\0\0\u0010\0\0\0\0\0\0\0\0\0����\f\0\0\0\0\0\0\0�\0\0����\0\0\0\0\0\0\u0010\0\0\0\0\0\0 \0\0\0\0\0\0\0\u0001\0\0\0\0\0\0\0\u0010\0\0\0\0\0\0�\0\0\0\0\0\0\0�����\u007f\0\0\u0002\0�\u0002\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0�\u000f�\0\0\0\0\0�\u000f�\0\0\0\0\0\u001f\0\0\0\0\0\0\0��������\u0010\u0001�\0\0\0\0\0\u0010\u0001�\0\0\0\0\0\u0018\0�\0\0\0\0\0\u0018\0�\0\0\0\0\0\0\0\0\0\0\0\0\0�\u0002�\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00\a�\0\0\0\0\00\a�\0\0\0\0\0�\u0002�\0\0\0\0\0�M�^\u000e\u000e_\u007f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\u0001\0\0\0\0\0\0\u0010\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\u0001\0\0\0\u0001\0\0\0\0\0\0\0\0\0\0\0\b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\u0001\0\0\0\b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`\a\0\0\0\0\0\0`\a\0\0\0\0\0\0\u0004\0\0\0\0\0\0\0\0�\u001f\0\0\0\0\0�\u001d\u0014)�\u007f\0\0����\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0�\a\0\u0002\0\0\0\0\0\0\0\0\0\0\0\0�\0\0\0\0\0\0\0\u0001\0\0\0\u0001\0\0\0\0\0\0\0\0\0\0\0P\u0001�\0\0\0\0\0\0\u0003�\0\0\0\0\0\u0010\u0003�\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0�

I continued to check each pass-through of this method for the 's' variable and found that I could not see any strings in this format.

My question is simple. What am I doing wrong that I cannot find this string? The dumping is succeeding, but something to do with my method of parsing is causing me trouble.

UPDATE (code for dumping memory)

    void ScanProcess(Process process)
    {
        // getting minimum & maximum address
        var sys_info = new SYSTEM_INFO();
        GetSystemInfo(out sys_info);
        var proc_min_address = sys_info.minimumApplicationAddress;
        var proc_max_address = sys_info.maximumApplicationAddress;
        var proc_min_address_l = (long)proc_min_address;
        var proc_max_address_l = (long)proc_max_address;

        //Opening the process with desired access level
        var processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_WM_READ, false, process.Id);
        var mem_basic_info = new MEMORY_BASIC_INFORMATION();
        var bytesRead = 0;  // number of bytes read with ReadProcessMemory

        while (proc_min_address_l < proc_max_address_l)
        {
            VirtualQueryEx(processHandle, proc_min_address, out mem_basic_info, 28); //28 = sizeof(MEMORY_BASIC_INFORMATION)

            //If this memory chunk is accessible
            if (mem_basic_info.Protect == PAGE_READWRITE && mem_basic_info.State == MEM_COMMIT)
            {
                //Read everything into a buffer
                byte[] buffer = new byte[mem_basic_info.RegionSize];
                ReadProcessMemory((int)processHandle, mem_basic_info.BaseAddress, buffer, mem_basic_info.RegionSize, ref bytesRead);

                var MemScanner = new MemScan();
                Memscanner.FindString(buffer, process.ProcessName, proc_max_address_l);
            }

            // move to the next memory chunk
            proc_min_address_l += mem_basic_info.RegionSize;
            proc_min_address = new IntPtr(proc_min_address_l);

            if (mem_basic_info.RegionSize == 0)
            {
                break;
                mem_basic_info.RegionSize = 4096;
            }
        }
    }

2 Answers2

0

For starters you can't use NotePad (or any non-binary capable viewing tool to look at your bytes).

You need to use the BitConverter APIs:

https://msdn.microsoft.com/en-us/library/system.bitconverter(v=vs.110).aspx

...to walk the data and compose/search the data to find what you're looking for (keeping whatever encoding you dumped the data in in mind).

BTW - Here's a useful HexEditor: http://www.hexworkshop.com/

curveto
  • 71
  • 2
  • 2
    _"For starters you can't use NotePad (or any non-binary capable viewing tool to look at your bytes)."_ - OP is not trying to _view binary content in NotePad_ rather he is using it as a testbed for triggering when the word _"test"_ appears in memory, such as when typing the word `test` into _NotePad_ –  Jan 27 '17 at 05:13
0

I don´t know what MemScan.FindString() does, but I guess the problem is that you are searching a string for a string, rather than for a byte array in a byte array.

By transforming the memory contents using System.Text.Encoding.UTF8.GetString(bytes); you assume that everything stored in memory can be interpreted as valid UTF8 encoding.

Your FindString() must accept parameters as byte[] rather than string, and you need to figure out how the process name is stored in memory (most likely UTF-16).

devio
  • 36,858
  • 7
  • 80
  • 143
  • FindString is defined in this post, at the top of it and it does accept byte arrays. – Steffon Scott Jan 27 '17 at 11:25
  • Oh, I overlooked this. Still, the question remains, how the process name is encoded in memory, and you need to search on byte-level, not for strings. See http://stackoverflow.com/questions/4859023 – devio Jan 27 '17 at 11:35