首页
论坛
课程
招聘

[调试逆向] [原创]【逆向分析】RIMWORLD游戏逆向分析

2020-5-16 16:44 901

[调试逆向] [原创]【逆向分析】RIMWORLD游戏逆向分析

2020-5-16 16:44
901

游戏介绍:

        RIMWORLD(环世界)游戏是一款模拟经营游戏,上手容易,玩家可以创造一个属于自己的世界指挥你的殖民者在陌生星球建立据点,并发展下去统领全球。有兴趣可以玩一下。

准备工作:

        这款游戏是我在以前上学的时候放假打发时间用的,建造经营感觉还不错,今天就拿这个游戏练练手,逆向分析然后修改游戏数据,做一个简单的游戏修改器。

目标:

        1.修改物品

        2.修改人物状态

        3.加速研究建造速

需要CE任何版本的都可以,

环世界游戏,我准备了单机环世界:

链接:https://pan.baidu.com/s/1xhlgiYs2HS2Fdzq-7ffnDQ

提取码:h910

编程使用的VS2017


修改的方法是DLL注入,注入工具大家可以随便在网上找找,一大堆,随便一个就可以。


首先运行游戏,新建游戏,创建一个剧本,

普通剧情简单模式


跳过不重要的选项,选择小地图便于分析


进入游戏后存档,准备完成,游戏的界面:


修改物品逆向

        在游戏界面中,我们可以发现由每个物品都有数量,使用CE进行搜索木材54,然后随便建造一点使用木材的建筑,根据更改搜索变动。

        用同样的方法搜索另一个类型的白银,会得到白银和木头的地址,将他们的结构保存下来进行每个字节的修改来判断物品的每个字段是什么类型,具体方法就是将白银的相同位置改到木头上,查看游戏变化,来判断那个位置属于什么,当然这种只能判断一部分,另一部分可以在带用他们的代码上进行分析。这一部分是比较消耗时间的,因为需要一点点判断,找出有用信息。


例如修改蓝色区域就能判断出为坐标,一点一点查找可以用到的字段

医药物品:

84 9E C2 19 00 00 00 00 20 D9 FD 19 00 00 00 00 

20 D9 FD 19 *物品类型

84 9E C2 19

00 00 00 00 40 1B 8E 1A F8 54 CB 43 74 71 00 00

40 1B 8E 1A *物品贴图

74 71 00 00 像是序号

00 00 00 00 58 00 00 00 00 00 00 00 60 00 00  00

58、60 该物品座标


00 00 00 00 05   00 00 00 3C 00 00 00

05 00 00 00物品数量

3C 00 00 00耐久度

 经过动态更改和比较能够判断出物品结构体部分类型

typedef struct _GoodsInfo{
 int unknown0;
 int unknown4;
 PGoodsTypes GoodsType;   //物品类型
 int unknown12;
 int unknown16;
 int GoodsIconId;  //物品贴图
 int unknown24;
 int unknown28;
 int unknown32;
 int GoodsX;   //座标 从左至右变大
 int x_null;
 int GoodsY;   //座标 从下之上变大
 int y_null;
 int GoodsNumber;  //物品数量
 int GoodsDurable;  //物品耐久
}*PGoodsInfo, GoodsInfo;

找到了物品的地址就使用CE进行附加查看访问该位置的地方来查看那部分的代码进行分析。

我们在这个位置发现会访问物品的信息,并且是个循环线程,一直遍历访问所有物品,所以对这个函数进行hook就可以不断获取所有的物品。


HOOK的代码我会放在项目hook.cpp中 这个函数的第二个参数就是物品的地址。使用结构体指向这里就可以获取所有的信息。

因为这里的函数是动态内存中随机地址,所以不能通过模块+偏移的方式确定位置,所以我们需要遍历特征找到这个函数的位置,定义一个特征:

/*调用物品信息的函数特征,他的第二个参数是我能获得的物品结构地址,
这个函数是一个大循环里面的,会一直执行
028F1790    55              push ebp
028F1791    8BEC            mov ebp,esp
028F1793    83EC 08         sub esp,0x8
028F1796    8B4D 0C         mov ecx,dword ptr ss:[ebp+0xC]
028F1799    8B41 34         mov eax,dword ptr ds:[ecx+0x34]
028F179C    8B49 08         mov ecx,dword ptr ds:[ecx+0x8]
028F179F    83EC 04         sub esp,0x4
028F17A2    51              push ecx
028F17A3    50              push eax
028F17A4    FF75 08         push dword ptr ss:[ebp+0x8]
*/
char mem_of_goods[] = { 0x55,0x8B,0xEC,0x83,0xEC,0x08,0x8B,0x4D,0x0C,0x8B,0x41,0x34,0x8B,0x49,0x08,0x83,0xEC,0x04,0x51,0x50,0xFF,0x75,0x08 };

遍历所有的内存模块找到这个特征地址进行定位代码过长就放在项目的EnumAllMemoryBlocks函数和MemoryCmpToFeatureCode函数配合查找位置。这个游戏中我们需要的内存块都是固定属性的,所以我们只遍历该属性内存块就可以:

 // 经过分析我们需要的内存块属性分别是是PAGE_EXECUTE_READWRITE\MEM_COMMIT\MEM_PRIVATE,所以将不必要的内存块排除掉
  if (memInfo.Protect == PAGE_EXECUTE_READWRITE)
   if (memInfo.State == MEM_COMMIT)
    if (memInfo.Type == MEM_PRIVATE)
     memories.push_back(memInfo);// 将内存块信息追加到 vector 数组尾部

有了位置修改物品的数量就轻而易举。因为hook函数是一只循环的,所以我根据第一次遍历到的地址保存,再次遍历到这个地址为一次循环,结束遍历,通过控件消息可重新更新遍历。

效果图:

人物状态逆向

点击人物,显示需求,会看到0.63/1的信息


同样使用CE进行搜索,不过是浮点类型的,所有介于两者之间,变化一点搜索一点,找到地址后,同样使用谁访问过这个位置,有很多地方都访问,这个位置是一个人物结构的状态,人物的结构指向这个位置,这个结构中装有很多人物信息,所以找到访问这个人物的代码,从中选择一个循环遍历所有人物的代码就可以,然后更改他跳转到我们的写好的改变状态代码上就可了。


调用任务信息的理想函数:


所对这个函数做特征,然后将1的位置跳转到我们的代码执行后在跳转回来就可以了

/*循环访问所有人物结构特征
24ADB2C8 - 55                    - push ebp
24ADB2C9 - 8B EC                 - mov ebp,esp
24ADB2CB - 83 EC 08              - sub esp,08 { 00000008 }
24ADB2CE - 8B 45 08              - mov eax,[ebp+08]
24ADB2D1 - 8B 40 08              - mov eax,[eax+08]
24ADB2D4 - 8B 40 64              - mov eax,[eax+64]
24ADB2D7 - 8B 40 10              - mov eax,[eax+10]
24ADB2DA - 85 C0                 - test eax,eax*/
char mem_of_callpeople[] = { 0x55,0x8b,0xec,0x83, 0xec, 0x08, 0x8b, 0x45, 0x08, 0x8b, 0x40, 0x08, 0x8b, 0x40, 0x64, 0x8b, 0x40, 0x10, 0x85, 0xc0,0x00 };
void InitPeopleStateData()
{
 peopleStateMem = (CHAR*)malloc(0x200);//申请我们的代码
 /*
   56                                            push    esi//跳转到这里
   8B 70 10                                      mov     esi, [eax+10h]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 5D 01 00 00                             jle     loc_147016D
   8B 76 0C                                      mov     esi, [esi+0Ch]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 4E 01 00 00                             jle     loc_147016D
   8B 76 0C                                      mov     esi, [esi+0Ch]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 3F 01 00 00                             jle     loc_147016D
   8B 76 08                                      mov     esi, [esi+8]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 30 01 00 00                             jle     loc_147016D
   8B 76 08                                      mov     esi, [esi+8]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 21 01 00 00                             jle     loc_147016D
   81 7E 0C 63 00 6F 00                          cmp     dword ptr [esi+0Ch], 6F0063h//判断人物信息
   0F 84 1F 00 00 00                             jz      loc_1470078
   81 7E 0C 74 00 72 00                          cmp     dword ptr [esi+0Ch], 720074h
   0F 84 12 00 00 00                             jz      loc_1470078
   81 7E 0C 50 00 6C 00                          cmp     dword ptr [esi+0Ch], 6C0050h
   0F 84 05 00 00 00                             jz      loc_1470078
   E9 F5 00 00 00                                jmp     loc_147016D
            ; ---------------------------------------------------------------------------
   
            loc_1470078:                           
                     
   83 3D 78 01 47 01 00                          cmp     ds:people_mood, 0//判断开启
   0F 84 16 00 00 00                             jz      loc_147009B
   8B 70 10                                      mov     esi, [eax+10h]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E D9 00 00 00                             jle     loc_147016D
   C7 46 14 00 00 80 3F                          mov     dword ptr [esi+14h], 3F800000h//将人物相关结构位置的数据改为浮点1
   
            loc_147009B:                           
   83 3D 7C 01 47 01 00                          cmp     ds:people_food, 0
   0F 84 16 00 00 00                             jz      loc_14700BE
   8B 70 14                                      mov     esi, [eax+14h]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E B6 00 00 00                             jle     loc_147016D
   C7 46 14 00 00 80 3F                          mov     dword ptr [esi+14h], 3F800000h
   
            loc_14700BE:                            
   83 3D 80 01 47 01 00                          cmp     ds:people_rest, 0
   0F 84 16 00 00 00                             jz      loc_14700E1
   8B 70 18                                      mov     esi, [eax+18h]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 93 00 00 00                             jle     loc_147016D
   C7 46 14 00 00 80 3F                          mov     dword ptr [esi+14h], 3F800000h
   
            loc_14700E1:
   83 3D 84 01 47 01 00                          cmp     ds:people_joy, 0
   0F 84 16 00 00 00                             jz      loc_1470104
   8B 70 1C                                      mov     esi, [eax+1Ch]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 70 00 00 00                             jle     loc_147016D
   C7 46 14 00 00 80 3F                          mov     dword ptr [esi+14h], 3F800000h
   
            loc_1470104:                      
   83 3D 88 01 47 01 00                          cmp     ds:people_beauty, 0
   0F 84 16 00 00 00                             jz      loc_1470127
   8B 70 20                                      mov     esi, [eax+20h]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 4D 00 00 00                             jle     loc_147016D
   C7 46 14 00 00 80 3F                          mov     dword ptr [esi+14h], 3F800000h
   
            loc_1470127:                          
   83 3D 8C 01 47 01 00                          cmp     ds:people_space, 0
   0F 84 16 00 00 00                             jz      loc_147014A
   8B 70 24                                      mov     esi, [eax+24h]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 2A 00 00 00                             jle     loc_147016D
   C7 46 14 00 00 80 3F                          mov     dword ptr [esi+14h], 3F800000h
   
            loc_147014A:                         
   83 3D 90 01 47 01 00                          cmp     ds:people_comfort, 0
   0F 84 16 00 00 00                             jz      loc_147016D
   8B 70 28                                      mov     esi, [eax+28h]
   81 FE 00 00 10 00                             cmp     esi, 100000h
   0F 8E 07 00 00 00                             jle     loc_147016D
   C7 46 14 00 00 80 3F                          mov     dword ptr [esi+14h], 3F800000h
   
            loc_147016D:                       
   5E                                            pop     esi
   8B 40 10                                      mov     eax, [eax+10h]//原来的代码要正确执行
   85 C0                                         test    eax, eax
   E9 ?? ?? ?? ??                                jmp     --old address//计算原来的位置跳回去
            sub_1470000     endp
   
            ; ---------------------------------------------------------------------------
   00 00 00 00                   people_mood     dd 1
   00 00 00 00                   people_food     dd 1
   00 00 00 00                   people_rest     dd 1
   00 00 00 00                   people_joy      dd 1
   00 00 00 00                   people_beauty   dd 0
   00 00 00 00                   people_space    dd 0
   01 00 00 00       people_comfort  dd 1
   00 00 00 00
   3F800000代表单浮点数的1
 */
char changePeopleStateByte[] = {
 0x56,0x8B,0x70,0x10,0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,0x5D,0x01,0x00,0x00,
 0x8B,0x76,0x0C,0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,0x4E,0x01,0x00,0x00,0x8B,
 0x76,0x0C,0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,0x3F,0x01,0x00,0x00,0x8B,0x76,
 0x08,0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,0x30,0x01,0x00,0x00,0x8B,0x76,0x08,
 0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,0x21,0x01,0x00,0x00,0x81,0x7E,0x0C,0x63,
 0x00,0x6F,0x00,0x0F,0x84,0x1F,0x00,0x00,0x00,0x81,0x7E,0x0C,0x74,0x00,0x72,0x00,
 0x0F,0x84,0x12,0x00,0x00,0x00,0x81,0x7E,0x0C,0x50,0x00,0x6C,0x00,0x0F,0x84,0x05,
 0x00,0x00,0x00,0xE9,0xF5,0x00,0x00,0x00,0x83,0x3D,0x78,0x01,0x47,0x01,0x00,0x0F,
 0x84,0x16,0x00,0x00,0x00,0x8B,0x70,0x10,0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,
 0xD9,0x00,0x00,0x00,0xC7,0x46,0x14,0x00,0x00,0x80,0x3F,0x83,0x3D,0x7C,0x01,0x47,
 0x01,0x00,0x0F,0x84,0x16,0x00,0x00,0x00,0x8B,0x70,0x14,0x81,0xFE,0x00,0x00,0x10,
 0x00,0x0F,0x8E,0xB6,0x00,0x00,0x00,0xC7,0x46,0x14,0x00,0x00,0x80,0x3F,0x83,0x3D,
 0x80,0x01,0x47,0x01,0x00,0x0F,0x84,0x16,0x00,0x00,0x00,0x8B,0x70,0x18,0x81,0xFE,
 0x00,0x00,0x10,0x00,0x0F,0x8E,0x93,0x00,0x00,0x00,0xC7,0x46,0x14,0x00,0x00,0x80,
 0x3F,0x83,0x3D,0x84,0x01,0x47,0x01,0x00,0x0F,0x84,0x16,0x00,0x00,0x00,0x8B,0x70,
 0x1C,0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,0x70,0x00,0x00,0x00,0xC7,0x46,0x14,
 0x00,0x00,0x80,0x3F,0x83,0x3D,0x88,0x01,0x47,0x01,0x00,0x0F,0x84,0x16,0x00,0x00,
 0x00,0x8B,0x70,0x20,0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,0x4D,0x00,0x00,0x00,
 0xC7,0x46,0x14,0x00,0x00,0x80,0x3F,0x83,0x3D,0x8C,0x01,0x47,0x01,0x00,0x0F,0x84,
 0x16,0x00,0x00,0x00,0x8B,0x70,0x28,0x81,0xFE,0x00,0x00,0x10,0x00,0x0F,0x8E,0x2A,
 0x00,0x00,0x00,0xC7,0x46,0x14,0x00,0x00,0x80,0x3F,0x83,0x3D,0x90,0x01,0x47,0x01,
 0x00,0x0F,0x84,0x16,0x00,0x00,0x00,0x8B,0x70,0x2C,0x81,0xFE,0x00,0x00,0x10,0x00,
 0x0F,0x8E,0x07,0x00,0x00,0x00,0xC7,0x46,0x14,0x00,0x00,0x80,0x3F,0x5E,0x8B,0x40,
 0x10,0x85,0xC0,0xE9,0x90,0x90,0x90,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
 memcpy(peopleStateMem, changePeopleStateByte, 0x200);
 DWORD dwOldAttrubet;
 VirtualProtect(peopleStateMem,
  0x200,
  PAGE_EXECUTE_READWRITE,
  &dwOldAttrubet);
 g_pStateOfPeo = (PStateData)(peopleStateMem + 0x178);
 *(DWORD*)(peopleStateMem + 0x7a) = (DWORD)(&g_pStateOfPeo->mood);//用于判断是否开启
 *(DWORD*)(peopleStateMem + 0x9d) = (DWORD)(&g_pStateOfPeo->food);
 *(DWORD*)(peopleStateMem + 0xc0) = (DWORD)(&g_pStateOfPeo->rest);
 *(DWORD*)(peopleStateMem + 0xe3) = (DWORD)(&g_pStateOfPeo->joy);
 *(DWORD*)(peopleStateMem + 0x106) = (DWORD)(&g_pStateOfPeo->beauty);
 *(DWORD*)(peopleStateMem + 0x129) = (DWORD)(&g_pStateOfPeo->space);
 *(DWORD*)(peopleStateMem + 0x14c) = (DWORD)(&g_pStateOfPeo->comfort);
}

将要跳转的地址计算填入特征位置,跳转回去的地址填入位置,计算位置这个看代码吧不好描述。

bool ChangePeopleMem(char* changePeopleMem)
{
 HANDLE selfProHandle = GetCurrentProcess();
 DWORD dwOffset;
 /*
 address + 0000 0000 - 55                    - push ebp
 address + 0000 0001 - 8B EC                 - mov ebp,esp
 address + 0000 0003 - 83 EC 08              - sub esp,08
 address + 0000 0006 - 8B 45 08              - mov eax,[ebp+08]
 address + 0000 0009 - 8B 40 08              - mov eax,[eax+08]
 address + 0000 000C - 8B 40 64              - mov eax,[eax+64]
 address + 0000 000F - 8B 40 10              - mov eax,[eax+10]  ---------------------------》改到自己的内存 E9 ?? ?? ?? ??  
 address + 0000 0012 - 85 C0                 - test eax,eax  
 address + 0000 0014 - 75 08                 - jne 24D70D26    《----------------------------运行完自己的逻辑在跳转回来
 */
 char changePeopleByte[] = { 0xE9,0x90,0x90 ,0x90 ,0x90 };
 bool flag_research = true;
 int addressOffset = 0;
 int offset_addr = 0;
 if (EnumAllMemoryBlocks(selfProHandle, vec)) {
  for (int i = 0; i < vec.size(); i++) {
   // 查找特征
   addressOffset = MemoryCmpToFeatureCode(vec[i].BaseAddress, vec[i].RegionSize, mem_of_callpeople);
   if (addressOffset != -1)
   {
    for (int j = 0; j < vecCodeAddr.size(); j++) {
     int int_value = (int)vec[i].BaseAddress + (int)vecCodeAddr[j];
     g_changePeopleAddress = (PDWORD)(int_value + 0xF);//定位到修改
     dwOffset = ((DWORD)changePeopleMem - ((DWORD)g_changePeopleAddress)) - 0x5;//计算位置
     *(DWORD*)(changePeopleByte + 0x1) = dwOffset;
     memcpy(g_changePeopleAddress, changePeopleByte, 0x5);
     g_changePeopleAddress = (PDWORD)(int_value + 0x14);
     dwOffset =(DWORD)g_changePeopleAddress - (DWORD)(changePeopleMem + 0x173)-0x5;//跳转回来
     *(DWORD*)(changePeopleMem + 0x173 + 0x1) = dwOffset;
     return true;
    }
   }
  }
 }
 else
 {
  MessageBox(NULL, "memallpeople failed.", "failed", NULL);
  return false;
 }
}

对应图:


快速研究及建造

研究也是按照同样的方法搜索,不知道类型就搜索所有类型根据改变一点一点确定范围,找到访问的位置


函数特征

/*访问研究数值修改位置的特征
1607BBC5 - 8D 4C B1 10           - lea ecx,[ecx+esi*4+10]
1607BBC9 - D9 19                 - fstp dword ptr [ecx]
1607BBCB - 8B 48 30              - mov ecx,[eax+30]  -------》跳到我们地址
1607BBCE - 41                    - inc ecx 
1607BBCF - 89 48 30              - mov [eax+30],ecx  
1607BBD2 - 8D 65 F4              - lea esp,[ebp-0C]
1607BBD5 - 5E                    - pop esi
1607BBD6 - 5F                    - pop edi
1607BBD7 - 5B                    - pop ebx
1607BBD8 - C9                    - leave 
1607BBD9 - C3                    - ret 
  */  
char mem_of_fast_research[] = { 0x8D ,0x4C, 0xB1, 0x10,0xD9, 0x19,0x8B, 0x48 ,0x30,0x41,0x89, 0x48, 0x30,0x8D, 0x65, 0xF4,0x5E,0x5F,0x5B,0xC9,0xC3,0x00 };

但是这个访问的位置不一定是研究,还有其他的数据,我们只修改研究,所以要先判断修改的数据地址是否在数据地址附近,说实话这个方法不好,正常应该找到像人物数据一样的结构存放,我这里偷懒值直接特征码数据获取地址进行判断。


同样跳转到自己的代码

void InitFastResearchData()
{
 fastResearchMem = (CHAR*)malloc(0x2A);
 /*
  0208153B - D9 45 10              - fld dword ptr [ebp+10]
  0208153E - 39 71 0C              - cmp [ecx+0C],esi
  02081541 - 0F86 3F000000         - jbe 02081586
  --------跳到下面这
  02081547 - 8D 4C B1 10           - lea ecx,[ecx+esi*4+10]
  0208154B - D9 19                 - fstp dword ptr [ecx]
  0040EB19      8B09     - mov ecx,dword ptr ds:[ecx]
  0040EB1B      81C1 FFFF0000   - add ecx,0xFFFF
  0208154D - 8B 48 30              - mov ecx,[eax+30]
  02081550 - 41                    - inc ecx
  02081551 - 89 48 30              - mov [eax+30],ecx
  02081554 - 8D 65 F4              - lea esp,[ebp-0C]
  02081557 - 5E                    - pop esi
  02081558 - 5F                    - pop edi
  02081559 - 5B                    - pop ebx
  0208155A - C9                    - leave 
  0208155B - C3                    - ret
  0040EAEA      81F9 ????????    cmp ecx,0x12345678 大 判断是不是数据的地址不是跳过 
  0040EAF0      77 10            ja short 0040EB02
  0040EAF2      81F9 ????????    cmp ecx,0x12345678 小 判断是不是数据的地址不是跳过
  0040EAF8      76 08            jbe short 0040EB02
  0040EAFA      8B09             mov ecx,dword ptr ds:[ecx]
  0040EAFC      81C1 FFFF0000    add ecx,0xFFFF
  0040EB02      90               nop
  0040EB03      8B48 30          mov ecx,dword ptr ds:[eax+0x30]
  0040EB06      41               inc ecx
  0040EB07      8948 30          mov dword ptr ds:[eax+0x30],ecx
  0040EB0A      8D65 F4          lea esp,dword ptr ss:[ebp-0xC]
  0040EB0D      5E               pop esi
  0040EB0E      5F               pop edi
  0040EB0F      5B               pop ebx
  0040EB10      C9               leave
  0040EB11      C3               retn
  81F978563412771081F97856341276088B0981C1FFFF0000908B4830418948308D65F45E5F5BC9C3
 */
 char changeByte[] = { 0x81,0xF9,0x78,0x56,0x34,0x12,0x77,0x13,0x81,0xF9,0x78,0x56,0x34,0x12,0x76,0x0B,0x50,0x8B,0x01,0x05,0xFF,0xFF,0x00,0x00,0x89,0x01,0x58,0x8B,0x48,0x30,0x41,0x89,0x48,0x30,0x8D,0x65,0xF4,0x5E,0x5F,0x5B,0xC9,0xC3 };
 //char changeByte[] = { 0x8D ,0x4C ,0xB1 ,0x10 ,0xD9 ,0x19 ,0x8B,0x09 ,0x81,0xC1 ,0xFF,0xFF,0x00,0x00,0x8B ,0x48 ,0x30 ,0x41 ,0x89 ,0x48 ,0x30,0x8d,0x65,0xf4,0x5e,0x5f,0x5b,0xc9,0xc3 };
 memcpy(fastResearchMem, changeByte, 0x2A);
 DWORD dwOldAttrubet;
 VirtualProtect(fastResearchMem,
  0x2A,
  PAGE_EXECUTE_READWRITE,
  &dwOldAttrubet);
}


最后是快速建造,方法大家研究吧,因为写这个的时候也没怎么做笔记,从新记录下来会丢失很多细节,这些都是再边逆向,边编程解决的,不过大致方法和原理都是一样的。

找到关键函数,直接NOP掉2中的代码就会建造成功。


特征:

/*
seg000:0C4EEE56 D9 43 58                                      fld     dword ptr [ebx+58h]
seg000:0C4EEE59 D9 45 F0                                      fld     [ebp+var_10]
seg000:0C4EEE5C DE C1                                         faddp   st(1), st
seg000:0C4EEE5E D9 5B 58                                      fstp    dword ptr [ebx+58h]
seg000:0C4EEE61 D9 43 58                                      fld     dword ptr [ebx+58h]
seg000:0C4EEE64 D9 45 E0                                      fld     [ebp+var_20]
seg000:0C4EEE67 DF F1                                         fcomip  st, st(1)
seg000:0C4EEE69 DD D8                                         fstp    st
seg000:0C4EEE6B 7A 23                                         jp      short loc_C4EEE90 ---nop
seg000:0C4EEE6D 77 21                                         ja      short loc_C4EEE90 ---nop
seg000:0C4EEE6F 83 EC 08                                      sub     esp, 8
seg000:0C4EEE72 56                                            push    esi
seg000:0C4EEE73 53                                            push    ebx
seg000:0C4EEE74 39 1B                                         cmp     [ebx], ebx
*/
char mem_of_fast_bulid[] = { 0xD9, 0x43, 0x58, 0xD9, 0x45, 0xF0, 0xDE, 0xC1, 0xD9, 0x5B, 0x58, 0xD9, 0x43, 0x58, 0xD9, 0x45, 0xE0, 0xDF, 0xF1, 0xDD, 0xD8, 0x7A, 0x23, 0x77, 0x21, 0x83, 0xEC, 0x08, 0x56, 0x53, 0x39, 0x1B ,0x00 };

对应图:


值得注意的点

快速研究游戏中必须要有工作台才能分析,特征中不能含有00,我的是遍历字符串自动算长度,所以我改成了如特征中由00的话,需要传特征长度到函数

//匹配内存中参数特征的位置
long MemoryCmpToFeatureCode(PVOID BaseAddress, long mem_size, PCHAR Strings, int isstrlen = 0)
{
 vecCodeAddr.clear();
 vecCodeAddr.reserve(200);
 int index = 0;
 int flag = -1;
 int strlens;
 //获取特征长度
 if (isstrlen == 0)
 {
  strlens = strlen(Strings);
 }
 else
 {
  strlens = isstrlen;
 }
 for (long j = 0; j < mem_size - strlens; j++)
 {
  index = 0;
  for (int i = 0; i < strlens; i++)
  {
   char* compare = (char*)BaseAddress;
   //判断内存特征与传进来的特征对比
   if (compare[j + i] != Strings[i])
   {
    break;
   }
   index++;
  }
  if (index == strlens)
  {
   vecCodeAddr.push_back(j);
   flag = 1;
  }
 }
 return flag;
}


我将遍历到的所有地址保存到了容器中,然后再从容器中循环获取地址,因为遍历的特征可能不止一处。可能还有遗漏,但是暂时想不到了,这个帖子适用新手,当当练手,大神就算了。还可以扩展很多功能,这些也够了。文章并没有十分详细,只有大概过程思路。还有就是游戏一定要载入地图后再注入,因为我没有做是否已经再入地图的判断,和游戏结束的判断。

代码工程在这:https://github.com/Cc28256/GameAnalysisOfRimWorld

环世界游戏:

链接:https://pan.baidu.com/s/1xhlgiYs2HS2Fdzq-7ffnDQ

提取码:h910

CE和dll注入器大家应该都有吧。

 



[推荐]看雪企服平台,提供项目众包、渗透测试、安全分析、定制项目开发、APP等级保护等安全服务!

最后于 2020-5-16 16:44 被驱动骑士编辑 ,原因:
最新回复 (2)
hzqst 3 2020-5-16 19:39
2
0
rimworld是C#写吧?特征码对JIT生成的代码不一定靠谱
Editor 2020-5-17 07:55
3
0
感谢分享!
游客
登录 | 注册 方可回帖
返回