学习逆向知识之用于游戏外挂的实现.第二讲,快速寻找植物大战僵尸阳光基址.以及动态基址跟静态基址的区别

              通过游戏外挂,学习逆向技术之快速寻找植物大战僵尸阳光基址.以及动态基址跟静态基址的区别

一丶静态基址. 动态基址. 基址的区别

 通过上一讲超级马里奥的游戏外挂技术制作.我们学习到了静态基址.以及观看内存区域得出相关偏移出的静态基址.

那么什么是静态基址.什么是动态基址. 什么是基址.

1.静态基址

  静态基址指的是.程序在启动后地址是不变的.游戏关闭后重新启动.那么地址也是不会变的.我们通过逆向技术直接对其修改那么则可以进行我们的外挂制作.

2.动态地址.

  动态地址是指当前地址保存了我们想要的属性信息. 但是当游戏重新打开.的时候.其当前地址的信息已经不是我们的信息了.所以我们要寻找基址.

3.基址

  基址指的就是最顶层的地址. 也就是C语言中的结构体的地址,这个地址是不会改变的.除非游戏重新编译.或者增加减少成员.

二丶以植物大战僵尸为例.寻找当前动态地址.

植物大战僵尸这款游戏.相信我们大家都应该玩过.那么我们通过这款游戏.来学习 动态地址. + 基址的寻找方法. 

文字简介:  CE附加植物大战僵尸进程 -> 搜索阳光数量(精确数值 4字节搜索) -> 改变阳光数值 -> CE再次搜索改变之后的数值.

改变阳光数值.点击再次扫描.进行新的搜索.

通过在次扫描之后.我们得出一个地址.这个地址是一个动态地址. 怎么判断是否是动态地址.

1.我们首先修改这个地址里面的值. 看看是否能把阳光修改 (已经测试.可以修改.不截图说明了)

2.我们重新打开游戏.看看当前地址里面的值是否是我们阳光的值. (不是,已经测试)

经过上面两个步骤.我们可以得出.这个地址是一个动态地址.所以我们还要继续向上寻找.

三丶寻找基址.

  通过上面的地址我们知道这一个是一个动态的地址.那么我们需要找到基址应该怎么寻找?

思路: 如果找到一个动态地址.那么修改阳光肯定会修改这个地址这个地址里面的值. 所以我们可以下一个写入断点

1.我们可以用CE 下写入断点. 找出什么修改了这个地址

2.我们可以用OD / x32Dbg 下写入断点

上面两种方式都是可以完成的.

我们双击打开反汇编

可以看到里面的值是 add[eax + 0x5560],ecx

那么我们寻找到了一级偏移. 5560

那么这里涉及到偏移. 我们讲下原理吧.

其实很简单.植物大战僵尸编写的时候都是对象或者结构体成员.

例如:

  

struct Plant
{
   
    ......
    +5560 int sunNumber;  
}

而在汇编指令中则是 结构体到地址 + 偏移 得出 阳光的个数.

所以我们要继续寻找结构体首地址. 也就是谁保存了结构体首地址.所以根据上图汇编得出.我们需要继续寻找eax

继续寻找eax

CE 以16进制搜索eax的值

根据上图可以得出. 多个地址里面都保存了结构体的值. 那么随便选一个看似是堆内存的地址,(地址不连续的02xxx开头的地址)猜想这个可能就是结构体的首地址了.我们使用CE的手动添加地址添加我们的偏移看一下.

我们也不知道上面的地址那个是保存了结构体的地址. 不过CE一般都是前五个.当前也不一定.可以尝试一下.

根据上图我们可以得出 0299a4a0地址的内容是结构体首地址. 根据CE的手动添加指针.我们加上我们的偏移.可以得出阳光的地址.(对地址取内容则是阳光的值)

现在我们找的这个地址还是一个动态地址. 所以我们要找一下什么访问了这个地址为什么是访问? 因为要操作阳光.肯定会访问这个地址. 如果修改阳光则会修改这个阳光的值.

因为这个地址保存了结构体首地址.那么他肯定不会改写了.所以肯定会访问.所以我们找一下访问的地址.

 

 根据上图的值, 看汇编代码得出 mov esi[edi + 0x768] 访问了这个地址.

那么同理 [edi + 0x768]保存了结构体的地址. 那么edi 是一个新的结构体的地址. 而我们进行搜索的时候会发现其实这是一个结构体的嵌套.

例如:

  

struct aaa
{
    .......
    struct plant plant    //0x768
    {
        int SunNumber;  //0x5560
    }
}

所以我们要继续寻找edi是谁保存了.

继续寻找edi的值我们发现有几个绿色的值.一般遇到这个很有可能是基址了.

那么我们尝试一下.使用CE自带的手动添加地址.

确实是我们的地址.那么我们继续看谁访问.

发现我们地址都是这样了.汇编指令 mov reg,[常量地址]   那么则确定我们找到了我们的基址了.

原理:

  如果对基址不太熟悉.那么熟悉C++语法的大概能明白.

struct aaa
{
    struct plant
   {
          int SunNumber;
   }
}


aaa *p= new aaa;

new aaa 是我们的结构体首地址

new aaa + 768 = plant结构体的首地址

new aaa + 768 + 5560 = 阳光个数的地址

那么我们知道 new aaa是一个无名对象.所以肯定有一个变量保存着.
所以 *p 这个变量就是我们寻找的基址.

[[p + 768] + 5560] = 阳光个数地址
*(unsigned int *)((char*)*(char*)(p + 768) + 5560 ) = 阳光个数.
所以我们找的基址就是p的地址. 而p保存的就是 new aaa的地址 new aaa中保存了 plant结构体的地址.

如果不理解也可以滤过. 熟悉我们的寻找方法即可.

通过上面我们的汇编指令.

add [reg + 0x5560],ecx       注意reg代表是任何寄存器.   add指令在汇编中是增加的意思. []的意思是对这个地址的内容进行操作

上面的汇编指令的意思是: 对 reg + 5560 的这个地址进行操作.因为带有中括号.[] 所以意思是对reg + 5560这个地址里面的值进行操作.

 

mov reg,[reg + 0x768]. 内容同上.  mov 指令是传送指令.  也就是将这个地址里面的值辅赋值给左操作数.

 

[[[6A9EC0] + 0x768] + 0x5560] = 阳光的地址.

所以我们可以写程序来实现增加阳光跟减少阳光了

 

C++ :  学习OpenProcess  WriteProcessMemory  //注意: 在调用OpenProcess获得进程句柄前.需要获得进程PID.  可以通过FindWindow 查找窗口句柄.然后通过GetWindowsThreadProcessID() 通过窗口句柄获取进程pID. 当前也可以通过 进程快照.遍历进程.得出进程PID.都是可以的.具体不在累赘. 

易语言: 因为使用了超级模块所以 熟悉 取进程ID  十六到十 写内存整数型即可.

因为易语言实现简单.所以直接使用易语言写一个了.

 

 

 总结:

  通过这一讲.我们学习了 add 汇编指令. mov 汇编指令. 以及结构体在汇编中表现的形式. 例如 [reg + 5560] 这样的其实是结构体偏移.

学会了如果通过动态地址寻找基址.

课堂资料下载:  链接:https://pan.baidu.com/s/1DDWfx68wi37Dc2OV2aTpqQ 密码:3w2x

posted @ 2018-08-21 18:22  iBinary  阅读(2522)  评论(0编辑  收藏  举报