
在这个教程里面,你不会看到任何图片,因为我觉得我能用纯文字教你使用CE,如果你觉得没有图片就一定学不会,我想你没必要看下去了,因为我没空做图片,并且我觉得文字已经足够表达,没必要用多余的图片。
还有如果你喜欢这个入门教程,你可以把它转载到任何地方,但在转载之前,请你征得本人的同意,并且在转载时注明作者为CCB。
好了,废话少说,进入正题吧。
其实,使用CE的基本步骤,可以简单到一句话:
1.运行CE->2.运行游戏->3.在CE中指定要修改的游戏->4.首次搜索一个数值->5.回游戏中让这个数值增加或减少->6.回CE按数值增减的情况再次搜索->7.重复5和6直到得到一个或很少的几个结果->8.在这几个结果中判断哪一个是真正的结果。
而下面的这个教程,就是要对上面说的这些步骤进行详细的解释,然后再用一个具体的例子来让大家真正掌握CE的用法。
当然,要用一个具体的例子来讲解CE的用法,需要一个游戏,以这个游戏的修改来讲解。不过,如果真正的用一个游戏来做例子,那么大家也得找到我用的游戏,就算找得到,还有可能要安装,确实比较麻烦。幸好,CE本身带了一个TUTORIAL,就是教程的意思,不过这个TUTORIAL,本身也是一个程序,它是作者为了让使用的人进行练习而编写的,它不但会一步一步地教你怎么用CE,而且它本身也和游戏差不多,除了没有游戏的画面。如果你能使用CE按这个TUTORIAL的要求对它进行修改,我想你也应该能用CE对真正的游戏进行修改了。
OK,LET'S GO!
-------------------------------------------------------------------------------------------
CE操作入门
一,如果你还没安装CE,那么开始这一切之前,当然是把它安装上,CE的安装也和其他的软件一样,很简单,没必要再罗嗦。安装后,在开始菜单上会有CE的程序组,而在桌面上会有CE的快捷方式。
二,安装好之后,就可以运行CE了,运行后,会看到CE的主界面。其实CE的主界面真的非常非常简单,简单到不能再简单了,以至于我本来想给它做汉化,结果看到它的主界面上的英语单词少得可怜,根本不需要汉化。如果你连这几个单词都没办法或者不想去弄懂,我想,你的智商应该不足以用来修改游戏,那么赶快把CE删了吧,这不是你玩的东西。
三,现在我来描述一下CE的主界面,并且解释上面的各个部分的功能和简单的用法介绍,至于使用上的具体细节,请看后面的实例。
在CE主窗口的标题栏下面,左上方有三个按钮。
第一个按钮,是指定进程的按钮。在刚运行CE,还没指定所要修改的进程时,它的外框会不停地闪动,这个是作者提醒你,使用CE要做的第一件事,就是指定一个进程(什么叫进程?简单地说,就是你系统当前正在运行的程序)。这样CE才知道你要修改的是正在运行的程序中的哪一个。点击之后,会出来一个新窗口,窗口的标题是Process List,就是当前在你的系统上运行的所有进程的列表。这个窗口的下方,还有几个按钮,你暂时不用管(一个好的学习方法,就是在接触一个新的东西的时候,先弄懂那些非知道不可的东西,然后再更细致地学习,当然最后是要什么都知道。就是说要分主次先后来学。如果一开始就去注重很多暂时不需要知道的细节,结果反而会忽略了最需要先弄懂的东西,这样的学习方法就不好了)。在这里可以找到并选择你要修改的游戏,然后点OK按钮,或者简单地就双击要修改的进程。
左上方另外的两个按钮,图标就象其他的软件一样,一个是打开的文件夹,这个是用来打开以前保存的CE的地址列表(*.CT)的打开按钮,另一个是一张软盘的图标,这个是把地址列表保存下来的。
在这三个按钮的右边,上面是一行英文,下面是一个进度条,上面的英文,当CE还没选择要修改的进程时,它会显示“No Process Selected”,表示你还没选择进程,如果已经选择了一个进程,那么它会显示你选择的进程的ID和进程名,进程ID是一个由8个十六进制代码组成的标识号,后面的进程名就是你所选择的程序,即游戏的名称。而下面进度条,是当你在进行扫描的时候,显示当前的进度。
然后,在左上角三个按钮的下方,有个英文FOUND后面有个数字,这个是表示找到的结果的数目,当还没开始扫描或最后的扫描结果是0时,显示FOUND:0。如果某次扫描时,找到的结果很多,也暂时不会显示,但在这里可以看到目前为止找到的结果数量是多少。
在主窗口中间的左边,是一个扫描结果的地址列表,一般找到的结果少于某个数(默认的设置是少于50个)时,找到的结果会全部显示在这个列表中,而如果目前找到的结果多于设置的数量时就暂时不显示。这个列表有两个栏,Address是内存地址,而Value是该地址当前的数值。地址当然是十六进制表示的,而数值是十进制的。
在主窗口中间的右边,是CE的扫描部分,上面是三个按钮,First Scan,Next Scan和Undo Scan。下面是一个输入数值的地方Value,再下来,是选择扫描方式的Scan Type,选择数据类型的Value Type,再下面是设置内存扫描选项的Memory Scan Options,这里一般不需要修改,暂时不用管它。还有右边有个Enable Speedhack的选项,这个也先不管。第一次扫描时选择好扫描类型,输入好数值后点First Scan,这是开始一个全新的扫描,当数值变化之后输入新的数值再点Next Scan直到找到正确的内存地址。扫描后First Scan会变成New Scan,如果想开始一个新的扫描,点New Scan之后会清除以前扫描的结果,并且释放上次扫描所占用的内存,这样你就能重新开始。而有时当你在扫描中间选错了而影响了结果,可以点Undo Scan,这样会清除掉最后一次你做的选择,并把结果恢复到前一次扫描时的状态。
在主窗口的下方,又是一个地址列表,这个和上面那个不一样,上面那个是CE扫描的临时结果,而下方的这个,是你选择了的地址。它有五个栏,Frozen是对地址进行锁定用的,Description是对该地址的注释,Address是地址,Type是数值的类型,Value是该地址的数值。
在主窗口的中间,有一个斜向右下的红箭头的按钮,这个用于从左边的地址列表中把地址移到下方的地址列表的。你可以在左边列表中选择一个或多个地址,然后按这个按钮把它们移到下方的地址列表中。当然,你双击左边的地址列表,也能把它移动到下方的列表中。
在中间还有另一个红色停止符号的按钮,这个是清除下方地址列表中所有的地址的。
最后,在下方地址列表的左上和右上,各有一个按钮。左边的一个是Memory View,这个是CE最有用的按钮之一,它是用来查看和修改内存的,而它的功能还不仅仅是查看和修改内存,CE的最有用的一个功能——反汇编,也是在这个里面,不过暂时不想详细介绍这个按钮里面的功能,你知道它是做什么的就行了。右边的一个Add address manually,这个是用于手工向下方的地址列表添加地址的,如果你以前找到过某个地址,知道具体的地址,可以不用扫描,手工把地址加上。
CE的主界面基本就是这些,其实你用一秒钟就能看清楚,我却要打字打了半天:)
其实到现在为止,你还没真正掌握CE的使用,当然了,如果你会了,我就不用再继续写下去了,我早就去睡觉了。不要紧,下面结合实例来说明,你会真正掌握CE的使用的。
----------------------------------------------------------------------------
CE使用实例:
现在,我们来开始一步一步学习CE的使用吧,通过完成CE带的那个TUTORIAL,按它的要求一步一步做完,如果你做得到,你就基本上算是掌握了CE的用法了。
CE带的TUTORIAL,是英文的,不过没关系,我在教你使用CE来完成这个TUTORIAL的同时,会把TUTORIAL上面的所有英文都翻译出来让你看明白,所以不用怕。
CE带的这个TUTORIAL,是CE作者做的用来让你练习的一个程序,它里面也和游戏一样,在每一个步骤都会有一些类似血(HEALTH)或子弹数量的东西,并且你点了上面某个按钮之后,这些数值也会象游戏中一样减少,这样让你象是修改游戏一样,去找到它的地址,并按TUTORIAL上面的要求修改,当你按它的要求做到了,才让你做下一步。而在第一步时那个输入密码的地方,不是说这个TUTORIAL要输入密码才能运行,而是有时你需要从中间某一步开始时,输入相应的密码会直接从某一步开始,而不用每一次都从第一步开始的。而你每完成一步之后,它也会给你相应的密码。
好了,也许你等不及了,那么我们现在就开始吧。
第一步:
先在开始菜单上找到CE的程序组,找里面的“Cheat Engine Tutorial”(以下简称TUT),点击运行。这个时候就出来这个TUT的对话框,上面一大段英文,而Next这个按钮是灰的,为什么呢?让我翻译一下上面的英文吧,你就明白。TUT上面的英文的译文,我会用【】号把它们括起来。
【欢迎你来到CE的教程(V2.4)
这个教程试图解释在游戏中作弊的基本步骤,并让你更熟悉CE的使用。
首先运行CE,如果你还没运行的话(CCB:因为还没运行,所以Next按钮才是灰色的:)。
然后点击"open process"按钮(在左上角那个有电脑图标的那个)
当进程列表窗口打开后,找到这个教程,进程的名字应该是“tutorial.exe”,除非你把它改名了。选择它,并点击OK。现在先不要管其他所有的按钮,如果你喜欢,以后再研究它们。
当这一切都做对了之后,进程选择窗口将会消失并且在CE上方会显示进程名。
现在,点击NEXT按钮继续到下一个步骤(或者输入密码而进到你想去的其他步骤)。
】
好了,上面的这些英文,我翻译过来了,所以这一步应该不需要我再补充什么,看这些译文应该能明白怎么做,就是开TUT,开CE(哪个先开都没关系),然后点击CE左上的那个选择进程的按钮,选择这个TUT的进程,这样就可以点NEXT进到下一步了。
第二步:
【第二步:精确数值扫描(密码:090453)
现在你已经在CE中打开了TUT,让我们进入到下一步吧。
你看到在这个窗口的下方的文字Health:XXX
每次你点击"Hit me"(打我)时,你的Health(血)会减少。
要进到下一个步骤,你必须找到这个数值并把它改为1000
要找到这个数值,有几个不同的方法,但我会告诉你一个最简单的,'Exact Value(精确数值扫描)':
首先确认数值类型设置为2字节或4字节,1字节也可以的,但当你最后在修改它时你会遇到麻烦(虽然很容易解决)(CCB:大家不会忘了吧?1字节表示的最大数值是255,而这里要你改为1000,所以虽然用1字节能找到,但要改却要连前一字节一起改,所以有点麻烦,不过不是大麻烦)。8字节可能也可以,如果这个地址后面是0的话,不过我不敢打赌。Single, Double, 以及其他的扫描方式不行,因为它们储存数值的方式不同。
当数值类型设置正确后,确认扫描方式设置在'Exact Value'
把血的数值填在数值输入框上,并点击'First Scan(首次扫描)'
过一会儿(如果你有一个非常慢的电脑的话)扫描完成并且扫描的结果会显示在左边(如果找到的地址的数量少于设置的数值的话)。
如果你找到多于一个地址而你不知道哪一个是正确的地址的话,点击TUT上的'Hit me',并把新的血的数值填到数值输入框,并点'Next Scan(再次扫描)'
重复这些步骤直到你确认你已经找到它的地址了(在地址列表上只有一个地址)
现在双击左边列表上的地址,这样会让这个地址移动到下方的列表上并显示它的当前数值。
双击(下方列表的)数值栏(或者选择它,并按回车),并把它修改为1000。
如果一切都OK,NEXT按钮将会变成可点击的了,你就准备好了进入下一步了。】
这一步,也不用我再补充什么了,这个TUT已经说得很清楚,这是使用CE的最基本功能,即找到数值,如果扫描结果太多,试图改变数值然后再次扫描,直到结果剩下很少或者1个为止,这样你就找到了要修改的数值的地址,并且也就能修改它了。到这一步,你已经能对付很简单的游戏了,不过现在的大多数游戏都没这么简单,但至少你已经学到最基本的一步,就是精确数值的扫描和修改了。现在就点击NEXT进入下一步吧!
第三步:
【第三步:未知初始数值(密码:419482)
OK,看来你已经理解了怎样使用精确数值扫描找到一个数值了,让我们进入下一步吧。
在上一步中我们知道初始数值所以我们进行了精确数值扫描,但现在我们有一个进度条,我们不知道它开始时的数值。
我们只知道这个数值是在0到500之间,并且每次你点'Hit me'之后你会减一些血,每次减的血量会显示在进度条的上方。
同样的有好几个方式找这个数值,(例如使用“减少了什么数值”的扫描方式),但我只解释最简单的方式,“Unknown initial value”(未知初始数值)和“Descreased value(减少了的数值)”。
因为你不知道现在它的数值是多少,所以使用精确数值不行了,所以选择扫描方式为"Unknown initial value",同样的,数值类型选择4字节,(大多数WINDOWS应用程序使用4字节数据)
点击'First scan'并等它扫描完成。
当扫描完成后点击'Hit me',你会掉一些血(掉的血量多少会在血条上方显示几秒然后消失,但你不需要这个数值)
现在回到CE,并选择'Decreased Value'(减少了的数值),并点击“Next Scan”
当扫描完成后,再次点击'Hit me',并重复上面的步骤,直到你找到了若干地址。
我们知道这个数值是在0到500之间,所以选择比较象我们要的那个地址是,并把它加到下边的列表。
现在,把它改为5000,才能进到下一步。
】
这一步,稍为复杂一点了,这是对那些血条之类的东西的扫描。作者说知道数值是0到500之间,但没说是怎么知道的。我的看法是,这东西一方面靠猜,另一方面靠试。你也许会说,比如血条或蓝条,上面或下面不是有数字吗?是的,有些有,有些没有,但有时,血条上面有个表示血的数字,说血是548,但你就知道它是真的按这个值存在内存的吗?不一定的哦,很多游戏的开发者,可能会用某一个方式存真正的血的数值,而用另一个方式显示,例如,最简单的就是,真正的血是你看到的数值的3倍,例如上面说的548,其实在内存可能是14,而当它要显示的时候才把14除以3然后显示出来,所以如果你受这个显示数字的误导,结果就有可能找不到真正的地址。所以关于那些以长度表示的数值,一般还是靠猜,然后根据猜测来找。还有,CCB友情提醒一下,其实有时在找到的数值比较多的时候,试试在扫描的过程中,确认数值确实没改变的情况下,多加几次"Unchange"(无变化)扫描,这样可以再减掉一些无关的结果。另外,其实在这一步,如果你够聪明,每次点了Hit me之后记住血条上面显示的减少的数字,再在CE中输入刚才的数字(负号不要,负号只是表示它是减少的),并选择'Decreased value by',即“减少了什么数值”,这样也能更快地找到准确的地址,但这种方式是在要知道减少了多少这个具体数值才有用。好了,继续下一步吧。
第四步:
【第四步:浮点数(密码:0124)
在前面的教程中,我们使用字节来扫描,但有些游戏使用了叫做“浮点数”的记数方法。
(可能是为了防止简单的内存扫描)
浮点数是带有小数点的一些数字(如5.12或11321.1)
如下边你看到你的血(Health)和子弹(Ammo)。两者都以浮点数储存,但血是储存为float(浮点数)而子弹是储存为double(双精度浮点数)(CCB:这是数据类型的术语,float和double都是浮点数,但float为单精度数,而double为双精度数,它们在电脑里面占用的字节数长度不同,而所能表示的精度也不同,看不懂不要紧,反正知道这是两种不同的浮点数就行)。
点击Hit me可以减少一些血,而点击shoot(CCB:其实是Fire)可以用掉0.5的子弹。
你得把这两者都修改到5000或者更多才能进下一步。
精确数值扫描方式在这一步能工作得很好,但也许你想试试其他的扫描方式。(CCB友情提示:扫描子弹的时候试试'Decreased value by'方式就不错,数值填入0.5,很快就能找到)
】
这一步,其实也没什么,只是让你熟悉不同数据类型的扫描。再次提醒一下,其实有时游戏的开发者为了不让你太容易扫描到数值的地址,所以有时故意颠倒黑白,例如你看到有小数的地方,有时在内存却是用整数来保存,而你明明看到是显示为整数的数值,却有可能在内存中是用小数来保存,所以有时不要轻易地被你看到的东西误导,特别是在多次搜索不到结果的时候,有时要换换别的方式,不要让狡猾的游戏开发者骗了:)。
第五步:
【代码寻找(密码:8889)
有时一些东西的保存位置在你重新开始游戏时会改变,甚至是在你玩的时候也会变,在这种情况下,你用二件事仍然能做出可以用的内存列表。
在这一步我会描述怎样用寻找代码功能。
下面的数值每次你开始这个TUT的时候会存放在不同的位置,所以一个普通的内存地址列表将会不适用。
首先找到这个数值的内存地址(你能进到这一步,我假设你已经知道怎么做了)
当你找到地址后,右击CE中的这个地址,并选择“Find out what writes to this address”(找到是什么改写这个地址),一个窗口将会出现,上面会有一个空的列表。
然后,点击这个TUT上的'Change value'(改变数值)按钮,回到CE,如果一切都做得对,会看到一个地址和一些汇编代码。
点击这个地址并选择Replace(替换)选项把它替换成什么也不做的代码,这样还会将代码地址加到高级选项窗口上的代码列表(它将会一起保存,如果你保存地址表的话)。
点击Stop,这样游戏(CCB:指这个TUT)将会再次正常地运行下去,并点Close关闭这个窗口。
现在,点击这个TUT上的Change value按钮,如果一切都做对,NEXT按钮将会变成可点击的了。
注:如果你以足够快的速度锁定这个地址,这个NEXT按钮也会变成可见的。
]】
越来越精彩了,现在不但教你找地址,还教你找那条修改这个地址的指令了,虽然,你还不太清楚怎样手工修改找到的地址,但至少也比单纯地找数值的地址并修改和锁定要好一些了,不是吗?别急,更精彩的还在后面呢。
第六步
【指针(密码098712)
在上一步我解释了怎样用代码寻找功能对付变化位置。但单独用那个方法不容易找到地址来修改为你要的数值。
这就是为什么要用到指针了:
在TUT下面你会找到两个按钮,一个会改变数值,另一个不但会改变数值并且还会改变数值在内存中的位置。
在这一步,你不需要真的懂汇编,但如果你懂的话会很有帮助。
首先找到数值的地址,当你找到后,再找找是什么在改写这个地址。再次改变这个数值,这样会找到一个代码地址,双击这个代码地址(或者选择它并点击More info),这样一个新的窗口会打开并显示详细的信息告诉你当这个指令运行时会发生什么事(CCB:这个新出来的窗口上,那条指令会是红色的)。如果这个汇编指令里面没有包括一个在方括号中的东西,(CCB:说明这个不是我们要的)那么再看看代码地址列表中另一个代码地址。如果有方括号,就是说CE认为找到了数值的指针了。
回到CE主窗口,(你可以让那个扩展信息窗口开着,但如果你关了,要记住在方括号中间的内容)(CCB:要关了那个有代码地址列表的窗口,才能回到CE主窗口,但扩展信息窗口可以不用关掉),并做一次4字节的扫描,扫描扩展信息窗口告诉你的十六进制数。(CCB:就是方括号里面的内容,如果方括号里面是[eax],那么看看扩展信息窗口下面EAX=后面的数值)。当扫描完成时它可能返回一个或几百个地址。大多数情况下你要的会是最小(CCB:指地址最小,也就是排在列表的最上面)那一个。现在点击手工添加内存地址(Add address manually)并在pointer(指针)这个选项上打勾。
这个窗口将会改变,并允许你填入指针的地址和偏移量。
在地址那里填入你刚才扫描到的地址。
如果汇编指令在后面有一个计算(例如:[esi+12])那么把数值填在后面,否则让它保持0(CCB:就是如果有类似那样的计算,把12这个数值填在偏移量(OFFSET)那里,否则那里填0),如果是更复杂的指令,看看它的算式。
举例说明更复杂的算式:
[EAX*2+EDX+00000310] eax=4C 并且 edx=00801234.(CCB:这时各个寄存器的值到底是多少,要看扩展信息窗口下方,那里有各个寄存器在执行这条指令时的值)
在这个情况下EDX会是数值的指针,而EAX*2+00000310则是它的偏移量,所以你要填的偏移量会是2*4C+00000310=3A8.(这些都是在十六进制下计算的,使用WINDOWS的计算器在科学方式下用十六进制计算)。
回到TUT(CCB:?),点击OK,这个地址将会加到列表上,如果没搞错,将会显示P->xxxxxxxx,xxxxxxxx会是你找到的数值的地址。如果不正确,那你一定是哪里做错了。
现在,使用那个指针改变数值为5000并锁定(就是在下面的地址列表中,点最前面FROZEN那一栏的勾)它,然后(CCB:应该是这里才回到TUT吧?),点击'Change pointer'按钮,如果一切正确,那么NEXT按钮将变成可见的了。
额外信息:
在这个TUT中,事实上数值是由一个指针指向另一个指针(CCB:再指向真正的数值,就是使用了“指针的指针”,有点象绕口令:),但要完成这个TUT只需要一个指针。要找到这个指针(CCB:是说要找到指向指针的另一个指针),只要搜索是什么改变那个指针。
如果你懂汇编,你可能会看到类似这样的:
mov eax,[ebp-4]
mov eax,[eax+310]
这些别搞混了,只使用扩展信息窗口告诉你的数值。ebp-4指向堆栈中保存了指向这个指针的指针,但堆栈的位置总是在变化,所以不要搜索ebp,而要搜索eax的数值。
】
这一步,确实就够复杂了,也许你到这一步真的有点想放弃了。不过,如果我告诉你,这是这个TUT的最后一步了,你还会想放弃吗?呵呵,坚持啊,看不懂就问,把CCB这家伙问倒了才好呢:)。其实这就是对付DMA的方法之一了,就是先找到地址然后找到指针,找到指针就好办了。
【做得好,你完成了CE的教程了,再玩玩这个TUT并学习一下其他的扫描方法怎样工作的】
==============================================================
如果你一边看一边做,已经做到了这一步,CCB要恭喜你,你已经领到2005年第一学期的GH小学入学证书了,呵呵。以后就是个小学生了,可要听家长和老C的话哦,不要捣乱,不要迟到旷课,知道吗?
其实,这个教程,本身也并不很详细,而且本身可能由于作者疏忽并且英语也不是作者的母语吧,所以里面也有些不正确的地方,有些地方我是根据我的理解做了修正的,虽然即使你做完成了这个教程,也不是说你就很了不起了,但至少,你已经学会了CE的基本操作了,只要再多做练习,熟悉CE的操作和各种扫描方式的使用,对付一些简单的游戏,已经是游刃有余了,但要更深入地使用CE的更高级的功能,还要再多学习的。
其实到这里为止,CE界面上的一些东西还没有详细的讲过呢,不过在你做完这个教程之前,其实讲了可能你也听不太清楚,所以我会在大家熟悉了CE的操作后,再另外写一个相对全面一点的介绍CE各个部分和各个功能的帖子。
怎么写了一夜,都不觉得是自己在写东西,倒象是在翻译呢?也许是职业病吧,告诉你,在很久很久以前,CCB还不懂电脑的时候,就是专业做翻译的,不过不是做英语的翻译:)。
有时真的搞不懂,我自己三分钟就能做完的这个教程,翻译起来再拼凑上自己的几句,就竟然要花掉我五六个小时?也许,这就是创作和享受的差别吧。种田的人,从一棵谷苗到一把米,要花多长的时间?你却一口就能把它吃下:)
最后,欢迎大家提问题和扔臭鸡蛋,当然,扔几个魔功120的魔灵,我也绝对不反对的。不过一定要记得扔在小青蛇,别的区,你扔了我还不想捡呢:)
我想大家在最后一步都被搞糊涂了,大概有两个原因,最主要的一个原因是大家对DMA还不了解,另外一个就是CE作者在TUTORIAL里面也没说得很清楚,而我基本上是翻译的,只做了一些简单的补充,没有更详细和深入地说明所以大家都被搞糊涂了。
先来说说DMA,其实以前和椰子树有讨论过,论坛这里能找到我们当时聊天的记录。
DMA是动态内存定位,相对来说,不使用DMA的游戏,就是静态内存定位,意思是说例如HP之类的位置每次运行游戏都在一个固定的位置,而DMA则不然,每次运行游戏,或者每次重新开始游戏,HP的位置都会变。所以你第一点要明白的就是DMA这个概念。
因此,使用DMA的游戏,就算你找到了HP所在的位置,只做了这一点的话意义也不是很大,因为你把地址记下来或者把地址表保存下来也没用,因为下次运行游戏(或者重新开始游戏)时HP的位置又变了。而游戏使用DMA其中有一个方面就是不想让人家用简单的内存扫描来修改游戏,这是第二点要明白的。
但反过来说,虽然HP的位置有变化,但游戏程序本身也要知道这个变化了的位置,它才能去读写HP的数值,所以虽然HP位置变化了,但我们还是有办法找到变化后的地址的。这就是指针,指针其实也是一个地址,不过这个地址的内容不是直接保存着游戏的HP数值之类的东西,它的内容是一个内存地址,就是现在保存着HP数值的内存地址。所以你还要搞清楚指针这个概念。
听到这里可能有些人又开始糊涂了,不过不要紧,听我再继续说下去。
如果我举个例子,你应该就能明白了。比如说一个DMA的游戏,现在的HP是95,我们之前经过搜索知道这个HP现在是保存在00400023这里,而内存中有个地址00410056这里保存的内容是00400023,这个00410056就是指针,即:
地址 内容
00400023 95
00410056 00400023
那么下次运行游戏,HP的位置可能就不在00400023这里了,假设现在是在00400078了,那么现在的情况就是这样的:
地址 内容
00400078 98
00410056 00400078
就是说,保存HP的内存地址每次变化,但保存这个地址的位置却不变,那么这个不变的位置就是指针。所以回过头来说,记住00400023或者00400078这些地址没什么用,因为它是每次变化的,反而只要找到指针,就是说找到00410056这个地址,以后要找HP保存在哪里还不容易吗?简单地读出00410056里面的内容就是当前HP的内存地址了。
那么剩下的问题就是如何找指针这个问题了。其实这个问题也不难,其实和找HP的地址一样简单,也许你不信。
想想我们是怎样找HP,怎样找MONEY的,我们都是通过数值的变化来找的,那么,保存HP位置的这个内存地址不是变化的吗?我们根据它的变化来找它不就是很简单的事吗?
首先当然是先找到HP目前在什么位置,得到当前HP的内存地址,在内存中搜索这个地址,看看哪些地址的内容是这个地址,然后等HP的位置变化了,再在搜索结果中再次搜索变化后的地址,按上面的过程重复就能找到指针了。以上面的例子来说,我们先找到了00400023这个地址,然后在内存中搜索“00400023”,等地址变化为00400078之后,我们再次扫描,这次输入的值是“00400078”,依此类推,这样就能找到指针了,即找到00410056了。其实由于内存地址长度是四字节,所以一般第一次搜索到的结果就很少,有时甚至一次就能判断出哪一个是正确结果。
而在CE的教程中,做法有点复杂,以上面的例子来说,在找到了当前HP的位置是00400023之后,教程要求大家用CE的FIND OUT THAT WRITES THIS ADDERSS这个功能来找到是哪一条指令修改了HP的值(或者说修改了00400023这个地址的内容),找到这条指令后再根据这条指令算出这个00400023,再去搜索“00400023”,其实我个人觉得不用使用FIND OUT,,这个功能,找到当前HP的地址之后直接搜索就行,我想就是这一点把大家搞糊涂了吧。不过CE作者这样做有他的道理,因为对付DMA的游戏,这条修改HP值的指令(就是用FIND OUT THAT,,找到的那条指令)是很关键的,特别是要做外挂的时候,因为DMA要写补丁(CODE CAVE)来处理,但一般如果你只是想直接用CE来修改游戏,只要能找到指针就行,在地址表中以指针形式添加这个指针就能直接在CE的地址表上修改或锁定HP值了,也主只可以不用FIND OUT,,这个功能去找指令了。
都明白了没有?
武林外传辅助工具详细制作过程[第一篇:基址寻找方法]
好了,开始正题
一,打开游戏和CE5.2用CE载入游戏
二,让你的血量回到最满状态,记住血量值
如上图,我的是1312点血,好的,用CE搜"1312",.用"Exact Value"方式,4字节
搜到N个址,好,再回到游戏里,我们让人物掉点血(打怪什么的,最好多掉点,这样方便后面来查数),再用"Decreased Value"(减少了的数)来搜,这样掉点血,搜一次,搜点血搜一次,几次下来,好的,找到的地址就只剩四个了(我是两次就找到只剩四个了,电脑不同,可能找的次数也不同,不过方法是一样的,先找最大血量值,然后,再掉点血,再用减少的搜,如此循环几次就OK了)记下第一个地址(为什么用第一个地址,CE的教程里说,一般如果找到少量的地址后,正确的一般在第一个,如果你不确定,你可以让人物自动回血,就可以看到,第一个地址的数也在跟着增加~)
接着,把第一个地址双击,加入下面的栏里,再在地址上单击右键,弹出菜单中选"Find out what writes to this address"(谁在改定这个地址),调出监视窗口,再回到游戏,掉点血,就可以看到监视窗口里己经有改写该地址的命令了~
选中该命令,点"Mor information得到如下图
mov [esi+00000254],ecx 红色加亮的这句,(+00000254也就是血量的偏移量了)
可以看到,是把ECX的值写入ESI+00000254这个内存地址中,所以,我们记下下面的ESI地址:ESI=05C0B548,再回到CE主界面,搜"05C0B548"这个数(选中HEX,用十六进制四字节方式搜)
得到26个地址都含有这个数,好的,把最前面的三个数保存到下栏里,然后,小退一下(回到人物选择界面,再进入游戏),就可以看到,三个地址的数值都有变化了.好,再重新找血量地址,然后再"Find out what writes to this address"(谁在改定这个地址)这个地址,得到ESI的值,记下来,对比刚保存 下来的三个地址内的数,呵呵,发现
010AEAE4里的值刚好等于ESI,这就可以肯定,010AEAE4一定二级基址了,好,我们监视010AEAE4,"Find out what writes to this address".好,再次小退一下,再进入游戏,这时监视窗口有东东了,如下图
得到:mov [esi+24],0000000
记下ESI的值,010AEAC0,再回到CE主界面,用十六进制的方法找010AEACO
得到N个数,反复搜几次,好,得到下图
按CE教程说的,一般最是地址最小的就是正确的,呵呵,有点那个啊,~~~~~~~~~~~~ 选第一个008BE594,加到下面的栏里,完全退出游戏,再进入游戏 重复,最后还是得到008BE594,这样就可以肯定,008BE594就是一级基址了 得出公式如下 一级基址:008BE594 008BE594地址里面保存的数值+24的偏移=二级基址 二级基址里面保存的地址数+254的偏移得到血量的地址 | ||
| 武林外传辅助工具详细制作过程[第二篇:查看数据] 1.我们可以用CE打开武林外传。运行CE,按照下图的次序打开(...\武林外传\\element\\elementclient.exe) 2.游戏启动后,别忘了选择游戏窗口。 3.这是游戏中人物的数据。 4.好,现在我们要在CE中显示人物的生命值。同样按照图中的顺序打开“添加地址”对话框,在数据框中添加我们已知的内存地址。当然,我们要用指针的方式,因为存储这些数据的地址是不固定的,我们可以用8C6A54这个固定的基地址以及相关的偏移地址找到我们需要的数据。我们就来看看生命的值,完成图上的项目点“确定”来看看结果。 5.怎么样!是不是角色的生命值呢,使自己失去一些血量看看这个值是不是也在跟着变化。 6.根据已知的人物地址,我们还可以显示其它数据。 文章涉及软件: Cheat Engine游戏修改器下载 用讯雷吧...哇哈哈 相关武林外传地址: 一级基址=8CF51C 人物基址=+24 当前血=+254 最大血=+26C 当前蓝=+258 最大蓝=+270 以上数字均为16进制 | ||
武林外传辅助工具详细制作过程[第三篇:显示游戏数据]
1.建立一个新的标准EXE工程,我们就可以开始这次的学习了。
2.我们要建立一个模块,然后添加以下代码:
Option Explicit
'---------------声明函数-----------------------
'得到窗体句柄的函数,FindWindow函数用来返回符合指定的类名( ClassName )和窗口名( WindowTitle )的窗口句柄
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'得到窗体控件句柄的函数
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
'得到进程标识符的函数
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
'得到目标进程句柄的函数
Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
'关闭句柄的函数
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'读取进程内存的函数
Public Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long
'参数决定了对进程的存储权限,使用完全控制
Public Const PROCESS_ALL_ACCESS = &H1F0FFF
3.接下来Form中,我们要在程序启动时连接游戏窗口,以下是Form_Load的代码:
Dim hwd As Long ‘ 储存 FindWindow 函数返回的句柄
Dim pid As Long
Dim hProcess As Long '存放进程句柄
Private Sub Form_Load()
hwd = FindWindow("QElementClient Window", "Element Client")
If hwd = 0 Then
MsgBox "未启动游戏", vbOKOnly, "提示"
Unload Form1
End If
GetWindowThreadProcessId hwd, pid '获取进程标识符
'将进程标识符做为参数,返回目标进程PID的句柄,得到此句柄后
'即可对目标进行读写操,PROCESS_ALL_ACCESS表示完全控制,权限最大
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
If hProcess = 0 Then
MsgBox "不能打开进程", vbOKOnly, "提示"
Unload Form1
End If
CloseHandle hProcess
4.我们在Form中添加一个Label控件和一个Timer控件,设置Timer的Interval属性为100,Timer1_Timer的代码如下:
Dim h As Long
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, pid)
If hProcess Then
ReadProcessMemory hProcess, ByVal &H8C6A54, h, 4, 0& ‘这三条代码读取获得生命值
ReadProcessMemory hProcess, ByVal h + &H24, h, 4, 0&
ReadProcessMemory hProcess, ByVal h + &H254, h, 4, 0&
CloseHandle hProcess
End If
| Label1.Caption = h '输出生命值 |
1.首先我们要绘制一个界面,最先添加一个Frame控件、最少两个Label控件用于输出生命和真气值、两个Text控件用于输入数据还有两个Timer控件,分别改名为TimerList及TimerAdd,最后添加一个Command控件。可以参考下图,呵呵~我知道你可以画的更好看!
2.下一步就是添加代码了,和上次一样新建一个模块,模块内容如下:
Option Explicit
'---------------声明函数-----------------------
'得到窗体句柄的函数,FindWindow函数用来返回符合指定的类名( ClassName )和窗口名( WindowTitle )的窗口句柄
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'得到窗体控件句柄的函数
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
'得到进程标识符的函数
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
'得到目标进程句柄的函数
Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
'关闭句柄的函数
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'读取进程内存的函数
Public Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long
'参数决定了对进程的存储权限,使用完全控制
Public Const PROCESS_ALL_ACCESS = &H1F0FFF
'发送信息的函数
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'延迟函数
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
发送消息函数和延迟函数是以前内容没有用过的,这回我们将涉及发送模拟键盘消息给窗口,所以加入这两个函数。
3.做好模块,下一步该写Form了。同样还是声明一些变量及Form_Load,代码如下:
Dim hwd As Long
Dim pid As Long
Dim hProcess As Long '存放进程句柄
Dim base As Long '存放人物基地址
Dim hp As Long '存储生命值
Dim hpmax As Long '存储生命最大值
Dim mp As Long '存储真气值
Dim mpmax As Long '存储真气最大值
Private Sub Form_Load()
hwd = FindWindow("QElementClient Window", "Element Client")
If hwd = 0 Then
MsgBox "未启动游戏", vbOKOnly, "提示"
Unload Form1
End If
GetWindowThreadProcessId hwd, pid '获取进程标识符
'将进程标识符做为参数,返回目标进程PID的句柄,得到此句柄后
'即可对目标进行读写操,PROCESS_ALL_ACCESS表示完全控制,权限最大
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
If hProcess = 0 Then
MsgBox "不能打开进程", vbOKOnly, "提示"
Unload Form1
End If
CloseHandle hProcess
End Sub
4.下一步,我们通过TimerList显示人物信息,设置TimerList的Interval属性值为1000,其代码如下:
Private Sub TimerList_Timer() '显示人物信息时钟
Dim name(31) As Byte '存储人物名称
Dim name_temp As Long
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, pid)
If hProcess Then
ReadProcessMemory hProcess, ByVal &H8C9E54, base, 4, 0&
ReadProcessMemory hProcess, ByVal base + &H24, base, 4, 0& '得到为人物基地址,方便以后使用
ReadProcessMemory hProcess, ByVal base + &H254, hp, 4, 0& '得到生命值
ReadProcessMemory hProcess, ByVal base + &H26C, hpmax, 4, 0& '得到生命最大值
ReadProcessMemory hProcess, ByVal base + &H258, mp, 4, 0& '得到真气值
ReadProcessMemory hProcess, ByVal base + &H270, mpmax, 4, 0& '得到真气最大值
ReadProcessMemory hProcess, ByVal base + &H390, name_temp, 4, 0&
ReadProcessMemory hProcess, ByVal name_temp, name(0), 32, 0& '得到人物名称
CloseHandle hProcess
End If
Frame1.Caption = name '显示人物名称
Label2.Caption = "生命值:" & hp & "/" & hpmax '显示生命值
Label3.Caption = "真气值:" & mp & "/" & mpmax '显示真气值
End Sub
现在可以运行一下看看数值是否能正常显示!
5.在来做第二个TimerAdd,设置Enabled = False,Interval属性值为100,期代码如下:
Private Sub TimerAdd_Timer() '加血判断时钟
If Val(Text1.Text) > hp Then '比较当前血量是否比预定值低,是则按下F1健
SendMessage hwd, &H100, &H70, 0& '按住F1键,&H100代表按下,&H70代表F1
SendMessage hwd, &H101, &H70, 0& '松开F1键,&H101代表松开,&H70代表F1
Sleep Val(Text2.Text) '延迟text2中的数值,用val()取数值
End If
End Sub
6.最后就剩下Command了,设置其Caption属性为“开始”,期代码如下:
Private Sub Command1_Click()
If Command1.Caption = "开始" Then '按下标签为“开始”的按钮,激活TimerAdd并改变标签为“停止”
TimerAdd.Enabled = True
Command1.Caption = "停止"
ElseIf Command1.Caption = "停止" Then '刚好和上面相反
TimerAdd.Enabled = False
Command1.Caption = "开始"
End If
End Sub
7.小功告成!运行测试看看,能否实现加血功能!那加蓝、补助技能呢?
8.本次内容重点:
SendMessage /通过此函数实现模拟键盘操作功能
Sleep /必不可少的延迟函数
9.当然,你看完整个文章或者在测试的时候会发现,这个程序还有很多的漏洞或者说还可以做的更完善,没错,这就是接下来你要做的,还是那句话:“因为我知道你可以做的到”
ps:自己设置按键
SendMessage hwd, &H100, Key(Combo1.ListIndex), 0&
SendMessage hwd, &H101, Key(Combo1.ListIndex), 0&
Private Function Key(Anjian As Long) As Long '用于转换按键的函数
Select Case Anjian
Case 0
Key = &H70 ‘F1
Case 1
Key = &H71 'F2
Case 2
Key = &H72 'F3
Case 3
Key = &H73 'F4
Case 4
Key = &H74
Case 5
Key = &H75
Case 6
Key = &H76
Case 7
Key = &H77
Case 8
Key = &H31 '1
Case 9
Key = &H32 '2
Case 10
Key = &H33 '3
Case 11
Key = &H34
Case 12
Key = &H35
Case 13
Key = &H36
Case 14
Key = &H37
Case 15
Key = &H38
Case 16
Key = &H39 '9
Case 17
Key = &H30 '0
End Select
| End Function |
我们已经学会如何监视血量达到加血的功能,其实自动攻击和加血的核心原理是一样的,同样是发送消息给游戏窗口,只不过要先通过按Tab键选去身边的怪然后按攻击快捷键打怪。
提示:
SYSKEYDOWN = &H104
KeyDOWN = &H100
KeyUP = &H101
CHAR = &H102
SHIFT = &H10 'Shift键的常数
CONTROL = &H11 'Ctrl键的常数
MENU = &H12 'Windows键的常数
TAB = &H9 'Tab键的常数
[[eax]+ &H798] '&H798 或地址 &H0354AF44 当前目标怪物ID ,为负就是怪,为正就是NPC或玩家,为0则怪物死亡或没有选择
[[eax] + &H408] '人物攻击状态,攻击时为1,无动作为0
[[eax] + &H25C] '&H25C 当前经验值,十进制
[[[[eax]+&h8]+&h24]+&h14] '地上所有物品数量,包含别人打掉地上的物品
2.我们要做一个小程序,用于显示地面上的所有物品。添加一个List控件、一个Time控件,如下图所示。
3.下面添加代码!
3.1.模块:
Option Explicit
'---------------声明函数-----------------------
'得到窗体句柄的函数,FindWindow函数用来返回符合指定的类名( ClassName )和窗口名( WindowTitle )的窗口句柄
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'得到窗体控件句柄的函数
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
'得到进程标识符的函数
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
'得到目标进程句柄的函数
Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
'关闭句柄的函数
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'读取进程内存的函数
Public Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long
'参数决定了对进程的存储权限,使用完全控制
Public Const PROCESS_ALL_ACCESS = &H1F0FFF
3.2.Form_Load:
Option Explicit
Dim hwd As Long
Dim pid As Long
Dim hProcess As Long '存放进程句柄
Private Sub Form_Load()
hwd = FindWindow("QElementClient Window", "Element Client")
If hwd = 0 Then
MsgBox "未启动游戏", vbOKOnly, "提示"
Unload Form1
End If
GetWindowThreadProcessId hwd, pid '获取进程标识符
'将进程标识符做为参数,返回目标进程PID的句柄,得到此句柄后
'即可对目标进行读写操,PROCESS_ALL_ACCESS表示完全控制,权限最大
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
If hProcess = 0 Then
MsgBox "不能打开进程", vbOKOnly, "提示"
Unload Form1
End If
End Sub
3.3.Timer_Timer:
'Timer.interval=1000,利用1秒的延迟显示列表
Private Sub Timer1_Timer() '显示地面物品名称列表
Dim base As Long '存储地址
Dim mecxi As Long '存储地址
Dim pn As Integer '循环变量
Dim WpName(65) As Byte '存储物品名称
List1.Clear '用于刷新物品列表
If hProcess Then
ReadProcessMemory hProcess, ByVal &H8C9E54, mecxi, 4, 0
ReadProcessMemory hProcess, ByVal mecxi + &H8, mecxi, 4, 0
ReadProcessMemory hProcess, ByVal mecxi + &H24, mecxi, 4, 0 '得到物品数量
If mecxi <> 0 Then
For pn = 0 To 768 '循环用来判断那个值内存在物品
ReadProcessMemory hProcess, ByVal mecxi + &H18, base, 4, 0
ReadProcessMemory hProcess, ByVal base + pn * 4, base, 4, 0 '从列表中选出地面上物品的地址
If base > 0 Then '判断是否存在物品
ReadProcessMemory hProcess, ByVal base + 4, base, 4, 0
ReadProcessMemory hProcess, ByVal base + &H1, base, 4, 0
ReadProcessMemory hProcess, ByVal base, WpName(0), , 0 '得到物品名称
List1.AddItem WpName '添加到List控件
End If
Next pn
End If
End If
End Sub
3.4.Form_Unload:
Private Sub Form_Unload(Cancel As Integer)
CloseHandle hProcess
End Sub
接下来我们就能让可恶的配方从此在背包中消失
2.首先看看图片,我要用到那些控件
主要控件:
List1 /用于显示地面物品
List2 /用于显示需要过滤的物品名称
Timer1 /用于刷新地面物品
Timer2 /用于过滤地面物品
Combo1 /用于添加或保存过滤物品名称
Command1 /添加按钮
Command2 /删除按钮
模块添加:
'存储进程内存的函数
Public Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
3.我们来看看过滤物品的核心代码,以下为Timer2_Timer代码:
Private Sub Timer2_Timer()
Dim base As Long '存储地址
Dim mecxi As Long '存储地址
Dim WpNameT As Long '存储地址
Dim pn As Integer '循环变量
Dim WpName(65) As Byte '存储物品名称
Dim x As Integer
If hProcess Then
ReadProcessMemory hProcess, ByVal &H8C9E54, mecxi, 4, 0
ReadProcessMemory hProcess, ByVal mecxi + &H8, mecxi, 4, 0
ReadProcessMemory hProcess, ByVal mecxi + &H24, mecxi, 4, 0 '得到物品数量
If mecxi <> 0 Then
For pn = 0 To 768 '循环用来判断那个值内存在物品
ReadProcessMemory hProcess, ByVal mecxi + &H18, base, 4, 0
ReadProcessMemory hProcess, ByVal base + pn * 4, base, 4, 0 '从列表中选出地面上物品的地址
If base > 0 Then '判断是否存在物品
ReadProcessMemory hProcess, ByVal base + 4, base, 4, 0
ReadProcessMemory hProcess, ByVal base + &H1, WpNameT, 4, 0
ReadProcessMemory hProcess, ByVal WpNameT, WpName(0), , 0 '得到物品名称
For x = 0 To List2.ListCount - 1 '用循环查找是否是过滤表内要过滤的物品
If InStr(WpName, List2.List(x)) > 0 Then '用InSet()进行对比,存在过滤表内容则过滤
WriteProcessMemory hProcess, ByVal base + &H110, 0, 4, 0 '变ID为0,有捡物品动作但背包内无此物品
Label1.Caption = "已过滤:" & CStr(WpName) '过滤提示,观察用
End If
Next x
End If
Next pn
End If
End If
End Sub
3.1.地面上的物品得用一个0 to 768循环来判断哪个值内存在物品,比如说地面上有四个物品,则0 to 768里面就会有4个值是存在着物品,也就说游戏最多能显示769件地面物品。
3.2.首先判断地面上是否存在物品,如果存在则循环769次查找物品,当找到0 to 768中的一个物品时,程序得到物品的名称,接下来用一个循环来对比物品名称与过滤表做对比,如果为要过滤的物品则改变当前物品在内存的ID,游戏程序再执行捡取动作就会实现过滤功能,物品检起来了,但是并不在背包内,也没有捡到物品的提示。
4.最后就是过滤表的制作了,这个很简单,只要有添加项目和删除项目的功能就可以。这里我用到Combo控件作为输入框,因为可以记录一些可能会用到的物品名称。
Private Sub Command1_Click() '添加物品名称
If Combo1.Text <> "" Then List2.AddItem Combo1.Text
End Sub
Private Sub Command2_Click() '删除物品名称
If List2.ListIndex <> -1 Then List2.RemoveItem (List2.ListIndex) '当选中某项则删除某项
End Sub
5.最后的成品!标签显示了已经过滤的物品。最后,默哀5分钟以悼念做测试时销毁的5个大补丸
| 武林外传辅助工具详细制作过程[第七篇:刷新背包] 1.在模块添加以下代码: '读配置文件 Public Declare Function GetPrivateProfileString& Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) 2.以下是用于刷新背包物品名称Timer3的代码: Private Sub Timer3_Timer() '用于刷新背包物品名称 Dim base As Long '存储地址 Dim mecxi As Long '存储地址 Dim pn As Integer '循环变量 Dim pd As Long '判断变量 'Dim BaoName(35) As Byte '存储物品名称 Dim BaoN As Long '背包格数 List3.Clear '清除,用于刷新物品列表 If hProcess Then ReadProcessMemory hProcess, ByVal Buffer, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H24, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H854, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H10, BaoN, 4, 0 '得到背包格数 ReadProcessMemory hProcess, ByVal mecxi + &HC, mecxi, 4, 0 For pn = 0 To BaoN - 1 '循环查询背包内所有格子内的物品 ReadProcessMemory hProcess, ByVal mecxi + pn * 4, base, 4, 0 ReadProcessMemory hProcess, ByVal base + &H14, pd, 4, 0 '得到格子内物品数量,因为没有确认格内存在物品的地址,所以暂用这个判断是否存在物品 If pd > 0 Then '大于0表示存在物品 ReadProcessMemory hProcess, ByVal base + &H8, base, 4, 0 '得到物品ID ItemList (CStr(base)) '交给转换名称函数处理 'ReadProcessMemory hProcess, ByVal base + &H44, base, 4, 0 'ReadProcessMemory hProcess, ByVal base + &HE, BaoName(0), 34, 0 'If InStr(BaoName, "\\r") - 1 > 0 Then List3.AddItem Left(BaoName, InStr(BaoName, "\\r") - 1) End If base = 0 pd = 0 Next pn Frame3.Caption = "背包物品 * " & List3.ListCount '根据list3的项目数得到物品数量 End If End Sub 3.自建一个函数用于把得到ID转换成物品名称,以下是代码: Private Sub ItemList(ItemName As String) '用于转换物品名称函数 Dim name As String '存储物品名称 Dim dz As String '存放文件地址 Dim a As Integer '用于判断 name = Space$(35) '定义读取值的字串宽度 a = GetPrivateProfileString("item", ItemName, "", name, 35, App.Path & "\\config.ini") '在文件中查找匹配物品名称 name = Trim$(name) '去掉多余字符 If a = 0 Then '输出到List的判断 List3.AddItem ItemName & "****" '当无匹配项目则输出物品ID和无资料 Else List3.AddItem name End If End Sub 4.我用config.ini保存物品名称对应表 [item] 28=精炼石 34=菜鸟布衣(男) 35=丝衣(男) 36=缎衣(男) 38=掩心甲(男) 39=鳞甲(男) 40=金缕甲(男) 41=豹皮战甲(男) 42=狮蛮甲(男) ............ 5.程序运行,物品名称正确的显示出来,不过随着游戏的更新你也许需要不断的更新你的文config.ini。 注: 背包物品地址: [[[[&H8C9E54]+&h24]+&h854]+&h10] 是角色背包最大容量 [[[[&H8C9E54]+&h24]+&h854]+&hC] 是角色背包首地址 [[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号] 是格子物品首地址(格子数从0开始) [[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号]+&h14] 是此格物品的数量 [[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号]+&h18] 是此格物品的堆叠上限 [[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号]+&h4] 背包内物品类型 (装备&戒指&项链为0,生产材料&声望材料为1,药品为2,精炼石为7,垃圾石头为8,配方为17,宠物牌为23) [[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号]+&h8] 物品ID GetPrivateProfileString: DWORD GetPrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName); 参数的意义: lpAppName : 配置文件的section名 lpKeyName : 配置文件的key名 lpDefault : 如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量. lpReturnedString : 接收INI文件中的值的CString对象,即目的缓存器. nSize : 目的缓存器的大小. lpFileName : 是完整的INI文件名. 例: config.ini的内容: [item] 28=精炼石 34=菜鸟布衣(男) 35=丝衣(男) 36=缎衣(男) 38=掩心甲(男) 39=鳞甲(男) 40=金缕甲(男) 41=豹皮战甲(男) 42=狮蛮甲(男) GetPrivateProfileString& "item", 36, "", name, 35, App.Path & "\\config.ini") 在[item]下,找36这项,将值存入变量name,宽度为35,文件地址为App.Path & "\\config.ini" | |
本篇后不会提供新过程.以后靠大家自己做吧...
内容:
1.我们将使用EnumWindows枚举Windows所有窗口。首先来看看MSDN说明:
函数功能:该函数枚举所有屏幕上的顶层窗口,办法是先将句柄传给每一个窗口,然后再传送给应用程序定义的回调函数。EnumThreadWindows函数继续到所有顶层窗口枚举完为止或回调函数返回FALSE为止函数原型:BOOL EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam);
参数:
lpEnumFunc:指向一个应用程序定义的回调数指针,请参看EnumWindowsProc。
lPararm:指定一个传递给回调函数的应用程序定义值。
返回值:如果函数成功,返回值为非零;如果函数失败,返回值为零。若想获得更多错误信息,请调用GetLastError函数。
2.模块部分:
Option Explicit
'得到窗口的标题条文本
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
'枚举所有屏幕上的顶层窗口
Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
Dim S As String
S = String(80, 0)
Call GetWindowText(hwnd, S, 80)
S = Left(S, InStr(S, Chr(0)) - 1)
If Len(S) > 0 Then Form1.List1.AddItem S
EnumWindowsProc = True
End Function
3.Form部分,我们需要一个List控件用于显示:
Private Sub Form_Load()
EnumWindows AddressOf EnumWindowsProc, 0&
End Sub
4.运行程序,显示了所有窗口的文本。
5.好了,我们完成了核心程序。
现在我们要接着往下做三个工作:(1)只显示我们想要的窗口、(2)显示人物名称、(3)选择目标人物连接游戏窗口。
5.1.筛选枚举出来的窗口。这个很简单,只要在插入List之前的If中再加入一个判断窗口文本内容就可以实现。
If Len(S) > 0 and UCase(S) = "ELEMENT CLIENT" Then Form1.List1.AddItem S
5.2.显示人物名称,我想这个大家都会吧!
If Len(S) > 0 And UCase(S) = "ELEMENT CLIENT" Then
Dim ProcID As Long, hpID As Long, BuffEnum(35) As Byte, ECXI As Long, eax As Long, Str As String
GetWindowThreadProcessId hwnd, hpID
ProcID = OpenProcess(PROCESS_ALL_ACCESS Or PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, hpID)
ReadProcessMemory ProcID, ByVal &H8C9E54, ECXI, 4, 0 '这个是存放基址的地址
ReadProcessMemory ProcID, ByVal ECXI + &H24, eax, 4, 0
ReadProcessMemory ProcID, ByVal eax + &H390, ECXI, 4, 0
ReadProcessMemory ProcID, ByVal ECXI, BuffEnum(0), 36, 0
Str = Left$(BuffEnum, 36)
Form1.List1.AddItem hpID & " " & Str ‘这里我耍了一个小聪明,可以省好多事。
End If
5.3.选择目标窗口连接游戏。
当然要在List1_Click中插入代码了。我使用两个Form,先显示Form1选择游戏窗口,传递游戏窗口的PID给Form2,然后再Form2里OpenProcess即可。所以我的List1_Click代码:
Form2.Show
Me.Hide
6.写到这里,后面的大家就应该知道怎么吧。这次就不公布源码了,因为特征码的关系遭的几率太大,另外这样也好给大家留出一些设计的空间。
注意:
如果你在原有程序的基础上,添加新的Form2用于选择游戏窗口,请设置从Form2启动。
| 程序关闭时别忘卸载隐藏的Form。 |
用OD启动游戏
为了实习找死亡回城函数,大家建个小号,先弄死它
我们转回OD
在OD的左下角可以打入命令 bp send 回车
之后立即回到游戏,点游戏里的<回到附近城市>,
这时OD断在71A2428A > 8BFF MOV EDI,EDI
这是发包函数的入口,属于ws2_32.dll的一个函数
游戏是要和服务器保持连接的。你一打bpsend 就断了那不是断到回城的调用上
一直接f9直到游戏正常
按过返城后,那个断才有用!
71A2428A > 8BFF MOV EDI,EDI
断到这后,按ctrl+f9 就执行到这个函数的末尾
71A24310 C2 1000 RETN 10
执行到这
再按f8就回到了函数主体中
005706C9 |. 8B0D 4CEC8C00 MOV ECX,DWORD PTR DS:[8CEC4C]
005706CF |. 6A 00 PUSH 0 ; /Flags =
0005706D1 |. 6A 01 PUSH 1 ; |DataSize = 1
005706D3 |. 68 005A8C00 PUSH elementc.008C5A00 ; |Data = elementc.008C5A00
005706D8 |. 51 PUSH ECX ; |Socket =>100
005706D9 |. E8 28031D00 CALL 005706DE |. EB 07 JMP SHORT elementc.005706E7在这里 005706D9 |. E8 28031D00 CALL 其它有两个比较重要,一个是datasize 一个是data 这两个一个是包长,一个是包首地址 Data = elementc.008C5A00 这里的data大家可以跟一下,恳定是加密的数据,一般没什么规律的。 然后继续ctrl+f9 又执行到末尾 00570721 \\. C2 0C00 RETN 0C 再f8就回到上一层调用 (不死游戏也可以下断。但是断后,往回找,是找不到有用的东西的) 按f800568825 |. 8B5424 08 MOV EDX,DWORD PTR SS:[ESP+8] 00568829 |. 52 PUSH EDX ; /Arg3 0056882A |. 8B5424 08 MOV EDX,DWORD PTR SS:[ESP+8] ; | 0056882E |. 52 PUSH EDX ; |Arg2 0056882F |. 50 PUSH EAX ; |Arg1 00568830 |. E8 2B7D0000 CALL elementc.00570560 ; \\elementc.00570560 00568835 |. C2 0800 RETN 8 回到这样一个调用 有三个参数 这三个参数不知道是什么, 要想看,就需要在00568830 |. E8 2B7D0000 CALL elementc.00570560 ;\\elementc.00570560去下断。 因为现在游戏已经停了。要按f9才能继续 50的游戏有个事,就是OD停了过久,就会当掉。所以我们不按f9继续ctrl+f9 再按f8 停在0058CB46 |. A1 44638C00 MOV EAX,DWORD PTR DS:[8C6344] 0058CB4B |. 6A 02 PUSH 2 ; /Arg2 =00000002 0058CB4D |. 56 PUSH ESI ; |Arg1 0058CB4E |. 8B48 20 MOV ECX,DWORD PTR DS:[EAX+20] ; | 0058CB51 |. E8 0AE1FDFF CALL elementc.0056AC60 ;\\elementc.0056AC60 0058CB56 |. 56 PUSH ESI 这里大家可以发现,有一个相当熟悉的 地址 是的8C6344这就是目前50的一级基址 CALL elementc.0056AC60 从这个函数看来,是一个可以调用的函数了 它有三个参数,两个是显示的,一个是隐式的 隐式的是ecx ecx=[一级base]+20 取值 这个函数先分析到这。我们继续按ctrl+f9 ,再按f8 00565C56 |. C700 00000000 MOV DWORD PTR DS:[EAX],0 00565C5C |. E8 CF6E0200 CALL elementc.0058CB30 00565C61 |> 83C4 0C ADD ESP,0C 这个调用更简单了。 给eax附值0,并调用.0058CB30 可以试着调用一下。也许这个就是死亡回城函数 刚才的断点有作记录吧 重新启动游戏后,可以直接断在刚才分析的地方了。就可以进行分析了 所有的函数操作,都是这个找法 经过一定的动作分析后,发现停在 0058CB46 |. A1 44638C00 MOV EAX,DWORD PTR DS:[8C6344] 0058CB4B |. 6A 02 PUSH 2 ;/Arg2=00000002 0058CB4D |. 56 PUSH ESI ; |Arg1 0058CB4E |. 8B48 20 MOV ECX,DWORD PTR DS:[EAX+20] ; | 0058CB51 |. E8 0AE1FDFF CALL elementc.0056AC60 ; \\elementc.0056AC60 0058CB56 |. 56 PUSH ESI明文发包函数 0012F400 10FC4450 |Arg1 = 10FC4450 0012F404 00000002 \\Arg2 = 00000002看明文发包,死亡回城就里的参数是上面这样的 10FC4450数据区里的数 是10FC4450 04 00 说明给明文发包函数传 0400 这个命令就可以死亡回城了 (记录失败的话)你可以断在0058CB30这里。继续ctrl+f9 ,f8回到上一城 回到上一层,是这样的一个函数 004FB000 . E8 BBB5FAFF CALL elementc.004A65C0 004FB005 . 8D88 EC000000 LEA ECX,DWORD PTR DS:[EAX+EC] 004FB00B . E8 10AC0600 CALL elementc.00565C20这个便是我们最终找到的死亡回城函数了 00466707 |. 8B4C24 2C MOV ECX,DWORD PTR SS:[ESP+2C] 046670B |. 51 PUSH ECX 0046670C |. 50 PUSH EAX 0046670D |. E8 4E791200 CALL elementc.0058E060买东西了。 07BE2BA8 BD 06 00 00 00 00 00 00 10 00 00 00 ?...... ....发送数据为物类别ID,在NPC中格子的位置 数量 要买卖东西 ,要熟知包果中的物品的位置,类加ID,和数量 买东西,要知道NPC中包的物品类别ID,位置,和购买数量 周前,一个对外挂一无所知的人,在广海的成长过程 来到广海,曙光到来... 今天,用vb配合pb编写出刀剑游戏的循环智能挂机,以下是我的学习过程,每天16个小时+ --------------------------------------------------------------------------- 基础绝对意义上零的我,如何学习,一头雾水,面对密密麻麻的16进制码简直就头晕脑胀 外挂是什么东西,想到小时候玩单机的时候拿FPE作弊过...幻想着应该网络游戏也是这样的吧... 于是开始搜索教程的漫漫长路.... 看到广海的大侠们,都用武林,诛仙,完美这几款游戏练手,我也不例外,带着移动硬盘去网吧,拷贝回来了个诛仙,开工... 从哪里入手呢,上天看我可怜,让我发现了 <一天一天教你做外挂教程>,真是好东西,从里面,我知道了由CE这个东西。 然后用了几天CE,看到广海上好多人在求基址,不明白是为什么, 于是又到了百度 又让我发现了<手把手教你如何学习找基址>这篇文章 照着上面的一步一步做,找到了诛仙的基址.虽然这时还不明白原理,但是也让我找到啦 又回到了,<一天一天教你做外挂教程>, 上面的第2天,根据基址显示数据,发现里面有个东西叫VB,这个又是什么.............. 百度...百度就是最好的老师,通过百度我知道VB是一种计算机语言,下载了一个VB入门教程,熟读了1个通宵,对面向对象编程有了个大概的了解,知道一些软件是怎么编出来的了 到此时,我从零基础 ,已经可以基本掌握VB语言,会自己寻找一些数据的基址,这个时候,我按照<一天一天教你做外挂教程>,,终于实现了对自己人物所有属性的显示. 如何实现自动打怪,卖东西,才是最重要的....于是,新的知识又来了, 什么是call,什么是调用call,什么是OD 找call,用call,都离不开od,于是我立刻又找到了百度,下载OD,打开OD界面后,我差点没崩溃掉,这都是什么东西啊,完全看不懂 耐心的来,不能被这些在我看乱码似的东西吓到,于是我继续百度, :OD使用教程,入门,一系列的搜索 发现了一篇帖子《OD基本知识》从里面我才知道这些乱码的名字叫汇编,但是依然看不懂,这时我有点想放弃了... 没有办法,在广海上看大家的帖子,想看看从哪里入手,在一篇帖子的回帖中,我看到了songyi大师的一句话,令我茅塞顿开: 想做外挂,不会汇编,那你是做梦! 不用想,百度:汇编语言, 在CSDN上找到了王爽老师的汇编基础,3天没有出屋,什么都暂时放下, OD,ce,基址,开始学习汇编 终于,我明白了CPU工作机制,明白了基址寻找方法的真正意义,明白了什么是寄存器,什么是堆栈 我想我现在可以开始OD的学习了,找到下载OD的网站,看雪论坛,既然是初学OD,我先弄明白它的主要功能和操作方法 在看雪的软件破解版快里,找到了OllyDB入门教程.chm 这个东西, 自己拿VB写了个注册程序,用OD打开我的程序自己对自己的程序开始进行了破解,按照教程的思路,加上汇编知识,我完成了我的处女破 慢慢的对OD的操作,和原理,下断都掌握了,有了汇编知识,OD操作方法,我现在信心满满的开始了call调用和call函数寻找的相关知识学习 很快,我在百度上和论坛等地方知道如果要调用call必须要注入hook,hook是什么,又是新的知识点,依旧自己查询,互联网是一个知识宝库,不要怕麻烦,只要肯找,就一定能找到想要的东西! 于是我明白了注入的是一个.dll文件,也明白了这种东西必须是一个基本的正常的.dll,也明白了vb写不出这样的东西,一般都用vc++和delphi语言写 我有点伤心,刚刚开始熟练掌握VB就要我放弃,换编程环境, 还好,前天夜里,无意中发现了一篇帖子,顿时好像看到了救世主, 里面的dll是拿pb写的,【POWERBASIC是VB工程师们解决DLL编写的最佳解决方案】 立刻下载POWERBASIC,打开人家写好的hook,一点一点的扣,遇到看不懂的指令,就用《指令字典2005XT》查 终于明白了编写的原理 到此,正式进入用OD找CALL的积累阶段 找到了原来喜欢玩的网游,刀剑,开始分析数据,查找基址,OD断点,查找CALL函数,调用,一个一个的功能在我手下实现,其中的成就感和喜悦感无以言表 在此感谢所有在论坛上无私奉献的人们,文中所有搜索到的东西均来自百度,搜索内容我一个字也没有改,链接我就不在这里放了 和我一样的新手们,学习外挂不要遇到问题就问,广海搜索模块,百度搜索引擎,都是我们的好老师 我来教你们做菜鸟挂 很简单的首先准备2个工具 1.CE最好是改过的 2.VB工具 准备好后去google或百度 输入 网络蜘蛛补血补篮视频外挂教程(分为2个视频 上部是补血补篮 下部是自动拾物自动打怪) 下载好后 恭喜你完成第一步了 接下来就是海挂论坛看下CE教程找基地(要偏移基地很简单的只要找血和蓝基地就可以了)网络上教程很多 恭喜你完成第二步了 最后第三步就是把网络蜘蛛视频里的VB挂原原本本的抄下来 然后把源码里面的久基地改成自己刚找的基地 生成下就可以了 菜鸟可以把别人的源码 改下久的基地就可以使用了 现在菜鸟们都会了吧 只要你稍微学下CE找基地(只要血与蓝基地) 其他什么都不会也没关系 PS:不过这种垃圾挂只能做些 自动挂机(自动打怪)自动补血补篮 自动拾物 自动逃跑(你可以在血下面加行当血值少于等于文本里的值 就按下某键 如F3键是我完美国际的飞行技能 每隔1秒就按空格键 直到血值大于文本里的值再按下某键 如F3键 这就成了自动逃跑 是不是很简单 )还可以自动回城修装备 (这个还要再学会找其他地址 如坐标 背包地址等等) 还有做按键挂最好去网上看下键盘上每个按键的ASCII码值也可以做些不错的挂 不说了睡觉了 大家不懂可以问 88一个礼拜前,对外挂(内挂)的工作机制完全不知道..
