qq四国军旗2.1 beat03 builde018记牌器开发思路(三)

今天发现,四国的版本更新为18了.对应棋子内存起始值变为0x4979fc.全地址为:

//C#代码
private static readonly IntPtr baseAddresss = (IntPtr)(0x4979fc);

            int address = baseAddresss.ToInt32();

            for (int i = 0; i < 17; i++) {

                for (int j = 0; j < 17; j++) {

                    land[i, j] = address;

                    address += 12;

                    Console.Write(land[i, j].ToString("x"));

                    Console.Write("\t");

                }

                Console.WriteLine();

            } 

是一个17×17的数组,元素长度12,前4字节为棋子,中间4个字节是棋子的颜色。有朋友问,确定在客户端验证?要是客户端验证就是开发作弊器而不是记牌器了。

接着前文讲,还在找CALL(前文的地址已经不适用,但是特征码还是可以使用的。)

上文说到,在MOV EAX,DWORD PTR DS:[EBX+110]和MOV EAX,DWORD PTR DS:[4976F4(更新为496754)]之间,应该有重要的数据分析段。那么整段代码就是:

0041155F    8B83 10010000   MOV EAX,DWORD PTR DS:[EBX+110]
00411565    85C0            TEST EAX,EAX

00411567    0F84 CA010000   JE JunQiRpg.00411737

0041156D    8B0D D89A4900   MOV ECX,DWORD PTR DS:[499AD8]

00411573    85C9            TEST ECX,ECX

00411575    75 06           JNZ SHORT JunQiRpg.0041157D

00411577    894C24 14       MOV DWORD PTR SS:[ESP+14],ECX

0041157B    EB 0E           JMP SHORT JunQiRpg.0041158B

0041157D    A1 DC9A4900     MOV EAX,DWORD PTR DS:[499ADC]

00411582    2BC1            SUB EAX,ECX

00411584    C1F8 02         SAR EAX,2

00411587    894424 14       MOV DWORD PTR SS:[ESP+14],EAX

0041158B    A1 54674900     MOV EAX,DWORD PTR DS:[496754]

但是进行详细跟踪以后,无法找到内存坐标(比如棋子从498638 走到 49856C这样的数据。)而里面也有有用的数据。关键是下面几句

0041156D    8B0D D89A4900   MOV ECX,DWORD PTR DS:[499AD8]

0041157D    A1 DC9A4900     MOV EAX,DWORD PTR DS:[499ADC]

00411582    2BC1            SUB EAX,ECX

00411584    C1F8 02         SAR EAX,2

发现了什么?499AD8内的值,始终不变(一个生命周期内),而499ADC内的值是其增量,可以理解为一个步进,步进大小是4字节。走一步,那就是增加8,走两步就是增加12.为什么?这个值应该是描绘其完整路径的,比如,从498638 走到 49856C,就走了一步,但是它要表示其原先的位置和现在的位置,虽然是一步,但是值明显是2.

拿到这个也没有用,但是对0041158B    A1 54674900     MOV EAX,DWORD PTR DS:[496754]下面的代码认真分析以后,也无法找到地址。这就说明一个问题,起始和结束标记不是用内存地址标记的。如果是用内存地址标记,在走路时候下断,在内存中必然有起始和结束地址。

换个思路,注意到文章开头讲的17维数组没?那么起始和结束也完全可能是用数组索引来实现。找一个索引为[6,15]的棋子,走到[6,14],断点后在数据段搜索 06 15或者15 06(字节高低位可能会倒过来,这是堆栈的一个特性。)没有!!!没有搜索到,贫道郁闷了....

再思考了一下整个步骤,发现漏了一个问题,搜索的时候需要搜索16进制,也就是说,需要搜索06 0F或者0F 06,一搜索,果然存在这个值的地址。通过这样的分析,发现,走路时,起始索引在00499ac6中(16字节),结束索引在00499ac8(16字节)。就在499AD8步进地址的上面,相差1行,却要分析好长时间啊。起始和结束的C++代码大体是:
typedef struct {

        byte x,

        byte y
} Node;

Node from;
Node to;

那么,如果需要这两个数据的话,就有两种处理方式了,就是第一篇文章讲到的,动态内存扫描或者是HOOK API.扫描的方式容易实现,但是出错的概率也高,要想不出错,最好是一直扫描,这样精度就高,但是也可能会出现数据不同步的问题,和数据库脏数据的原理一样。而 HOOK API技术难一点,程序稳定性会更好。

posted @ 2009-09-10 14:40 Birdshover 阅读(...) 评论(...) 编辑 收藏