robin_be Geplaatst: 1 oktober 2017 Rapport Geplaatst: 1 oktober 2017 (bewerkt) ADMA en geheugenmanipulatie zonder CLEO Title says all Benodigdheden GTA:SA en Sannybuilder basis SCM-kennis (Basis SCM-scripten: tutorial door @Dutchy3010 & @PatrickW) Best ook even de arrays in SCM tutorial bekijken als je dit nog niet onder de knie hebt. We zullen ook werken met het geheugen (Werken met geheugen (adressen) in CLEO: tutorial door @Crypteq) Omdat we zaken in het geheugen aanpassen, zullen mijn voorbeelden waarschijnlijk niet op alle versies werken, maar bij de meeste personen blijkt dit geen probleem te zijn. Deze tutorial gaat behoorlijk diep op geheugenmanipulatie dus kennis en ervaring met bits en bytes is vereist. --------------------------- ADMA Wat ADMA staat voor Advanced Direct Memory Access, en is simpel gezegd gewoon een andere manier om globale variabelen aan te spreken. Het verschil met globale variabelen is dat je elk stuk van het geheugen waar de variabelen opgeslaan staan per byte kan aanspreken. Ondertussen weet je waarschijnlijk dat een normaal getal in SCM 4 bytes lang is. Variabele $0 zal dus theoretisch bytes 0, 1, 2 en 3 nemen om de waarde op te slaan. $1 neemt dan bytes 4, 5, 6 en 7 in beslag. Een ADMA geaddresseerde variabele (aangeduid door een &-teken) wordt per byte geaddresseerd, maar is nog steeds 4 bytes lang. &0 gebruikt dus bytes 0, 1, 2 en 3. &1 gebruikt bytes 1, 2, 3 en 4. &2 gebruikt 2, 3, 4 en 5, enzovoort. Om een globale variabele aan te spreken met een ADMA variabele moet je dus zijn nummer vermenigvuldigen met 4. $4 = &16, $10 = &40 etc. Omgekeerd, om een ADMA variabele aan te spreken met een gewone globale variabele, moet je zijn nummer delen door 4 (als dit kan). &8 = $1, &16 = $4 etc. Onderstaande afbeelding schetst hopelijk meer duidelijkheid: de zwarte nummers zijn gewoon de waardes die in het geheugen zitten. $0 en $1 staan hier niet op omdat die eigenlijk niet gebruikt kunnen worden. Als je $0 en $1 gebruikt, zal de compiler die veranderen naar een variabele die ergens anders staat (bron). Dit komt omdat dit eigenlijk het begin is van de SCM code in het geheugen, en hier zet sannybuilder een jump naar waar de echte code start, dus op die eerste twee plaatsen kunnen geen variabelen staan. Hier moet je niet echt van wakker liggen, maar houd er zeker rekening mee dat $0 niet overeenkomt met &0, en dat $1 niet overeenkomt met &4! Vanaf $2 klopt dit wel ($2 = &8). Voorbeeld Een kleur kan je hexadecimaal voorstellen, bijvoorbeeld: 0xFF8000FF is oranje (RGBA). $10 = 0xFF8000FF // oranje RGBA Als je liever rood groen en blauw apart aanpast, zonder te moeten werken met hexadecimaal, kun je ADMA gebruiken. De volgorde moet je wel omdraaien, omdat de bytes in little-endian opgeslaan worden (de kleinste waarde zit in het laagste geheugenadres, dus bijvoorbeeld 0x10203040 ziet er zo uit: 0x40 0x30 0x20 0x10): &40 = 255 // alpha &41 = 0 // blauw &42 = 128 // groen &43 = 255 // rood Op deze manier heb je ook 0xFF8000FF in $10 zitten, maar pas op! Hier worden er ook 4 bytes weggeschreven bij elke operatie, dus een deel van $11 wordt overschreven! (de 3 laagste bytes om exact te zijn) Geheugenmanipulatie zonder CLEO Uitleg + voorbeeld 1 Dankzij ADMA en arrays kunnen we data in het geheugen van het spel aanpassen! Het is gekend op welk adres de waardes van globale variabelen staan. Als we dan een veel te grote (of veel te kleine, negatieve) index gebruiken in een array, kunnen we stukken uit het geheugen manipuleren. De eerste variabele, &0 (niet $0, lees het laatste stukje in de uitleg van ADMA), zit op geheugenadres 0xA49960 (als je een andere exe hebt, kan dit natuurlijk anders zijn). Een waarde op adres 0xB7CE50 houdt bij hoeveel geld de speler heeft. (Zo'n leuke addressen kan je trouwens vinden in diverse topic en sites, zoals Documenting GTA-SA memory addresses op gtaforums.com) Wat we nu moeten doen om het geld aan te passen (zonder een simpele opcode te gebruiken), is bepalen op welke index die variable zogezegd zit als we een array gebruiken op basis van &0. Per index verspring je 4 bytes. Als je bijvoorbeeld 2@[1] gebruikt, ben je aan het werken op 3@. Stel dat 2@ op adres 0x20000 staat, dan zal 3@ dus op adres 0x20004 staan. (index 1 maal 4 bytes per index = 4 bytes verder). Dus, &0 zit op 0xA49960. We moeten op adres 0xB7CE50 geraken. Het verschil is 0xB7CE50 - 0xA49960 = 0x1334F0. De waarde die we moeten aanpassen zit dus 0x1334F0 bytes verder in het geheugen. Maar we moeten de index hebben, dus doen we 0x1334F0 gedeeld door 4, wat 0x4CD3C is. Nu kunnen we de waarde aanpassen: 0006: 2@ = 0x4CD3C // l=i (int) 0004: &0(2@,1i) = 500000 // g=i (int) En voila, we hebben ons geld op $500000 gezet door in het geheugen te prutsen! Natuurlijk kan je die volledige berekening ook overlaten aan het spel: 0006: 2@ = 0xB7CE50 // l=i (int) 000E: 2@ -= 0xA49960 // l-=i (int) 0016: 2@ /= 4 // l/=i (int) 0004: &0(2@,1i) = 500000 // g=i (int) Zonder ADMA notatie Alle stukken code die ik gezien heb, gebruiken ADMA om geheugen te bewerken. Ik heb echter gemerkt dat dit ook met normale globale variabele notatie werkt. Pas wel op dat je niet $0 of $1 gebruikt, want die staan niet waar je zou denken dat ze staan. Als we bijvoorbeeld $4 gebruiken, moeten we het nummer 0xA49970 aftrekken (= 0xA49960 + 4 * 4). Nog eens het laatste voorbeeld, maar met normale globale variabele notatie: 0006: 2@ = 0xB7CE50 // l=i (int) 000E: 2@ -= 0xA49970 // l-=i (int) 0016: 2@ /= 4 // l/=i (int) 0004: $4(2@,1i) = 500000 // g=i (int) Voorbeeld 2 Op adres 0xBAB230 staat de kleur die gebruikt wordt bij een ~g~ gxt code (= groen). (Heb ik hier gevonden: [Memory] GTA SA HUD Addresses, staan veel van die leuke addressen in). Die kleur wordt onder andere ook gebruikt voor je geld (als die positief is tenminste), en autonamen. 0006: 2@ = 0xBAB230 // l=i (int) 000E: 2@ -= 0xA49960 // l-=i (int) 0016: 2@ /= 4 // l/=i (int) 0004: &0(2@,1i) = 0xFFFF00FF // g=i (int) De kleur staat hier in ABGR volgorde dus het resultaat is een iets rozere HUD: Voorbeeld 3 Iets geavanceerder nu, we willen hetzelfde doen als deze schrijfoperatie (komt uit mijn simpele ELS mod tut): 0A8C: write_memory 0x6E1D4F size 1 value 2 vp 0 De grote moeilijkheid hier is dat we slechts 1 byte willen aanpassen (size 1). Dit kan gelukkig redelijk simpel met bitmanupulatie opcodes (08BA-08BF), hiermee kunnen we een enkele bit veranderen, dus als we op de manier 8 bits (= 1 byte) veranderen zijn we er. Dus, we doen 0x6E1D4F - 0xA49960 = 0xFFC983EF (-3570705). Maar dit getal is niet deelbaar door 4! We hebben een index nodig in onze array, en om die te hebben moeten we het verschil kunnen delen door 4. ADMA to the rescue! &0 heeft adres 0xA49960, dus &3 heeft adres 0xA49963. Als we nu dus &3 nemen, doen we 0x6E1D4F - 0xA49963 = 0xFFC983EC (-3570708). Dit is wel deelbaar door 4, dus dit kunnen we gebruiken. 0xFFC983EC gedeeld door 4 is 0xFFF260FB. Hier kun je dus geen normale globale variabele notatie gebruiken, omdat het verschil in geheugenadressen dan niet deelbaar is door 4 (tenzij je dit anders aanpakt). Om dus een waarde 2 te schrijven, kunnen we alle bits juistzetten. 2 is 00000010 in binair. De meest linkse bit is bit nummer 7, de meest rechtse is bit nummer 0. De code wordt: 0006: 2@ = 0xFFF260FB // l=i (int) for 3@ = 0 to 7 08C2: clear &3(2@,1i) bit 3@ // zet bit nummer 3@ op 0 end 08BA: set &3(2@,1i) bit 1 // zet bit nummer 1 op 1 En we hebben dezelfde werking als de CLEO opcode ----------------- Hopelijk is deze tutorial een beetje duidelijk Bewerkt: 1 oktober 2017 door robin_be extra voorbeeldje Reageren
Recommended Posts
Een reactie plaatsen
Je kan nu een reactie plaatsen en pas achteraf registreren. Als je al lid bent, log eerst in om met je eigen account een reactie te plaatsen.