偶与同学玩游戏时,不仅想起作弊,是可以让我所做的操作更少呢?或者改掉程序里的数据呢?就这样我开始写这个的一个程序。向程序发消息,从程序得到消息,然后在程序内存空间找我要的数据,然后再更改。在Windows下做这些事情好像不是很难,但我遇到的问题可以说是一个API就是一个问题,当然最后还是写了一个小模型。现将经验写于此记之,给遇上同样问题的同行以帮助, 并盼望更多的高手以指教。(开发平台:WinXP,VB6,VC6)
>>使用Hook(钩子)去拦截游戏进程中的键盘消息
在这个过程中,我为了写一个全局的钩子,所以我得写一个DLL,而这个DLL一定要有一个共享节,不然就不能得到所有GUI进程的键盘消息。在这里我写了好长的时间,我的那个DLL就是不行。后来我找到《Visual Basic Win32 API》上面的源代码,才得以解决。
#pragma data_seg("Shared")
HHOOK ghHook = NULL;
HHOOK ghKBHook = NULL;
HANDLE ghSubclassedForm = NULL;
int lMsgID;
#pragma data_seg()
// Tell linker to make this section shared and read-write
#pragma comment(linker, "/section:Shared,rws")
以上就是我写DLL时的共享节,当时我看到书上说可以在编译器上设置/section:Shared,rws参数,但是编译器总是提示EXP中找不到该节,而生成的DLL文件就只能在本进程注入(SetWindowsHookEx)。我百思不得其解,后来都怀疑是不是机器有问题呢?最终,我还是以别人写的源代码改写的,才没有问题,我想应该是我编译设置有问题,但是现在我还没有找到,幸好问题得到了解决,我的DLL可以注入到我想注入的GUI进程。
>>在VB中写API的一些感悟
在VB下开发已经很长时间了,VB本身的问题还是不成问题了,但是一但要用到API,问题就多了。以下就我个人在用VB时,出错较多的几点说一下。
1、不要太想信API函数声明软件,因为有很多问题就是它引起的,比如在传参数上面,如果出现保护异常,那大部分是因为参数声明有误,比如需要地址的时候,就不能使用传引用,或者直接传变量地址过去,比如ReadProcessMemory函数第二个参数不能传地址,因为他代表的就是一个值而已,而API声明软件就认为其是一个地址,将参数声明引用,这样的话,是很容易出问题的。
2、在不太明白参数声明的时候,调用函数的时候一定要带byval调用,像用VarPtr函数得到地址后,就一个要传值,不然程序就得不到正确的结果。
3、在不是很明白VB中的String时,与API交互的时候就不要用。这也是所谓的BSTR,COM中用的,我现在也不太懂。如果需要用字符串的时候,就使用BYTE类型,得到结果后使用StrConv将其转换过来就可以了。《Visual Basic Win32 API》这本书上讲得很清楚,很经典的。当然《Advanced VB》那本书就是很牛的了。
>>在读写其它进程空间数据时的问题
如果对Windows进程与内存管理不是很熟悉的时候写这样的程序,真是问题很多啊,而且是在VB这样的环境下面,更是问题多多,几乎是每一个API函数就是一个问题。笔者就是这样子将一个程序写完的,其中的艰辛不言而喻啦。在读内存的时候主要问题就是权限与指针问题,你不要想从WINDOWS那里得到一些错误帮助信息,因为错误之后得到的结果就是“操作成功完成。”,所以一旦出现问题,就不知错在那里。比如在使用ReadProcessMemory函数的时候,如果具有PROCESS_VM_READ面不拥用PROCESS_VM_OPERATION打开进程(OpenProcess)时,你就甭想得到数据。很多时间你拥有PROCESS_VM_WRITE的时候,还是不能得到写进程地址空间的权限,最好就是PROCESS_ALL_ACCESS这样的标志打开的进程就比较爽了。但有的还是不能写,而得到该区域的权限与状态(VirtualQueryEx)都提示可写,可就是写不了,我也不知道是什么原因。
ByVal hProcess As Long, _
ByVal lpBaseAddr As Long, _
ByVal idxFind As Long, _
ByVal x As Long) As Long
Dim mPageSize As Long '系统最小页尺寸
Dim mMinAppAddr As Long
Dim mMaxAppAddr As Long
Dim mbi As MEMORY_BASIC_INFORMATION '内存基本信息
Dim sysInfo As SYSTEM_INFO_ART
Dim mBaseAddr As Long
Dim mBuffer() As Byte
Dim midxFind As Long '找到计数
midxFind = 0
'获得系统信息
Dim r As Long
Call GetSystemInfo_ATR(sysInfo)
mPageSize = sysInfo.dwPageSize
mMinAppAddr = sysInfo.lpMinimumApplicationAddress
mMaxAppAddr = sysInfo.lpMaximumApplicationAddress
Dim lenmbi As Long
Dim i As Long
Dim mNumberOfBytesRead As Long
Dim temp As Long '用于从4个BYTE中得到一个LONG数据
'用于将内存存储模式转换为实际可读模式
Dim src(0 To 3) As Byte
Dim dst(0 To 3) As Byte
'确定地址范围
lenmbi = LenB(mbi)
If lpBaseAddr < mMinAppAddr Then
mBaseAddr = mMinAppAddr
Else
mBaseAddr = lpBaseAddr
End If
r = VirtualQueryEx(hProcess, mBaseAddr, mbi, lenmbi)
'枚举所有进程地址空间
Do While (r)
'处理内存信息
If r <> lenmbi Then Exit Do '返回值不正常则终止
If mbi.dwState And MEM_COMMIT Then
'如果该区域是可读就试着读它
If 0 = (mbi.dwProtect And (PAGE_EXECUTE Or PAGE_NOACCESS)) Then
'重新定义缓冲区大小
ReDim mBuffer(0 To mbi.dwRegionSize)
'读内存
r = ReadProcessMemory(hProcess, mBaseAddr, _
ByVal VarPtr(mBuffer(0)), mPageSize, mNumberOfBytesRead)
If mNumberOfBytesRead <> mPageSize Then
Debug.Print "Err--ReadProcessMemory:" & GetLastErrMsg
Else
For i = LBound(mBuffer) To UBound(mBuffer) - 1 Step 4
'得到源与目标的内存模式拷贝
CopyMemory src(0), mBuffer(i), 4
CopyMemory dst(0), x, 4
If ComareByteArr(src, dst, 4) Then
'已找到需要的数据
midxFind = midxFind + 1
'如果找到了指定索引的数据,则返回
If idxFind = midxFind Then
VirtualQueryValue = mBaseAddr + i
Exit Function
End If
'如果不是指定索引,则继续
End If
Next i
End If
End If 'PAGE_READWRITE
End If
'向下搜索
On Error Resume Next
If mBaseAddr < 0 Then Exit Do '超过VB表示范围
mBaseAddr = mBaseAddr + mbi.dwRegionSize
'如果完成所有地址搜索,则退出
If mBaseAddr > mMaxAppAddr Then Exit Do
On Error GoTo 0
DoEvents
r = VirtualQueryEx(hProcess, mBaseAddr, mbi, lenmbi)
Loop
End Function
'修改指定内存值
Function VirtualModifyValue(ByVal hProcess As Long, _
ByVal lpAddress As Long, ByVal x As Long) As Long
Dim r As Long, lenmbi As Long
Dim mbi As MEMORY_BASIC_INFORMATION
Dim src(0 To 3) As Byte
Dim s As String
lenmbi = LenB(mbi)
'查看该区域是否可写
r = VirtualQueryEx(hProcess, lpAddress, mbi, lenmbi)
'不可写则退出
If 0 <> (mbi.dwProtect And PAGE_NOACCESS) Then Exit Function
If mbi.dwState <> MEM_COMMIT Then Exit Function
'试图改写内存
CopyMemory src(0), x, 4
VirtualModifyValue = WriteProcessMemory(hProcess, ByVal lpAddress, ByVal VarPtr(src(0)), 4, ByVal 0&)
End Function
以上是用VB写的读写内存地址空间的一段代码,我写了好久好久,遇到了好多好多问题最终,因为游戏数据在空间中找不到(也许是加密了吧),而告终,但我还是知道如何修改我自己写的俄罗斯方块的分数了。以下就重要函数的声明:
ByVal hProcess As Long, _
ByVal lpAddress As Long, _
ByRef lpBuffer As MEMORY_BASIC_INFORMATION, _
ByVal dwLength As Long _
) As Long
Public Declare Function WriteProcessMemory Lib "kernel32.dll" ( _
ByVal hProcess As Long, _
ByVal lpBaseAddress As Long, _
ByRef lpBuffer As Long, _
ByVal nSize As Long, _
ByRef lpNumberOfBytesWritten As Long) As Long
Public Declare Function ReadProcessMemory Lib "kernel32.dll" ( _
ByVal hProcess As Long, _
ByVal lpBaseAddress As Long, _
ByRef lpBuffer As Long, _
ByVal nSize As Long, _
ByRef lpNumberOfBytesWritten As Long) As Long
版权声明:本文为博主原创文章,未经博主允许不得转载。