Aller au contenu


Photo

Tutorial Read/write Memory Arma3


  • Veuillez vous connecter pour répondre
Aucune réponse à ce sujet

#1 kickbar

kickbar

    Devlopette

  • Membre
  • 539 messages
  • Hobbies :Informatiques, jeux vidéo, botting !!!! ;D

Posté 27 February 2014 - 05:52

Itération des entités


Tout comme arma 2, arma 3 à une façon bien particulière de stocker les entités,
Il faudra parcourir 3 "master" table qui contiennent les offsets de chacune des "Slave" table qui contiennent a leur tour les Offsets des entités.

Il y a en tout 3 Master table et 4 Slave pour chacune d'entre elle, la 3émes master table comporte 2 slaves de plus

La place d'une entité dans l'une ou l'autre slave/master dépends essentiellement de la distance de cette entité par rapport a vous, elles sont donc amené a être
modifié en permanence selon vos déplacement ig.
Cas particulier pour la master 3, qui contient des slaves qui sont réservé pour certain type d’entité, comme les "Constructions" et les entités de type nature (Bâtiment, tente, abeille, serpent etc...) mais aussi les loots générer au sol par les joueurs (qui aurait par exemple jeté leur arme)


Offset de décalage pour atteindre les Master Table & slave table:
int[] MasterTableArray = { 0x46c, 0x710, 0x9b4 };
int[] SlaveTableArray = { 0x8, 0xb0, 0x158, 0x200, 0x2a8, 0x350 } //Les deux dernières slave sont utilisée uniquement pour la master 3 

Comme pour tous les jeux, il existe une offset de base, qui nous permet d'atteindre toute les structures qui nous intéresse, en l’occurrence l’itération de nos entités, ici nous l’appelleront "GameBase".
int GameBase = 0x160ED88 //Cette valeur peut varier à chaque update du jeux

Maintenant mettons en utilisations Notre GameBase Pour atteindre nos Master Table :
 int MasterArray = GameBase] +0x7c4] +0x0]

Appliquons maintenant les decallages contenut dans MasterTableArray
for(int i=0; i < MasterTableArray.Lenght; i++){
	CurrentMasterptr = MasterArray + MasterTableArray[i]]
}

CurrentMasterptr contient donc l'adresse de debut de chaque master.
Nous pouvons donc maintenant nous attaquer au Slave Table de chaque master.
Rapellez vous, les slaves table sont lié a chaque master, il faudra donc iterer chaque slave dans la boucle
d'iteration des masters.
Cependant je vous rapelle que nous avons declarer 6 slave, les deux derniere sont utilisé uniquement pour la master 3, il
faudra donc sauter les deux derniere iteration des slave si l'on itere la master 1 et 2

for(int y=0; y < SlaveTableArray.Lenght; y++)
{

	if(i < 2 && y > 3 ) continue; //Si on itere la master 1 & 2 et que l'on itere la slave 5 et 6 on saute

	CurrentSlavePtr = CurrentMasterptr + SlaveTableArray[y]]
	CurrentSlaveCount = CurrentMasterptr + SlaveTableArray[y] + 0x4]

}

Nous avons donc récupéré le CurrentslavePtr, point d'entré de notre listing d’entité ainsi que CurrentSlaveCount qui définit le nombre d'enregistrement à l’intérieur de notre CurrentSlavePtr.

une fois dans notre slave nous faisons comme suit pour recuperer l'ofs de nos entitiés
for(int z=0; z < CurrentSlaveCount; z++){
	EntOfs = CurrentSlavePtr + z*0x4] 
}

Et Voila on récupère un à un les Ofs de toute nos entités


Local entités

L’entité qui représente notre joueurs est présente dans les Master/slave mais il existe un chemin plus court pour obtenir son adresse
SelfEntOfs = 0x160ED88] +0x1704] +0x4]


La Struct de l'entité

Spoiler


VecPos Struct :
Spoiler


int ModelPtr : Pointeur qui nous donne accé au model1name et model2name
string model1name = ModelPtr + 0x38] + 0x8
String model2name = ModelPtr + 0x30] + 0x8
Pour le moment vous devrez utilisez le model1name pour déduire le type de l'entité (Humain/Ai, véhicule, lootable etc...)

"int PartPtr" et "int PartCount" : nous donne accès a un array de float qui decrive l'état des différentes partit d'une entité cassable (ex: vehicule), si = 1 -> complètement détruit, si 0 -> complètement neuf (un petit coup de Write et votre véhicule est tout neuf !)

int SideId : Représente l'id du camp de l'entité, Cette valeur change en fonction des serveurs, vous pouvez quand même l'utilisé pour retrouver les membres de votre équipe ou les membres de l'équipe adverse.

bool IsDead : Définit si l'entité est en vie ou non.

ItemOlderPtr : Nous donne accès au Older de l’entité (utile uniquement si l'entité peut contenir des items) (nous y reviendront)

WeaponPtr : Nous donne accès a l'array de struct weapon (munition infinie, balle plus rapide que l’éclair, c'est ici) (nous y reviendront)

BackPackPtr : Nous donne accès a l'ofs de l'entité qui représente notre sac a dos (même si il est sur le dos de quelqu’un le sac existe comme entité, cela nous permet donc de faire la liaison entre une entité et son sac)

WeaponId : Nous permet de retrouver dans WeaponPtr notre arme actuelle (nous y reviendront)

NameId : Nous permet de retrouver le Pseudo ou RealName d'une entité Joueur (nous y reviendront)

DriverPtr : Nous donne l'ofs de l'entité qui conduit

PassengerPtr et PassengerCount : Permet d'obtenir la liste des entités qui sont passager dans un véhicule



Réparé un Véhicule

vous ne pourrez réparer un véhicule uniquement que si vous êtes a la place conducteurs, et que ce dernier n'a pas explosé ;D
La technique est relativement simple :
- Récupérer l'ofs de votre entité
- Itérer les entités jusqu’à ce que DriverPtr soit égale a l'ofs de votre self entité.

Une fois cela fait, vous avez trouvé l'adresse de votre véhicule, a partir de la il vous suffit de lire PartPtr et PartCount.
PartPtr est un array de float de PartCount éléments
entOfs //Ofs de votre véhicule

int PartPtr = entOfs + 0x168]
int PartCount = entOfs + 0x16c]

for(int i=0; i < PartCount){
     Write(Part + i*0x4, 1f)
}

Et voila votre véhicule est tout neuf !!!!


Itération des olders

Un older est un conteneur, une entité qui peut contenir un ou plusieurs item (par exemple un véhicule a un Older car il peut contenir des items)
Toute entités pouvant contenir des items peut être définit comme possédant un Older

Un Older est une structure qui contient 8 informations dont nous avons besoin, 4 pointer qui nous permette d'obtenir le nom des objets classé par type, ainsi que le count respectif de chaqu'un d'entre eux

Pour l'instant, nous avons recensé 4 type d'item :
- Arme
- Consommable (Ammo, food, water etc...)
- Tool (GPS, map, toolbox etc)
- BackPack (sac a dos)

Chaque type d'item est regroupé et est stocké dans un tableau d'item différent, dans un older nous avons donc 4 tableau et leur count associé


OlderWeapon:
ItemOlderPtr //Valeur de L'ItemOlderPtr de la current entité

WeaponOlderPtr = ItemOlderPtr + 0x28]
WeaponOlderCount = ItemOlderPtr + 0x2c] 

for(int i=0; i < WeaponOlderCount; i++){
  CurrentWeaponOlder = WeaponOlderPtr + 0x4 * i] + 0x28] + 0x1c]
  string CurrentWeaponName = CurrentWeaponOlder + 0x8]
}

OlderConsomable:
ItemOlderPtr //Valeur de L'ItemOlderPtr de la current entité

ConsomableOlderPtr = ItemOlderPtr + 0x44]
ConsomableOlderCount = ItemOlderPtr + 0x48] 

for(int i=0; i < ConsomableOlderCount; i++){
  CurrentConsomableOlder = ConsomableOlderPtr + 0x4 * i] + 0x28]
  string CurrentConsomableName = CurrentConsomableOlder + 0x8]
}

OlderTool:
ItemOlderPtr //Valeur de L'ItemOlderPtr de la current entité

ToolOlderPtr = ItemOlderPtr + 0x34]
ToolOlderCount = ItemOlderPtr + 0x38] 

for(int i=0; i < ToolOlderCount; i++){
  CurrentToolOlder = ToolOlderPtr + 0x4 * i] + 0x20] +0x18]
  string CurrentToolName = CurrentToolOlder + 0x8]
}

OlderBackPack:
ItemOlderPtr //Valeur de L'ItemOlderPtr de la current entité

OlderBackPackOlderPtr = ItemOlderPtr + 0x70]
OlderBackPackOlderCount = ItemOlderPtr + 0x74] 

for(int i=0; i < BackPackOlderCount; i++){
  CurrentBackPackOlder = BackPackOlderPtr + 0x4 * i] + 0xD0] +0x30]
  string CurrentBackPackName = CurrentBackPackOlder + 0x8]
}


Munition Infinie & Vélocité

Cette opération s'effectue sur notre entité, il faut avoir une arme, et avoir ou déjà posséder des balles depuis que l'arme est en main.
Nous allons intervenir sur la quantité de balle se trouvant dans le chargeur en cours d'utilisation, si vous ramassez une arme sans balle, le chargeur de l'arme ne sera pas initialiser en mémoire, il nous sera donc impossible d’écrire la quantité de balle que nous souhaitons.
La quantité de balle est gérer par un système de XOR entre deux valeur, si l'une d'elle ne correspond pas a la deuxième valeur vous vous retrouverez sans munition ;D

Pour récupérer l'offset qui nous intéresse nous allons avoir besoin de WeaponPtr et WeaponID de l'entité qui représente notre joueur

Nous allons dans un premier temps récupérer le maximum de munition que peut accueillir notre chargeur puis l’écrire en mémoire dans notre chargeur

int WeaponPtr = WeaponPtr + (WeaponID * 0x30) + 0c]
int MaxMagCap = WeaponPtr + 0x34] + 0x40]

int garbadge1Ofs = WeaponPtr + 0x38
int garbadge2Ofs = WeaponPtr + 0x58
int VelocityOfs = WeaponPtr + 0x34] + 0x48

int Garbadge1 = (int)(MaxMagCap ^ 0xBABAC8B6) << 1
int Garbadge2 = (int)(MaxMagCap ^ 0xBABAC8B6) - Garbadge1

Write(garbadge1Ofs, Garbadge1)
Write(garbadge2Ofs, Garbadge2)
Write(VelocityOfs, 99999f) //Vélocité à 99999 


RealName / Pseudo

Lorsque vous itérer une entité de type joueur, vous n'avez pas dans la structure les informations nécessaire pour savoir comment ce dernier s’appelle.
Il existe un système de scoreboard qui contient les pseudo ainsi qu'un identifiant unique lié, le nameId, nous allons donc utiliser le nameID contenus dans l'entité pour la lié a un pseudo

La struct de type ScoreBoard contient :
int NameId; //0x4
int ptrSteamId; //0xc
int ptrName; //0xa8

Itérer le ScoreBoardArray:
ScoreBoardArrayPtr = 0x15FD8B4] + 0x18]
ScoreBoardArrayCount = 0x15FD8B4] + 0x1c]

for(int i=0; i < ScoreBoardArrayCount; i++){

String NickName = ScoreBoardArrayPtr + (i*0x120)] + 0xa8] + 0x8]
int NameID = ScoreBoardArrayPtr + (i*0x120)] + 0x4]

}


A venir

- World to Screen
  • Kunu911 et tcthebear aiment ceci