Compartilhe
avatar
Scripter CLEO - Avançado
Scripter CLEO - Avançado
Título : Não quero acreditar, quero saber.
Mensagens : 21893
Reputação : 676
Desde : 03/05/2012
Idade : 22
Localização : Ibitinga - SP
Link : www.MixMods.com.br
Ver perfil do usuáriohttp://MixMods.com.br
  • Reputação da mensagem: 100% (2 votos)

M.1. Introdução à manipulação de memória

em Sex 14 Jul 2017, 02:31


Concluindo esta parte você vai:
Saber os princípios do manipulamento de memória, a sua utilidade e como usar os comandos READ_MEMORY e WRITE_MEMORY

Esta é uma parte fora dos "essenciais". É aqui que começamos a nos aprofundar na criação dos mods!

Atenção:
Por favor, se você está aqui eu imagino que você já esteja começando a ficar bom na criação de mods cleos.
Este "episódio" onde eu ensino sobre memórias eu imagino que você já tenha lido todas as partes "Essenciais" do índice, senão você terá dificuldades.




Introdução

Os comandos WRITE_MEMORY e READ_MEMORY foram os 2 primeiros comandos da biblioteca CLEO, ainda lá na CLEO 1.

E por que eles são tão especiais assim? Por que justamente estes dois comandos foram os primeiros de tantos? É agora que você entenderá.


Embaixo do capô

Modding é uma forma de hacking, e para fazermos estes hacks geralmente precisamos ir mais a fundo do que realmente podemos (poderíamos).
Com o manuseamento/manipulamento de memória nós podemos quebrar todos os limites que tínhamos, encontrando/alterando qualquer valor, cada byte, cada bit do jogo inteiro, e até mesmo coisas fora dele.

Isso serve principalmente para fazer coisas que nenhum comando existente faz. De fato, todo o funcionamento de um jogo (programa e seja o que for) funciona numa memória, como já foi levemente introduzido na parte 8 do tutorial que você pode querer revê-la antes de prosseguir.

Tendo os endereços ("ponteiros", "pointers") para os locais destes valores na memória, nós podemos fazer o que bem entender, e estou falando de uma coisa que pode valer tanto para um endereço do próprio executável (que é estático) quanto para endereços dinâmicos, como o endereço onde está armazenado informações de um pedestre específico, como por exemplo, saber qual é o "skill" de arma dele (uma coisa que ainda não existe comando para isso, entendeu?)


Como usar os comandos?

Argumentos:
Código:
READ_MEMORY endereço tamanho virtual_protect (valor_retorno)
endereço
 (INT) um ponteiro para algum local da memória, geralmente escrito em hexadecimal (0x)

tamanho
(INT) número de bytes para serem lidos, geralmente 1, 2 ou 4.

virtual_protect
(BOOL)* ative-o caso a memória tenha proteção. De fato, você só precisará caso fazer operações mais avançadas como hooks e NOPs, portanto, simplesmente sempre use desativado e não se preocupe com isso.
* Lembrando que boolean pode ser usado como "0", "FALSE" ou "OFF" como desativado, e "1", "TRUE" ou "ON" para ativado.

valor_retorno
(QUALQUER) a variável que ganhará o valor que foi lido. Aceita qualquer data type, onde obviamente o compilador não sabe que valor irá retornar, portanto ele não te alertará de nada caso você estiver usando data type incorreto.

Exemplo:
Código:
READ_MEMORY 0xB7CE50 4 FALSE (var)
0xB7CE50
ponteiro onde está armazenado o dinheiro do player.

4
está armazenado em DWORD, onde uma DWORD contém 4 bytes, portanto, vamos ler 4 bytes desse endereço.

FALSE
é só uma simples leitura de um endereço comum, podemos usar FALSE (0) sem problemas.

var
variável onde será armazenado o valor contido neste endereço, onde neste caso em particular, é o dinheiro do player, e o dinheiro está armazenado em um INT (número inteiro), portanto vamos usar uma variável INT aqui.

Ou seja, agora a variável "var" tem o valor presente no endereço 0xB7CE50, que é o dinheiro do player.
Se você agora mostrar na tela:
Código:
PRINT_FORMATTED_NOW "%i" 1000 (var)
Verá o valor do dinheiro do player.

E se nós quisermos escrever um novo valor lá? WRITE_MEMORY!

Argumentos:
Código:
WRITE_MEMORY endereço tamanho (valor) virtual_protect
Auto-explicativo. Igual ao READ_MEMORY, só mudando a ordem do argumento do valor.

Portanto...:
Código:
READ_MEMORY 0xB7CE50 4 FALSE (var)
var += 100
WRITE_MEMORY 0xB7CE50 4 (var) FALSE
Aumentei 100 no valor do dinheiro que antes eu li, e re-escrevi o novo valor na memória, assim sobrescrevendo o valor anterior pelo meu novo valor. O que eu fiz foi simplesmente aumentar "100" no dinheiro do player.

Outro exemplo:
Código:
WRITE_MEMORY 0xB7CE50 4 (1000) FALSE
Isso simplesmente mudou o valor do dinheiro do player para "1000", simplesmente escrevendo o valor "1000" para onde o dinheiro dele está armazenado.

Ei, mas isso é totalmente inútil, pois nós podemos usar os comandos STORE_SCORE e ADD_SCORE para manipular o dinheiro do player!

Você está certo meu caro questionador anônimo. Então que tal criarmos uma previsão do tempo? Sim, vamos prever o tempo melhor do que qualquer meteorologista:
Código:
READ_MEMORY 0xC8131C 2 FALSE (next_weather)
Pronto. A variável "next_weather" agora tem o valor do próximo clima que está chegando (mais especificamente, um número de identificação). E sim, você pode inclusive mudar este valor com o WRITE_MEMORY.

Mas possivelmente isso está te deixando mais confuso ainda: De onde diabos eu arranquei esse 0xB7CE50 e 0xC8131C????? Como que eu sei que um é 4 e outro é 2 bytes??

É aí que as coisas ficam mais interessantes!


Encontrando endereços para usar

Estes endereços são descobertos pela comunidade. Alguém conseguiu de alguma forma (geralmente tentando entender o arquivo .exe do jogo, usando um processo relativamente considerado ilegal chamado "engenharia reversa", usando IDA (Interactive Disassembler) ou até mesmo Cheat Engine) ...e a tal pessoa soube que aquilo é o número de identificação do próximo clima, pois o número contido neste endereço de memória é usado dentro do .exe na função onde processa o próximo clima do jogo e assim por diante... (Ora ora, temos um Xeroque Rolmes aqui)

Você também pode encontrar seus próprios endereços de memória, mas eu não recomendo que você, neste momento, com baixa experiência, tente isso (principalmente caso não saiba os básicos do C++ e Assembly)
Ao invés, pesquise e encontre. Existe milhares de endereços já documentados que você pode usá-los.

Eu recomendo altamente que você tente brincar com esta lista aqui:
http://www.gtamodding.com/wiki/Memory_Addresses_(SA)
Eu particularmente me encantei quando aprendi a manipular valores de endereços de memória e conheci esta lista!

Por exemplo:
Código:
0x863984 - [float] Gravity (default value: 1.0f/125.0f = 0.008f)
Isso quer dizer, que:
Código:
READ_MEMORY 0x863984 4 FALSE (gravity)
A variável "gravity" (que é uma FLOAT) agora terá o valor "0.008", e você pode por exemplo aumentar, diminuir etc e reescrever o valor lá.

Assim como... Que tal simular a gravidade de outros planetas/astros?
Código:
WRITE_MEMORY 0x863984 4 (0.00304) 0 // Mercúrio
WRITE_MEMORY 0x863984 4 (0.0072) 0 // Vênus
WRITE_MEMORY 0x863984 4 (0.00304) 0 // Marte
WRITE_MEMORY 0x863984 4 (0.021144) 0 // Júpiter
WRITE_MEMORY 0x863984 4 (0.009272) 0 // Saturno
WRITE_MEMORY 0x863984 4 (0.00936) 0 // Urano
WRITE_MEMORY 0x863984 4 (0.0088) 0 // Netuno
WRITE_MEMORY 0x863984 4 (0.000528) 0 // Plutão
WRITE_MEMORY 0x863984 4 (0.224) 0 // Sol
WRITE_MEMORY 0x863984 4 (0.00136) 0 // Lua

E você ainda pode estar confuso sobre a quantidade de bytes (argumento "size", o tamanho pra ser lido ou escrito), mas dá para simplificar:

Byte = 1 Byte é uma letra ou um número inteiro de valor 0 até 255 (ou -128 até 127 em certo casos)
(2 bytes é até 65535, 4 bytes é até 2147483647)

Word = 2 Bytes
Dword = 4 Bytes
Qword = 8 Bytes — lembrando que nossas variáveis INT só cabem 4 bytes. 8 Bytes nem deve existir no GTA SA por ser um jogo de 32 bits.
Float = 4 Bytes

E isso é muito mais dinâmico que você possa imaginar.

Você pode ter o ponteiro de literalmente qualquer coisa (desde que você consiga, de alguma forma).

Por exemplo:
Código:
GET_VAR_POINTER var1 (pvar1)
A variável "pvar1" terá o ponteiro para a variável "var1".

Se por exemplo a variável "var1" contém uma string (text label) com valor "ABCDEF" e agora você fizer isto:
Código:
pvar1 += 2
WRITE_MEMORY pvar1 1 (0x41) FALSE // 0x41(65) = "A"
Agora a variável "var1" terá o valor "ABADEF", pois eu peguei o ponteiro para a (o início da) variável "var1", subi 2 bytes (ou seja, duas letras) e escrevi o valor hexadecimal "0x41" lá (que é o mesmo de decimal "65", só muda a forma de escrever), que é o hexadecimal para a letra "A" maiúscula. Com size de 1 byte, pois é só 1 letra. Se fosse "size 2" o nosso "A" sobrescreveria duas letras, ficando "ABAAEF". Está entendendo?

Sabendo que no fim de uma string contém um "null terminator" (você lembra da parte 9 do tutorial?) dizendo "fim da string", se nós escrevêssemos o valor "0" ali (que é o valor para o null), a string da variável "var1" seria, de fato, somente "AB", pois agora você colocou o null terminator ("0") logo após o "B" e assim agora a string só é considerada até lá. Interessante, não? Não que isso seja útil ao criar mods simples, mas ilustra muito bem o que temos aqui.

Este é só um dos exemplos mais "avançados" e "dinâmicos" que você pode fazer, onde, de fato, você pode imaginar qualquer coisa, desde que entenda como os valores são armazenados numa memória (o que as vezes pode ser confuso, mas você vai aprendendo com o tempo).




Esta é só a primeira parte de uma parte mais avançada deste tutorial, e você ainda verá muito sobre endereços de memória, ponteiros, offsets etc nas próximas partes.
Neste momento você pode treinar um pouco com a lista que já citei aqui, mesmo que não tenha tanta coisa, há bastante coisa útil.

Aqui no fórum há um tópico específico para compilar uns locais onde você pode encontrar mais endereços de memórias / ponteiros, e até mesmo offsets:
http://brmodstudio.forumeiros.com/t3754-medio-locais-para-encontrar-enderecos-de-memoria


Próxima parte:
Thread Memory


Última edição por Junior_Djjr em Qua 26 Jul 2017, 18:36, editado 2 vez(es)

______________________________

avatar
Scripter CLEO - Básico
Scripter CLEO - Básico
Mensagens : 1023
Reputação : 82
Desde : 04/03/2013
Idade : 17
Ver perfil do usuário
  • Reputação da mensagem: 100% (1 votos)

Re: M.1. Introdução à manipulação de memória

em Sex 14 Jul 2017, 10:36
Quantidade de bytes e valores mínimos e máximos:
avatar
Scripter CLEO - Avançado
Scripter CLEO - Avançado
Título : Não quero acreditar, quero saber.
Mensagens : 21893
Reputação : 676
Desde : 03/05/2012
Idade : 22
Localização : Ibitinga - SP
Link : www.MixMods.com.br
Ver perfil do usuáriohttp://MixMods.com.br

Re: M.1. Introdução à manipulação de memória

em Sex 14 Jul 2017, 16:09
Raramente você encontrará os endereços do GTA SA informados destas maneiras.

______________________________

avatar
Mensagens Nível 1
Mensagens Nível 1
Mensagens : 8
Reputação : 0
Desde : 03/08/2016
Idade : 14
Localização : Caixas City - RJ
Ver perfil do usuário

Re: M.1. Introdução à manipulação de memória

em Ter 18 Jul 2017, 00:13
Usei um endereço de memória da lista para montar um script teste, onde mostra o ID do clima atual (apertando a letra R) e poder alterar o ID, para mais ou para menos (tecla A para adicionar e tecla D para diminuir). Só que eu não sabia que existia ID negativo no GTA e quando fui abaixar para o ID -8, a água começou a se esparramar para todo lado e acabou levantando e capotando o veículo onde eu estava (igual mod de Tsunami, só que era do próprio jogo o bug). Achei que ia voltar de volta para o clima 0, mas foi parar no clima -65546 ._.

Spoiler:

Código:
SCRIPT_START
{
NOP

LVAR_INT current_weather

main_loop:
WAIT 0

READ_MEMORY 0xC81320 4 FALSE current_weather

IF IS_KEY_PRESSED VK_KEY_R
    PRINT_FORMATTED_NOW "ID do clima atual: %i" 300 current_weather
ENDIF

IF IS_KEY_PRESSED VK_KEY_M
    current_weather += 1
    WRITE_MEMORY 0xC81320 4 current_weather FALSE
    WAIT 300
ENDIF

IF IS_KEY_PRESSED VK_KEY_N
    current_weather -= 1
    WRITE_MEMORY 0xC81320 4 current_weather FALSE
    WAIT 300
ENDIF

GOTO main_loop

}
SCRIPT_END
avatar
Mensagens Nível 4
Mensagens Nível 4
Título : Arthropod ¬¬
Mensagens : 332
Reputação : 11
Desde : 02/06/2017
Localização : Vila Velha; Estado do Espírito Santo; Brazil;
Link : 127.0.0.1:80
Ver perfil do usuário

Re: M.1. Introdução à manipulação de memória

em Ter 18 Jul 2017, 00:58
Id negativo? Creio que não. Você provavelmente truncou o valor que, provavelmente, não é signado. Eu te sugiro tentar escrever dois bytes ao invés de quatro bytes.

______________________________
avatar
Mensagens Nível 1
Mensagens Nível 1
Mensagens : 8
Reputação : 0
Desde : 03/08/2016
Idade : 14
Localização : Caixas City - RJ
Ver perfil do usuário

Re: M.1. Introdução à manipulação de memória

em Ter 18 Jul 2017, 01:20
Bem que eu achei estranho ter "ID negativo" ali: era o 4  mesmo que tava permitindo ir para a casa dos negativos e causando o erro dos números se multiplicando na casa dos negativos. Então, no caso do Tsunami made in Gta, o ID para causar esse bug na verdade é 65528 ao invés de -8, como eu tinha falado. Aliás, nesses IDs pertos do 65528, o clima fica doido assim como a água e o Sol (que em alguns climas tem efeito de Espectro visível ao invés do Sol)

E obrigado por ter me ajudado a achar o erro (WINK)

______________________________
Eu tô aqui. Você tem + 2 desejos ♥ u-u
avatar
Scripter CLEO - Avançado
Scripter CLEO - Avançado
Título : Não quero acreditar, quero saber.
Mensagens : 21893
Reputação : 676
Desde : 03/05/2012
Idade : 22
Localização : Ibitinga - SP
Link : www.MixMods.com.br
Ver perfil do usuáriohttp://MixMods.com.br

Re: M.1. Introdução à manipulação de memória

em Ter 18 Jul 2017, 07:25
Por isso que causou o bug, pois "não existe".
Assim como você realmente errou na quantidade de bytes à serem escritos, está lá no site que é 2 bytes ("0xC81320 - [word] Current weather")

Pelo menos já conseguiu ter noção das loucuras que o jogo pode ter caso escrever incorretamente os locais da memória.

______________________________

avatar
Mensagens Nível 1
Mensagens Nível 1
Mensagens : 9
Reputação : 0
Desde : 18/07/2017
Idade : 26
Localização : parana
Ver perfil do usuário

Re: M.1. Introdução à manipulação de memória

em Seg 07 Ago 2017, 04:24
1-alguem poderia escrever um script com o ultimo exemplo que foi apresentado? eu tentei escrever de varias formas e so deu erro!!

2-e tambem... nao consegui entender esse ultimo exemplo... como assim "subiu dois bytes"? a string era ABCDEF e ficou ABADEF, ou seja, voltamos duas letras...(????????)

3- "quem", realmente alterou esse 'C' para 'A'??? foi a linha: pvar1 += 2? ou foi o 0x41 que sobrescreveu o 'C'????

4- veja essa img a seguir... como eu faço para obter o valor do 'centro de massa x'???  la em cima (abaixo de handling) tem um 'pointer', la em baixo, ao lado do texto detacado tem um +0x14... como assim (mais)0x14, o que eu faço meu Deus!!!!!!!!!!

avatar
Scripter CLEO - Básico
Scripter CLEO - Básico
Título : Noob
Mensagens : 933
Reputação : 30
Desde : 13/08/2015
Localização : Passo de Torres - SC
Ver perfil do usuário

Re: M.1. Introdução à manipulação de memória

em Seg 07 Ago 2017, 12:53
@ThiagoD escreveu:1-alguem poderia escrever um script com o ultimo exemplo que foi apresentado? eu tentei escrever de varias formas e so deu erro!!

2-e tambem... nao consegui entender esse ultimo exemplo... como assim "subiu dois bytes"? a string era ABCDEF e ficou ABADEF, ou seja, voltamos duas letras...(????????)

3- "quem", realmente alterou esse 'C' para 'A'??? foi a linha: pvar1 += 2? ou foi o 0x41 que sobrescreveu o 'C'????

4- veja essa img a seguir... como eu faço para obter o valor do 'centro de massa x'???  la em cima (abaixo de handling) tem um 'pointer', la em baixo, ao lado do texto detacado tem um +0x14... como assim (mais)0x14, o que eu faço meu Deus!!!!!!!!!!

[img]

1) Tô com preguiça de fazer :/
2) Ele subiu 2 bytes. Cada caractere tem 1 byte, logo se ele subiu 2, ele subiu 2 letras.  A
3) Foi o 0x41 que ele escreveu.
4) Leia o tutorial sobre classes.

Edit: Visual bugado... a 2 ficou com a mensagem cortada :/. Mensagem inteira: https://pastebin.com/d7JSNGn3

______________________________
Caso te ajudei em algo, clique no botão de reputação (o "coraçãozinho" na parte de cima da mensagem).
avatar
Scripter CLEO - Básico
Scripter CLEO - Básico
Mensagens : 1023
Reputação : 82
Desde : 04/03/2013
Idade : 17
Ver perfil do usuário

Re: M.1. Introdução à manipulação de memória

em Seg 07 Ago 2017, 13:14
Código:
SCRIPT_START
{
    LVAR_INT pAnimal
    LVAR_TEXT_LABEL16 animal

    SET_LVAR_TEXT_LABEL16 animal "PATO" // escreve PATO na string animal

    GET_VAR_POINTER $animal (pAnimal) // pega o ponteiro da string animal e salva na variavel pAnimal

    WRITE_MEMORY pAnimal 1 0x41 FALSE // escreve o char 0x41 (A) (ver tabela ASCII) no começo da string

    PRINT_STRING_NOW $animal 5000 // vai printar AATO
    WAIT 5000

    pAnimal += 1 // vamos mais um byte a frente, agora estamos no segundo elemento da string

    WRITE_MEMORY pAnimal 1 0x42 FALSE // escreve o char 0x42 (B) no segundo elemento da string

    PRINT_STRING_NOW $animal 5000 // vai printar ABTO

    // ....
}
SCRIPT_END
Conteúdo patrocinado

Re: M.1. Introdução à manipulação de memória

Permissão deste fórum:
Você não pode responder aos tópicos neste fórum