实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)

一、启动游戏

1、准备好帝国时代游戏、窗口化工具(D3DWindower.exe),运行游戏
窗口化工具不是必须的,只是为了切换窗口方便。

二、打开ce,找一下资源地址并修改

2、打开cheat engine,选择游戏进程


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第1张图片
image.png

3、先找下食物的吧
食物初始有200


image.png

valuetype选择float,value输入200,然后点击firstscan,找到39个


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第2张图片
image.png

然后造一个农民,这时候食物就剩150了


image.png

ce里面输入150,然后nextscan,就剩一条了,太easy了(有的游戏可能需要搜更多次),双击一下地址添加到地址列表


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第3张图片
image.png

双击一下下面列表中的value列,修改值为15000


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第4张图片
image.png

回到游戏发现已经生效了


image.png

同样的方式很容易就可以找到其他几个资源。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第5张图片
image.png

然后就可以爽一局了,但是也只有一局,因为游戏重新开始后,地址通常就变了,还要再找一次。

这个问题就要通过基址+偏移的方式来解决了。

三、找到基址和偏移

右键食物的地址列,点击“find out what writes to this address”


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第6张图片
image.png

打开一个列表,只有一条,双击一下,看到一句话“the value of the pointer needed to find this address is probably 11BA4CD0”,就是说我们要找的指针的值可能是11BA4CD0


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第7张图片
image.png

这句话是说,某个地址的值是可能是11BA4CD0,而11BA4CD0恰好就是食物的地址;反过来说,就是我们如果知道这个地址,取他的值,就是食物的地址了;如果这个地址是个静态地址,那么我们就大功告成了,那么这个地址是多少呢?我们用11BA4CD0这个值来搜索,看看有多少个地址的值是它。

新开始一个scan,选择hex值,搜索,好巧,只有一个,这个就是我们找的地址,按照刚才说的,每次只要找到了这个地址,读他的值,就是食物的地址了。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第8张图片
image.png

然而经过试验发现,这个地址也是每次重启游戏就会变化的。
其实不用试验,图中可以看到这个地址是黑色的,黑色就代表是动态地址,绿色才是静态地址,我们需要的是一个静态地址。

失败了吗?没有!继续找。我们现在知道了,有且只有11B737F8这个地址保存了食物的地址,那么游戏开发者想改变食物的值,一样要通过11B737F8这个地址来找,他每次重启游戏是怎么找到11B737F8这个地址的呢?肯定是某个地址存储着这个地址,如下图,一层套一层,某个地址存储着11B737F8,11B737F8又存储着11BA4CD0,甚至更多级,我们要做的就是耐心往上溯源。

实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第9张图片
image.png

搜索一下谁保存了11B737F8这个值,然而并没有(如下图)!!!


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第10张图片
image.png

那么这个值怎么产生的呢。。。看看谁写了这个地址(如下图),很尴尬,白板。——解释一下,这个地址确实会有人写,但是是在游戏初始化的时候,初始化之后,我们就监控不到了,那么怎么办呢,刚才说到了,初始化之后,游戏开发者想要改变食物的值,仍然需要知道这个地址,那么他虽然不会写这个地址,但是他会读啊,那么我们来看看谁读了这个地址。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第11张图片
image.png

看看谁读了,终于有了(如下图),某个地址存储着11B737A8,而不是11B737F8
请注意看,下面的列表中写着,EAX=11B737A8,上面写着EAX+50,EAX+50刚好是11B737F8,也就是说,游戏开发人员并不是用某个地址存了11B737F8,而是在某个地址存了11B737A8,每次他根据那个地址获取到11B737A8之后,再+50,就得到了11B737F8,哈哈,让我们发现了,这样我们就知道规律了。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第12张图片
image.png

来看看哪个地址存着11B737A8,我擦,有15个之多,而且全都不是静态地址,还得往上找,这就相当于往上溯源的过程中出现了岔路,只能看运气了,好在ce比较智能,往往把可能性大的放在上面,从第一个开始尝试吧。当然,如果失败了,就再回到岔路口换下一条路继续尝试就行了。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第13张图片
image.png

我把前三个都加到下面列表中一个一个尝试,看看谁读了这些地址。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第14张图片
image.png

发现后两个都是白板,没人读这俩地址,第一个打开之后有两行,分别是下面这两个图。
第一个图又回到了11B737A8这个地址,没啥意义。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第15张图片
image.png

第二个图出现了一个新的值1173B390,然后加上ecx*4(ecs是1)得到我们前面的1173B394


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第16张图片
image.png

搜索1173B394得到新的地址07AF1D08


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第17张图片
image.png

这个地址依然是一个动态地址,还得往上找。不过我们先总结一下。

07AF1D08 ==> 1173B390
1173B390+4 = 1173B394
1173B394 ==> 11B737A8
11B737A8+50 = 11B737F8
11B737F8 ==> 11BA4CD0
11BA4CD0 ==> 食物的数量

ok,我们手里的王牌是07AF1D08,用上面的方法继续战斗
07AF1CC8+40 = 07AF1D08


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第18张图片
image.png

搜索07AF1CC8,我的天!出现了两个绿色的地址,很可能就是基址,2A06B0和3BE7A8


image.png

插入一个知识点,静态地址的真正地址并不是2A06B0这样的,双击之后可以看到是进程名+地址,也就是“Empires.exe+2A06B0”,记住就好,后面要用到。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第19张图片
image.png

我们再总结一下,现在除了哪个是真的基址不清楚,其他都知道了

2A06B0或3BE7A8 ==> 07AF1CC8
07AF1CC8+40 = 07AF1D08
07AF1D08 ==> 1173B390
1173B390+4 = 1173B394
1173B394 ==> 11B737A8
11B737A8+50 = 11B737F8
11B737F8 ==> 11BA4CD0
11BA4CD0 ==> 食物的数量

知道上面的流程之后,我们来写一个公式把上面这些串起来,点击“Add Address Manually”,然后勾选pointer


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第20张图片
image.png

把上面的公式填写进来,这个是从下往上看的,最下面写基址,右边可以看到基址对应的值是07AF1CC8
然后倒数第二行,07AF1CC8+40这个地址的值是1173B390
1173B390+4这个地址的值是11B737A8
11B737A8+50这个地址的值是11BA4CD0
11BA4CD0就是食物的地址


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第21张图片
image.png

看下这两行,值是一样的,都是15050。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第22张图片
image.png

说到这里,注意看一下地址列表的前四行,食物、木材、石头、黄金的地址,不难看出一个规律:
食物地址+4=木材地址
食物地址+8=石头地址
食物地址+C=黄金的地址(注意这里是十六进制,12也就是C)

那么我们可以用同样的方式写出木材的串联,只需要把最上面的格子改成4:


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第23张图片
image.png

好了,说回到刚才2个基址的问题,基址通常只有一个,怎么确定哪个才是真正的基址,重启游戏即可。
我们现在来重启游戏,然后用ce重新附加。

可以看出,最前面的4个地址的值已经是??了,说明已经失效了。但是我们最后添加的两个串联,也就是食物和木材,依然是有效的。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第24张图片
image.png

我们把串联中的基址换成另一个,发现同样有效,那么说明这两个基址确实真的都可以。。


实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第25张图片
image.png

我们来改一下食物和木材的值,可以看到,立即就生效了,这样我们就不用每次都找一遍地址了。


image.png
image.png

四、编写外挂

ce算是一个开发环境,如果我们想把上面这一堆研究成果分享给小伙伴,不懂编程的他们未必能懂啊,最简单的方式当然是封装一个exe,双击就能开搞。

这里我们用C#来实现一个(ce也能直接生成一个exe,有兴趣的自行研究一下)
1、写一个方法,读取Empires进程,然后用上面的公式流程先找到食物的地址foodAddr,然后循环4次依次遍历食物、木材、石头和黄金,如果数值小于5000,就改成10000

读写内存这里用到了一个MemorySharp框架(github传送门),这个并不是关键,类似的框架有很多,也可以用原生dll


        private static void findProcessAndHack_Empires()
        {
            var process = System.Diagnostics.Process.GetProcessesByName("Empires").FirstOrDefault();
            if (process == null)
            {
                Console.WriteLine("未找到进程...");
                Thread.Sleep(2000);
                return;
            }
            var sharp = new MemorySharp(process);


            IntPtr baseAddr = sharp.Modules.MainModule.BaseAddress;
            int addr1 = sharp.Read(new IntPtr(0x2A06B0));
            int addr2 = sharp.Read(new IntPtr(addr1) + 0x40, false);
            int addr3 = sharp.Read(new IntPtr(addr2) + 0x4, false);
            int foodAddr = sharp.Read(new IntPtr(addr3) + 0x50, false);

            //IntPtr foodAddr = baseAddr + 0;
            //IntPtr woodAddr = foodAddr + 4;
            //IntPtr stoneAddr = woodAddr + 4;
            //IntPtr goldAddr = stoneAddr + 4;
            for (int i = 0; i < 4; i++)
            {
                try
                {
                    IntPtr addr = new IntPtr(foodAddr) + i * 4;
                    float val = sharp.Read(addr, false);
                    //Console.WriteLine("i={0}, val={1}", i, val);
                    if (val < 5000)
                    {
                        sharp.Write(addr, 10000, false);
                        Console.WriteLine("增加资源");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("error:{0}", ex);
                }
            }

        }

2、main方法里面每隔3秒调用一次上面的方法,加了一个try,这样即使写内存失败,也不会出错。

        static void Main(string[] args)
        {
            Console.WriteLine("hack程序运行成功,开启游戏开搞即可。");
            while (true)
            {
                try
                {
                    findProcessAndHack_Empires();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
                Thread.Sleep(3000);
            }

3、这样我们就实现了,每3秒写一次内存,只要你开着这个程序,四种资源就永远用不完,是不是比输入woodstock这种每次加1000资源的命令更爽?

五、总结

写的很啰嗦,如果你能看完,说明你真得是毅力很大,为了尽量写的详细,我把为什么这样操作都写上了。总的来说,分为几个步骤:
1、根据游戏数值的变化找地址(需要注意的是数值类型的选择,比如有的是4byte,有的是float,这个得尝试了,发现不对就换一个试试)
2、找到一次之后,就结合谁写/读了你的地址,来一步步跟踪,这是最关键的过程,也是最繁琐的过程,还带着一些运气,可能还需要稍微看一下汇编代码。我这个例子算是很简单了。找的过程中记得把偏移记录下来。
3、都找到之后就简单了,用你熟悉的语言,按照流程读写内存就可以了。C++、C#、易语言是最常用的,其他的java、nodejs、python也都可以找到对应的读写内存的库。

就酱,有问题可Q我376665005一起学习,请备注“帝国时代外挂探讨”。

实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现)_第26张图片
老胡的公众号,关注一波吧

你可能感兴趣的:(实战帝国时代(罗马复兴)外挂编写(CE找基址、C#实现))