Search code examples
c#pointerscheat-engine

c# memory THREADSTACK0 base address


Below is my C# code that I use to read-memory (for pointers with multiple offsets). However, how should I modify it so it can be used for accessing pointers with '"THREADSTACK0"-0000032C' as a base address (instead of 0x1002CAA70)?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        const int PROCESS_WM_READ = 0x0010;

        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

        [DllImport("kernel32.dll")]
        public static extern bool ReadProcessMemory(int hProcess,
        Int64 lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);

        static void Main(string[] args)
        {
            Process process = Process.GetProcessesByName("Tutorial-x86_64")[0];
            IntPtr processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id);

            int bytesRead = 0;
            byte[] buffer = new byte[4];

            //Byte[] buffer = new Byte[4];

            Int64 baseAddress = 0x1002CAA70;
            ReadProcessMemory((int)processHandle, baseAddress, buffer, buffer.Length, ref bytesRead);
            Int64 baseValue = BitConverter.ToInt32(buffer, 0);

            Int64 firstAddress = baseValue + 0x10;
            ReadProcessMemory((int)processHandle, firstAddress, buffer, buffer.Length, ref bytesRead);
            Int64 firstValue = BitConverter.ToInt32(buffer, 0);

            Int64 secondAddress = firstValue + 0x18;
            ReadProcessMemory((int)processHandle, secondAddress, buffer, buffer.Length, ref bytesRead);
            Int64 secondValue = BitConverter.ToInt32(buffer, 0);

            Int64 thirdAddress = secondValue + 0x0;
            ReadProcessMemory((int)processHandle, thirdAddress, buffer, buffer.Length, ref bytesRead);
            Int64 thirdValue = BitConverter.ToInt32(buffer, 0);

            Int64 fourthAddress = thirdValue + 0x18;
            ReadProcessMemory((int)processHandle, fourthAddress, buffer, buffer.Length, ref bytesRead);
            Int64 fourthValue = BitConverter.ToInt32(buffer, 0);

            ReadProcessMemory((int)processHandle, fourthValue, buffer, buffer.Length, ref bytesRead);
            Console.WriteLine(BitConverter.ToInt32(buffer, 0));
            Console.ReadLine();
        }
    }
}

I found this thread "Using Pointers Found in Cheat Engine in C#", but I'm having trouble implementing it.


Solution

  • To find the address of the THREADSTACK you must:

    Get the id of each thread: Take a snapshot of all the threads in the process by calling ToolHelp32Snapshot() with the TH32CS_SNAPTHREAD argument. Loop through the THREADENTRY32 structs using Thread32Next() and save all the th32ThreadID member variables.

    Get a Handle to the thread: Use OpenThread() on each threadID to get the handle to each thread

    Armed with handle and ID, get the thread stack base address: Next you need to import NtQueryInformationThread which is an undocumented function exported by ntdll.dll

    Then you call NtQueryInformationThread() with the thread handle in the first argument and ThreadBasicInformation as the second. The result is a THREAD_BASIC_INFORMATION structure with member variable StackBase.

    StackBase is the address of THREADSTACK, just match it with the correct id.

    An excellent C++ source code showing this written by makemek

    Typically you don't want to use THREADSTACK pointers because they are very volatile. They exist in the context of a thread, the process may have many threads and they will be in different states of execution and the threadstack pointer you are using may not always be correct.

    Instead of using threadstack pointers you should use regular pointers. The best thing you can do is use pattern scanning to get an instruction which accesses the address you need. Then even if the process receives an update, it will get the correct address dynamically.