Salut à tous

Je reprends le développement du MultiToolD2 qui était dispo sur Arkalys et Azote pour ceux qui se souviennent, le soft fonctionne pour le moment mais je voulais le faire fonctionner en emulant l’Ankama launcher pour pouvoir lancer ses compte directement depuis le tool, est-ce que quelqu’un a des infos à ce niveau le but serait de pouvoir faire fonctionner le multicompte sur serveur mono compte comme l’outil Frigost

Le soft sera entièrement open source et ouvert à la commu code en C#

Solution 1 emuler le launcher

Solution 2 retourner à l’ancien système de login

Toute info est bonne à prendre

Salut, je connais pas le tool mais j'en ai créé un similaire qui te permet de bind ton client sur l'interface réseau que tu veux et ajouter un proxy. Si t'as besoin d'infos pour récupérer le token regarde ce thread. Pour créer un émulateur il faut juste écouter sur le port 26117 et renvoyer le paquet "auth_getGameToken {token}\0" après avoir récupéré le token, rien de très compliqué.

img

    AzureHaze

    Salut, je connais pas le tool mais j'en ai créé un similaire qui te permet de bind ton client sur l'interface réseau que tu veux et ajouter un proxy. Si t'as besoin d'infos pour récupérer le token regarde ce thread. Pour créer un émulateur il faut juste écouter sur le port 26117 et renvoyer le paquet "auth_getGameToken {token}\0" après avoir récupéré le token, rien de très compliqué.

    img

    As-tu plus d'information?

      Yuxepe

      As-tu plus d'information?

      Par rapport à quoi? Tu bloques à quel endroit?

      J'ai fait rapidement le diagramme de sequence de connexion pour mieux comprendre:

      img

      AzureHaze

      Salut, je connais pas le tool mais j'en ai créé un similaire qui te permet de bind ton client sur l'interface réseau que tu veux et ajouter un proxy. Si t'as besoin d'infos pour récupérer le token regarde ce thread. Pour créer un émulateur il faut juste écouter sur le port 26117 et renvoyer le paquet "auth_getGameToken {token}\0" après avoir récupéré le token, rien de très compliqué.

      img

      Woah j’adore ! Serait tu d’accord pour partager la source ? Ou au moins détailler complètement comment tu a fais pour l’adapter réseau etc ?

      J’avoue ne ps avoir trop de connaissance en réseau et j’ai du mal à comprendre ton diagramme.m bien qu’il soit super détaillé

        Moi aussi j'ai envie d'apprendre :/ parce que j'aime pas le frigost

        Sly

        Woah j’adore ! Serait tu d’accord pour partager la source ? Ou au moins détailler complètement comment tu a fais pour l’adapter réseau etc ?

        J’avoue ne ps avoir trop de connaissance en réseau et j’ai du mal à comprendre ton diagramme.m bien qu’il soit super détaillé

        Flemme de drop les sources mais fais ça par étape,

        Pour binder ton client sur un adaptateur spécifique c'est simple, tu hook la fonction connect() (ws2_32.dll) et tu bind sur ton interface réseau avant de te connecter, tu peux même rajouter un proxy.

        sockaddr_in adapterName{};
        adapterName.sin_addr.s_addr = inet_addr("x.x.x.x"); // ip de l'adaptateur réseau
        adapterName.sin_family = AF_INET;
        adapterName.sin_port = 0;
        bind(s, (sockaddr*)&adapterName, sizeof(adapterName));
        

        Par contre un truc auquel il faut faire attention, sur le client electron il faut que ce soit le bon processus que tu hook (celui lancé avec --utility-sub-type=network.mojom.NetworkService en arguments)

        Yuxepe

        prix vip? :(

        Pas encore released et pas forcément à vendre non plus (c'est pas l'idée du forum). Mais si je pouvais t'aider à dev le tien ce serait avec plaisir.

        Si ça peut t'aider voilà ce que j'utilise pour émuler le launcher directement au niveau de mon client:

        std::optional<std::string> GetToken()
        {
            CURL* curl;
            CURLcode res;
            curl = curl_easy_init();
            std::string token;
        
            try
            {
                const auto data = std::format("login={}&password={}&game_id=101", globals::login, globals::password);
                struct curl_slist* headers = nullptr;
                
                headers = curl_slist_append(headers, "Content-Type: application/json");
                curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
                curl_easy_setopt(curl, CURLOPT_URL, "https://haapi.ankama.com/json/Ankama/v5/Api/CreateApiKey");
                curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
                curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
                curl_easy_setopt(curl, CURLOPT_USERAGENT, "Zaap 3.7.4");
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
                curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.data());
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onResponseWrite);
        
                res = curl_easy_perform(curl);
        
                auto json = nlohmann::json::parse(buffer);
                const auto apiKey = json["key"].get<std::string>();
        
                buffer.clear();
                curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
                curl_easy_setopt(curl, CURLOPT_URL, "https://haapi.ankama.com/json/Ankama/v5/Account/CreateToken?game=101");
                headers = curl_slist_append(headers, std::format("apiKey: {}", apiKey.data()).data());
                curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                res = curl_easy_perform(curl);
        
                json = nlohmann::json::parse(buffer);
                token = json["token"].get<std::string>();
        
                buffer.clear();
            }
            catch (...)
            {
                MessageBoxA(0, "Failed to get game token!", "error", 0);
            }
        
            curl_easy_cleanup(curl);
        
            return token;
        }
        
        DWORD WINAPI StartLauncherEmulator(LPVOID lpData)
        {
            SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
            std::array<char, 4086> buffer{ 0 };
        
            SOCKADDR_IN name;
            name.sin_addr.s_addr = inet_addr("127.0.0.1");
            name.sin_port = htons(globals::launcherPort);
            name.sin_family = AF_INET;
        
            bind(s, (SOCKADDR*)&name, sizeof(name));
            listen(s, 1);
        
            SOCKET client = accept(s, nullptr, nullptr);
        
            int bytesRead = recv(client, buffer.data(), std::size(buffer), 0);
            auto token = GetToken();
            auto response = std::format("auth_getGameToken {}", token->data()) + '\0';
        
            WSABUF buf;
            buf.buf = response.data();
            buf.len = response.size();
            DWORD bytesSent = 0;
            
            WSASend(client, &buf, 1, &bytesSent, 0, nullptr, nullptr);
          
            closesocket(s);
            closesocket(client);
        
            return 0u;
        }

          AzureHaze

          Pas encore released et pas forcément à vendre non plus (c'est pas l'idée du forum). Mais si je pouvais t'aider à dev le tien ce serait avec plaisir

          si quiero aprender pero no se nada de programacion :( estoy 0/0 aun asi puedes? y donde podria contactarte?

          AzureHaze

          Pas encore released et pas forcément à vendre non plus (c'est pas l'idée du forum). Mais si je pouvais t'aider à dev le tien ce serait avec plaisir.

          Si ça peut t'aider voilà ce que j'utilise pour émuler le launcher directement au niveau de mon client:

          std::optional<std::string> GetToken()
          {
              CURL* curl;
              CURLcode res;
              curl = curl_easy_init();
              std::string token;
          
              try
              {
                  const auto data = std::format("login={}&password={}&game_id=101", globals::login, globals::password);
                  struct curl_slist* headers = nullptr;
                 
                  headers = curl_slist_append(headers, "Content-Type: application/json");
                  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
                  curl_easy_setopt(curl, CURLOPT_URL, "https://haapi.ankama.com/json/Ankama/v5/Api/CreateApiKey");
                  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
                  curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
                  curl_easy_setopt(curl, CURLOPT_USERAGENT, "Zaap 3.7.4");
                  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
                  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.data());
                  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onResponseWrite);
          
                  res = curl_easy_perform(curl);
          
                  auto json = nlohmann::json::parse(buffer);
                  const auto apiKey = json["key"].get<std::string>();
          
                  buffer.clear();
                  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
                  curl_easy_setopt(curl, CURLOPT_URL, "https://haapi.ankama.com/json/Ankama/v5/Account/CreateToken?game=101");
                  headers = curl_slist_append(headers, std::format("apiKey: {}", apiKey.data()).data());
                  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                  res = curl_easy_perform(curl);
          
                  json = nlohmann::json::parse(buffer);
                  token = json["token"].get<std::string>();
          
                  buffer.clear();
              }
              catch (...)
              {
                  MessageBoxA(0, "Failed to get game token!", "error", 0);
              }
          
              curl_easy_cleanup(curl);
          
              return token;
          }
          
          DWORD WINAPI StartLauncherEmulator(LPVOID lpData)
          {
              SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
              std::array<char, 4086> buffer{ 0 };
          
              SOCKADDR_IN name;
              name.sin_addr.s_addr = inet_addr("127.0.0.1");
              name.sin_port = htons(globals::launcherPort);
              name.sin_family = AF_INET;
          
              bind(s, (SOCKADDR*)&name, sizeof(name));
              listen(s, 1);
          
              SOCKET client = accept(s, nullptr, nullptr);
          
              int bytesRead = recv(client, buffer.data(), std::size(buffer), 0);
              auto token = GetToken();
              auto response = std::format("auth_getGameToken {}", token->data()) + '\0';
          
              WSABUF buf;
              buf.buf = response.data();
              buf.len = response.size();
              DWORD bytesSent = 0;
             
              WSASend(client, &buf, 1, &bytesSent, 0, nullptr, nullptr);
           
              closesocket(s);
              closesocket(client);
          
              return 0u;
          }

          Est-ce que tu peux me contacter en priver qu’on puisse passer sur discord pour en discuter ?

          Sly

          Salut merci pour les sources ça pourrait être utile mais je ne comprends pas pourquoi le hash est code en dur, je n’ai pas essayé de lancer le jeu avec ta valeur, on a un code fonctionnel pour rétro mais pas sur la version 2 :/

          Ca semble pas poser de problème sur retro que le client n'ait pas défini le hash id mais sur d2 il tente pas de se connecter au launcher si on lui passe pas en argument ^-^

          4 mois plus tard

          AzureHaze

          Pas encore released et pas forcément à vendre non plus (c'est pas l'idée du forum). Mais si je pouvais t'aider à dev le tien ce serait avec plaisir.

          Si ça peut t'aider voilà ce que j'utilise pour émuler le launcher directement au niveau de mon client:

          std::optional<std::string> GetToken()
          {
              CURL* curl;
              CURLcode res;
              curl = curl_easy_init();
              std::string token;
          
              try
              {
                  const auto data = std::format("login={}&password={}&game_id=101", globals::login, globals::password);
                  struct curl_slist* headers = nullptr;
                 
                  headers = curl_slist_append(headers, "Content-Type: application/json");
                  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
                  curl_easy_setopt(curl, CURLOPT_URL, "https://haapi.ankama.com/json/Ankama/v5/Api/CreateApiKey");
                  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
                  curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
                  curl_easy_setopt(curl, CURLOPT_USERAGENT, "Zaap 3.7.4");
                  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
                  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.data());
                  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onResponseWrite);
          
                  res = curl_easy_perform(curl);
          
                  auto json = nlohmann::json::parse(buffer);
                  const auto apiKey = json["key"].get<std::string>();
          
                  buffer.clear();
                  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
                  curl_easy_setopt(curl, CURLOPT_URL, "https://haapi.ankama.com/json/Ankama/v5/Account/CreateToken?game=101");
                  headers = curl_slist_append(headers, std::format("apiKey: {}", apiKey.data()).data());
                  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                  res = curl_easy_perform(curl);
          
                  json = nlohmann::json::parse(buffer);
                  token = json["token"].get<std::string>();
          
                  buffer.clear();
              }
              catch (...)
              {
                  MessageBoxA(0, "Failed to get game token!", "error", 0);
              }
          
              curl_easy_cleanup(curl);
          
              return token;
          }
          
          DWORD WINAPI StartLauncherEmulator(LPVOID lpData)
          {
              SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
              std::array<char, 4086> buffer{ 0 };
          
              SOCKADDR_IN name;
              name.sin_addr.s_addr = inet_addr("127.0.0.1");
              name.sin_port = htons(globals::launcherPort);
              name.sin_family = AF_INET;
          
              bind(s, (SOCKADDR*)&name, sizeof(name));
              listen(s, 1);
          
              SOCKET client = accept(s, nullptr, nullptr);
          
              int bytesRead = recv(client, buffer.data(), std::size(buffer), 0);
              auto token = GetToken();
              auto response = std::format("auth_getGameToken {}", token->data()) + '\0';
          
              WSABUF buf;
              buf.buf = response.data();
              buf.len = response.size();
              DWORD bytesSent = 0;
             
              WSASend(client, &buf, 1, &bytesSent, 0, nullptr, nullptr);
           
              closesocket(s);
              closesocket(client);
          
              return 0u;
          }

          Lorsque j'utilise ce code, j'ai un code d'erreur 1020 quelqu'un sait à quoi ça correspond ?

            5 jours plus tard

            kei3004

            Lorsque j'utilise ce code, j'ai un code d'erreur 1020 quelqu'un sait à quoi ça correspond ?

            Oui c'est le code retour de cloudflare qui est un WAF (wab application firewall), il détecte les requêtes douteuses. Pour contourner ça tente de forcer le tls 3, fait des test avec postman pour voir déjà si la requête fonctionne avant de l'implémenter dans du code.

            Fait attention aux entêtes et aux paramètres de ta requêtes.

            Le tout c'est de tester et re tester jusqu'à ce que ta requête passe avec certains paramètres. C'est pas une science exacte les protections cloudflare car personne sait vraiment comment elles fonctionnent.