Здравствуй, хабр! Мой прошлый пост «Как мы читы разрабатывали или кого сгубила жадность» вызвал у многих мракобесие, и в одном из советов от меня требовали конкретики. Требовали — держите мануал о том, как можно заменить Игровой Центр Mail.Ru (заодно расскажу про систему авторизации в Игровом Центре Mail.ru). Поехали!
Что нам понадобится?
Во-первых, нам нужен сервер с установленным на него PHP.Во-вторых, нам нужна Visual Studio для разработки на C#В-третьих, как можно было догадаться, нам нужна ОС Windows.Разберемся с авторизацией Игрового Центра
(далее ГЦ)
1. Первым делом ГЦ отправляет на сервер запрос с логином/мэйлом и паролем пользователя (обращается к php-скрипту).2. В ответе скрипт отсылает xml-данные в виде simple-xml, содержащий GcToken3. ГЦ отправляет второй запрос на сервер параметром GcAuth4. В ответе скрипт отсылает xml, содержащий SessionKey, Uid, Token, MinVersion и Timestamp5. ГЦ запускает игру с Токеном, номером сервера и UidНачинаем разработку
Сначала напишем веб-интерфейс для управления программой
Создаем простую html-страничку с кнопкой «Start» и пишем JS-код для отправки POST-запросов и получения данных.
Центр Игр
Регистрируем протокол, по которому будем осуществлять связь с программой
Создаем файл starter.regREGEDIT4 [HKEY_CLASSES_ROOT\starter] @=«URL: Starter Protocol» «URL Protocol»=«starter» [HKEY_CLASSES_ROOT\starter\shell] [HKEY_CLASSES_ROOT\starter\shell\open] [HKEY_CLASSES_ROOT\starter\shell\open\command] @=»\«C:\\GameCenter@Mail.Ru.exe\» \»%1\«Откроем файл и добавим данные в реестрПишем клиентское приложение на C#
1.Создаем новый проект Windows Forms в Visual Studio2. Редактируем файл Program.cs
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;
namespace WindowsFormsApplication1
{
static class Program
{
///
/// Главная точка входа для приложения.
///
static String ProcessInput (string s)
{
return s;
}
[STAThread]
private static void Main (string[] args) //объявляем параметры (аргументы)
{
Application.EnableVisualStyles ();
Application.SetCompatibleTextRenderingDefault (false);
foreach (string s in args)
{
string[] arguments; // параметры
string[] arr; // массив
string uid; // ID юзера
string token;// токен (уникальный ключ)
arguments = ProcessInput (s).Split (':');
arr = arguments[1].Split (',');
uid = arr[0];
token = arr[1];
/*- Далее добавляем переменные среды, если их не существует -*/
if (Environment.GetEnvironmentVariable («GC_PROJECT_ID») == null)
// GC_PROJECT_ID 1177
Environment.SetEnvironmentVariable («GC_PROJECT_ID»,»1177»);
if (Environment.GetEnvironmentVariable («GC_TYPE_ID») == null)
// GC_TYPE_ID 0
Environment.SetEnvironmentVariable («GC_TYPE_ID»,»0»);
if (Environment.GetEnvironmentVariable («GC_PIPE_NAME») == null)
// GC_PIPE_NAME GameCenterV3
Environment.SetEnvironmentVariable («GC_PIPE_NAME», «GameCenterV3»);
if (Environment.GetEnvironmentVariable («GC_GCLAY_PATHNAME») == null)
// GC_GCLAY_PATHNAME C:\…\Local\Mail.Ru\GameCenter\GCLay.dll
Environment.SetEnvironmentVariable («GC_GCLAY_PATHNAME», @«Путь к \GameCenter\GCLay.dll»); // Здесь указываем путь к GCLay.dll
if (Environment.GetEnvironmentVariable («CHROME_ALLOCATOR») == null)
// CHROME_ALLOCATOR TCMALLOC
Environment.SetEnvironmentVariable («CHROME_ALLOCATOR», «TCMALLOC»);
Environment.SetEnvironmentVariable («MOZ_CRASHREPORTER_DATA_DIRECTORY»,»);
Environment.SetEnvironmentVariable («MOZ_CRASHREPORTER_RESTART_ARG_0»,»);
Environment.SetEnvironmentVariable («MOZ_CRASHREPORTER_STRINGS_OVERRIDE»,»);
Process.Start («C:\\GamesMailRu\\Warface\\Bin32Release\\Game.exe»,»--shard_id=0 +online_server s0.warface.ru -uid »+uid+» -token »+token); // Запускаем Warface с параметрами
MessageBox.Show («Click [OK] to close»); // Тормозим завершение программы
}
}
}
}
*Скомпилированная программа должна лежать в C:\\GameCenter@Mail.Ru.exeНастраиваем серверную часть
Пишем PHP-скрипты для получения токенов и т.д.
*Мы не будем снифферить отправляемые и принимаемые заголовки, а используем те, которые уже были полученыСоздаем файл gcauth.php
');
// возвращать результат работы
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
// не проверять SSL сертификат
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
// не проверять Host SSL сертификата
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/x-www-form-urlencoded'));
// это необходимо, чтобы cURL не высылал заголовок на ожидание
// выполнить запрос
curl_exec ($ch);
// получить результат работы
$result = curl_multi_getcontent ($ch);
$data = curl_exec ($ch);
$xml = htmlspecialchars ($result);
preg_match ('/SessionKey=[»\']?([^»\' ]*)[»\' ]/is',$xml,$sessionKeyArr); // Выделяем SessionKey из ответа регулярками
preg_match ('/Uid=[»\']?([^»\' ]*)[»\' ]/is',$xml,$uidArr); // То же самое с ID юзера
preg_match ('/Token=[»\']?([^»\' ]*)[»\' ]/is',$xml,$tokenArr); // … с Токеном
preg_match ('/MinVersion=[»\']?([^»\' ]*)[»\' ]/is',$xml,$minVersionArr); // Минимальная версия, нам это не понадобится
//preg_match ('/Timestamp=[»\']?([^»\' ]*)[»\' ]/is',$xml,$timestampArr); // Время, нам тоже не нужно
$SessionKey = str_replace (»\»,»,$sessionKeyArr[1]);
$Uid = str_replace (»\»,»,$uidArr[1]);
$Token = str_replace (»\»,»,$tokenArr[1]);
$replace_quotes = array ('»',»'»);
$MinVersion = str_replace ($replace_quotes,», $minVersionArr[1]);
/*- Выводим данные -*/
echo $SessionKey;
echo »%»;
echo $Uid;
echo »%»;
echo $Token;
echo »%»;
echo trim ($MinVersion);
//echo $Timestamp;
//echo $xml;
//echo $matches;
// закрыть сессию работы с cURL
curl_close ($ch);
?>
Теперь создадим autologin.php
';
curl_setopt ($ch, CURLOPT_POSTFIELDS, $postfield);
// возвращать результат работы
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
// не проверять SSL сертификат
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
// не проверять Host SSL сертификата
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/x-www-form-urlencoded'));
// это необходимо, чтобы cURL не высылал заголовок на ожидание
// выполнить запрос
curl_exec ($ch);
// получить результат работы
$result = curl_multi_getcontent ($ch);
$data = curl_exec ($ch);
$xml = htmlspecialchars ($result);
preg_match ('/PersId=[»\']?([^»\' ]*)[»\' ]/is',$xml,$persIdArr); // Выделяем PersId из массива полученных данных
preg_match ('/Key=[»\']?([^»\' ]*)[»\' ]/is',$xml,$keyArr); // то же самое с Key
$PersId = str_replace (»«,»,$persIdArr[1]);
$Key = str_replace (»«,»,$keyArr[1]);
/*- Выводим полученные данные -*/
echo $PersId;
echo »%»;
echo $Key;
// закрыть сессию работы с cURL
curl_close ($ch);
?>
Теперь осталось лишь залить все на сервер и испытать. На время написания статьи могла быть написана какая-либо проверка еще на что-то.
Спасибо за прочтение мануала. Надеюсь, в чем-то я вам помог, удачи!
Разработчикам Mail.Ru советую доработать клиентское приложение, чтобы исходящие соединения не показывались.