对的,这是可能的
我将向您解释一下大多数游戏是如何做到的(我从未逆转过任何 GTA,但我想无论如何都是这样的)。
我将介绍结构的静态和动态分配。
静态方式:
GlobalGameInfo g_info;
// ...
g_info.some_data = 1;
这就是 IDA 中的静态偏移量,如下所示:
lea eax, [g_info + 0xAABB] ; suppose 0xAABB is the offset for 'some_data'
mov [eax], 1;
g_info
总是会保持相同的偏移量,因此一旦找到它,您就可以使用它g_info + offset
来获取数据。
动态方式:
Player* players; // can be defined as Player* players[<count>] or Player** players;
// it's the same
// ...
players = new Player[players_count];
// ...
players[1].alive = false;
然后导致:
; this is a static location which is actually the "players" variable
; and it contains an address which points to the offset in memory of the
; actual players structure
dword_xxxx dd ?
因此,要在 Cheat Engine 中使用它,您Add a new address
,检查Pointer
,添加 的xxxx
部分dword_xxxx
,然后在偏移量中放置所需的偏移量。例如,要获取players[1].alive
,alive
在偏移量(例如 0x100)上,您需要计算:
value_stored_in_dword_xxxx + sizeof(Player) * player_id + 0x100
因此,如果dword_xxxx
-> 0xAABBCCDD
、sizeof(Player)
-> 0x204
、player_id
->8
和offset
-> 0x100
,您的计算将是:
0xAABBCCDD + (0x204 * 8) + 0x100
// ^base ^size ^id ^offset
这个例子
既然你给了我们mov [esi + 0x2F], dl
:
esi
是指向结构的指针。看上面(在拆卸中)。
mov esi, dword ptr [dword_xxxx]
(最有可能)意味着它正在取消引用一个指针,这意味着该结构是动态分配的。
mov esi, offset dword_xxxx
(最有可能)意味着它只是将地址(xxxx
部分)分配给esi
,所以这是一个静态地址。
用法
作弊引擎
在作弊引擎中,输入指针和偏移量很容易:
如您所见,0x5CCB138
是dword_xxxx
,里面的值dword_xxxx
是0x09021A00
,+ 0x142
(我的偏移量)导致游戏内名称的开头。
C
如果您想以编程方式执行此操作,您可以在 C 中这样做:
PCHAR my_name = PCHAR (*PDWORD(0x5CCB138) + 0x142);
^save the addr| | ^deref to get | add the offset
| ^cast | 0x09021A00 |
// -> be careful, do not surpass the max length!
// -> also remember that there's 'your name' length + 1 \x00 byte
// at the end!
char new_name[] = "newName";
strncpy(my_name, new_name, sizeof(new_name)); // again: be careful with the length!
然而,正确的方法是像这样反转整个结构:
struct player_data {
int ID;
char name[15];
int some_data;
...;
};
// make sure the order / size of each item is correct!
// a single error can fuck up the entire struct
// I'm going to assume you understand pointers
player_data* data = *(player_data**) 0x5CCB138;
// do your changes
// again, be careful with the length!
// also note that sizeof() will not work if you use char*
char new_name[] = "new name!";
strncpy(data->name, new_name, sizeof(new_name));