• 大富翁8分析


    最近看了下"大富翁8",玩了一下。玩的时候想用个修改器改改东西,就粗略的研究了一下。

    一、用户内存数据

    我使用WinDbg挂住richman8.dat后,通过内存搜索命令查找现金、存储、点券等数据,在内存中定位到对应的用户数据位置。

    下面是我找到的

    image

    如上找到对应的几个数据,从这可以推断Rich8的用户数据可能在一块,对应着一个数据结构。

    二、反汇编相应部分代码

    在对应的内存数据(现金、点券等)上设置内存断点。这样代码在访问内存时会断下来,比如在现金上设置写内存断点,这样会在用户金钱变动时断下来,

    那么对应的调用代码就是和修改金钱对应的代码。分析断下时的调用堆栈,找出可能相关的代码段。

    下面是我分析的,使用的是IDA5.5,richman8.da是使用PECompact 2.x -> Jeremy Collake加壳的。可以使用工具或自己手工脱。

         v30 = CardValueCalcFromIndex(gRichCardsTable, *((_DWORD *)v13 + *((_DWORD *)v13 + 96) + 7));
          if ( *(_DWORD *)(gRichDataInfo + 0xC) <= 0 )
          {
            v24 = 0;
          }
          else
          {
            IndexOfUser = *(_DWORD *)(gRichDataInfo + 0x2C);
            if ( IndexOfUser >= 0 && *(_DWORD *)(gRichDataInfo + 12) > IndexOfUser )
             
    v25 = *(void **)(*(_DWORD *)gRichDataInfo + 4 * IndexOfUser);
            else
              v25 = 0;
            v24 = v25;
          }
          v2 = sub_4E6880(v30);
          CardAdd(v24, *((_DWORD *)v13 + *((_DWORD *)v13 + 96) + 7), v2);
    这里v24是一个玩家信息对象,v2是第几个卡片,第二参数可以不管

    而v24是从gRichDataInfo这个对象中取得,gRichDataInfo是全局的对象
     
    signed int __thiscall CardAdd(void *this, int a2, int a3)
    {
      signed int result; // eax@3
      int v4; // [sp+0h] [bp-8h]@1
      int ValueOfCard; // [sp+4h] [bp-4h]@1

      v4 = (int)this;
      ValueOfCard = CardValueCalcFromIndex(gRichCardsTable, a2);
      if ( ValueOfCard && UserAddCard((void *)(v4 + 692), ValueOfCard, -1) )
      {
        sub_4898C0(v4, a3, 0);
        sub_480A60(v4);
        sub_480C00(v4);
        result = 1;
      }
      else
      {
        result = 0;
      }
      return result;
    }
    这里通过CardValueCalcFromIndex函数取得卡片索引对应的实际值。
     
    signed int __thiscall UserAddCard(void *this, int ValueOfCard, signed int IndexOfCard)
    {
      signed int result; // eax@12
      signed int i; // [sp+8h] [bp-8h]@4
      signed int v5; // [sp+Ch] [bp-4h]@2

      if ( !ValueOfCard )
        goto LABEL_16;
      v5 = IndexOfCard;
      if ( IndexOfCard < 0 || IndexOfCard >= 8 )
      {
        for ( i = 0; i < 8; ++i )
        {
          if ( !*((_DWORD *)this + 3 * i) )         // 找到第一个为空的位置
          {
            v5 = i;
            break;
          }
        }
      }
      if ( v5 < 0 || v5 >= 8 || *((_DWORD *)this + 3 * v5) )
      {
    LABEL_16:
        result = 0;
      }
      else
      {
        *((_DWORD *)this + 3 * v5) = ValueOfCard; //设置卡片的值
        *((_DWORD *)this + 3 * v5 + 1) = 0;
        CardTotalCountCalc(this);
        result = 1;
      }
      return result;
    }
    这里就是把卡片对应的这设置到对应的内存位置中
     
    int __thiscall CardTotalCountCalc(int this)
    {
      int result; // eax@1
      signed int i; // [sp+4h] [bp-4h]@1

      result = this;
      *(_DWORD *)(this + 0x6C) = 0;                 // 计算总的卡数
      for ( i = 0; i < 8; ++i )
      {
        result = this;
        if ( *(_DWORD *)(this + 12 * i) )
        {
          result = this;
          ++*(_DWORD *)(this + 0x6C);               //卡片数增加   
        }
      }
      return result;
    }
    这里从新统计玩家对应的卡片数量

    三、确定内存数据结构

    现在根据上面分析出的数据关系,确定对应的数据结构。

    这里涉及到3个对象

    gRichDataInfo     内存中全局变量
    gRichCardsTable   内中所有卡片的表
    v24               内存中对应单个玩家的数据

    分析他们之间的对应的偏移、包含关系,确定数据结构。

    下面是我分析的数据结构

    00000000 RICH_DATA_INFO struc ; (sizeof=0x30)

    00000000 UserDataArray dd ?

    00000004 Reserved1 dd ?

    00000008 Reserved2 dd ?

    0000000C UserTotalCount dd ?

    00000010 Reserved3 db 28 dup(?)

    0000002C IndexOfUserSelected dd ?

    00000030 RICH_DATA_INFO ends

      

    00000000 RICH_CARD_INFO struc ; (sizeof=0x10)

    00000000 CardValueTable dd ?

    00000004 Reserved1 dd ?

    00000008 Reserved2 dd ?

    0000000C CardTotalCount dd ?

    00000010 RICH_CARD_INFO ends

      

    00000000 RICH_USER_INFO struc ; (sizeof=0x328)

    00000000 Reserved1 db 656 dup(?)

    00000290 CashValue dd ?

    00000294 SavingsValue dd ?

    00000298 Reserved2 db 28 dup(?)

    000002B4 ArrayOfUserCard RICH_USER_CARD_ITEM 8 dup(?)

    00000314 Reserved3 dd ?

    00000318 Reserved4 dd ?

    0000031C Reserved5 dd ?

    00000320 CountOfUserCard dd ?

    00000324 CouponValue dd ?

    00000328 RICH_USER_INFO ends

      

    00000000 RICH_USER_CARD_ITEM struc ; (sizeof=0xC)

    00000000 CardValue dd ?

    00000004 Reserved1 dd ?

    00000008 Reserved2 dd ?

    0000000C RICH_USER_CARD_ITEM ends

    在定义的数据结构中,由于我只需要修改它的现金、储蓄、点券和卡片,所以就只定义了几个我需要的变量,其余的那些如贷款、

    状态什么的我就没有去看它对应着哪个,不过估计就在我定义的那些预留变量中。

    (头好酸啊,一个晚上就这样过去了...困惑

  • 相关阅读:
    python如何编译py文件生成pyc、pyo、pyd以及如何和C语言结合使用
    urllib.parse:很底层,但是是一个处理url路径的好模块
    pandas中的Series
    pandas中Series对象下的str所拥有的方法(df["xx"].str)
    10.集成学习与随机森林
    9.决策树
    8.支撑向量机SVM
    HTTP协议详细介绍
    mysql 总结
    MySql练习题参考答案
  • 原文地址:https://www.cnblogs.com/Quincy/p/1936754.html
Copyright © 2020-2023  润新知