Comunidade Clash

 


Você não está conectado. Conecte-se ou registre-se

Ver o tópico anterior Ver o tópico seguinte Ir em baixo  Mensagem [Página 1 de 1]

#1
 Gabriel

Fundador
Fundador

avatar
Memory Hacking.





Os códigos de programação deste tutorial destinam-se, exclusivamente, para fins de estudos e pesquisas. Sua utilização para outras finalidades é de responsabilidade de seus usuários.



Denomina-se memory hacking o ato de mexer, de forma interna, em uma porção da memória principal do computador que é restrita a um determinado programa .



Com isso é possível, por exemplo, fazer um processo que mude o valor de uma variável de outro processo.



A Windows API será utilizada nos códigos, portanto, estes só funcionarão em ambiente Windows .



Também trabalharemos com o jogo Grand Theft Auto: San Andreas 1.0, software de código fechado que permite modificações de acordo com sua licença.





1 - Requerimentos.




Consideremos os seguintes tipos de endereços de memória :



Físico - O endereço físico é o utilizado pelo processador para manipular a memória principal. Na presença de endereços virtuais, ele é obtido pelo núcleo do sistema operacional com uma conversão.


Lógico - O lógico é aquele que é trabalhado nos programas, em linguagens como C e Assembly. Ele pode ser igual ao endereço físico ou igual ao endereço virtual, dependendo do sistema operacional.


Virtual - É um endereço especial. Em alguns casos, como no Windows, os processos são forçados a mexerem em endereços dessa categoria para torná-los isolados uns dos outros, evitar que o sistema seja derrubado por seus erros de execução, etc .


Base - Endereço que serve como referencial a todo um bloco de dados.


Estático - Esse endereço sempre é representado pelo mesmo número e aponta para o mesmo dado na memória.


Dinâmico - É o endereço de uma informação o qual muda.



Atualmente, o Windows e muitos sistemas operacionais fazem com que os programas executados neles considerem "endereços virtuais" como endereços de memória.



Por isso, seria impossível construir um executável que, só com ponteiros, efetuasse um memory hacking em outro .



Contudo, no Windows, com privilégios administrativos, pode-se elaborar técnicas para o memory hacking com a Windows API. Algumas destas serão abordadas a seguir.






2 - WriteProcessMemory.




O nome dessa função significa "escrever memória de processo" .



Ela serve basicamente para alterar o valor de uma variável de um processo específico.



Veremos agora como ficaria um código que mudasse a quantidade de dinheiro do personagem do jogo GTA pelo nome de seu executável:


Código:
Código:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>



int main(void)
{
    puts("Valor em dado do processo modificado.");
    getchar();
    return 0;
}
Essa estrutura é de uma aplicação console .



Os arquivos de cabeçalho stdio.hwindows.h e tlhelp32.h definiriam as funções puts e getchar, muitas funções da Windows API, e, a funçãoCreateToolhelp32Snapshot, respectivamente.



A partir daqui, os códigos mostrados ficariam no main.


Código:
Código:

HANDLE ProcessoHandle;
DWORD Valor = 500;
LPVOID Endereco = (LPVOID) 0xB7CE50;
Essas variáveis fariam o seguinte: ProcessoHandle armazenaria o handle do processo a ser afetado, Endereco o endereço da variável do processo a ser modificada e Valor o novo valor que ela teria.



De modo mais abstrato, a variável Valor conteria o total de dinheiro no jogo GTA: San Andreas e a variável Endereco, o seu endereço estático (pois sempre é 0xB7CE50) .



Sendo gta_sa.exe o nome do executável que originaria o processo do GTA, o próximo código seria:


Código:
Código:

HANDLE SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
PROCESSENTRY32 Lista;
Lista.dwSize = sizeof(PROCESSENTRY32);
Process32First(SnapshotHandle, &Lista);
do
{
    if(!strcmp(Lista.szExeFile, "gta_sa.exe"))
    {
        ProcessoHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Lista.th32ProcessID);
    }
}
while(Process32Next(SnapshotHandle, &Lista));
CloseHandle(SnapshotHandle);
Primeiramente criamos uma variável chamada SnapshotHandle. Esta armazena o handle de um snapshot (uma espécie de gravação) de todos os processos existentes no momento, que é feito pela função CreateToolhelp32Snapshot.



Em seguida declaramos uma struct de nome Lista para guardar as informações dos processos do snapshot, um de cada vez.



A chamada do Process32First grava as informações do primeiro processo em Lista, permitindo que o nome de seu executável seja acessado na construção if que é lida logo depois .



Nesse if, verifica-se se aquele nome é igual a gta_sa.exe. Caso sim, a função OpenProcess gera um handle para o processo (pelo seu ID, também obtido de Lista), que é armazenado na variável ProcessoHandle (lembra dela ?).



Os outros processos são analisados devido às execuções do Process32Next, que ficou no while justamente para percorrer todos eles.



Por fim, CloseHandle torna inválido o handle do snapshot que utilizamos, uma vez que não precisamos mais dele.



Agora, lembra do primeiro argumento do OpenProcess ? Ele era PROCESS_ALL_ACCESS, constante que oferece, entre outros, o direito de escrever na memória do processo indicado.



Com isso, já podemos usar a função WriteProcessMemory, e efetuar o memory hacking :


Código:
Código:

WriteProcessMemory(ProcessoHandle, Endereco, &Valor, sizeof(Valor), NULL);
O valor da variável cujo endereço está em Endereco seria alterado para o valor em Valor.



A quantidade de dinheiro no jogo seria modificada também.



Só faltaria então, invalir o handle do processo que criamos:


Código:
Código:

CloseHandle(ProcessoHandle);
Para o memory hacking via WriteProcessMemory estar completado.



O código final seria :


Código:
Código:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>



int main(void)
{
    HANDLE ProcessoHandle;
    DWORD Valor = 500;
    LPVOID Endereco = (LPVOID) 0xB7CE50;
    HANDLE SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    PROCESSENTRY32 Lista;
    Lista.dwSize = sizeof(PROCESSENTRY32);
    Process32First(SnapshotHandle, &Lista);
    do
    {
        if(!strcmp(Lista.szExeFile, "gta_sa.exe"))
        {
            ProcessoHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Lista.th32ProcessID);
        }
    }
    while(Process32Next(SnapshotHandle, &Lista));
    CloseHandle(SnapshotHandle);
    WriteProcessMemory(ProcessoHandle, Endereco, &Valor, sizeof(Valor), NULL);
    CloseHandle(ProcessoHandle);
    puts("Valor em dado do processo modificado.");
    getchar();
    return 0;
}



3 - ReadProcessMemory.




O nome dessa função, por sua vez, significa "ler memória de processo".



Em termos de código, a aplicação dela difere do WriteProcessMemory principalmente em sua chamada :


Código:
Código:

ReadProcessMemory(ProcessoHandle, Endereco, &Valor, sizeof(Valor), NULL);
No caso, a variável Valor que seria alterada, passando a conter o valor no endereço de memória armazenado em Endereco.



Se efetuada no GTA, por exemplo, essa função serviria para obter dados do jogo, como a quantidade de vida do personagem.



Exemplo em código completo de executável :


Código:
Código:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>



int main(void)
{
    HANDLE ProcessoHandle;
    DWORD Valor;
    LPVOID Endereco = (LPVOID) 0xB7CE50;
    HANDLE SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    PROCESSENTRY32 Lista;
    Lista.dwSize = sizeof(PROCESSENTRY32);
    Process32First(SnapshotHandle, &Lista);
    do
    {
        if(!strcmp(Lista.szExeFile, "gta_sa.exe"))
        {
            ProcessoHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Lista.th32ProcessID);
        }
    }
    while(Process32Next(SnapshotHandle, &Lista));
    CloseHandle(SnapshotHandle);
    ReadProcessMemory(ProcessoHandle, Endereco, &Valor, sizeof(Valor), NULL);
    CloseHandle(ProcessoHandle);
    printf("Valor em dado do processo obtido: %d.", Valor);
    getchar();
    return 0;
}




4 - Injeção de DLL.




Essa é a mais complexa das técnicas, porém fornece um controle melhor.



Fundamenta-se em forçar um processo a carregar uma DLL (biblioteca dinâmica) com códigos de memory hacking.



O que é acontece é que, com a DLL carregada, as memórias dela e do processo ficam unidas, permitindo que um modifique o outro diretamente.



A maneira mais simples de lidar com o processo através da DLL é com a keyword __asm do Microsoft C .



Isso quer dizer que, mexeremos, dentro de códigos C, com um pouco de Assembly nesta seção do tutorial.



Vamos, antes disso, construir a função para injetar a DLL:


Código:
Código:

VOID InjetarDLL(HANDLE ProcessoHandle, PCHAR CaminhoDLL)
{

}
O parâmetro ProcessoHandle serviria para passar o handle do processo a carregar a DLL e o parâmetro CaminhoDLL para passar o caminho da DLL ao corpo da função InjetarDLL.



A partir daqui, os códigos citados ficariam nessa função .


Código:
Código:

INT TamanhoCaminho = strlen(CaminhoDLL) + 1;
LPVOID EnderecoFoco = VirtualAllocEx(ProcessoHandle, NULL, TamanhoCaminho, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(ProcessoHandle, EnderecoFoco, CaminhoDLL, TamanhoCaminho, NULL);
A variável TamanhoCaminho armazenaria o tamanho, em bytes, da string do caminho da DLL.



VirtualAllocEx reservaria memória no espaço do processo para colocar o caminho da DLL lá. O ponteiro EnderecoFoco guardaria o valor retornado: o endereço base do conjunto de dados .



E então, WriteProcessMemory preencheria aquela porção de memória com o caminho da DLL.


Código:
Código:

HMODULE Kernel32Handle = GetModuleHandle("kernel32.dll");
LPTHREAD_START_ROUTINE Kernel32Funcao = (LPTHREAD_START_ROUTINE) GetProcAddress(Kernel32Handle, "LoadLibraryA");
HANDLE ThreadHandle = CreateRemoteThread(ProcessoHandle, NULL, 0, Kernel32Funcao, EnderecoFoco, 0, NULL);
WaitForSingleObject(ThreadHandle, INFINITE);
Bem, GetModuleHandle retorna o handle da DLL carregada kernel32.dll (da Windows API), do nosso programa.



Depois, cria-se a variável Kernel32Funcao, que armazena o endereço da DLL correspondente à função LoadLibraryA .



Poteriormente a função CreateRemoteThread é executada com algumas das variáveis que declaramos. Isso resulta em uma nova thread (sub-processo) para o processo no qual queremos fazer o memory hacking.



Acontece que a nova thread acaba tendo o LoadLibraryA como sua função principal e o endereço do caminho da DLL (que reservamos anteriormente) como o argumento dela.



Isso já faz com que a DLL seja carregada na memória do processo .



WaitForSingleObject espera a execução da thread terminar, para que possamos remover tudo que agora é desnecessário:


Código:
Código:

DWORD DLLHandle;
GetExitCodeThread(ThreadHandle, &DLLHandle);
CloseHandle(ThreadHandle);
VirtualFreeEx(ProcessoHandle, EnderecoFoco, TamanhoCaminho, MEM_RELEASE);
Com a variável DLLHandle, pega-se o código de saída da thread. Esse é o mesmo retorno do LoadLibraryA, logo, o número de handle dele.



Em seguida, o CloseHandle destrói a thread e invalida seu handle .



VirtualFreeEx libera a string do caminho da DLL.


Código:
Código:

Kernel32Funcao = (LPTHREAD_START_ROUTINE) GetProcAddress(Kernel32Handle, "FreeLibrary");
ThreadHandle = CreateRemoteThread(ProcessoHandle, NULL, 0, Kernel32Funcao, (LPVOID) DLLHandle, 0, NULL);
WaitForSingleObject(ThreadHandle, INFINITE);
CloseHandle(ThreadHandle);
Para descarregar a DLL, executamos, no processo, o FreeLibrary com o handle da DLL como seu argumento, do mesmo jeito que fizemos com o LoadLibraryA e o caminho da DLL.



WaitForSingleObject espera o processamento da thread terminar, e, por fim, o CloseHandle destrói-a e invalida seu handle.



O código final:


Código:
Código:

VOID InjetarDLL(HANDLE ProcessoHandle, PCHAR CaminhoDLL)
{
    INT TamanhoCaminho = strlen(CaminhoDLL) + 1;
    LPVOID EnderecoFoco = VirtualAllocEx(ProcessoHandle, NULL, TamanhoCaminho, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(ProcessoHandle, EnderecoFoco, CaminhoDLL, TamanhoCaminho, NULL);
    HMODULE Kernel32Handle = GetModuleHandle("kernel32.dll");
    LPTHREAD_START_ROUTINE Kernel32Funcao = (LPTHREAD_START_ROUTINE) GetProcAddress(Kernel32Handle, "LoadLibraryA");
    HANDLE ThreadHandle = CreateRemoteThread(ProcessoHandle, NULL, 0, Kernel32Funcao, EnderecoFoco, 0, NULL);
    WaitForSingleObject(ThreadHandle, INFINITE);
    DWORD DLLHandle;
    GetExitCodeThread(ThreadHandle, &DLLHandle);
    CloseHandle(ThreadHandle);
    VirtualFreeEx(ProcessoHandle, EnderecoFoco, TamanhoCaminho, MEM_RELEASE);
    Kernel32Funcao = (LPTHREAD_START_ROUTINE) GetProcAddress(Kernel32Handle, "FreeLibrary");
    ThreadHandle = CreateRemoteThread(ProcessoHandle, NULL, 0, Kernel32Funcao, (LPVOID) DLLHandle, 0, NULL);
    WaitForSingleObject(ThreadHandle, INFINITE);
    CloseHandle(ThreadHandle);
}
Lembra do lugar onde colocávamos o WriteProcessMemory/ReadProcessMemory nas partes anteriores do tutorial ?



A função de injetar DLL deveria ser chamada em locais como aquele, onde há um handle de processo válido, etc.



Vejamos como ficaria o source da DLL :



Código:
Código:

#include <windows.h>



int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void *lpReserved)
{
    return 1;
}
No corpo do DllEntryPoint, ficariam os códigos Assembly para o memory hacking:



Código:
Código:

#define Endereco 0x863984
FLOAT Valor = 0.0005;
__asm
{
    mov eax, Valor
    mov [Endereco], eax
}
Esse código alteraria a gravidade do jogo, mudando o valor da variável responsável por isso através de seu endereço.



Código:
Código:

#define Endereco 0x863984
FLOAT Valor;
__asm
{
    mov eax, [Endereco]
    mov Valor, eax
}
Já esse copiaria o valor da variável da gravidade, pelo seu endereço, para a variável Valor.



E a melhor parte, subprogramas :



Código:
Código:

#define Endereco 0x439600
__asm
{
    mov eax, Endereco
    call eax
}
Isso chamaria uma das funções do GTA a partir de seu endereço.



O resultado no jogo seria a obtenção de uma jetpack (mochila a jato).






5 - Outros.




Os endereços do GTA trabalhados até o momento eram estáticos: apontavam sempre para os mesmos elementos do jogo.



Quando um endereço de um mesmo dado varia, ele é dinâmico .



Seria preciso outro dado de endereço fixo que atuasse como referencial, se quiséssemos obter um valor em um endereço dinâmico.



No caso do GTA, por exemplo, há a vida do jogador.



Para conseguir seu endereço, deve-se realizar este cálculo:



(Valor no endereço 0xB6F5F0) + (0x540)



Programas mapeadores de memória, como o Cheat Engine, ajudam a encontrar endereços de dados específicos .




Espero ter ajudado .

http://comunidadeclash.forumbrasil.net

#2
 leco


avatar
Belo topico Parabéns

#3
 Gabriel

Fundador
Fundador

avatar
kkk eu tava testando o background

http://comunidadeclash.forumbrasil.net

#4
 Conteúdo patrocinado


Ver o tópico anterior Ver o tópico seguinte Voltar ao Topo  Mensagem [Página 1 de 1]


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