请高手来帮我看看这段用钱买回来的代码--关于读写内存的 ( 积分: 200 )

  • 主题发起人 VasonChen
  • 开始时间
V

VasonChen

Unregistered / Unconfirmed
GUEST, unregistred user!
[red]1、代码如下,不太理解它的原理,高手们能否讲解一下?<br>2、在C++Builder6下运行是死循环,中间是否有错?<br>3、DWORD&nbsp;dwFindValue这个参数应该设置为什么东西?假如我想查找一串字符,可以吗?[/red]<br>int&nbsp;SetProcMem(HWND&nbsp;hwnd,DWORD&nbsp;dwFindValue,DWORD&nbsp;dwReplaceValue)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwPID;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetWindowThreadProcessId(hwnd,&nbsp;&amp;dwPID);<br> HANDLE&nbsp;hProcess&nbsp;=&nbsp;OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID);<br> if(NULL&nbsp;==&nbsp;hProcess)<br> {&nbsp;return&nbsp;0;}<br> SYSTEM_INFO&nbsp;stSysInfo;<br> GetSystemInfo(&amp;stSysInfo);<br> BYTE&nbsp;*pCurrent&nbsp;=&nbsp;(BYTE&nbsp;*)stSysInfo.lpMinimumApplicationAddress;<br> MEMORY_BASIC_INFORMATION&nbsp;stMem;<br> ZeroMemory(&amp;stMem,sizeof(MEMORY_BASIC_INFORMATION));<br> int&nbsp;nWritedCount&nbsp;=&nbsp;0;<br> while(pCurrent&nbsp;&lt;(BYTE&nbsp;*)stSysInfo.lpMaximumApplicationAddress)<br> {<br> int&nbsp;ir=VirtualQueryEx(&nbsp;hProcess,(&nbsp;void&nbsp;*)pCurrent,&amp;stMem,&nbsp;sizeof(&nbsp;MEMORY_BASIC_INFORMATION));<br> if(stMem.State&nbsp;!=&nbsp;MEM_COMMIT)<br> {<br> pCurrent&nbsp;=&nbsp;(&nbsp;BYTE&nbsp;*)((&nbsp;DWORD)stMem.BaseAddress&nbsp;+&nbsp;stMem.RegionSize);<br> continue;<br> }<br> if(!(stMem.Protect&nbsp;&amp;(PAGE_READWRITE&nbsp;|&nbsp;PAGE_EXECUTE_READWRITE)))<br> {<br> pCurrent&nbsp;=&nbsp;(&nbsp;BYTE&nbsp;*)((&nbsp;DWORD)stMem.BaseAddress&nbsp;+&nbsp;stMem.&nbsp;RegionSize);<br> continue;<br> }<br> BYTE&nbsp;*pbData&nbsp;=&nbsp;new&nbsp;BYTE[stMem.RegionSize];<br> if(!ReadProcessMemory(hProcess,(LPCVOID)stMem.BaseAddress,pbData,stMem.RegionSize,NULL))<br> {<br> delete[]pbData;<br> pbData&nbsp;=&nbsp;NULL;<br> pCurrent&nbsp;=&nbsp;(&nbsp;BYTE&nbsp;*)((DWORD)stMem.BaseAddress&nbsp;+&nbsp;stMem.RegionSize);<br> continue;<br> }<br> DWORD&nbsp;*pLoc&nbsp;=(DWORD&nbsp;*)pbData;<br> while(pLoc&nbsp;&lt;=(DWORD&nbsp;*)((DWORD)pbData&nbsp;+&nbsp;stMem.RegionSize&nbsp;-&nbsp;4))<br> {<br> if(*pLoc&nbsp;==&nbsp;dwFindValue)<br> {<br> WriteProcessMemory(hProcess,(LPVOID)pLoc,(LPVOID)&amp;dwReplaceValue,sizeof(dwReplaceValue),NULL);<br> pLoc++;<br> nWritedCount++;<br> }<br> else<br> {<br> pLoc&nbsp;=&nbsp;(DWORD&nbsp;*)((DWORD)pLoc&nbsp;+&nbsp;1);<br> }<br> }<br> delete[]pbData;<br> pbData&nbsp;=&nbsp;NULL;<br> }<br> pCurrent&nbsp;=&nbsp;NULL;<br> CloseHandle(&nbsp;hProcess&nbsp;);<br> hProcess&nbsp;=&nbsp;NULL;<br> return&nbsp;nWritedCount;<br>}
 
真可怜<br>连个帮顶的人都没有!<br>帮顶顶
 
知识帖帮顶,不能轻易沉&nbsp;&nbsp;了
 
这是个在进程内存中搜索数据并替换指定值的过程<br>感觉和金山游戏修改大师中的搜索相似的功能<br>DWORD&nbsp;dwFindValue:要查找的4字节值<br>如果你要查找字符串的话&nbsp;程序要进行相应的改动
 
to:&nbsp;hellbeast,&nbsp;<br><br>假如我要查找的窗口中可能包含有“ABCD”这个字符串,要怎么修改才能实现呢?<br><br>另外是这段代码我测试过是个死循环,指针pCurrent没有被改变到,所以无法跳出循环<br>请问是哪里有问题吗?
 
这样的垃圾代码也要钱啊
 
晕&nbsp;&nbsp;还是用RMB买的
 
拜托各位老大,如果你觉得代码很普通、没难度的话,就请你解答一下我的问题好不好?
 
就是因为这个代码太乱,没注释,看起来乱七八糟,所以别人才没心情看的.<br>我写了个速度比这个快得多的控件,看看有没有兴趣了。
 
to&nbsp;白河愁:<br>1、如果你的控件是BCB且免费的,我很需要:vasonchen@163.com,并且衷心感谢!<br>2、代码我买回来的时候根本是没格式的,我耐心地编辑好的。<br>3、代码相当的短了,主要的也就那么几条语句,以我的水平我都觉得能看得下去,那么诸位高手更应该没问题啊。<br>&nbsp;&nbsp;拜托各位了!
 
BCB&nbsp;语法不太,&nbsp;delphi&nbsp;的倒可以.如果你不要求最快的算法,那到时可以免费给你一个.
 
bcb下死循环,试过别的编译环境没?
 
to:白河愁<br>感谢你的义举,等待你的代码:vasonchen@163.com<br><br>to:&nbsp;iwalk<br>没试过别的环境,但估计问题是出现在代码本身<br>要么就是winXP系统下实现不了这些功能
 
随手写了一个,可能有Bug<br><br>procedure&nbsp;ReadMemorySlow(dwPID:&nbsp;DWORD);&nbsp;//进程&nbsp;ID<br>var<br>&nbsp;&nbsp;hProcess:&nbsp;DWORD;<br>&nbsp;&nbsp;Addr:&nbsp;PByte;<br>&nbsp;&nbsp;Buf:&nbsp;array[0..1023]&nbsp;of&nbsp;Char;<br>&nbsp;&nbsp;nr:&nbsp;DWORD;<br>begin<br>&nbsp;&nbsp;hProcess:=&nbsp;OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID);<br>&nbsp;&nbsp;Addr:=&nbsp;Pointer($400000);<br><br>&nbsp;&nbsp;while&nbsp;Addr&nbsp;&lt;&nbsp;Pointer($80000000)&nbsp;do&nbsp;//读&nbsp;400000&nbsp;-&nbsp;800000000<br>&nbsp;&nbsp;&nbsp;&nbsp;begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReadProcessMemory(hProcess,&nbsp;Addr,&nbsp;@Buf[0],&nbsp;1024,&nbsp;nr);&nbsp;//读内存到&nbsp;Buf<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;nr&nbsp;&gt;&nbsp;0&nbsp;then&nbsp;Inc(Addr,&nbsp;nr)&nbsp;//读出多少,步进多少<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;Inc(Addr,&nbsp;$1000);&nbsp;//读不出,步进&nbsp;$1000<br>&nbsp;&nbsp;&nbsp;&nbsp;end;<br><br>&nbsp;&nbsp;CloseHandle(hProcess);<br>end;
 
to&nbsp;白河愁:<br>你的代码我也无法理解啊。<br>为什么是要//读&nbsp;400000&nbsp;-&nbsp;800000000&nbsp;这个区域呢?<br>是不是相当于&nbsp;<br>SYSTEM_INFO&nbsp;stSysInfo;&nbsp;GetSystemInfo(&amp;stSysInfo);<br>BYTE&nbsp;*pCurrent&nbsp;=&nbsp;(BYTE&nbsp;*)stSysInfo.lpMinimumApplicationAddress;<br>这两句所得呢?<br><br>我又得翻译成BCB来运行了,不知道得出的结果与delphi会不会有所不同呢
 
唉,运行得不出什么结果啊。
 
GetSystemInfo(&amp;stSysInfo);获取基址<br>VirtualQueryEx(&nbsp;hProcess,(&nbsp;void&nbsp;*)pCurrent,&amp;stMem,&nbsp;sizeof(&nbsp;MEMORY_BASIC_INFORMATION));&nbsp;察看该块内存属性<br>ReadProcessMemory(hProcess,(LPCVOID)stMem.BaseAddress,pbData,stMem.RegionSize,NULL))读取进程内存,大小为stMem.RegionSize
 
再给你贴片文章&nbsp;,原理和你这个程序一样<br>从进程中获取QQ号码<br><br>一.&nbsp;取QQ号码原理:&nbsp;<br><br>QQ程序在运行过程中,&nbsp;所有数据都是存放在进程空间中,QQ号码也不例外,&nbsp;要取QQ号码,&nbsp;从QQ进程空间着手是最保险的.&nbsp;<br>怎样确定QQ号码在QQ进程空间的位置?&nbsp;&quot;goomoo&quot;的方法是搜索&quot;clientuin=&quot;关键字,这个关键字之后紧跟着就是QQ号码.&nbsp;但我发现,&nbsp;&quot;clientuin=&quot;后面也不一定总是登陆的QQ号码,有时是别的字符,有时是本地登陆的其他QQ号码,&nbsp;有时又是好友的QQ号码.&nbsp;所以这个通过这个关键字来定位是不准确的.&nbsp;<br>经过分析,&nbsp;我发现,QQ运行过程中会读取&quot;MsgEx.db&quot;文件,&nbsp;在这个文件的全路径中就包含了QQ号码,&nbsp;路径格式为:&nbsp;QQ路径&nbsp;+&quot;/&quot;&nbsp;+&nbsp;QQ登陆号码&nbsp;+&nbsp;&quot;/MsgEx.db&quot;,&nbsp;找到&quot;/MsgEx.db&quot;关键字,&nbsp;然后提取关键字前面的第一个&quot;/&quot;和第二个&quot;/&quot;之间的文本,不就是QQ号码了吗?&nbsp;对,正是这样.&nbsp;<br>在QQ进程中,&nbsp;&quot;/MsgEx.db&quot;&nbsp;的地方很多,&nbsp;有些前面跟的不是QQ号码.为了保证取到号码的正确性,&nbsp;我们需要加入一些判断技巧.&nbsp;大家知道,QQ号码都是数字格式的,&nbsp;所以只要我们判断取出来的号码是不是数字,&nbsp;如果不是数字,就继续查找,直到找到是数字的文本为止.&nbsp;<br><br>二.&nbsp;怎样搜索QQ进程空间的数据?&nbsp;<br><br>1.应用程序进程<br>&nbsp;&nbsp;&nbsp;&nbsp;进程是当前操作系统下一个被加载到内存的、正在运行的应用程序的实例。每一个进程都是由内核对象和地址空间所组成的,内核对象可以让系统在其内存放有关进程的统计信息并使系统能够以此来管理进程,而地址空间则包括了所有程序模块的代码和数据以及线程堆栈、堆分配空间等动态分配的空间。进程仅仅是一个存在,是不能独自完成任何操作的,必须拥有至少一个在其环境下运行的线程,并由其负责执行在进程地址空间内的代码。在进程启动的同时即同时启动了一个线程,该线程被称作主线程或是执行线程,由此线程可以继续创建子线程。如果主线程退出,那么进程也就没有存在的可能了,系统将自动撤消该进程并完成对其地址空间的释放。<br>&nbsp;&nbsp;&nbsp;&nbsp;加载到进程地址空间的每一个可执行文件或动态链接库文件的映象都会被分配一个与之相关联的全局唯一的实例句柄(Hinstance)。&nbsp;<br><br>2.&nbsp;进程空间<br>在WIN32中,每个应用程序都可“看见”4GB的线性地址空间,&nbsp;其中最开始的4MB和最后的2GB由操作系统保留,低的2GB为进程的私有空间(如果在Boot.ini文件中使用“/3GB”的开关可以使进程的私有空间增大到3GB,系统空间1GB)。对于每个进程来讲其虚拟的地址空间是连续的,实际上它们是以页面为单位离散的存在于物理内存中,一些可能被交换到硬盘上的页面文件中,而且还有大部分的空间是未提交(Uncommitted)的。一个进程的低2GB私有空间的分布如下表:&nbsp;<br><br>范围&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大小&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作用<br>-----------------------------------------------------------------------------------------------------------------------------<br>0x0~~0xFFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;64&nbsp;KB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不可访问区域,只是用来防止非法的指针访问,访问该范围的地址会导致访问违例。<br>0x10000~~0x7FFEFFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;GB&nbsp;减去至少192&nbsp;KB&nbsp;&nbsp;&nbsp;进程的私有地址空间<br>0x7FFDE000~~0x7FFDEFFF&nbsp;&nbsp;&nbsp;4&nbsp;KB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;进程中第一个线程的线程环境块,即TEB(Thread&nbsp;environment&nbsp;block)<br>0x7FFDF000~~0x7FFDFFFF&nbsp;&nbsp;&nbsp;4&nbsp;KB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;进程的进程环境块,即PEB(Process&nbsp;environment&nbsp;block)<br>0x7FFE0000~~0x7FFE0FFF&nbsp;&nbsp;&nbsp;4&nbsp;KB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个共享的只读用户数据块,该块映射到到系统空间的一个数据块,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其中存放的是一些系统信息如系统时间、时钟的滴答数、系统版本号等。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这样访问这些信息的时候系统就不用切换到核心模式。<br>0x7FFE1000~~0x7FFEFFFF&nbsp;&nbsp;&nbsp;60&nbsp;KB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不可访问<br>0x7FFF0000~~0x7FFFFFFF&nbsp;&nbsp;&nbsp;64&nbsp;KB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不可访问,用于防止线程的缓冲跨越两种模式空间的边界&nbsp;<br><br><br>一个进程的高2GB空间具体分配如下:<br>0xFFFFFFFF-0xC0000000的1GB&nbsp;&nbsp;&nbsp;用于VxD、存储器管理和文件系统;<br>0xBFFFFFFF-0x80000000的1GB&nbsp;&nbsp;&nbsp;用于共享的WIN32&nbsp;DLL、存储器映射文件和共享存储区;&nbsp;<br><br><br>虚拟内存通常是由固定大小的块来实现的,在WIN32中这些块称为“页”,每页大小为4,096字节。在Intel&nbsp;CPU结构中,通过在一个控制寄存器中设置一位来启用分页。启用分页时CPU并不能直接访问内存,对每个地址要经过一个映射进程,通过一系列称作“页表”的查找表把虚拟内存地址映射成实际内存地址。通过使用硬件地址映射和页表WIN32可使虚拟内存即有好的性能而且还提供保护。利用处理器的页映射能力,操作系统为每个进程提供独立的从逻辑地址到物理地址的映射,使每个进程的地址空间对另一个进程完全不可见。&nbsp;<br><br>我们要搜索另一个进程空间的数据,&nbsp;要扫描范围的起点和终点不是从0~~2GB,而只是其中的一部分。要得到这个起点和终点可以使用API函数GetSystemInfo,函数的原型如下:<br>VOID&nbsp;GetSystemInfo(<br>&nbsp;&nbsp;LPSYSTEM_INFO&nbsp;lpSystemInfo<br>);<br>而在结构SYSTEM_INFO中有两个值:lpMinimumApplicationAddress和&nbsp;lpMaximumApplicationAddress,<br>就是一个应用程序可用的最小和最大的地址空间。这样我们就得到了要扫描的地址的起点和终点。那么是不是这起点和终点间所有的地址都要扫描呢?并不是这样的,因为一般情况下一个进程是用不着这么大(接近2GB)的地址空间的。因此一个进程的大部分地址空间都是未用(Free)或是保留(Reserved)的,真正用到的只是那些已提交(Committed)的内存而已。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>内存页面可以有三种状态:未用(Free)、保留(Reserved)和提交(Committed)。一个未用的页面是指该页面未被保留或是提交,对一个进程来讲一个未用的页面是不可访问的,访问这样的页面将导致访问违例。进程可以要求系统保留一些页面以备后用,系统返回一段保留的地址给进程,但是这些地址同样是不可访问的,进程若想使用这段地址空间,使用必须先提交。只有一个提交的页面才是一个真正可以访问的页面。不过你提交了一个页面,系统并不会马上分配物理页面,只有在该页面第一次被访问到时,系统才会分配页面并初始化。另外,这三个状态的两两之间都是可以相互转化的。<br>这样我们的工作已大大减少了,只需要扫描那些提交的页面就好了。接下来要做的就是得到一个进程的已提交的页面范围。这就要用到另外两个API函数VirtualQuery和VirtualQueryEx。两个函数的功能相似,不同就是VirtualQuery只是查询本进程而VirtualQueryEx可以查询指定进程的内存空间信息,后者正是我们所需要的,函数原型如下:<br>DWORD&nbsp;VirtualQueryEx(<br>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hProcess,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;进程的句柄<br>&nbsp;&nbsp;&nbsp;&nbsp;LPCVOID&nbsp;lpAddress,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;内存地址指针<br>&nbsp;&nbsp;&nbsp;&nbsp;PMEMORY_BASIC_INFORMATION&nbsp;lpBuffer,&nbsp;//&nbsp;指向MEMORY_BASIC_INFORMATION结构的指针,用于返回内存空间的信息<br>&nbsp;&nbsp;&nbsp;&nbsp;SIZE_T&nbsp;dwLength&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;lpBuffer的长度<br>);&nbsp;<br><br>再来看一下结构MEMORY_BASIC_INFORMATION的声明:<br>typedef&nbsp;struct&nbsp;_MEMORY_BASIC_INFORMATION&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;BaseAddress;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//查询内存块的基地址<br>&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;AllocationBase;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//用VirtualAlloc分配该内存时实际分配的基地址,可以小于BaseAddress,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//也就是说BaseAddress一定包含在AllocationBase分配的范围内<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;AllocationProtect;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//分配该页面时,页面的一些属性,如PAGE_READWRITE、PAGE_EXECUTE等<br>&nbsp;&nbsp;&nbsp;&nbsp;SIZE_T&nbsp;RegionSize;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//从BaseAddress开始,具有相同属性的页面的大小<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;State;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//页面的状态,有三种可能值:MEM_COMMIT、MEM_FREE和MEM_RESERVE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这个参数对我们来说是最重要的了,从中我们便可知指定内存页面的状态了<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;Protect;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//页面的属性,其可能的取值与AllocationProtect相同<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;Type;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//该内存块的类型,有三种可能值:MEM_IMAGE、MEM_MAPPED和MEM_PRIVATE<br>}&nbsp;MEMORY_BASIC_INFORMATION,&nbsp;*PMEMORY_BASIC_INFORMATION;&nbsp;<br><br>进一步研究发现,&nbsp;要搜索数据,&nbsp;只要搜索&nbsp;类型=MEM_PRIVATE&nbsp;页面属性=PAGE_READWRITE&nbsp;的内存块就好了,&nbsp;这样可以大大提高搜索速度.&nbsp;<br><br>这样我们就可得到进程中需要扫描的地址范围了。到这里剩下的问题就是要读取指定的进程的指定的地地址空间的内容了。这里要用到的是用于调试程序和错误处理(Debugging&nbsp;and&nbsp;Error&nbsp;Handling)的API函数中的ReadProcessMemory,它的原型如下:<br>BOOL&nbsp;ReadProcessMemory(<br>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hProcess,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;被读取进程的句柄<br>&nbsp;&nbsp;&nbsp;&nbsp;LPCVOID&nbsp;lpBaseAddress,&nbsp;&nbsp;&nbsp;//&nbsp;读的起始地址<br>&nbsp;&nbsp;&nbsp;&nbsp;LPVOID&nbsp;lpBuffer,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;存放读取数据缓冲区<br>&nbsp;&nbsp;&nbsp;&nbsp;SIZE_T&nbsp;nSize,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;一次读取的字节数<br>&nbsp;&nbsp;&nbsp;&nbsp;SIZE_T&nbsp;*&nbsp;lpNumberOfBytesRead&nbsp;//&nbsp;实际读取的字节数<br>);&nbsp;<br><br>参数很简单从它们的名字都可以猜出其意义了,这里就不多做说明了。要说明的是要对一个进程进行ReadProcessMemory操作,当前进程对要读的进程必须有PROCESS_VM_READ&nbsp;和&nbsp;PROCESS_QUERY_INFORMATION&nbsp;访问权。要获得一个进程的句柄和对这个进程的一些控制权可以使用API函数OpenProcess得到,其使用不做详细说明了,只给出其原型:<br>HANDLE&nbsp;OpenProcess(<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwDesiredAccess,&nbsp;&nbsp;&nbsp;//&nbsp;访问标志<br>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bInheritHandle,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;继承标志<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwProcessId&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;进程ID<br>);&nbsp;<br><br>3.如何获取QQ进程ID&nbsp;<br><br>进程ID可由&nbsp;Process32First&nbsp;和&nbsp;Process32Next&nbsp;得到,这两个函数可以枚举出所有开启的进程。<br>Process32First&nbsp;和&nbsp;Process32Next原形如下:&nbsp;<br><br>BOOL&nbsp;WINAPI&nbsp;Process32First<br>(<br>HANDLE&nbsp;hSnapshot&nbsp;&nbsp;&nbsp;//由&nbsp;CreateToolhelp32Snapshot&nbsp;返回的系统快照句柄;<br>LPPROCESSENTRY32&nbsp;lppe&nbsp;&nbsp;&nbsp;//&nbsp;指向一个&nbsp;PROCESSENTRY32&nbsp;结构;<br>);<br>BOOL&nbsp;WINAPI&nbsp;Process32Next<br>(<br>HANDLE&nbsp;hSnapshot&nbsp;&nbsp;&nbsp;//&nbsp;由&nbsp;CreateToolhelp32Snapshot&nbsp;返回的系统快照句柄;<br>LPPROCESSENTRY32&nbsp;lppe&nbsp;//&nbsp;指向一个&nbsp;PROCESSENTRY32&nbsp;结构;<br>);&nbsp;<br><br>CreateToolhelp32Snapshot&nbsp;原形如下:<br>HANDLE&nbsp;WINAPI&nbsp;CreateToolhelp32Snapshot<br>(<br>DWORD&nbsp;dwFlags,&nbsp;&nbsp;&nbsp;//&nbsp;快照标志;&nbsp;<br>DWORD&nbsp;th32ProcessID&nbsp;//&nbsp;进程ID;<br>);&nbsp;<br><br>现在需要的是进程的信息,所以将&nbsp;dwFlags&nbsp;指定为&nbsp;TH32CS_SNAPPROCESS,th32ProcessID&nbsp;忽略;&nbsp;<br><br>PROCESSENTRY32&nbsp;结构如下:<br>typedef&nbsp;struct&nbsp;tagPROCESSENTRY32&nbsp;{&nbsp;<br>DWORD&nbsp;dwSize;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;结构大小;<br>DWORD&nbsp;cntUsage;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;此进程的引用计数;<br>DWORD&nbsp;th32ProcessID;&nbsp;&nbsp;&nbsp;//&nbsp;进程ID;<br>DWORD&nbsp;th32DefaultHeapID;&nbsp;//&nbsp;进程默认堆ID;<br>DWORD&nbsp;th32ModuleID;&nbsp;&nbsp;&nbsp;//&nbsp;进程模块ID;<br>DWORD&nbsp;cntThreads;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;此进程开启的线程计数;<br>DWORD&nbsp;th32ParentProcessID;//&nbsp;父进程ID;<br>LONG&nbsp;pcPriClassBase;&nbsp;&nbsp;&nbsp;//&nbsp;线程优先权;<br>DWORD&nbsp;dwFlags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;保留;&nbsp;<br>char&nbsp;szExeFile[MAX_PATH];&nbsp;//&nbsp;进程全名;<br>}&nbsp;PROCESSENTRY32;&nbsp;<br><br>三.&nbsp;程序流程&nbsp;<br><br>知道了上面的原理&nbsp;,&nbsp;编写程序就很简单了&nbsp;.程序流程如下:&nbsp;<br><br>1.&nbsp;遍历系统进程,&nbsp;找到所有QQ进程的ID;&nbsp;<br>2.&nbsp;通过ID打开每个QQ进程,&nbsp;获得操作句柄;&nbsp;<br>3.&nbsp;读取QQ进程&nbsp;&quot;类型=MEM_PRIVATE&nbsp;页面属性=PAGE_READWRITE&quot;&nbsp;的内存块到自己程序的缓冲区,&nbsp;然后搜索关键字&nbsp;&quot;/MsgEx.db&quot;位置;<br>4.&nbsp;提取关键字前面的QQ号码.<br>5.&nbsp;显示QQ号码.结束.
 
为什么要读<br><br>范围&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大小&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作用<br>-----------------------------------------------------------------------------------------------------------------------------<br>0x0~~0xFFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;64&nbsp;KB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不可访问区域,只是用来防止非法的指针访问,访问该范围的地址会导致访问违例。<br>0x10000~~0x7FFEFFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;GB&nbsp;减去至少192&nbsp;KB&nbsp;&nbsp;&nbsp;进程的私有地址空间
 
to&nbsp;无欲则刚:<br>你的理论我是看懂了不少,也对我有所提示。甚至与我贴的代码就是相对应的。<br>但是,在关键处仍然是无法突破啊。真的恳请能详细指点一下啊。
 
顶部