首页 > 系统相关 >碎冰挂船与按键精灵读内存地址

碎冰挂船与按键精灵读内存地址

时间:2023-01-08 20:01:05浏览次数:59  
标签:Gosub VBSCall HP VBS 按键精灵 内存 碎冰 Byte 内存地址

昨天使用古老的按键精灵写个脚本,用来给老叶的海盗王挂船熟,每隔一个小时都要补一次船实在太麻烦了。

好吧,古老的游戏,和古老的工具。一般很少上游戏了,也不想打装备,不想升级装备,没有人玩船,所以我就升升船。

使用湾湾工具Game Master获得坐标字符串的内存地址,就可以自动跑船了。但是很快又发现了一个大问题,每次运行Game.exe,当前位置坐标和船只补给的内存地址都会变?!真是防到家了。

脚本贴出来(VB风格):

  1 [General]
  2 Description=碎冰船熟
  3 BeginHotkey=120
  4 BeginHotkeyMod=2
  5 PauseHotkey=0
  6 PauseHotkeyMod=0
  7 StopHotkey=123
  8 StopHotkeyMod=0
  9 RunOnce=1
 10 EnableWindow=
 11 Enable=1
 12 AutoRun=0
 13 [Repeat]
 14 Type=0
 15 Number=1
 16 [Relative]
 17 SetupOCXFile=
 18 [Comment]
 19 Content=
 20 
 21 [Script]
 22 VBS Dim curShape,comShape,attShape,nowayShape,peopleShape,npcShape,skillShape,pickupShape
 23 VBS Dim Addr1,Addr2,M1,M2,M3
 24 VBS Dim BasescrX,BasescrY,CenterX,CenterY
 25 VBS Dim M,N,zbd0x,zbd0y,zbd_1x,zbd_1y,zbd1x,zbd1y,zbd2x,zbd2y,zbd3x,zbd3y
 26 VBS Dim curSupply,protectSupply
 27 VBS Dim r,i,kstep,basekstep,span,x0,y0,x,y,k
 28 //Addr1 位置坐标的内存地址,Addr2 补给的内存地址
 29 Addr1 = &H00696C48:Addr2 = &H0D4BD20C
 30 //Addr1 = &H00626C48:Addr2 = &H0E57413C
 31 M1=1:M2="":M3=Addr1
 32 BasescrX=0:BasescrY=0
 33 CenterX=474:CenterY=352
 34 zbd0x=2255:zbd0y=1085
 35 zbd_1x=2257:zbd_1y=1094
 36 zbd1x=2272:zbd1y=1070
 37 zbd2x=2306:zbd2y=1075
 38 zbd3x=2301:zbd3y=1100
 39 zbd4x=2299:zbd4y=1117
 40 xzb=0:yzb=0
 41 curSupply=100:protectSupply=50
 42 comShape = 528446959
 43 attShape = 1848294001
 44 nowayShape = 1458522284
 45 peopleShape = 921605627
 46 npcShape = 1482209781
 47 skillShape = 1157927434
 48 pickupShape = 119364435
 49 J=1:basekstep=0.25:span=12
 50 Gosub getWinBasePos
 51 M=zbd0x:N=zbd0y
 52 Gosub MoveToMN
 53 For 1000
 54     Plugin File.WriteINI("Command", "Val1",  "进入主循环:J=" & J, ".\qqnc_debugtext.ini")
 55     Gosub ZDGongji
 56     Gosub getSupply
 57     Gosub 返回挂点
 58     Plugin File.WriteINI("Command", "Val1",  "主循环完成一轮:J=" & J, ".\qqnc_debugtext.ini")
 59     Delay 1000
 60     J=J+1
 61 EndFor 
 62 Plugin File.WriteINI("Command", "Val1",  "脚本停止运行!", ".\qqnc_debugtext.ini")
 63 Plugin File.WriteINI("Command", "Val2",  "", ".\qqnc_debugtext.ini")
 64 Plugin File.WriteINI("Command", "Val3",  "", ".\qqnc_debugtext.ini")
 65 Plugin File.WriteINI("Command", "Val4",  "", ".\qqnc_debugtext.ini")
 66 Plugin File.WriteINI("Command", "Val5",  "", ".\qqnc_debugtext.ini")
 67 EndScript 
 68 Sub getInMem
 69     M2=""
 70     VBSCall ReadMemory(M3,0,M1)
 71     While M1 > 0
 72         M2 = M2 & Chr(M1)
 73         M3 = M3 + 1
 74         VBSCall ReadMemory(M3,0,M1)
 75     EndWhile 
 76 Return getInMem
 77 Sub Czb
 78     tmpStr1="":tmpStr2=""
 79     VBS ipo=InStr(M2,",")
 80     VBS tmpStr1=Left(M2,ipo-1)
 81     VBS tmpStr2=Replace(M2,tmpStr1 & ",","")
 82     VBS xzb=Clng(tmpStr1):yzb=Clng(tmpStr2)
 83     //xzb & "," & yzb & ";"
 84 Return Czb
 85 Sub Csp
 86     tmpStr1="":tmpStr2=""
 87     VBS ipo=InStr(M2,"/")
 88     VBS tmpStr1=Left(M2,ipo-1)
 89     VBS tmpStr2=Replace(M2,tmpStr1 & "/","")
 90     VBS curSupply=Clng(tmpStr1)
 91 Return Csp
 92 Sub getXYzb
 93     M3=Addr1
 94     Gosub getInMem
 95     Gosub Czb
 96 Return getXYzb
 97 Sub getWinBasePos
 98     dim hwnd,wndClientPos,tmpstr1,tmpstr2,tmpstr3,iwin
 99     Plugin hwnd=Window.Foreground()
100     Plugin wndClientPos=Window.GetClientRect(hwnd)
101     VBS iwin=InStr(wndClientPos,"|")
102     VBS tmpstr1=Left(wndClientPos,iwin-1)
103     VBS tmpstr3=Replace(wndClientPos,tmpStr1 & "|","")
104     VBS iwin=InStr(tmpstr3,"|")
105     VBS tmpstr2=Left(tmpstr3,iwin-1)
106     VBS BasescrX=Clng(tmpStr1):BasescrY=Clng(tmpStr2)
107     CenterX=BasescrX+466:CenterY=BasescrY+322
108 Return getWinBasePos
109 Sub MoveToMN
110     Plugin File.WriteINI("Command", "Val5",  "MoveToMN,M=" & M & ",N=" & N & ",M2:" & M2, ".\qqnc_debugtext.ini")
111     MoveTo CenterX,CenterY
112     Delay 200
113     VBSCall Dim xzb,yzb,u,v,w,cxpos,cypos
114     Gosub getXYzb
115     u=M-xzb:v=N-yzb
116     w=Sqr(u*u+v*v)
117     If abs(u)>=5 Or abs(v)>=5
118         cxpos=CenterX+u*180/w
119         cypos=CenterY+v*180/w
120         MoveTo cxpos,cypos
121         Delay 1000
122         LeftClick 1
123         Delay 100
124         LeftClick 1
125         Delay 1000
126         Gosub MoveToMN
127     ElseIf Abs(u)>=2 Or Abs(v)>=2
128         Delay 3500
129         MoveR u*23,v*23
130         Delay 200
131         LeftClick 1
132         Delay 4500
133         Gosub MoveToMN
134     EndIf 
135     Plugin File.WriteINI("Command", "Val5",  "完成MoveToMN:" & M & "," & N ";", ".\qqnc_debugtext.ini")
136 Return MoveToMN
137 Sub MoveAboutMN
138     Plugin File.WriteINI("Command", "Val5",  "MoveAboutMN,M=" & M & ",N=" & N & ",M2:" & M2, ".\qqnc_debugtext.ini")
139     MoveTo CenterX,CenterY
140     Delay 200
141     VBSCall Dim xzb,yzb,u,v,w,cxpos,cypos
142     Gosub getXYzb
143     u=M-xzb:v=N-yzb
144     w=Sqr(u*u+v*v)
145     If abs(u)>=8 Or abs(v)>=8
146         cxpos=CenterX+u*180/w
147         cypos=CenterY+v*180/w
148         MoveTo cxpos,cypos
149         Delay 1000
150         LeftClick 1
151         Delay 100
152         LeftClick 1
153         Delay 200
154         Gosub MoveAboutMN
155     EndIf 
156     Plugin File.WriteINI("Command", "Val5",  "完成MoveAboutMN:" & M & "," & N ";", ".\qqnc_debugtext.ini")
157 Return MoveAboutMN
158 Sub ZDGongji
159     MoveTo CenterX,CenterY
160     u=zbd_1x-zbd0x:v=zbd_1y-zbd0y
161     MoveR u*22,v*22
162     KeyDown 17,1
163     KeyDown 16,1
164     Delay 200
165     LeftClick 1
166     Delay 200
167     LeftClick 1
168     Delay 200
169     LeftClick 1
170     KeyUp 16,1
171     KeyUp 17,1
172 Return ZDGongji
173 Sub getSupply
174     Plugin File.WriteINI("Command", "Val1",  "进入getSuppply:J=" & J, ".\qqnc_debugtext.ini")
175     curSupply=0:M3=Addr2
176     Gosub getInMem
177     Gosub Csp
178     Plugin File.WriteINI("Command", "Val2",  "当前坐标:xzb=" & xzb & ",yzb=" & yzb, ".\qqnc_debugtext.ini")
179     Plugin File.WriteINI("Command", "Val3",  "curSupply:" & curSupply, ".\qqnc_debugtext.ini")
180     Plugin File.WriteINI("Command", "Val5",  "", ".\qqnc_debugtext.ini")
181     If curSupply >protectSupply
182         wsnd=CInt(5.0*(curSupply-protectSupply)/3.0)
183         Plugin File.WriteINI("Command", "Val4",  "等待时间wsnd:" & wsnd, ".\qqnc_debugtext.ini")
184         Delay wsnd*1000
185     EndIf 
186     Gosub CancleSkill
187     M=zbd1x:N=zbd1y
188     Gosub MoveAboutMN
189     M=zbd2x:N=zbd2y
190     Gosub MoveAboutMN
191     M=zbd3x:N=zbd3y
192     Gosub MoveAboutMN
193     M=zbd4x:N=zbd4y
194     Gosub MoveToMN
195     Gosub 补给修理
196     Plugin File.WriteINI("Command", "Val1",  "退出getSuppply:J=" & J, ".\qqnc_debugtext.ini")
197 Return getSupply
198 Sub 补给修理
199     Plugin File.WriteINI("Command", "Val2",  "进入补给修理:J=" & J, ".\qqnc_debugtext.ini")
200     curSupply=0:M3=Addr2
201     Gosub getInMem
202     Gosub Csp
203     Plugin File.WriteINI("Command", "Val3",  "死循环关键参数curSupply:" & curSupply, ".\qqnc_debugtext.ini")
204     While curSupply < protectSupply
205         Gosub FindNPC
206         curSupply=0:M3=Addr2
207         Gosub getInMem
208         Gosub Csp
209         Plugin File.WriteINI("Command", "Val3",  "死循环关键参数curSupply:" & curSupply, ".\qqnc_debugtext.ini")
210     EndWhile 
211     Plugin File.WriteINI("Command", "Val2",  "退出补给修理:J=" & J, ".\qqnc_debugtext.ini")
212 Return 补给修理
213 Sub 返回挂点
214     Plugin File.WriteINI("Command", "Val1",  "进入返回挂点:J=" & J, ".\qqnc_debugtext.ini")
215     Plugin File.WriteINI("Command", "Val2",  "", ".\qqnc_debugtext.ini")
216     Plugin File.WriteINI("Command", "Val3",  "M2=" & M2, ".\qqnc_debugtext.ini")
217     Plugin File.WriteINI("Command", "Val4",  "", ".\qqnc_debugtext.ini")
218     Plugin File.WriteINI("Command", "Val5",  "", ".\qqnc_debugtext.ini")
219     M=zbd3x:N=zbd3y
220     Gosub MoveAboutMN
221     M=zbd2x:N=zbd2y
222     Gosub MoveAboutMN
223     M=zbd1x:N=zbd1y
224     Gosub MoveAboutMN
225     M=zbd0x:N=zbd0y
226     Gosub MoveToMN
227     Plugin File.WriteINI("Command", "Val1",  "退出返回挂点:J=" & J, ".\qqnc_debugtext.ini")
228 Return 返回挂点
229 Sub CancleSkill
230     //VBSCall CurShape=GetCursorShape(0)
231     //While curShape=skillShape
232     SaveMousePos 
233     MoveTo BasescrX-8+32,BasescrY-30+90
234     Delay 100
235     RightClick 1
236     Delay 100
237     RightClick 1
238     Delay 100
239     RightClick 1
240     Delay 100
241     RestoreMousePos 
242     Delay 300
243     //VBSCall CurShape=GetCursorShape(0)
244     //EndWhile
245 Return CancleSkill
246 Sub FindNPC
247     r=0:i=0:kstep=basekstep
248     While r<78
249         r=25+i*span
250         Gosub 画圆
251         i=i+1
252     EndWhile 
253 Return FindNPC
254 Sub 画圆
255     x0=CenterX:y0=CenterY:x=0:y=0:k=0
256     While k<3.1415926*2
257         x=x0+r*1.4*cos(k)
258         y=y0-r*sin(k)
259         MoveTo x,y
260         Gosub att
261         Delay 90
262         k=k+kstep
263     EndWhile 
264 Return 画圆
265 Sub att
266     VBSCall CurShape=GetCursorShape(0)
267     If CurShape=npcShape
268         LeftClick 1
269         Delay 800
270         VBSCall FindPic(BasescrX-8+80,BasescrY-30+170,BasescrX-8+800,BasescrY-30+550,"船只补给.bmp",0.9,intX,intY)
271         If intX+intY > 0
272             MoveTo intX+30,intY+6
273             Delay 600
274             LeftClick 1
275             Delay 600
276             k=6.3:r=78
277         EndIf 
278     EndIf 
279 Return att

在这个过程中,发现使用Game Master(湾湾工具)搜索值可以选字符串,以前只知道可以搜索整数类型的数据,所以就想到了其它数据类型,本着多了解一些的想法,在网上找到了不知道转载了几手的这文章,还不错,文章也是湾湾人写的?

http://www.360doc.com/content/13/1130/14/9200790_333409537.shtml

嗯?防复制?先来个浏览器脚本吧……greasefork.org打不开??上知乎(https://zhuanlan.zhihu.com/p/513275228)找一个资源地址……啊,找到了,资源在这里(https://greasyfork.org/zh-CN/scripts/405130-%E6%96%87%E6%9C%AC%E9%80%89%E4%B8%AD%E5%A4%8D%E5%88%B6)

好吧,现在可以复制了。

[转]关于内存地址的个人理解和操作原理1(按键精灵)

2010-04-09 11:10:19|  分类: 默认分类 |字号 订阅

 

转自:http://hi.baidu.com/cxhphoto/blog/item/d56797efa037cb17fdfa3cab.html
关于内存地址的个人理解和操作原理

最近看见太多人询问内存地址的作用和使用方法,我来做个大概的解释吧
    内存地址,其实电脑的每个操作都会在内存中先存储,然后经CPU处理后返回内存最终显现出来,而内存里有个内存地址,是为了区分各种不同数据的,而每个地址则相对应一个数据。
网络游戏中,数据也会先存放到内存中,然后进行处理,包括坐标、血量、MANA等,其实所有信息都是在内存中一一存放并等待处理。处理完毕后结果将会返回原来的地址中(当然也有返回到其他的)。
通过以上的解释,大家可以明白一个道理,其实任何数据都是会下载到本地电脑上然后经过处理后再返回的(至于返回到网络和返回到本地就看数据的重要性了)包括网页的浏览等,任何在你电脑上可以看见的东西必定先存放到本地内存中或硬盘中等待处理后才会显现出来的。

内存和外挂:
说到这里当然要给大家举个例子了,就拿网络游戏来说吧。以前的网络游戏很多数据都是在本地电脑上进行处理和比对的,例如曾经的精灵,它的游戏币是在本地电 脑上进行处理的,处理后的结果再返回服务器,这样就导致了当时的刷钱外挂,因为大家可以修改本地电脑上的内存地址中的数值,然后再返回给服务器。从以上可 以知道单机游戏锁血锁蓝是多么简单的事了吧。因为所有的数据操作都是在本地运行计算的。
当然,还有的外挂是通过改变封包数据来达到效果的。例如魔兽世界加速外挂,比如我现在人物的坐标是0   0然后按照正常速度走的话下一秒坐标是1   1。 因为魔兽世界是在本地对人物坐标进行处理,如果只是单一的改变本地游戏坐标的位置,或许你在自己电脑上会看见自己一下跑到 3   3的位置了,但实际游戏服务器上的人物还在1   1这个位置,那就毫无意义。我们可以截取发送坐标的封包,修改我们下一秒跨度的数值,向服务器发送 我下一秒会在3   3的位置,这时服务器处理后你的人物就在3   3的位置了。当然,整个过程只是改变封包内的数据值,并没有向服务器多发送封包,所以有 的人说是加速外挂给游戏带来了压力的说法是错误的。当然,运营商也可以通过检查你的日常数据来判断你是否使用外挂,所以是没有查不出的外挂,只有不愿意查 的外挂。
而现在的网络游戏血、经验、等级、金钱等重要数据都是由服务器计算然后返回给客户端(就是我们),而且每次存放血、蓝等信息的内存地址在每次游戏的启动都 会变化,在现在来说,修改其数值已经没有任何意义了,因为那只能让你在本地读取的数值不同而已,而真正的数据被存储在了服务器上,你无法修改。但是我们可 以通过读取内存地址中的数值来精确我们脚本的计算。

脚本与读取内存地址:
例如我要做一个脚本,需要在血或蓝少于一个具体的值的时候加血加蓝,这时候我们就可以采用内存地址的读取,因为这种做法可以让脚本以最精确的方式去加血加蓝,而不是去看血条蓝条(其实血条蓝条这时候已经根本不重要)。在按键精灵里
有这么一个脚本。
VBSCall ReadMemory(内存地址:整数(16进制),类型:0-字节 1-整数 2-长整数,输出值-所读取的内容:长整型变量)

实际应用(中间的内存地址为假设):
VBSCall ReadMemory( &H400000,2,xue)
这句脚本的意思为,&H400000为读取内存地址400000中数值;2为读取类型,为长整数;xue则把读取出来的数值保存到xue这个变量中去。
如果这个400000的地址是用来储存血量的。那我们就可以对xue这个变量来进行判断计算。实际应用如下

If xue<500
//放入加血的脚本
EndIf
也就是当血量少于500的时候我们开始加血。这个500你可以随意改变

实际应用2挂机打怪,然后人物回到挂机点(中间的内存地址为假设):
vbs dim x,y,a,b
//申明变量(其实在按键精灵里不用这么做)
VBSCall ReadMemory( &H400000,2,x)
//读取地址中的纵坐标保存到x
VBSCall ReadMemory( &H800000,2,y)
//读取地址中的横坐标保存到y
vbs a=100
vbs b=100
//也就是原始坐标或者是你想定点的坐标
if x>a and y>b
moveto 300   500
   //以上坐标为虚拟,根据游戏不同自己更改,以下放入这个游戏里移动的移动方式的脚本
endif
//如果两个坐标都大于我们希望保存的地方,我们就开始向另一个方向移动

由此我们可以生成
if x<a and y<b
if x>a and y<b
if x<a and y>b
if x=a and y=b
一共5种不同的处理方法,这样让人物回到原来的点继续开始打怪就可以轻松制作原点挂机的脚本

说了那么多,一定会产生一个很大的问题,如何查找游戏内的内存地址。
内存地址的查找
    我一般用金山游侠 例如我要找红,先在自己满血的时候输入上限,然后搜索,这时候会搜索出很多地址,一些是代表你当前的红,和你的上限,还有一些正好是搜索时碰巧一样的。
    OK,在结果里再搜索一次,会去掉一些,这样搜索3次基本上结果已经很少了,但还不准确。
    现在,你要做的是就是让自己死了,不同游戏可能不同,死的时候血是0,那就去自杀吧(如果掉经验用小号)。
    在结果里用0搜索一次。
    别以为这样就结束了,这次要让自己不死,那就让自己少点血,我一般采用脱掉加血上限的装备,让自己的血减少。
    依照以上方法反复尝试,最后确定一个地址。
    地址出现以后别高兴太早,现在很多游戏内存地址是变动的(至少每次开游戏时就变动),所以可能这次管用,到下次还要重新搜索。

以上这些都是我个人的经验之谈,可能有不精确之处,但我想基本上可以解决大部分问题,如果还有不懂的下面跟贴。
PS:这里的人看贴不回的习惯太不好了 以下发文观点皆以 "您已经会使用金山游侠、FPE2000、GameMaster等辅助软体来找寻资料"

相信不少玩家都经歷过那段记忆体只有 1M 时代,常常為為了挤那1,2k出来
跟OS争的你死我,再看看现在的电脑规格...,科技真一日千里 XD~

切入我们的主题,找到某游戏的内存位址数值后该怎麼用。

第一先从按精提供的函数来看

VBSCall ReadMemory(v1,v2,v3)
v1:内存地址:整数(16进制)
v2:类型:0-字节 1-整数 2-长整数
v3:输出值-所读取的内容:长整型变量

我想很多人一开始就算你找到了数值,却卡在这边不知道要输入什麼,包括我第一次使用也
遇到这个问题,所以我觉得有必要就这个部份说明一下。


VBSCall ReadMemory(&HFAC8EA,1,HP)
上面这行您一定常用

&HFAC8EA 是内存地址 , 1 是读取一个整数然再后再存进 HP 变量裡面
不管您用过几次,下面这三个参数说明您一定要看完。

-------------------------------------------------------------------------------------------
ReadMemory()第一个参数 内存地址:整数(16进制)
-------------------------------------------------------------------------------------------
&HFAC8EA 是什麼东西,為什麼可以代表一个内存地址?

来测试一下,在按精脚本输入

[Copy to clipboard] CODE: VBSCall MessageBox(a)
VBSCall MessageBox(typename(a))
结果:
第一次显示 16435434
第二次显示 Long

没错,&HFAC8EA 是一个长整数,&H就是用来将一个10进制的数字转成16进制的表示法,
他的反函数是HEX(),按精测试 VBSCall MessageBox(HEX(16435434))会显示 FAC8EA。

*因為我没有 ReadMemory() 这个函数的原形,所以我并不知道為什麼说明文件上面写整数(16进位)
也许是很早之前的按精版本确实只能使用整数,只是说明文件没改,也许是他确实是传入一个整数
,只是我误会他的意思,有时间我会把函数dump出来看看再上来加註,或是总版老大来龙去脉可以
说明一下。

不过他是什麼型态无所谓,至少用到现在没有出错过(不过还是有必要瞭解一下),我们只要确定一点
a = &HFAC8EA,变量 a 的型态确实是一个长整数!! 就算你把他强制转形,他还是一个长整数。且看
以下。

[Copy to clipboard] CODE: VBSCall MessageBox(typename(a))

//强制转形為整数
a = CINT(a)
VBSCall MessageBox(typename(a))
嗯,二次都是显示 Long,这是因為VBS的特性会根据变量内容来决定他是什麼型态如同以下程式

[Copy to clipboard] CODE:
b = 3
VBSCall MessageBox(a + b)
得到 8,因為VBS变数宣告的不定型特性,相对VBS也调整了一些运算子的自动转换,这样是好还是不好,
好处就是乱乱写也通,坏处就是在脚本裡做判断时很容易出错,因為你不知道他什麼时候偷偷帮你转形,
或是你以為他有帮你转形,事实上并没有,下就这段就不能执行了。

[Copy to clipboard] CODE:
b = 3
VBSCall MessageBox(a + b)
这种情况其实常常发生从文字档裡读出使用者界面参数做判断时,有时应该要HP=30自动吃补药,但是没吃,
不是按精有问题,而是你的判断式不正确,避免这种情况发生,读取文字档裡的变数出来后一律强制转形一
次(一个被变数型态搞到失眠的人留),微软出了一个VBS不知道该说造大眾还是害死一堆入门设计师。

偏主题有点久了,这部份详细请参考拙作(其实是写给我自已看的)。
按键精灵与 VBscrīpt 的基础观念(一)/viewth ... &extra=page%3D2
按键精灵与 VBscrīpt 的基础观念(二)/viewth ... &extra=page%3D2

-------------------------------------------------------------------------------------------
ReadMemory()第二个参数 类型:0-字节 1-整数 2-长整数
-------------------------------------------------------------------------------------------
為什麼我这麼在意变量是整数还是长整数,原因就在这,第二个参数型态直接就影响到输出的结果,
字节跟整数跟长整数有什麼不同,最大就差别就在范围值
字节 = 1 Byte (-127 ~ 128) 或不带正负号 (0 ~ 255)   = 256
整数 = 2 Byte (-32,768 ~ 32,767) 或 (0 ~ 65535) =   65536(256 ^ 2)
长整数 = 4 Byte (-2,147,483,648 ~ 2,147,483,647) 或 (0 ~ 4294967296) = 256 ^ 4

上面的范围很重要在,超过原本型态的范围就会產生溢位(overflow)的错误。

整数一定是 2Byte ? 不一定,要看你用的是哪一套程式语言,像 .NET Framework 中的整数就是
4个 Byte,Long 是 8 个 Byte,有一种叫 短整数 才是 2 Byte。那你怎麼知道按精是什麼语言开
发的,对!我不知道...,那你怎麼知道上面字节要用1 Byte 整数要用 2 Byte,对!我猜的 =.=

呵呵,好啦,不要玩文字游戏了,没有特别的情况下一定是上面那种范围,我实测过的确第二个参数
是这个范围值没错,只是按精应该在指令说明上应该註明一下范围(ps.我的印像中好像
按精有一个地方有特别註明这个参数佔的Byte数,因為我看了5.9x简体版的说明文件还有繁体版的说明
文件还有官网上的按精宝典,都没有特别说明,我一时也想不起来在哪看过的,还是哪位高人po的帖子
有提及过,有版友可以提供我官方文件说明文件连结我就会回来编帖註解一下。[转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆)

这个跟我游戏中 血量是285 昇级经验值是 20000 有什麼关係?

所以重点就是如果你的血量是在 0~255内,你就要设 1(字节),0~65535就要设2(整数)

有时你现在的血量是124第二个参数你设1(字节),但可能你会昇级血量会超过255(字节的范围),读出来
的值最大就到255而己,所以你要先确定游戏中血量到底佔了几个Byte。



-------------------------------------------------------------------------------------------
ReadMemory()第三个参数 输出值-所读取的内容:长整型变量
-------------------------------------------------------------------------------------------
我们来看一张图


[转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆 图片附件: Memory1.gif (2006-8-18 07:32 AM, 7.97 K)



红框的部份就是从 &H000EA99A 读取 1 个byte放进HP变量
VBSCall ReadMemory(&H000EA99A,0,HP)

//绿框的部份就是从 &H000EA9BA 读取 2 个byte放进HP变量
VBSCall ReadMemory(&H000EA9BA,1,HP)

//蓝框的部份就是从 &H000EA9DA 读取 4 个byte放进HP变量
VBSCall ReadMemory(&H000EA9DA,2,HP)
如果要连续取12个 4 Byte要怎麼做? 好问题,什麼情况会连续读取内存,读中文和图形档! 稍后介绍 内存偏移设定:从一个位置就知道其它位置,动态计算位址。
-------------------------------------------------------------------------------------------
对於记忆体实际系统运作,不在本篇叙述内,我们只要知道在按精如何灵活运即可。
内存位址的偏移(加加减减)观念上与按精中的阵列(数组)运作方式是一样的,且看以下

[Copy to clipboard] CODE:
VBS Dim Memory(3)

//Assign Value
Memory(0) = &H6B
Memory(1) = &H00
Memory(2) = &H4B
Memory(3) = &H00
类似上面的阵列用法您一定常用

您可以把内存位址(如:&HFAC8EA) ,当做是阵列中的索引值(Memory(0)、Memory(1)

阵列中的数值 Memory(0) = &H6B、Memory(1) = &H00 当做是内存位址实际储存的数值,也就是您实际读取到的HP、MP值。

看一下这张图你就一目了然了。


[转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆 图片附件Memory2.gif (2006-8-18 09:40 PM, 6.28 K)



以上举例说明只是让您更瞭解内储位址的意义,只要知道一般我们在按精裡使用的变数、阵列是10进制,而内存不管
是索引还是存放的数字都是以16进制来表示。

假设我们用金山游侠之类的软体找到了游戏中的数值
目前血量值(HP):1575
目前魔法值(MP):1604
最大血量(TOP_HP):17414
最大魔法(TOP_MP):9990


[转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆 图片附件Memory3.gif (2006-8-18 09:40 PM, 12.47 K)



那麼按精中你会这样写

[Copy to clipboard] CODE:
VBSCall ReadMemory(&H001E3242,1,MP)
VBSCall ReadMemory(&H001E31B9,1,TOP_HP)
VBSCall ReadMemory(&H001E31BB,1,TOP_MP)

//转成百分比
My_HP = Round(HP / TOP_HP , 2)*100
My_MP = Round(MP / TOP_MP , 2)*100

//HP低於60%吃HP补药
If My_HP <= 60
Gosub 吃HP补药
End If

//MP低於30%吃MP补药
If My_MP <= 30
Gosub 吃MP补药
End If
注意一个地方!!
由上图 TOP_HP (&H001E31B9)内存位址(最上面那个红色框)得知
第1个 Byte 06
第2个 Byte 44
如果你在按精测试 VBSCall MessageBox(&H0644) 得到结果会是 1604 ,而不是我上面写的 17414
怎麼会这样? 不要担心,因為记忆体高低位元排列的关係,要测试的值要倒过来打,
VBSCall MessageBox(&H4406) ,才能显示你抓到的数值 17414。
这部份原理我就不赘述,因為按精ReadMemory函数已经帮你处理掉,输出长整数变数一定跟记忆体中存的数值没错,
用ReadMemory读出来也是10进位,而不是16进位,你的目的只是要读取内存资讯而己,所以不要想太多 [转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆

上面这个范例是按精中典形的用法,但是如果如果你需要使用大量的内存位址,万一游戏改版或其它因素导致内存位址改变了
那啟不是又要重头全部找一次?


所以有经验的玩家会使用相对位址来储存,只记录内存位址偏移(偏了几个Byte)。
通常有3,4个内存位址,我们会挑位址最前面(位址索引值最低)那个来储存当做是计算偏移起点,以上例来说就是 &H001E31B9(TOP_HP)。

&H001E31B9 (TOP_HP) < &H001E31BB (TOP_MP) < &H001E3240 (HP) < &H001E3242 (MP)


再来就是执行小算盘->检视->切换成工程型,用来计算偏移位址 (你要用手算也可以啦 ~_~)


[转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆 图片附件Memory4.gif (2006-8-18 09:40 PM, 16.34 K)



求各个内存位址 到 &H001E31B9(TOP_HP) 的偏移(距离)

HP - TOP_HP (目前血量 HP 的内存偏移)
小算盘输入(前置0不用打) 1E3240 - 1E31B9 = 87

MP - TOP_HP (目前魔法 MP 的内存偏移)
小算盘输入(前置0不用打) 1E3242 - 1E31B9 = 89

TOP_MP - TOP_HP (最大魔法值 TOP_MP 的内存偏移)
小算盘输入(前置0不用打) 1E31BB - 1E31B9 = 2

注意! 红色数字的偏移量是16进位
按精中实际脚本语法

[Copy to clipboard] CODE:
//目前血量内存位址
HP_Addr = TOP_HP_Addr + &H87

//目前魔法内存位址
MP_Addr = TOP_HP_Addr + &H89

//最大魔法内存位址
TOP_MP_Addr = TOP_HP_Addr + &H2

//将内存位址以变数传入
VBSCall ReadMemory(HP_Addr,1,HP)
VBSCall ReadMemory(MP_Addr,1,MP)
VBSCall ReadMemory(TOP_HP_Addr,1,TOP_HP)
VBSCall ReadMemory(TOP_MP_Addr,1,TOP_MP)
注意一个地方,如果您使用档案存取方式将起始偏移量储存起来,那麼要用 CLng 强制转形一次
因為预设读出来的值都是字串(字串和数值相加会错误,第一篇有提到这个问题)。

"&H001E31B9"
TOP_HP_Addr = CLng(TOP_HP_Addr)

或者是您只存了 "1E31B9"
TOP_HP_Addr = "1E31B9"
TOP_HP_Addr = CLng("&H" & TOP_HP_Addr)
*结论:
用这种只存起始位址和记录偏移量的好处就是,就算游戏改版改变起始位址,也只要找一次,不用每个都重找内存位址。
当然,碰上游戏大改版,在多了一些栏位(譬如多了什麼精神力、威望值等等),有可能重新排列过记忆体位址,就要重
新全部找一次了。(总不可能游戏天天在改版吧 / _ \)

记忆偏移设定教学就到这边。 内存中找中文这篇我延了一段时间才补上来,不是我偷懒,而是我在想该怎麼詮释
中文字在内存的值,我试著写了一些解释(word档二页),写到后面实在有点无力,
(没看没事,看完连我自己都开始疑问一大堆),於是我往现成网路资料找,也找到
一些相当不错的网站,请版友慢慢享用。

谈谈Unicode编码
http://fmddlmyy.home4u.china.com/text6.html
Unicode
/w/index. ... e&variant=zh-cn
Big5
/w/index. ... C&variant=zh-tw
GB 2312
/w/index. ... 2&variant=zh-cn
GB 18030
/w/index. ... 0&variant=zh-cn
ASCII
是的,中文在内存中的值取决於他是什麼编码类型,上面列表是比较常用的。

原则上,一个英文字 1 个 Byte ,一个中文字 2 个 Byte(台湾以前还有一个中文字3个Byte
的编码方式),Unicode 编码也很重要,详细请看上表,在以下教学中避免误导,不介绍此
编码方式。

我们先从比较没问题的英文字在内存看起,英文字编码是属於ASCII,建议您把上表中连
结开啟对照。(按精中有个指令叫 ASC 您应该有用过,就是ASCII的缩写,下例会用到)

假如某位玩家对您说 LOVE,经由辅助软体Game Master我们找
到 "LOVE" 在内存的位址 = &H001C19D8


[转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆 图片附件Memory5.gif (2006-8-20 06:58 PM, 3.46 K)



按精中读取LOVE字串内存的方法

//Love字串内存起始位址
LoveAddr = &H001C19D8

//读取 4 Byte(一个英文字一个Byte,这边我不用Len("Love")或是设定為变数计算的方式,稍后说明。)
iByte = 4

//从第 1 Byte读取
i = 1

//读取内存值存放变数
ReadString = ""
iStr = "" //fix iString rename iStr (0821)

//连续读取 4 个Byte内存资料(还记得上篇教的位址偏移量的使用吗 [转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆)
一定要先看完前二篇哦,不然看到这会很吃力
while i <= iByte
   VBSCall ReadMemory(LoveAddr + CLng("&H" & i-1) , 0 , iStr)
   iStr = CHR(iStr)
   ReadString = ReadString & iStr
   i = i + 1 //fix 0823
EndWhile

//男/女朋友密你,自动回话给他
If ReadString = "LOVE"
SayString "baby~ i love you too"
EndIf
说明:
* LOVE 跟 love 大小写不同内码值也不同,上面这个例子是用 ASC 的反函数 CHR 自动转换读取到
Ascii码所对应的字元。

* 不用 Len("Love") 或是 s = "Love" : Len(s) 这样的方式是因為Len是VBS函数,VBS属於作业系统一部份,Len会随著
作业系统的不同而有不同的值(Windows XP/2000作业系统本身就是Unicode系统),得到的值
是字串的字元长度,而不是字串的 Byte数,(你又开始在抽像了...),
作个实验就知道,在按精输入 VBSCall MessageBox(Len("abc中文")),得到的答案是 5 ,
怎会这样? 你不是说一个英文1个byte,一个中文二个byte,Len("abc中文") 不是应该要 3+2+2 = 7 吗?
答案就是从这段*号地方开始再看一次! 事实上 "abc中文" 在XP裡面是10个Byte(5x2),
VBS 另外有一个计算字元的Byte数的函数,在按精输入VBSCall MessageBox(LenB("abc中文")) ,显示 10 。

写到这边我都还没正式介绍内存读取中文哦,所以读取英文的情况下照我上面的范例不会错。
再说也许可能是要读取不同男/女朋友的英文名字,再判断是第几号情人再回话,万一回错了就好笑了,所以还是照这样用。

不过话又说回来,我不敢保证游戏中一定是用1个byte在存一个英文字,有的游戏设计有考虑到发行
到不语言的国家,很有可能会使用2个byte来存英文字,现我在测试的游戏英文是以1个Byte储存,实际上使用,您
还是要多观察内存值的变化,再正确的设定ReadMemory参数,这就是我為什麼要写了二页的word档之后又砍掉的原因了,
既然要使用内存来读取游戏数值,就要细心一点。


接下来继续介绍中文内存读取,原理跟英文字串差不多略作修改,假如我们要对应游戏中某张地图名称叫 "火山湖"
也找到内存位址起点。


[转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆 图片附件Memory7.gif (2006-8-20 06:58 PM, 4.58 K)



脚本命名:FindStrInMemory.txt

//要找的字串
FindStr = "火山湖"

//这个字串的内存起始位址
FindStr_Addr = &H00169380

//转换实际内存中字串佔的Byte数 (中文=2个Byte,英文字1个Byte)
VBSCall FindStrByte = StrLength(FindStr)@<StanleyUtl.vbs>

//从第1个Byte开始读取
i = 1

//内存中字串的16进制码
MemoryHexStr = ""

//迴圈开始读取
While i <= FindStrByte
VBSCall ReadMemory(FindStr_Addr   + CLng("&H" & i - 1) , 0 , bWord)
MemoryHexStr = MemoryHexStr & hex(bWord)
i=i+1
EndWhile

//将您要找的中文字串转成跟内存一样的格式
VBSCall returnStr = Str2Hex(FindStr)@<StanleyUtl.vbs>

//这裡写找到内存中文字串之后值判断式
If returnStr = MemoryHexStr
GoSub 地图区域处理副程式
EndIf
VBS自订函数档命名: StanleyUtl.vbs (跟上面这个脚本放同一目录)


Function Str2Hex(varstr)
Str2Hex=""
For i=1 To Len(varstr)
   varchar=Mid(varstr,i,1)
   varasc = Asc(varchar)
   If varasc<0 Then
      varasc = varasc + 65535
   End If

   If varasc>255 Then
      varlow = Left(Hex(Asc(varchar)),2)
      varhigh = right(Hex(Asc(varchar)),2)
      Str2Hex = Str2Hex & varlow & varhigh
   Else
      Str2Hex = Str2Hex & Hex(ASC(varchar))
   End If
Next
End Function

'计算byte(中文 2 Byte,英文 1byte)
Function StrLength(S)
n = 0
For i = 1 To Len(S)
   C = Asc(Mid(S, I, 1))

   If C >= 0 And C <128 Then
      N = N + 1
   Else
      N = N + 2
   End If
Next

StrLength = N
End Function
说明:

1.请注意我在脚本中 VBSCall ReadMemory(FindStr_Addr   + CLng("&H" & i - 1) , 0 , bWord)
这行是以 0 (字节:1个BYTE) 方式读取,原因是因為实际上您在游戏中可能要比对的字串中英文混合 "火山湖ab12有美女"
   ,所以我在 StanleyUtl.vbs 提供了一个字串转成内存实际佔用Byte的函数。

2.实际你只要比对内存字串值,不用刻意对中文转码,什麼咧Unicode转ansi,简体转繁体,转来转去头都晕了,当然啦,
上列脚本只是简单应用,也许演算法写得不很好,如果有更好的写法也欢迎您po上来讨论。

3.一句老话,使用内存多观察内存值变化情况,确定你要找个这个中(英)文字串的内存起始位址,才不会找错 [转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆


中文字在内存的应用介绍就到这边~ XD 很不好意思要这样跳来跳去看~ 全部写完会委请总版帮忙连在一起 [转]关于内存地址的个人理解和操作原理1(按键精灵) - 行者 - 行者无疆
 

 

 

 

 

 

标签:Gosub,VBSCall,HP,VBS,按键精灵,内存,碎冰,Byte,内存地址
From: https://www.cnblogs.com/argent/p/17035203.html

相关文章