循环变量(i)在Visual Studio中调试时在每个循环后神秘地重置为0(在不调试时工作)

Tom*_*ues 1 c#

我试图从C#中的进程中读取一些内存.这是我的辅助函数,用于从一系列偏移量中获取指针地址,以及相关的其他函数:

    [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Int32 ReadProcessMemory(
        IntPtr hProcess,
        IntPtr lpBaseAddress,
        [In, Out] byte[] buffer,
        UInt32 size,
        out int lpNumberOfBytesRead);

    public static bool ReadProcessMemoryHelper(
        IntPtr hProcess,
        long lpBaseAddress,
        [In, Out] byte[] buffer,
        UInt32 size,
        out int lpNumberOfBytesRead)
    {
        return ReadProcessMemory(
            hProcess,
            new IntPtr(lpBaseAddress),
            buffer,
            size,
            out lpNumberOfBytesRead) != 0;
    }
    public long Pointer(params int[] Offsets)
    {
        long pointerAddress = _baseAddr;

        if (Offsets.Length > 1)
        {
            byte[] buff = new byte[4];
            for (int i = 0; i < Offsets.Length - 1; i++)
            {
                int bytesRead;
                var cur = pointerAddress;
                var offset = Offsets[i];
                var next = cur + offset;
                Console.WriteLine("i = {0}", i);
                Console.WriteLine("[{0}+{1}], {2}", cur.ToString("X"), offset.ToString("X"), next.ToString("X"));

                if (0 == cur)
                {
                    return 0;
                }

                var readProcess = ReadProcessMemoryHelper(
                    _process.Handle,
                    next,
                    buff,
                    4,
                    out bytesRead);
                if (readProcess)
                {
                    pointerAddress = BitConverter.ToUInt32(buff, 0);
                }
                else
                {
                    return 0;
                }
                Console.WriteLine("i = {0}", i);
            }
        }

        return pointerAddress + Offsets[Offsets.Length - 1];
    }
Run Code Online (Sandbox Code Playgroud)

神秘的是,在调用ReadProcessMemoryHelper之后,循环变量i变为0.此循环仅终止,因为它最终无法从进程读取内存,返回0.

这是一些示例输出:

i = 0
[170000+FB02F0], 11202F0
i = 0
i = 1
[11469240+1C], 1146925C
i = 0
i = 1
[12DCC690+1C], 12DCC6AC
i = 0
i = 1
[114673A0+1C], 114673BC
i = 0
i = 1
[10F2C830+1C], 10F2C84C
i = 0
i = 1
[111561E0+1C], 111561FC
i = 0
i = 1
[E972CAE+1C], E972CCA
i = 0
i = 1
[1302736E+1C], 1302738A
i = 0
i = 1
[3E49+1C], 3E65
Run Code Online (Sandbox Code Playgroud)

也许更神秘.这只发生在连接调试器时(谈论Heisenbug).如果我从命令行运行它,我得到以下(正确)输出:

i = 0
[170000+FB02F0], 11202F0
i = 0
i = 1
[11469240+1C], 1146925C
i = 1
i = 2
[12DCC690+10], 12DCC6A0
i = 2
i = 3
[113E4430+130], 113E4560
i = 3
i = 4
[10F2CEF0+1C], 10F2CF0C
i = 4
Run Code Online (Sandbox Code Playgroud)

我不知道这可能做什么,这让我疯了.

jak*_*ket 5

我打算猜测你的进程是64位的.如果是这种情况,那么互操作签名是不正确的,因为最后一个参数的大小lpNumberOfBytesRead应该是64位而不是32位.

BOOL WINAPI ReadProcessMemory(
    _In_  HANDLE  hProcess,
    _In_  LPCVOID lpBaseAddress,
    _Out_ LPVOID  lpBuffer,
    _In_  SIZE_T  nSize,
    _Out_ SIZE_T  *lpNumberOfBytesRead);



#if defined(_WIN64)
typedef unsigned __int64 ULONG_PTR;
#else
typedef unsigned long ULONG_PTR;
#endif

typedef ULONG_PTR SIZE_T;
Run Code Online (Sandbox Code Playgroud)

你可以想象这会如何导致堆栈损坏.由于您无论如何都忽略了out参数,因此您可以在签名中使用IntPtr.