给初学者:用VB写外挂 ———— 实战一:动手写一个红色警戒金钱锁定工具

经过前面二节的介绍,相信大家已经学会如何从窗口名或类获取游戏PID并且读写指定位置的值了。今天就上一个代码:传颂之物修改器基础上,修改一下,来写一个真正可用的修改器,因为传颂之物的那个能力点数的地址是变化的,所以我们需要改比较多的代码,稍微复杂了一些,呵呵,以后我们再慢慢讲,先用这个红色警戒的温习一下知识,来个实战!

欲善其事,先利其器,先说说用到的工具:

1、游戏修改器:

用来查找金钱所在地址,必不可少 

2、跟踪工具:

用来跟踪金钱地址被哪个位置的代码更改,分析这些代码,并改写他们,就能达到我们的目的(汇编,头疼,我也不会,不过这个例子实在是简单,继续~~~)

以上2者一般分别用金山游侠(它的搜索能力至今我没找到一个可以媲美的,无论速度,还是其跟踪,这个跟踪我想大家都有体会,其他游戏修改器查不到的,它却能查到,也许是内置了代码分析功能吧,悍);而说起跟踪,大家都会马上想到动态调试利器SOFTICE;这两款软件确实是相当强,不过我是用不来的,装了虚拟机,装98,结果虚拟机的驱动竟然DW测试不通过,晕,换2K,测试通过,可BPM断点又拦不下来,看起来这些好东东和我无缘啊。不过你也别着急,既然修改器写出来了,就有其他办法可以施展,介绍一款游戏修改调试工具:

CE,呵呵,可谓大名鼎鼎了,全名是Cheat Engine我用的5.2版本,虽然刚刚上手,还不熟悉,不过已经够我们写修改器了,如果你真没用过,去下一个并且完成它的教程,大概也就几分钟。

窗口类及名称获取工具:

SPY+++(不是我打多了,是一个SPY++模仿版本,华军上有下的,比较和我的口味)

编程工具:

VB6+SP6

在你的电脑上开始做吧!跟我的步骤来:

1、运行RA2(我的是1.06版本),建立一个地图,哈,岛屿群,2个玩家,嘿嘿,这样即使下面步骤进行的慢电脑也不至于灭了我吧

2、打开SPY+++,点上面第2个按钮,获取进程列表,打开GAME.EXE进程树,单击列表查看窗口类名和窗口名

3、打开CE

a、点左上的小电脑,选择进程为GAME.EXE(别怀疑,就是它,不是RA2.EXE)

b、4字节方式搜索金钱地址(这个过程最好别建立矿厂哦,可能影响CE的汇编定位)最后有3个地址,选地址值比较长的那个,呵呵,选其他的也没关系,试验一下就知道了,你还会回来选长的那个的。

c、双击该地址,添加到CE下方列表,右键菜单中选择Find out what writes to this address,弹出对话框中选OK

d、回到游戏,花点钱,切回到CE,发现对话框里已经出现了一个汇编语句:004e53af - 89 83 4c 02 00 00  - mov [ebx+0000024c],eax,点More information可以查看到改汇编地址上下2行的汇编代码,发现上面有一个SUB,呵呵,一定是个关键喽(当然你也可以点Show disassembler查看整个汇编代码),读一读这些关键代码,反正我不是非常明白,总之,改改看了,据说90大法比葵花宝典用来舒服!

e、点Show disassembler,向上移动一行汇编窗口就可以看见004e53a9 - 2b c7  - sub eax,edi了,右键选择Replace with code that does nothing ,清空代码

f、回到游戏,花钱,钱已经不减少了。不放心的话可以多建一些建筑,多透支一些,呵呵。

4、分析过程基本结束了,需要我们记住的有以下数据:

a、SPY+++中,GAME.EXE列表里面Red Alert 2字段,这里窗口名与类名相同

b、004e53a9 - 2b c7  - sub eax,edi ,这个说明了004e53a9 地址代码为2字节:2b c7也就是说,004e53a9 为2b004e53aa 为c7,这里004e53a9和2字节是我们必要的信息

分析完毕,写代码吧,用我们前面一节介绍的代码来改就可以了!

模块如下:

Option Explicit

'查找窗体写内存等
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 Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, ByVal lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) 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 CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const SYNCHRONIZE = &H100000
Private Const SPECIFIC_RIGHTS_ALL = &HFFFF
Private Const STANDARD_RIGHTS_ALL = &H1F0000
Private Const PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF
Private Const PROCESS_VM_OPERATION = &H8&
Private Const PROCESS_VM_READ = &H10&
Private Const PROCESS_VM_WRITE = &H20&

'权限提升
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function LookupPrivilegeValue Lib "advapi32.dll" Alias "LookupPrivilegeValueA" (ByVal lpSystemName As String, ByVal lpName As String, lpLuid As LUID) As Long
Private Declare Function AdjustTokenPrivileges Lib "advapi32.dll" (ByVal TokenHandle As Long, ByVal DisableAllPrivileges As Long, NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, PreviousState As TOKEN_PRIVILEGES, ReturnLength As Long) As Long
Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long

Private Const TOKEN_ASSIGN_PRIMARY = &H1
Private Const TOKEN_DUPLICATE = (&H2)
Private Const TOKEN_IMPERSONATE = (&H4)
Private Const TOKEN_QUERY = (&H8)
Private Const TOKEN_QUERY_SOURCE = (&H10)
Private Const TOKEN_ADJUST_PRIVILEGES = (&H20)
Private Const TOKEN_ADJUST_GROUPS = (&H40)
Private Const TOKEN_ADJUST_DEFAULT = (&H80)
Private Const TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or TOKEN_ASSIGN_PRIMARY Or _
TOKEN_DUPLICATE Or TOKEN_IMPERSONATE Or TOKEN_QUERY Or TOKEN_QUERY_SOURCE Or _
TOKEN_ADJUST_PRIVILEGES Or TOKEN_ADJUST_GROUPS Or TOKEN_ADJUST_DEFAULT)
Private Const SE_PRIVILEGE_ENABLED = &H2
Private Const ANYSIZE_ARRAY = 1

Private Type LUID
    lowpart As Long
    highpart As Long
End Type

Private Type LUID_AND_ATTRIBUTES
    pLuid As LUID
    Attributes As Long
End Type

Private Type TOKEN_PRIVILEGES
    PrivilegeCount As Long
    Privileges(ANYSIZE_ARRAY) As LUID_AND_ATTRIBUTES
End Type

'获取占用内存
Private Declare Function GetProcessMemoryInfo Lib "PSAPI.DLL" (ByVal hProcess As Long, ppsmemCounters As PROCESS_MEMORY_COUNTERS, ByVal cb As Long) As Long
Private Type PROCESS_MEMORY_COUNTERS
   cb As Long
   PageFaultCount As Long
   PeakWorkingSetSize As Long
   workingSetSize As Long
   QuotaPeakPagedPoolUsage As Long
   QuotaPagedPoolUsage As Long
   QuotaPeakNonPagedPoolUsage As Long
   QuotaNonPagedPoolUsage As Long
   PagefileUsage As Long
   PeakPagefileUsage As Long
End Type

'提升权限为高
Public Function ToKen() As Boolean
Dim hdlProcessHandle As Long
Dim hdlTokenHandle As Long
Dim tmpLuid As LUID
Dim tkp As TOKEN_PRIVILEGES
Dim tkpNewButIgnored As TOKEN_PRIVILEGES
Dim lBufferNeeded As Long
Dim lP As Long
hdlProcessHandle = GetCurrentProcess()
lP = OpenProcessToken(hdlProcessHandle, TOKEN_ALL_ACCESS, hdlTokenHandle)
lP = LookupPrivilegeValue("", "SeDebugPrivilege", tmpLuid)
tkp.PrivilegeCount = 1
tkp.Privileges(0).pLuid = tmpLuid
tkp.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
lP = AdjustTokenPrivileges(hdlTokenHandle, False, tkp, Len(tkpNewButIgnored), tkpNewButIgnored, lBufferNeeded)
ToKen = lP
End Function

'获取内存内容
Public Function GetData(ByVal lppid As Long, ByVal lpADDress As Long, SaveData() As Byte, Optional ByVal dtLen As Long = 4)
Dim pHandle As Long ' 储存进程句柄
' 使用进程标识符取得进程句柄
pHandle = OpenProcess(PROCESS_ALL_ACCESS, False, lppid)
' 在内存地址中读取数据
ReadProcessMemory pHandle, ByVal lpADDress, ByVal VarPtr(SaveData(0)), dtLen, 0&
' 关闭进程句柄
CloseHandle pHandle
End Function

'将修改内存
Public Function SetData(ByVal lppid As Long, ByVal lpDestAddr As Long, lpSrcAddr() As Byte, Optional ByVal dtLen As Long = 4) As Boolean
On Error GoTo mErr
Dim lBytesReadWrite As Long
Dim pHandle As Long ' 储存进程句柄
' 使用进程标识符取得进程句柄
pHandle = OpenProcess(PROCESS_ALL_ACCESS, False, lppid)
WriteProcessMemory pHandle, ByVal lpDestAddr, ByVal VarPtr(lpSrcAddr(0)), dtLen, 0&
' 关闭进程句柄
CloseHandle pHandle
SetData = True
mErr:
End Function

Public Function GetPid(lpClassName As String, lpWindowName As String) As Long
' 取得进程标识符
GetWindowThreadProcessId FindWindow(lpClassName, lpWindowName), GetPid
End Function

'获取占用内存大小
Public Function GetMemorySize(ByVal lppid As Long) As Long
        Dim tPMC As PROCESS_MEMORY_COUNTERS
        Dim pHandle As Long ' 储存进程句柄
        pHandle = OpenProcess(PROCESS_ALL_ACCESS, False, lppid)
        GetProcessMemoryInfo pHandle, tPMC, Len(tPMC)
        CloseHandle pHandle
        GetMemorySize = tPMC.workingSetSize
End Function
主要修改了GETDATE函数,使之能够返回一个数组,其实这不是必须的,我们记下2b c7就可以了,不用去读,因为这是程序代码而不是数据,它的位置不会变,数据也不会变(当然是没有该死的保护程序时,这个以后等俺会了再告诉大家咋办吧,据说不修改代码而修改寄存器是不会被发现的哦,不过有的游戏已经把寄存器地址保护了,哎,写外挂还真不容易),把修改后的代码放在这里,也是想大家能复习一下SETDATA函数里面使用的方法:把数组作为参数交给程序处理后作为返回值,这样做有很多好处,相信大家以后编程时会感受到。

以下是窗体,(仍然是保存为 *.FRM文件)

VERSION 5.00
Begin VB.Form Form1
   AutoRedraw      =   -1  'True
   BorderStyle     =   3  'Fixed Dialog
   Caption         =   "★传颂之物修改器 VB DEMO"
   ClientHeight    =   885
   ClientLeft      =   45
   ClientTop       =   330
   ClientWidth     =   2670
   LinkTopic       =   "侠义道补药"
   MaxButton       =   0   'False
   MinButton       =   0   'False
   ScaleHeight     =   885
   ScaleWidth      =   2670
   ShowInTaskbar   =   0   'False
   StartUpPosition =   3  '窗口缺省
   Begin VB.CommandButton Command1
      Caption         =   "解除"
      Height          =   375
      Left            =   1440
      TabIndex        =   2
      Top             =   360
      Width           =   975
   End
   Begin VB.CommandButton Command2
      Caption         =   "开始"
      Height          =   375
      Left            =   120
      TabIndex        =   0
      Top             =   360
      Width           =   975
   End
   Begin VB.Label Label4
      Height          =   255
      Left            =   0
      TabIndex        =   1
      Top             =   0
      Width           =   2655
   End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
'请保留作者信息:
'ZCSOR于06-8-30开发
'E-MAIL:shaoyan5@163.com

Option Explicit

Dim SaveArr(1) As Byte

Dim GamePid As Long ' 储存进程标识符( Process Id )


Private Sub Command1_Click()
On Error GoTo m_Err

SetSub SaveArr()
Label4.Caption = "解除成功!"

m_Err:
Label4.Caption = "解除失败啦!"
Exit Sub
End Sub

Private Sub Command2_Click()
On Error GoTo m_Err

GamePid = GetPid("Red Alert 2", "Red Alert 2")


If GamePid = 0 Then
    MsgBox "游戏未启动", 48
    Exit Sub
End If

'获取写入金钱数据SUB实际内容(其实每次都一样啦是&H2B &HC7)
GetSub

Dim mBuff(1) As Byte '要写入的NOP指令
mBuff(0) = "&H90"
mBuff(1) = "&H90"

SetSub mBuff()

Label4.Caption = "锁定成功:)"
m_Err:
Label4.Caption = "锁定失败啦!"
Exit Sub

End Sub

Private Sub Form_Load()
ToKen
End Sub


Sub GetSub()
GetData GamePid, &H4E53A9, SaveArr(), 2
Debug.Print "&H" & Hex(SaveArr(0))
Debug.Print "&H" & Hex(SaveArr(1))
End Sub
Sub SetSub(buf() As Byte)

SetData GamePid, &H4E53A9, buf(), 2

End Sub
好了,重新运行游戏,切出来,锁定按钮,回去花钱,呵呵,大功告成,点解除,再回去花,不错吧!不过有一个问题,这样做以后,矿车采的钱还会加的,怎么让它不加呢?(谁闲钱多啊!我也不闲,但是我们还有工作要做)温习一下刚才的过程吧,重复刚才的步骤,把花钱变为钱增长,也就是说用Find out what writes to this address来看看钱增加的时候关键代码是什么,用90大法击败它吧。

恩,到这里,我们的教程先告一段落,相信大家已经具备写外挂的基本能力了,下一节是给修改器定义一个热键,然后才是用自定义汇编语句来修改金钱,呵呵(不过啊,红色警戒五项属性修改器不是这个思路,是去读金钱内存指针,然后直接写入,悍啊,读了3个地址然后写了1次,偶会把它的实现方法研究明白然后告诉大家的~~~)。

嘿嘿,不包括界面弹出显示,这方面的问题偶不会,但是大家可以参照帖子里面的一些内容:

http://community.csdn.net/Expert/topic/4894/4894060.xml?temp=.8059656

好了,本节结束!

本文代码和成品一发送到本站下载区,可以到那里去下载

http://down.csdn.net/html/2006-08/30/158792.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清晨曦月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值