Skip to content

Instantly share code, notes, and snippets.

@klecko
Created October 23, 2019 22:21
Show Gist options
  • Save klecko/761f696b3a73266f011f3499dd173a82 to your computer and use it in GitHub Desktop.
Save klecko/761f696b3a73266f011f3499dd173a82 to your computer and use it in GitHub Desktop.
/*
Este otro ejemplo está hecho para el cliente de un juego basurilla que hice con unos amigos:
https://github.com/klesoft/Anime-Battle-Online
El objetivo es crear un aimbot. Para ello, hookeamos la función recvfrom y parseamos los paquetes,
de manera que podamos tener las posiciones de los jugadores en todo momento. También hookeamos
la función sendto para guardar el socket y el sockaddr, de manera que podamos pasarlos como argumentos
cuando más tarde llamemos nosotros a sendto para enviar un paquete que dispare a la posición
del jugador seleccionado.
*/
#define _CRT_SECURE_NO_DEPRECATE
//DETOUR: Introduce un salto al inicio de sendto a hooked_sendto (tipo sendto_t). Esta puede interactuar con los argumentos. Al final de hooked_sendto se llama a una funcion que ejecuta
//las lineas sobreescritas por el JMP, y despues salta a sendto despues del JMP. Después hooked_sendto guarda lo que devuelve sendto original, y lo devuelve.
//Se llama a sendto --> salta a hooked_sendto --> codigo hack --> llama a funcion sendto_original -->
//--> ejecuta lineas faltantes en trampoline --> salta a sendto --> return sendto y vuelta a hooked_sendto -->
//--> hookedsendto devuelve lo que devuelve sendto --> fin.
#include <Windows.h>
#include <iostream>
#include <vector>
#include "detours.h"
#include "sigscan.h"
#pragma comment(lib, "detours.lib")
//Importo la librería de sockets para llamar yo a sendto, pero no es necesario,
//puedo llamar a originalSendto como en el otro ejemplo.
#pragma comment(lib, "WS2_32.lib")
typedef int (WINAPI *sendto_t)(SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen);
sendto_t originalSendto = 0;
struct sockaddr *originalSendSockaddr = new struct sockaddr;
SOCKET originalSocket = 0;
typedef int(WINAPI *recvfrom_t)(SOCKET s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen);
recvfrom_t originalRecvfrom = 0;
bool packetLogging = true;
struct Jugador{
int n;
int posx;
int posy;
};
std::vector<Jugador> Jugadores;
inline const char * const BoolToString(bool b)
{
return b ? "ON" : "OFF";
}
bool checkIfPlayerExists(int n)
{
for (Jugador player : Jugadores)
if (player.n == n) return true;
return false;
}
Jugador* getpPlayerByNumber(int n)
{
int i = 0;
for (Jugador player : Jugadores) {
if (player.n == n)
return &(Jugadores[i]);
i++;
}
}
int getIndexOfPlayerByNumber(int n)
{
int i = 0;
for (Jugador player : Jugadores){
if (player.n == n)
return i;
i++;
}
return -1;
}
std::vector<char*> splitPacket(char* packet, const char* delimiter)
{
std::vector<char*> result;
char* token = strtok(packet, delimiter);
while (token)
{
result.push_back(token);
//std::cout << token << std::endl;
token = strtok(NULL, delimiter);
}
return result;
}
int WINAPI hooked_sendto(SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen)
{
char* packet = new char[len + 1];
strncpy(packet, buf, len);
packet[len] = '\0';
if (packetLogging)
std::cout << "[PACKET][SEND] " << packet << std::endl;
*originalSendSockaddr = *to;
//SINONIMO: memcpy(original_sockaddr, to, sizeof(struct sockaddr));
originalSocket = s;
delete(packet);
return originalSendto(s, buf, len, flags, to, tolen);
}
int WINAPI hooked_recvfrom(SOCKET s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen)
{
int ret = originalRecvfrom(s, buf, len, flags, from, fromlen); //it calls the original function and saves what it returns
//it is necessary because the buf is empty until the function has been called and we have actually received something
char* packet = new char[ret + 1];
strncpy(packet, buf, ret);
packet[ret] = '\0';
if (packetLogging){
std::cout << "[PACKET][RECV] " << packet << std::endl;
}
std::vector<char*> packetSplitted = splitPacket(packet, "|");
if (!strcmp(packetSplitted[0], "pos")){
if (!checkIfPlayerExists(atoi(packetSplitted[1]))){
Jugador player;
player.n = atoi(packetSplitted[1]);
player.posx = atoi(packetSplitted[2]);
player.posy = atoi(packetSplitted[3]);
Jugadores.push_back(player);
//std::cout << "Nuevo jugador numero " << player.n << std::endl;
} else {
Jugador* player = getpPlayerByNumber(atoi(packetSplitted[1])); //&Jugadores[0];
player->posx = atoi(packetSplitted[2]);
player->posy = atoi(packetSplitted[3]);
//std::cout << "Jugador numero " << player->n << " ha cambiado su posicion: " << player->posx << " " << player->posy << std::endl;
}
} else if (!strcmp(packetSplitted[0], "bye")) {
Jugadores.erase(Jugadores.begin() + getIndexOfPlayerByNumber(atoi(packetSplitted[1])));
std::cout << "Jugador eliminado. " << std::endl;
}
/*int i = 0;
for (i = 0; i < packetSplitted.size(); i++)
{
std::cout << packetSplitted[i] << " ";
}
std::cout << std::endl;*/
delete(packet);
return ret;
}
void Hacks()
{
bool shooting = false;
int playerIndex = 0;
while (true) {
if (GetAsyncKeyState(VkKeyScan('1'))) {
packetLogging = !packetLogging;
std::cout << "[PACKET] PacketLogging is now " << BoolToString(packetLogging) << std::endl;
}
if (GetAsyncKeyState(VkKeyScan('2'))) {
if (originalSocket == 0)
std::cout << "[BOT] ERROR: Send function has not been called yet" << std::endl;
else {
shooting = !shooting;
std::cout << "[BOT] Shooting is now " << BoolToString(shooting) << std::endl;
}
}
if (GetAsyncKeyState(VK_TAB)){
//CAMBIAR int player
if ((playerIndex+1) == Jugadores.size()) //if it is pointing to the last player, now it points the first one
playerIndex = 0;
else //else, it points the next player
playerIndex = playerIndex + 1;
std::cout << "[BOT] Now pointing to player number " << Jugadores[playerIndex].n << ", index " << playerIndex << std::endl;
}
if (shooting){
char msg[40];
sprintf(msg, "shoot|%d|%d|", Jugadores[playerIndex].posx, Jugadores[playerIndex].posy);
sendto(originalSocket, msg, strlen(msg), 0, originalSendSockaddr, 16);
}
Sleep(200);
}
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH){
AllocConsole();
freopen("CONOUT$", "w", stdout); //Creates a console
std::cout << "[HELLO] Welcome to Hacking Anime Battle Online, a wonderful hack made by the creator of Anime Battle Online who has hacked his own game. Enjoy!" << std::endl;
SigScan Scanner; //Looks for the functions, and saves its locations
DWORD sendto_address = Scanner.FindPattern("WS2_32.dll", "\x8B\xFF\x55\x8B\xEC\x83\xEC\x14\x53\x56\x8B\x35\x00\x00\x00\x00\x33\xDB\x57\xBF\x00\x00\x00\x00\x3B\xF7\x0F\x85\x00\x00\x00\x00\x39\x1D\x00\x00\x00\x00\x74\x1E\xFF\x35\x00\x00\x00\x00\xFF\x15\x00\x00\x00\x00\x89\x45\xF8\x85\xC0\x74\x05\x89\x5D\xFC\xEB\x26\x8B\x35\x00\x00\x00\x00\x3B\xF7\x0F\x85\x00\x00\x00\x00\x8D\x45\xF8\x50\x8D\x45\xF4\x50\xE8\x00\x00\x00\x00\x89\x45\xFC", "xxxxxxxxxxxx????xxxx????xxxx????xx????xxxx????xx????xxxxxxxxxxxxxx????xxxx????xxxxxxxxx????xxx");
DWORD recvfrom_address = Scanner.FindPattern("WS2_32.dll", "\x8B\xFF\x55\x8B\xEC\x83\xEC\x14\x53\x56\x8B\x35\x00\x00\x00\x00\x33\xDB\x57\x81\xFE\x00\x00\x00\x00\x0F\x84\x00\x00\x00\x00\x8D\x45\xF8\x50\x8D\x45\xF4\x50\x81\xFE\x00\x00\x00\x00\x0F\x85\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x89\x45\xFC\x85\xC0\x0F\x85\x00\x00\x00\x00\x8B\x4D\x08\xE8\x00\x00\x00\x00\x8B\xF8\x85\xFF\x0F\x84\x00\x00\x00\x00\x8B\x45\x10\x8D\x4D\xFC\x8B\x77\x0C\x89\x45\xEC\x8B\x45\x0C\x51", "xxxxxxxxxxxx????xxxxx????xx????xxxxxxxxxx????xx????x????xxxxxxx????xxxx????xxxxxx????xxxxxxxxxxxxxxxx");
std::cout << "[HOOK] sendto function found: " << std::hex << sendto_address << std::endl;
std::cout << "[HOOK] recvfrom function found: " << recvfrom_address << std::dec << std::endl;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(LPVOID&)sendto_address, &hooked_sendto); //here sendto_address is changed:
//when it puts a jump at the beggining of the function, it overwrites a few lines. in order to fix that, it creates a new function godknowswhere in which it writes those lines,
//and then that function jumps to sendto after the jump. so the new sendto_address is the address of that function.
std::cout << "[HOOK] Send detour made" << std::endl;
DetourAttach(&(LPVOID&)recvfrom_address, &hooked_recvfrom);
std::cout << "[HOOK] Recv detour made" << std::endl;
DetourTransactionCommit();
std::cout << "[HOOK] Both detours commited" << std::endl;
originalSendto = (sendto_t)sendto_address; //the original_sendto function is located at sendto_address.
originalRecvfrom = (recvfrom_t)recvfrom_address;
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Hacks, 0, 0, 0);
std::cout << "[PACKET] Packetlogging ON. Press 1 to turn it off" << std::endl << "[BOT] Shooting OFF. Press 2 to turn it on, and TAB to change the player you're pointing to" << std::endl;
}
else if (dwReason == DLL_PROCESS_DETACH)
{
/*DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach((PVOID*)sendto_address, &hooked_sendto);
DetourTransactionCommit();*/
}
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment