Risolto TCP Proxy WinSock

Stato
Discussione chiusa ad ulteriori risposte.

pvssygino

Utente Silver
4 Luglio 2015
29
3
17
53
Salve a tutti, sto cercando di creare un proxy TCP che faccia da intermedio tra Client e il Server di un gioco per consentirmi di visualizzare i pacchetti scambiati tra il client e il server di gioco. Di seguito il codice C che ho implementato:

Gameclient.exe <->(recv) TCP proxy (send)<-> GameServer

C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")

#define PORT 8080

int main(int argc, char* argv[]) {
    WSADATA wsa;
    SOCKET s, new_socket;
    struct sockaddr_in server, client;
    int c;

    printf("\nInitializing Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
        printf("WSAStartup fallito. Errore!: %d", WSAGetLastError());
        return 1;
    }

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Impossibile creare il socket! : %d", WSAGetLastError());
    }

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_port = htons(PORT);

    if (bind(s, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
        printf("Impossibile comunicare! %d", WSAGetLastError());
    }

    listen(s, 3);

    puts("Aspettando connessioni..");
    c = sizeof(struct sockaddr_in);
    while ((new_socket = accept(s, (struct sockaddr*)&client, &c)) != INVALID_SOCKET) {
        puts("Connessione accettata!");

        SOCKET server_socket = socket(AF_INET, SOCK_STREAM, 0);
        if (server_socket == INVALID_SOCKET) {
            printf("Impossibile creare il socket: %d", WSAGetLastError());
            return 1;
        }

        struct sockaddr_in server_address;
        server_address.sin_family = AF_INET;
        server_address.sin_addr.s_addr = inet_addr("Remote IP SERVER");
        server_address.sin_port = htons(RemotePORTSERVER);
        if (connect(server_socket, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) {
            printf("Errore di connessione");
            return 1;
        }

        char buffer[1024];
        int bytes_received;
        while ((bytes_received = recv(new_socket, buffer, sizeof(buffer), 0)) > 0) {
            send(server_socket, buffer, bytes_received, 0);
            memset(buffer, 0, sizeof(buffer));

            bytes_received = recv(server_socket, buffer, sizeof(buffer), 0);
            send(new_socket, buffer, bytes_received, 0);
            memset(buffer, 0, sizeof(buffer));
        }

        closesocket(server_socket);
        puts("Server Remoto disconnesso");

        closesocket(new_socket);
        puts("Connessione client terminata");
    }

    WSACleanup();

    return 0;
}
Soltanto che non capisco come mai il proxy non funzioni.. ho verificato che la porta scelta sia abilitata alle connessioni in entrare ed in uscita nel firewall, ovviamente eseguo il proxy prima di aprire il client di gioco ma nulla. Il proxy resta sempre in attesa di una connessione, anche quando effettivamente avvio il gioco. Qualcuno potrebbe aiutarmi? Vi ringrazio in anticipo.
 
Il proxy resta sempre in attesa di una connessione, anche quando effettivamente avvio il gioco.

Questa frase mi fa pensare che non vedi stampare Connessione accettata. Visto che hai messo i controlli dell'errore prima sospetto che il gioco non stia provando a connettersi a 127.0.0.1:8080, come hai dirottato il traffico? Via file hosts, hooking, patch...? Riesci a vedere con wireshark se sta provando a connettersi da un altra parte?

Non so di che gioco si parla e che protocollo usa ma quel loop di recv e send mi sembra sospetto, ti faccio un esempio: se il gioco manda qualcosa ma è solo una parte o comunque non si aspetta una risposta del server, fa subito dopo recv su server_socket che potrebbe andare in timeout perché il server aspetta ancora una richiesta intera a cui rispondere. Dovresti anche uscire dal loop, chiudendo entrambe le connessioni, quando recv ritorna <= 0.
 
Questa frase mi fa pensare che non vedi stampare Connessione accettata. Visto che hai messo i controlli dell'errore prima sospetto che il gioco non stia provando a connettersi a 127.0.0.1:8080, come hai dirottato il traffico? Via file hosts, hooking, patch...? Riesci a vedere con wireshark se sta provando a connettersi da un altra parte?

Non so di che gioco si parla e che protocollo usa ma quel loop di recv e send mi sembra sospetto, ti faccio un esempio: se il gioco manda qualcosa ma è solo una parte o comunque non si aspetta una risposta del server, fa subito dopo recv su server_socket che potrebbe andare in timeout perché il server aspetta ancora una richiesta intera a cui rispondere. Dovresti anche uscire dal loop, chiudendo entrambe le connessioni, quando recv ritorna <= 0.
Hey ciao, ti ringrazio per la risposta. E' proprio come dici tu, il client del gioco non dirotta il traffico all'indirizzo 127.0.0.1:8080. Il fatto è che quando il gioco si apre si collega ad una porta locale che è dinamica, di conseguenza non posso avviare il proxy impostando la porta a priori perchè la conosco soltanto dopo aver avviato il gioco. Controllando la porta utilizzata tramite netstat cambia sempre, anche se mi sono accorto che resta in un certo range. In ogni caso dovrei avviare il proxy prima del gioco.. vorrei sapere se c'è un modo per conoscere la porta del gioco ancora prima che si avvii per poter configurare il proxy, oppure se posso forzare il traffico del gioco ad essere ascoltato su una determinata porta. Avviando il proxy e utilizzando telnet 127.0.0.1:8080 il proxy riceve la connessione in entrata, quindi presumo il codice sia giusto,col gioco non funziona perchè se cambio 8080 con la porta locale su cui si basa, al successivo avvio del gioco questa verrà cambiata
 
Hey ciao, ti ringrazio per la risposta. E' proprio come dici tu, il client del gioco non dirotta il traffico all'indirizzo 127.0.0.1:8080. Il fatto è che quando il gioco si apre si collega ad una porta locale che è dinamica, di conseguenza non posso avviare il proxy impostando la porta a priori perchè la conosco soltanto dopo aver avviato il gioco. Controllando la porta utilizzata tramite netstat cambia sempre, anche se mi sono accorto che resta in un certo range. In ogni caso dovrei avviare il proxy prima del gioco.. vorrei sapere se c'è un modo per conoscere la porta del gioco ancora prima che si avvii per poter configurare il proxy, oppure se posso forzare il traffico del gioco ad essere ascoltato su una determinata porta. Avviando il proxy e utilizzando telnet 127.0.0.1:8080 il proxy riceve la connessione in entrata, quindi presumo il codice sia giusto,col gioco non funziona perchè se cambio 8080 con la porta locale su cui si basa, al successivo avvio del gioco questa verrà cambiata

Immagino che per GameServer intendi un server remoto su internet, ma la connessione che stai cercando di intercettare da codice deve essere verso localhost, perché il gioco dovrebbe contattare 127.0.0.1 e non 123.123.123.123, ipotetico indirizzo del game server? Non ho capito a quale porta locale dinamica ti riferisci, il gioco ha forse più componenti che usano socket locali come IPC e tu vuoi intercettare quelle? Oppure vuoi far da proxy semplicemente alla connessione diretta che parte da clientgioco.exe e va all'IP remoto del GameServer? In quest'ultimo caso non importa la porta locale, conta quella remota, devi fare bind sulla stessa porta su cui ascolta il gameserver e poi trovare il modo per dirottare il traffico es. con file hosts:
127.0.0.1 server.di.gioco.com
Se invece è un IP statico dovrai fare un hook, una patch o cose più avanzate con driver di rete, injection...
 
Ultima modifica:
Scusami, forse non mi sono spiegato bene. Ti faccio un esempio :
quando mi collego al gioco e verifico come il mio client sta comunicando con il server tramite netstat o WireShark verifico che vi è una connessione stabilita cosi:
127.0.0.1:56703 -> ipremotodelserver : porta statica server di gioco
la porta che ora ho scritto con 56703 cambia ogni qual volta il gioco viene aperto. Se setto il tcp proxy ad ascoltare in locale su 127.0.0.1:56703 mentre il gioco è aperto, ovviamente non posso accedere a quella porta e mi da errore nell'inizializzazione del proxy, se chiudo e riapro il gioco la porta 56703 viene aggiornata in un altra e quindi il proxy ora sarà in ascolto su 127.0.0.1:56703 -> ipremotodelserver : porta statica server di gioco, ma la porta di gioco in locale è già cambiata
 
Quella porta viene scelta dal sistema operativo tra quelle libere ed assegnata al socket creato dal client di gioco. Guarda tu stesso con wireshark o netstat: anche telnet aprirà un socket client con alla sorgente una porta casuale. Consiglio questa risposta per fare chiarezza sulle porte locali. Ci sono tanti modi come ho detto per ottenere il risultato voluto e redirigere il traffico su localhost (o anche da altre parti), semplicemente da sistema non è prevista un API semplice che permetta a un processo medium integrity di fare quel che voglia con i socket degli altri processi suoi pari.

Ricordo bene un thread dove questo argomento è già stato trattato ed è disponibile il codice per la soluzione via dll injection che fa hooking su send e recv nel processo di gioco:

Comunque se il gioco usa un nome di dominio fisso faresti molto molto prima a scriverlo nel file hosts così puoi usare il codice che hai già scritto qua con qualche modifica (alla porta se necessario e al loop come ho detto prima).
 
  • Mi piace
Reazioni: pvssygino
Grazie per la delucidazione, se qualcuno vuole utilizzare il codice non c'è nulla di errato, e' soltanto necessario, come ha chiarito @JunkCoder, reindirizzare i pacchetti in locale. Per quanto riguarda lo sniff tramite le funzioni recv e send presenti nel codice oggetto del gioco, sapevo come poterle utilizzare per vedere lo scambio di pacchetti, ma volevo visualizzare il traffico tramite un software esterno e non tramite injection. Ti ringrazio tanto per i chiarimenti @JunkCoder, per me si può anche chiudere.
 
Stato
Discussione chiusa ad ulteriori risposte.