You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改C#内存读取代码以THREADSTACK0-0000032C为基地址?

如何将多偏移指针读取代码的基地址替换为THREADSTACK0-0x32C?

Got it, let's tackle this problem. To replace the fixed base address 0x1002CAA70 with THREADSTACK0 - 0x32C, we need to dynamically get the target thread's stack base address first—since THREADSTACK0 in Cheat Engine refers to the base address of the thread's stack. Here's how to modify your code:

Key Steps to Implement:

  1. Add Windows API Calls to retrieve thread information (we'll use NtQueryInformationThread to get the Thread Environment Block (TEB), which contains the stack base address).
  2. Calculate the New Base Address by subtracting 0x32C from the stack base address obtained from the TEB.
  3. Fix Potential 64-bit Compatibility Issues (your original code uses int for process handles, which can break on 64-bit systems—we'll switch to IntPtr instead).

Modified Full Code:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

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

        // Define structures for thread information
        [StructLayout(LayoutKind.Sequential)]
        struct THREAD_BASIC_INFORMATION
        {
            public IntPtr ExitStatus;
            public IntPtr TebBaseAddress;
            public IntPtr StackBase;
            public IntPtr StackLimit;
            public IntPtr SubSystemTib;
            // ... other fields we don't need can be omitted
        }

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

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

        [DllImport("ntdll.dll")]
        public static extern int NtQueryInformationThread(IntPtr threadHandle, int threadInformationClass, ref THREAD_BASIC_INFORMATION threadInformation, int threadInformationLength, out int returnLength);

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

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

                // Get target thread (we'll use the first thread of the process)
                ProcessThread targetThread = process.Threads[0];
                IntPtr threadHandle = OpenThread(THREAD_QUERY_INFORMATION, false, targetThread.Id);

                // Retrieve thread basic information to get TEB and stack base
                THREAD_BASIC_INFORMATION threadInfo = new THREAD_BASIC_INFORMATION();
                int returnLength;
                NtQueryInformationThread(threadHandle, ThreadBasicInformation, ref threadInfo, Marshal.SizeOf(threadInfo), out returnLength);

                // Calculate our new base address: THREADSTACK0 - 0x32C
                Int64 stackBase = (Int64)threadInfo.StackBase;
                Int64 baseAddress = stackBase - 0x32C;

                // Now proceed with your original pointer reading logic
                int bytesRead = 0;
                byte[] buffer = new byte[4];

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

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

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

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

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

                ReadProcessMemory(processHandle, fourthValue, buffer, buffer.Length, ref bytesRead);
                Console.WriteLine(BitConverter.ToInt32(buffer, 0));
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }
            Console.ReadLine();
        }
    }
}

Notes:

  • Thread Selection: The code uses the first thread of the process (process.Threads[0]). If your target pointer is tied to a specific thread, make sure to select that thread instead of the first one.
  • x64 Compatibility: We switched the hProcess parameter in ReadProcessMemory from int to IntPtr to support 64-bit processes and handles.
  • TEB Structure: The THREAD_BASIC_INFORMATION struct includes the StackBase field directly, which is exactly what Cheat Engine labels as THREADSTACK0.

内容的提问来源于stack exchange,提问作者shiny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:09:39