Rétro-ingénierie Red Dead Redemption 2

27/09/2025

Dans cet article, je vous fait part de ma méthode de travail en reverse-engineering du jeu Red Dead Redemption 2.

Qu'est-ce que c'est ?
Le reverse-engineering (rétro-ingénierie), c'est grossièrement expliquer comment un programme agit sur le système, par déduction après des tests par exemple...

Pour ma part, j'ai la chance d'avoir une grosse partie du travail qui est le code décompilé. Il y a des repo Github avec les scripts décompilés (en C).

Qu'est-ce que je cherche ?
Je cherche à comprendre l'utilité et le fonctionnement de fonctions à ce jour "non découvertes" par la communauté de moddeurs. Je fais des déductions puis leur donne une définition cohérente notamment avec l'aide d'une liste classant alphabétiquement les natives du jeu.

Pourquoi je fais ça ?
Premièrement ça me passionne, la satisfaction de réussir nourrit ma curiosité technologique.
Ensuite, j'aime me rendre utile à une communauté en y contribuant (et gratuitement !).

Comment je fais ?
Tout commence sur VS Code, je fais une recherche dans les fichiers décompilés en utilisant un paterne REGEX.

Ici je m'attaque à la native "0xE4B7945EF4F1BFB2".
Je vais commencer par remonter son paramètre "uParam0->f_14". Je finis par tomber sur cette ligne : "CAM::SET_CAM_ACTIVE(uLocal_52.f_14, true);"
Cette native qui a déjà était découverte utilise en premier paramètre la même adresse que la mienne, où sa valeur est un handle de caméra.

Maintenant, je vais remonter mon paramètre "uParam0->f_15".
En comparant avec d'autres utilisations j'en déduis la structure :
{
 float x0;
 float x1;
 float x2;
 float x3;
 float x4;
 float x5;
 bool x6;
 bool x7;
 bool x8;
 bool x9;
};

Maintenant que je sais comment utiliser cette fonction, il est temps de la tester avec des valeurs. Je me suis créé un script LUA qui l'utilise avec une caméra que j'ai créée au préalable et un buffer de mes configurations.

Exemple:
local struct = DataView.ArrayBuffer(10*8)
struct:SetFloat32(0*8, 5.0)
struct:SetFloat32(1*8, 2.0)
struct:SetFloat32(2*8, 128.0)
struct:SetFloat32(3*8, 25.0)
struct:SetFloat32(4*8, 25.0)
struct:SetFloat32(5*8, 60.0)
struct:SetInt32(6*8, 1)
struct:SetInt32(7*8, 0)
struct:SetInt32(8*8, 1)
struct:SetInt32(9*8, 1)
Citizen.InvokeNative(0xE4B7945EF4F1BFB2, cam, struct:Buffer())

Avec mon script, lorsque j'appuie sur une touche, ça va incrémenter/décrémenter sa valeur associée puis l'applique avec la native.

Après mes tests, je comprends que les 3 premiers float affectent la profondeur de champs et les 3 derniers sont liés à la distance focale.

J'en conclue cette définition :
void _SET_CAM_DOF_AND_FOCAL_PARAMS(Cam cam, const CamDofFocalParams* params);

struct CamDofFocalParams {
 float dofStrength;
 float dofNear;
 float dofFar;
 float focalLength;
 float minFocal;
 float maxFocal;
 bool enableDof;
 bool x7;
 bool x8;
 bool x9;
};

N'hésitez pas à me soutenir en laissant une petite étoile 😉
https://github.com/Sarbatore/rdr_natives