菜鸟写游戏外挂

偶与同学玩游戏时,不仅想起作弊,是可以让我所做的操作更少呢?或者改掉程序里的数据呢?就这样我开始写这个的一个程序。向程序发消息,从程序得到消息,然后在程序内存空间找我要的数据,然后再更改。在Windows下做这些事情好像不是很难,但我遇到的问题可以说是一个API就是一个问题,当然最后还是写了一个小模型。现将经验写于此记之,给遇上同样问题的同行以帮助, 并盼望更多的高手以指教。(开发平台:WinXP,VB6,VC6)

>>使用Hook(钩子)去拦截游戏进程中的键盘消息

在这个过程中,我为了写一个全局的钩子,所以我得写一个DLL,而这个DLL一定要有一个共享节,不然就不能得到所有GUI进程的键盘消息。在这里我写了好长的时间,我的那个DLL就是不行。后来我找到《Visual Basic Win32 API》上面的源代码,才得以解决。

// Set up shared data section in DLL
#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)都提示可写,可就是写不了,我也不知道是什么原因。

 

Public Function VirtualQueryValue( _
        ByVal hProcess 
As Long, _
        ByVal lpBaseAddr 
As Long, _
        ByVal idxFind 
As Long, _
        ByVal x 
As LongAs 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 3As Byte
    
Dim dst(0 To 3As 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, 4Then
                            
'已找到需要的数据
                            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 LongAs Long
        
    
Dim r As Long, lenmbi As Long
    
Dim mbi As MEMORY_BASIC_INFORMATION
    
Dim src(0 To 3As 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写的读写内存地址空间的一段代码,我写了好久好久,遇到了好多好多问题最终,因为游戏数据在空间中找不到(也许是加密了吧),而告终,但我还是知道如何修改我自己写的俄罗斯方块的分数了。以下就重要函数的声明:

Declare Function VirtualQueryEx Lib "kernel32" ( _
   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 LongAs 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 LongAs Long
以上就是我这次做完这个东东后写的,如果有错误,请与我联系EMAIL:yhb_yinhaibo@163.com

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2006-10-12 15:42  yin138  阅读(336)  评论(0编辑  收藏  举报