L'automatisation des actions des joueurs a toujours été un problème majeur dans les MMORPG tels que World of Warcraft et Runescape . Ce type de piratage de jeux est très différent des tricheurs traditionnels, par exemple chez les tireurs.
Un week-end, j'ai décidé de jeter un œil aux systèmes de détection que Jagex utilise pour empêcher Runescape d'automatiser les actions des joueurs.
La botanique
Au cours des derniers mois, le compte a
sch0u
joué 24 heures sur 24 sur le serveur du monde 67, effectuant des tâches monotones telles que tuer des foules et collecter des ressources. À première vue, ce compte ressemble à n'importe quel autre joueur, mais il y a une différence importante: c'est un bot .
J'ai lancé ce bot en octobre pour tester les capacités du système de reconnaissance de bot. Après avoir essayé de trouver des informations sur la façon dont Jagex lutte contre les robots robots, je n'ai trouvé que des vidéos de robots payants, dont les développeurs se vantaient que leurs systèmes de mouvement de souris ne se distinguaient pas des actions humaines.
Par conséquent, la seule chose que je pouvais comprendre était l' importance des mouvements de la souris , mais est-ce vraiment le cas?
Heuristique!
Pour confirmer cette théorie, j'ai commencé par examiner le client Runescape et j'ai presque immédiatement remarqué qu'une variable globale
hhk
était définie peu de temps après le lancement.
const auto module_handle = GetModuleHandleA(0);
hhk = SetWindowsHookExA(WH_MOUSE_LL, rs::mouse_hook_handler, module_handle, 0);
Ce code installe un intercepteur de bas niveau sur la souris qui est attachée à la chaîne d'intercepteur système . Cela permet aux applications Windows d'intercepter tous les événements de la souris, même s'ils ne sont pas associés à une application spécifique. Les intercepteurs de bas niveau (hooks) sont souvent utilisés par les enregistreurs de frappe , mais ils peuvent également être utilisés à des fins pacifiques, par exemple dans des heuristiques, comme l'intercepteur de souris susmentionné.
En fait, le gestionnaire de souris de Runescape est assez simple (le pseudocode a été modifié pour la beauté à la main):
LRESULT __fastcall rs::mouse_hook_handler(int code, WPARAM wParam, LPARAM lParam)
{
if ( rs::client::singleton )
{
// Call the internal logging handler
rs::mouse_hook_handler_internal(rs::client::singleton->window_ctx, wParam, lParam);
}
// Pass the information to the next hook on the system
return CallNextHookEx(hhk, code, wParam, lParam);
}
void __fastcall rs::mouse_hook_handler_internal(rs::window_ctx *window_ctx, __int64 wparam, _DWORD *lparam)
{
// If the mouse event happens outside of the Runescape window, don't log it.
if (!window_ctx->event_inside_of_window(lparam))
{
return;
}
switch (wparam)
{
case WM_MOUSEMOVE:
rs::heuristics::log_movement(lparam);
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
rs::heuristics::log_button(lparam);
break;
}
}
pour réduire la charge sur la liaison, ces fonctions
rs::heuristics::log_*
utilisent des algorithmes simples pour ignorer les données d'événement qui ressemblent à des événements précédemment enregistrés.
Plus tard, ces données d'événement sont analysées par une fonction
rs::heuristics::process
qui est appelée chaque image de la boucle de rendu principale.
void __fastcall rs::heuristics::process(rs::heuristic_engine *heuristic_engine)
{
// Don't process any data if the player is not in a world
auto client = heuristic_engine->client;
if (client->state != STATE_IN_GAME)
{
return;
}
// Make sure the connection object is properly initialised
auto connection = client->network->connection;
if (!connection || connection->server->mode != SERVER_INITIALISED)
{
return;
}
// The following functions parse and pack the event data, and is later sent
// by a different component related to networking that has a queue system for
// packets.
// Process data gathered by internal handlers
rs::heuristics::process_source(&heuristic_engine->event_client_source);
// Process data gathered by the low level mouse hook
rs::heuristics::process_source(&heuristic_engine->event_hook_source);
}
Loin du clavier?
Au cours du processus de rétro-ingénierie, j'ai essayé de comprendre l'importance pour moi de chaque fonction que j'ai apprise, généralement en créant des crochets ou des correctifs pour ces fonctions. Vous pouvez généralement dire si une fonctionnalité est pertinente en la rendant inutile et en surveillant l'état du logiciel. Cette méthodologie de recherche a conduit à une observation intéressante.
Ayant interdit au jeu d'appeler la fonction
rs::heuristics::process
, au début je n'ai rien remarqué, mais après exactement cinq minutes, le serveur m'a déconnecté. Evidemment, Runescape détermine l'inactivité du joueur uniquement par les données heuristiques transmises par le client au serveur, même si vous pouvez jouer tout à fait normalement. Cela a soulevé une nouvelle question: si le serveur pense que je ne joue pas, pense-t-il que je joue en tant que bot? ...
Après cela, j'ai passé quelques jours de plus à faire de la rétro-ingénierie de la couche réseau du jeu, afin que mon bot puisse maintenant faire presque tout en utilisant uniquement des paquets réseau .
Pour valider ma théorie, je me suis occupé 24 heures sur 24, sept jours sur sept, sans même bouger ma souris. Ayant passé des milliers d'heures comme ça, je peux affirmer avec certitude que soit le système de détection de bots utilise uniquement les données d'événements heuristiques envoyées au serveur par le client, soit ne fonctionne que lorsque le joueur n'est pas "afk". Tout joueur qui parvient à jouer sans déplacer le curseur doit être immédiatement banni, c'est-à-dire que les développeurs doivent faire attention à cette faille.