各位高人帮下忙!
这几天在写个内存修改的例子,现在有个问题是我搜索出来的地址从0x00400000-0x7FFFFFFF这么大的区间确只能搜索出50多个地址,这些地址的值也取的出来。其中用到了VirtualQueryEx这个API,请问下这个方法是一次跳过一块那样的执行方式吗?也就是说在后面地址累加时是这样的:BaseAddress = (IntPtr)(inf.BaseAddress + inf.RegionSize); 这里的regionsize增加的太快,所以我现在想让自定义个IntStr类型的地址StartAddress然后每查完一个就StartAddress+0x10也就是每次加16.但是这样是有问题的。
   上面是累加的问题,用那种方法就会出现问题了,将内存中的每个地址遍历出来那不是要浪费很长时间,请问下各位在做内存搜索时常用的做法是什么,还望各位帮下,答好的加分!

解决方案 »

  1.   

    我觉的这个用c或者c++做,
    c#在行的不是这个。
      

  2.   

    很有意思的问题,似乎不简单,这里有个现成的代码,我没怎么看。How to write a Memory Scanner using C#
    你下来分析下吧,看看有没有帮助
      

  3.   

    就是用你原本的方法。因为大部分地址空间是没有分配的,所以regionsize增加很快。
      

  4.   

                //开始循环搜索
                while(searchedLength==sizeof(MEMORY_BASIC_INFORMATION)&&(int)BaseAddress <  0x7FFFFFFF) {
                    System.Console.Write("当前第"+ y +"个 ");
                    searchedLength = (int)ProcessMemoryWorokApi.VirtualQueryEx(PinballHandle, BaseAddress, out inf,
                        sizeof(MEMORY_BASIC_INFORMATION));
                    Console.WriteLine(inf.State+" "+inf.Protect+" "+inf.State+" "+inf.RegionSize);
                    System.Console.Write(Convert.ToString(inf.BaseAddress, 16));
                    if (inf.State == MEMMessage.MEM_COMMIT &&
                        (inf.Protect == PAGEinfo.PAGE_READWRITE || inf.Protect == PAGEinfo.PAGE_WRITECOPY||
                        inf.Protect == PAGEinfo.PAGE_EXECUTE_READWRITE || inf.Protect == PAGEinfo.PAGE_EXECUTE_WRITECOPY))
                    {
                        y++;
                        ProcessMemoryWorokApi.ReadProcessMemory(PinballHandle,
                                (IntPtr)inf.BaseAddress, ReadByte, 16, (IntPtr)0);                    ReadString = ProcessMemoryWorokApi.ConvertByte(ReadByte);                    System.Console.WriteLine(" "+Convert.ToString(inf.BaseAddress,16)+"=" + ReadString);
                        
                        if (UserInputString.Trim().Equals(ReadString.Trim()))
                        {
                            MessageBox(new IntPtr(0), "查到了,恭喜你!", "提示", 0);
                            //修改游戏分数
                            ProcessMemoryWorokApi.WriteProcessMemory(PinballHandle,
                               (IntPtr)inf.BaseAddress, ProcessMemoryWorokApi.ConvertToBytes(inputByteStr), 16, (IntPtr)0);
                            break;
                        }
                        else
                        {
                            BaseAddress = (IntPtr)(inf.BaseAddress + inf.RegionSize);
                        }
                       
                    }
                    else if (inf.State == MEMMessage.MEM_FREE && inf.RegionSize > 0x08000000)
                    {
                        break;
                    }
                    else if (inf.Protect == PAGEinfo.PAGE_NOACCESS)
                    {
                        // || inf.Protect == PAGEinfo.PAGE_GUARD
                        Console.WriteLine("是不能访问的!");
                        
                        ProcessMemoryWorokApi.VirtualProtectEx(PinballHandle,
                            (IntPtr)inf.BaseAddress, inf.RegionSize, PAGEinfo.PAGE_READWRITE, PAGEinfo.PAGE_NOACCESS);                    ProcessMemoryWorokApi.ReadProcessMemory(PinballHandle,
                                (IntPtr)inf.BaseAddress, ReadByte, 16, (IntPtr)0);                    ReadString = ProcessMemoryWorokApi.ConvertByte(ReadByte);                    System.Console.WriteLine(" " + Convert.ToString(inf.BaseAddress, 16) + "=" + ReadString);
                        y++;
                        BaseAddress = (IntPtr)(inf.BaseAddress + inf.RegionSize);
                    }
                    else if (inf.Protect == PAGEinfo.PAGE_GUARD||inf.Protect == PAGEinfo.PAGE_READONLY ||
                        inf.Protect == 0 || inf.Protect == PAGEinfo.PAGE_EXECUTE_READ)
                    {
                        // || inf.Protect == PAGEinfo.PAGE_GUARD
                        Console.WriteLine("是不能访问的!");                    ProcessMemoryWorokApi.VirtualProtectEx(PinballHandle,
                            (IntPtr)inf.BaseAddress, inf.RegionSize, PAGEinfo.PAGE_READWRITE, inf.Protect);                    ProcessMemoryWorokApi.ReadProcessMemory(PinballHandle,
                                (IntPtr)inf.BaseAddress, ReadByte, 16, (IntPtr)0);                    ReadString = ProcessMemoryWorokApi.ConvertByte(ReadByte);                    System.Console.WriteLine(" " + Convert.ToString(inf.BaseAddress, 16) + "=" + ReadString);
                        y++;
                        BaseAddress = (IntPtr)(inf.BaseAddress + inf.RegionSize);
                    }
                    else
                    {
                        System.Console.WriteLine("xxxxxxxxxxxxxxxxxxxxx"+inf.Protect);
                        BaseAddress = (IntPtr)(inf.BaseAddress + inf.RegionSize);
                    }            }
      

  5.   

    以前写过一个类似于FPE的程序  内存搜索穷举很慢  先查属性在搜就快多了  不过有些地方会跳过 不过很准确        while (baseAddress < 0x7fffffff)
                {
                    WinAPI.MEMORY_BASIC_INFORMATION mbi = new WinAPI.MEMORY_BASIC_INFORMATION();
                    /*
                     * fuck, 返回len为0的原因是OpenProcess的参数不是PROCESS_ALL_ACCESS
                     */
                    int len = WinAPI.VirtualQueryEx(hProcess, baseAddress, ref mbi, System.Runtime.InteropServices.Marshal.SizeOf(mbi));
                    if (len != 0 && mbi.State == (int)WinAPI.MEMMessage.MEM_COMMIT && (mbi.Protect == (int)WinAPI.MEMMessage.PAGE_READWRITE || mbi.Protect == (int)WinAPI.MEMMessage.PAGE_EXECUTE_READWRITE))
                    {
                        memSize = (int)mbi.RegionSize;
                        memBytes = new Byte[memSize];
                        memBytes.Initialize();
                        ret = WinAPI.ReadProcessMemory(hProcess, baseAddress, memBytes, memSize, out bytesReaded);
                        if (ret == false)
                        {
                            goto NEXTLOOP;
                        }
                    }
                    else if (len == 0 || (mbi.State == (int)WinAPI.MEMMessage.MEM_FREE && mbi.RegionSize > 0x08000000))
                    {
                        Trace.WriteLine("fuck the address: 0x" + baseAddress.ToString("x") + " VirtualQueryEx returns: " + len.ToString());
                        break;
                    }
                    else
                    {
                        /*
                         * mbi.BaseAddress 和 baseAddress 用哪个?这是个问题
                         */
                        baseAddress += mbi.RegionSize;
                        //baseAddress = mbi.BaseAddress + mbi.RegionSize;
                        continue;
                    }                //TODO:读取比较代码:
                    bool found = false;
                    for (int i = 0; i < bytesReaded - targetBytes.Length; i++)
                    {
                        for (int j = 0; j < targetBytes.Length; j++)
                        {
                            //通配符 ? 匹配任何情况
                            if (targetBytes[j] == '?')
                            {
                                continue;
                            }
                            else if (memBytes[i + j] != targetBytes[j])
                            {
                                found = false;
                                goto ENDFIND;
                            }
                            found = true;
                        }
                    ENDFIND:
                        if (found == true)
                        {                        Trace.WriteLine(string.Format("Found!postion is 0x{0}", (baseAddress + i).ToString("X")));
                            Byte[] mem = new Byte[targetBytes.Length];
                            WinAPI.ReadProcessMemory(hProcess, (baseAddress + (uint)i), mem, mem.Length, out bytesReaded);
                            string tmp = getMemoryString(mem);
                        }
                    }            NEXTLOOP:
                    baseAddress += (uint)memSize;
                }
      

  6.   

    谢谢你们的回答 不过 C#语言就不一样了 哪有那么好取地址呢?
    现在不是那个问题了
    看下面:
    数据地址      块头地址    块大小  堆句柄
    0x000a0688  0x000a0680    6144  0x000a0000
    当我点这个地址时下面显示的是
    000A0688  00 00 00 00 00 00 00 00 04 00 00 01 00 00 00 00 
    000A0698  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   
    000A06A8  00 00 00 00 62 01 00 00 17 00 00 00 00 00 00 00
    ........上面是一个软件读出来的
    我用BaseAddress加上regionsize取出的地址是 上面的堆句柄的地址,请问各位我怎样取到 数据地址和块头地址,因为我要用数据地址当起始地址,要不我从堆句柄中读出的byte怎么计算它的内存地址呢,你们说呢!
      

  7.   

    八戒,他需要你code较详细的注释。
      

  8.   

    呵呵,谢谢楼上各位解答!但是你查下就知道了,现在baseaddress+regionsize这样就是循环的堆地址(这是那个软件中使用的名词),然后点这个堆地址时是可以显示出来regionsize个字节的数据,关键就在这了,对这些regionsize个字节如何做地址判断,还希望楼上的帮下哦!
      

  9.   

    你仔细看看代码就知道了
    对于一个地址(开始是baseaddr,后面循环加),请求属性会得到一个regionsize,也就是从某个地址开始后面regionsize个字节是可读/用的. 而不是对这些regionsize个字节做地址判断.也就是不可通过某块的数据来确定内存地址,只能通过内存地址获取某块数据
    如果你要搜索内存,就只能暴力比较.
      

  10.   

    数据地址      块头地址    块大小  堆句柄 
    0x000a0688  0x000a0680    6144  0x000a0000 
    当我点这个地址时下面显示的是 
    000A0688  00 00 00 00 00 00 00 00 04 00 00 01 00 00 00 00 
    000A0698  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
    000A06A8  00 00 00 00 62 01 00 00 17 00 00 00 00 00 00 00 那我要实现上面的功能该怎么办呢