Created
October 23, 2019 22:21
-
-
Save klecko/761f696b3a73266f011f3499dd173a82 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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