如何快速搜索内存数据

chb19810501 2008-03-09 09:53:02
如何快速搜索内存数据
...全文
1619 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
areyong 2011-01-07
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 lyserver 的回复:]
优化总结:
一、考虑内存对齐。其实仅此因素,速度就会提高大约16倍(而不是我前面说的4倍),即使是查找单个字符也如此,除了你的查找子串没有定义好而可能导致失败,比如某个进程有字符串“如何快速搜索内存数据”,而查找子串被定义为以“何”、“速”、“索”等未对齐的字开头会导致失败,此时可偏移2节字后做二次扫描,整个速度仍然而逐个字节比较快8倍。
二、缓存输出结果。在显示结果时使用你代码中的缓存,然后……
[/Quote]
lyserver
你这段代码很不错,很快,感谢!
cyradg 2008-04-30
  • 打赏
  • 举报
回复
例如内存为 FF FF FF FF FF FF 00 0A,如果查找0XFFFFFFFF,应该找到三个地址,如果只是找到第一个以后再跳4个字节,那结果只是找到一个.
cyradg 2008-04-30
  • 打赏
  • 举报
回复
For lpMBI = 1 To (MBI.RegionSize \ 4 - bSize)
For lpByte = 1 To bSize
bSuccess = (lpMemBuffer(lpMBI + lpByte) = lpDataBuffer(lpByte))
If Not bSuccess Then Exit For
Next
If bSuccess Then '找到目标内容
Debug.Print "找到目标内容,进程文件:", lpszFileName, "地址:", MBI.BaseAddress + lpMBI * 4
End If
Next
End If
============================
显然4个字节对齐,只是片面的,如果要查找0xFFFFFFFF之类的四个字节都相等的呢?那可不是4个字节一跳,而是1个字节一跳了.
lyserver 2008-03-31
  • 打赏
  • 举报
回复
优化总结:
一、考虑内存对齐。其实仅此因素,速度就会提高大约16倍(而不是我前面说的4倍),即使是查找单个字符也如此,除了你的查找子串没有定义好而可能导致失败,比如某个进程有字符串“如何快速搜索内存数据”,而查找子串被定义为以“何”、“速”、“索”等未对齐的字开头会导致失败,此时可偏移2节字后做二次扫描,整个速度仍然而逐个字节比较快8倍。
二、缓存输出结果。在显示结果时使用你代码中的缓存,然后一次性显示,速度又将提高数十倍(因为debug.print为图形操作,非常费时)。
三、排除系统核心进程。在进行全机进程范围内搜索时,应排除系统核心进程,如将
Call fnSearch(byteData, hProcessID, lpStart, lpEnd)
加上一个判断

'排除系统进程
If InStr(szModuleName, "[System Idle Process] wscntfy.exe svchost.exe winlogon.exe CSRSS.EXE SMSS.exe alg.exe ctfmon.exe rundll32.exe dllhost.exe Explorer.EXE spoolsv.exe services.exe msdtc.exe taskmgr.exe") = 0 Then
Call fnSearch(byteData, hProcessID, lpStart, lpEnd)
End If
速度又将提高N倍。
四、编译程序。也许楼主觉得这点是废话,其实不然,由于在IDE环境中程序被加入了调试信息,速度自然慢,编译后运和,提高的不此一个数量级。

优化后的实验结果:
我的机器配置为(赛扬1.7、256M内存、2002年组装),运行了VB6、MsDEV、FireFox、PPStream等8个应用程序,进行指定进程扫描时,耗时40毫秒(20次测试的最大值,最快达16毫秒),进行全机进程搜索时,耗时4000毫秒(20次测试的最大值)。楼主的机器应该比我的好,耗时应该只少不多。
你的分数太少,我不再啰嗦了,昨天下了点小雨,我得到菜地里看一看。
chb19810501 2008-03-31
  • 打赏
  • 举报
回复
非常感谢各位朋友的帮助,参考lyserver 的代码修改内存对齐部分,速度果然大幅度提高.
我查找12个字节的数据,用时:5.0625秒,已经能够满足我的需要了,再次谢谢大家!

大家如有空帮我看看另外1个问题:http://topic.csdn.net/u/20071126/11/fed822c2-8851-4e23-99eb-b31e796dba85.html
tzwsoho 2008-03-31
  • 打赏
  • 举报
回复
你的分数太少,我不再啰嗦了,昨天下了点小雨,我得到菜地里看一看。

///

学习了,谢谢农民叔叔同志
lyserver 2008-03-31
  • 打赏
  • 举报
回复
请楼主用以下函数替换前面同名的函数,由于下面函数考虑了内存对齐,速度提高大约4倍.
Private Function fnSearch(byteData() As Byte, ByVal p_ID As Long, ByVal lpStart As Long, ByVal lpEnd As Long)
Dim hProcess As Long '进程句柄
Dim lpBaseAddress As Long
Dim bSuccess As Boolean
Dim MBI As MEMORY_BASIC_INFORMATION
Dim lRet As Long '用于接收API返回值
Dim mbiSize As Long, bSize As Long, dwNeeded As Long
Dim lpMBI As Long, lpByte As Long
Dim lpMemBuffer() As Long '内存缓冲区指针
Dim lpDataBuffer() As Long '要查找的字符串缓冲区指针
Dim lpszFileName As String '进程模块名称数组

lpBaseAddress = lpStart
mbiSize = Len(MBI)
bSize = UBound(byteData)
bSize = (bSize \ 4) + IIf((bSize Mod 4) <> 0, 1, 0)
ReDim lpDataBuffer(bSize)
CopyMemory lpDataBuffer(1), byteData(1), UBound(byteData)

hProcess = OpenProcess(PROCESS_VM_READ Or PROCESS_QUERY_INFORMATION, False, p_ID)
If hProcess = 0 Then Exit Function

lpszFileName = String(MAX_PATH, vbNullChar) '取完整的进程模块名称
If GetModuleFileNameEx(hProcess, ByVal 0&, lpszFileName, MAX_PATH) Then
lpszFileName = Left(lpszFileName, InStr(lpszFileName, vbNullChar) - 1)
End If
lRet = VirtualQueryEx(hProcess, lpBaseAddress, MBI, mbiSize)

Do While ((lRet > 0) And (lpBaseAddress < lpEnd))
If (MBI.Protect And PAGE_READWRITE) And (MBI.State = MEM_COMMIT) Then
ReDim lpMemBuffer(MBI.RegionSize)
ReadProcessMemory hProcess, ByVal MBI.BaseAddress, lpMemBuffer(1), MBI.RegionSize, 0&
For lpMBI = 1 To (MBI.RegionSize \ 4 - bSize)
For lpByte = 1 To bSize
bSuccess = (lpMemBuffer(lpMBI + lpByte) = lpDataBuffer(lpByte))
If Not bSuccess Then Exit For
Next
If bSuccess Then '找到目标内容
Debug.Print "找到目标内容,进程文件:", lpszFileName, "地址:", MBI.BaseAddress + lpMBI * 4
End If
Next
End If
lpBaseAddress = lpBaseAddress + MBI.RegionSize
lRet = VirtualQueryEx(hProcess, lpBaseAddress, MBI, mbiSize)
DoEvents
Loop
CloseHandle hProcess
End Function
lyserver 2008-03-30
  • 打赏
  • 举报
回复
再说明一点,不知楼主是要搜索本地内存呢?还是要搜索所有进程的内存?
如果是后者,需要考虑VB字符与C++字符串的区别.
如果没有特别的事,我下午给你完整的VB示例代码.
lyserver 2008-03-30
  • 打赏
  • 举报
回复
此外还可使用进程调试API,但我没试过.
chb19810501 2008-03-30
  • 打赏
  • 举报
回复
大家继续啊
lyserver 2008-03-30
  • 打赏
  • 举报
回复
'VB字符串查找示例程序
'作者:lyserver

Option Base 1
Option Explicit

Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Const PAGE_READWRITE = &H4
Private Const MEM_COMMIT = &H1000
Private Type MEMORY_BASIC_INFORMATION
BaseAddress As Long
AllocationBase As Long
AllocationProtect As Long
RegionSize As Long
State As Long
Protect As Long
lType As Long
End Type
Private Declare Function VirtualQueryEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function DebugActiveProcess Lib "kernel32" (ByVal dwProcessId As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Const TH32CS_SNAPPROCESS As Long = &H2
Private Declare Function CreateToolhelp32Snapshot Lib "kernel32" (ByVal lFlags As Long, ByVal lProcessID As Long) As Long
Private Const MAX_PATH As Integer = 260
Private Type PROCESSENTRY32
dwSize As Long
cntusage As Long
th32ProcessID As Long ' this process
th32DefaultHeapID As Long
th32ModuleID As Long ' associated exe
cntThreads As Long
th32ParentProcessID As Long ' this process's parent process
pcPriClassBase As Long ' Base priority of process's threads
dwFlags As Long
szExeFile As String * MAX_PATH ' Path
End Type
Private Declare Function Process32First Lib "kernel32" (ByVal hSnapShot As Long, uProcess As PROCESSENTRY32) As Long
Private Declare Function Process32Next Lib "kernel32" (ByVal hSnapShot As Long, uProcess As PROCESSENTRY32) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Const PROCESS_VM_READ As Long = &H10 '允许读目标进程
Private Const PROCESS_QUERY_INFORMATION As Long = &H400 '允许查询内存状态
Private Const PROCESS_ALL_ACCESS As Long = &H1F0FFFF '允许完全控制目标进程
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function EnumProcessModules Lib "psapi.dll" (ByVal hProcess As Long, lphModule As Any, ByVal cb As Long, lpcbNeeded As Long) As Boolean
Private Declare Function GetModuleFileNameEx Lib "psapi" Alias "GetModuleFileNameExA" (ByVal hProcess As Long, ByVal hModule As Long, ByVal lpFilename As String, ByVal nSize As Long) As Long

Sub Main()
Dim s As String
Dim b() As Byte
Dim nLen As Long

s = "1234567890"
nLen = Len(s) * 2
ReDim b(nLen) As Byte
CopyMemory b(1), ByVal StrPtr(s), nLen

Call Search(b, GetCurrentProcessId())
End Sub


Public Sub Search(byteData() As Byte, Optional p_ID As Long = 0, Optional szWindowText As String = "", Optional ByVal lpStart As Long = &H100000, Optional lpEnd As Long = &H7FFFFFFF)
Dim hWnd As Long '窗口句柄
Dim hProcessID As Long '进程ID
Dim hProcessSnapShot As Long '进程快照句柄
Dim szModuleName As String '进程模块名称
Dim bSuccessHup As Boolean '进程挂起标志
Dim bFoundProcess As Boolean '进程查找标志
Dim stProcess As PROCESSENTRY32 '进程信息结构

'判断进程句柄是否存在,如果不存在,则查找进程
If p_ID > 0 Then '如果直接指定了要查找的目标进程的ID
hProcessID = p_ID
Else
If Len(szWindowText) > 0 Then '如果指定了窗口名称
hWnd = FindWindow(vbNullString, szWindowText)
If hWnd = 0 Then Exit Sub
GetWindowThreadProcessId hWnd, hProcessID
End If
End If
If hProcessID > 0 Then '查找特定的进程
Call fnSearch(byteData, hProcessID, lpStart, lpEnd)
Else '查找所有进程
stProcess.dwSize = Len(stProcess)
hProcessSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0&)
bFoundProcess = Process32First(hProcessSnapShot, stProcess)
Do While bFoundProcess
hProcessID = stProcess.th32ProcessID
szModuleName = Left(stProcess.szExeFile, InStr(stProcess.szExeFile, vbNullChar) - 1)
Call fnSearch(byteData, hProcessID, lpStart, lpEnd)
bFoundProcess = Process32Next(hProcessSnapShot, stProcess)
Loop
CloseHandle hProcessSnapShot
End If
End Sub

Private Function fnSearch(byteData() As Byte, ByVal p_ID As Long, ByVal lpStart As Long, ByVal lpEnd As Long)
Dim hProcess As Long '进程句柄
Dim lpBaseAddress As Long
Dim bSuccess As Boolean
Dim MBI As MEMORY_BASIC_INFORMATION
Dim lRet As Long '用于接收API返回值
Dim mbiSize As Long, bSize As Long, dwNeeded As Long
Dim lpMBI As Long, lpByte As Long
Dim lpBuffer() As Byte '内存缓冲区指针
Dim lpszFileName As String '进程模块名称数组

lpBaseAddress = lpStart
mbiSize = Len(MBI)
bSize = UBound(byteData)

hProcess = OpenProcess(PROCESS_VM_READ Or PROCESS_QUERY_INFORMATION, False, p_ID)
If hProcess = 0 Then Exit Function

lpszFileName = String(MAX_PATH, vbNullChar) '取完整的进程模块名称
If GetModuleFileNameEx(hProcess, ByVal 0&, lpszFileName, MAX_PATH) Then
lpszFileName = Left(lpszFileName, InStr(lpszFileName, vbNullChar) - 1)
End If
lRet = VirtualQueryEx(hProcess, lpBaseAddress, MBI, mbiSize)

Do While ((lRet > 0) And (lpBaseAddress < lpEnd))
If (MBI.Protect And PAGE_READWRITE) And (MBI.State = MEM_COMMIT) Then
ReDim lpBuffer(MBI.RegionSize)
ReadProcessMemory hProcess, ByVal MBI.BaseAddress, lpBuffer(1), MBI.RegionSize, 0&
For lpMBI = 1 To MBI.RegionSize - bSize
For lpByte = 1 To bSize
bSuccess = (lpBuffer(lpMBI + lpByte) = byteData(lpByte))
If Not bSuccess Then Exit For
Next
If bSuccess Then '找到目标内容
Debug.Print "找到目标内容,进程文件:", lpszFileName, "地址:", MBI.BaseAddress + lpMBI
End If
Next
End If
lpBaseAddress = lpBaseAddress + MBI.RegionSize
lRet = VirtualQueryEx(hProcess, lpBaseAddress, MBI, mbiSize)
DoEvents
Loop
CloseHandle hProcess
End Function

由于时间因素,加上VB指针功能弱,并未做前面说的优化,只再补充一点:
如果查找的进程不是用VB写的,字符串的存储方式是不一样的,楼主可以进一步添加模块枚举,判断是否包含MSVBVM60.DLL,如果包含,可如示例进行转换.
清晨曦月 2008-03-30
  • 打赏
  • 举报
回复
呵呵。。。。。


看来这个东西人们还是这么有兴趣。当然了,“这个东西”是指别人程序的内存,不是20分。


有兴趣的去我的下载区里面下载一下最后发布的那个版本的游戏修改器,VB.NET写的,反编译一下就可以了,之所以.NET写的那些程序都没有公布代码,就是因为都没有加密处理,直接反编译看代码就可以了。英雄无敌的修改器就不用反编译了,代码在我的博上放着呢。其实很简单的东西。。。。个人觉得没有讨论的价值了,那个.NET修改器的搜索速度你们可以自己试试,用个大点的游戏,别弄一些什么explorer,那才占几毛钱地方。
chb19810501 2008-03-30
  • 打赏
  • 举报
回复
是搜索别的进程的内存。
用NtSuspendProcess挂起进程再查找不可以,这个方法没有用。
chb19810501 2008-03-29
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 barenx 的回复:]
楼主可以参考winhex 的内存搜索,速度很理想。vb做这个的确不太适合,但也不是不能做

要解决几个问题
1.提升权限到se_debug使程序能够读写其他程序的内存空间
2.修改物理内存对象的权限,使其可以写入
3.在搜索目标进程的时候最好将其挂起,可以提高效率
4.字节对齐和比较的问题,可以通过调用系统的或者crt的api来实现
[/Quote]

第3条建议不错,我试试看
chb19810501 2008-03-29
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 lyserver 的回复:]
我这段时间正好涉及到内存搜索问题,有几点感受说明一下:
一、要考虑语言的因素(如VB指针功能太弱,执行效率较低),建议采取C++或MASM32写比较代码。
二、要考虑内存对齐情况,将被查找子串转换为4的倍数的数据(32位机),速度会大幅提升。
三、如果不考虑移植性,可采用MMX、SSE或SSE2指令进行优化,但AMD的CPU不支持。
四、尽量避免使用二次循环语句,速度将呈几级数增加。
在循环体内外判断子串长度,若为1则无…
[/Quote]

一、我目前只会VB。
二、如何内存对齐?
三、需要考虑移植性。
四、尽量避免使用二次循环语句,速度将呈几级数增加。

如果要查找的子串为"Hell",但是内存中为"asHellok",这时候4位4位的比较,怎么比?不是会遗漏吗?
FIRENDLESS 2008-03-28
  • 打赏
  • 举报
回复
楼上的模块很不错~
tzwsoho 2008-03-28
  • 打赏
  • 举报
回复
如果只是搜索了进程的可写部分的内存,还是比较慢,我试过

//

真的吗?请试试gcyun高人写的模块.....

Private Type MEMORY_BASIC_INFORMATION
BaseAddress As Long
AllocationBase As Long
AllocationProtect As Long
RegionSize As Long
State As Long
Protect As Long
lType As Long
End Type

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Sub api_CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
Private Declare Function VirtualProtectEx Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Private Declare Function VirtualQueryEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long) As Long


Private Declare Function CreateRemoteThread Lib "kernel32" (ByVal hProcess As Long, ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, ByVal lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Const PROCESS_ALL_ACCESS = &H1F0FFF
Private Const PAGE_READWRITE = &H4

Private Const MEM_COMMIT = &H1000

Private Const ERR_MEMRW = 40010

Private c_MemStop As Boolean
Private c_PID As Long

Private Function Mem_SearchBytArray(bytData() As Byte, ListAddress() As Long, _
Optional lpStart As Long = &H400000, _
Optional lpEnd As Long = &H7FFFFFFF) As Long
'16bit from &H80000000 to &HBFFFFFFF 2byte
'32bit from &H00400000 to &H7FFFFFFF 4byte
'all from &H00000000 to &HFFFFFFFF
Dim nCount As Long

Dim bfSize As Long
Dim mbSize As Long

Dim mbloop As Long
Dim bfloop As Long

Dim ret As Long
Dim lpAddress As Long
Dim hProcess As Long
Dim MBI As MEMORY_BASIC_INFORMATION
Dim lpBuffer() As Byte

c_MemStop = False
mbSize = Len(MBI)
bfSize = UBound(bytData)
lpAddress = lpStart

hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, c_PID)

ret = VirtualQueryEx(hProcess, lpAddress, MBI, mbSize)
Do While (ret And (lpAddress < lpEnd) And Not c_MemStop)
If (MBI.Protect And PAGE_READWRITE) And (MBI.State = MEM_COMMIT) Then
ReDim lpBuffer(MBI.RegionSize - 1)
ReadProcessMemory hProcess, ByVal MBI.BaseAddress, lpBuffer(0), MBI.RegionSize, 0&
For mbloop = 0 To MBI.RegionSize - 1 - bfSize
For bfloop = 0 To bfSize
If bytData(bfloop) <> lpBuffer(mbloop + bfloop) Then GoTo runSearchNext
Next
ReDim Preserve ListAddress(nCount) As Long
ListAddress(nCount) = mbloop + MBI.BaseAddress
nCount = nCount + 1
runSearchNext:
Next
End If
lpAddress = lpAddress + MBI.RegionSize
ret = VirtualQueryEx(hProcess, lpAddress, MBI, mbSize)
Loop

Mem_SearchBytArray = nCount
Call CloseHandle(hProcess)
End Function


我的老爷机(赛扬1G+256SDRAM)上搜索Explorer.exe进程,单字节,数值12,结果共25253项数据只用了1.15秒!!!
barenx 2008-03-28
  • 打赏
  • 举报
回复
楼主可以参考winhex 的内存搜索,速度很理想。vb做这个的确不太适合,但也不是不能做

要解决几个问题
1.提升权限到se_debug使程序能够读写其他程序的内存空间
2.修改物理内存对象的权限,使其可以写入
3.在搜索目标进程的时候最好将其挂起,可以提高效率
4.字节对齐和比较的问题,可以通过调用系统的或者crt的api来实现
chb19810501 2008-03-28
  • 打赏
  • 举报
回复
不仅仅只是搜索了进程的可写部分的内存,那个Delphi6源代码还有过滤某些文件类型的代码,不知道如何搞的。
如果只是搜索了进程的可写部分的内存,还是比较慢,我试过
lyserver 2008-03-28
  • 打赏
  • 举报
回复
我这段时间正好涉及到内存搜索问题,有几点感受说明一下:
一、要考虑语言的因素(如VB指针功能太弱,执行效率较低),建议采取C++或MASM32写比较代码。
二、要考虑内存对齐情况,将被查找子串转换为4的倍数的数据(32位机),速度会大幅提升。
三、如果不考虑移植性,可采用MMX、SSE或SSE2指令进行优化,但AMD的CPU不支持。
四、尽量避免使用二次循环语句,速度将呈几级数增加。
在循环体内外判断子串长度,若为1则无需优化,为2-3使用short,4-7使用long,8以上使用double。

比如要查找的子串为"Hello",那么可以首先将"Hello"截为一个4位的子串"Hell",然后转换为一个LONG。再以LONG的类型循环访问目标内存数据,比较二者是否相等,若相等,则为"Hell",然后后再进一步比较是否为"Hello"。
加载更多回复(15)

1,488

社区成员

发帖
与我相关
我的任务
社区描述
VB API
社区管理员
  • API
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧