Статьи Низкоуровневое исследование клиента игровой платформы Garena

Discussion in 'Статьи' started by Dosia, 14 Aug 2009.

  1. Dosia

    Dosia Member

    Joined:
    5 Jun 2009
    Messages:
    118
    Likes Received:
    81
    Reputations:
    6
    Низкоуровневое исследование игровой платформы Garena (или попросту реверсинг популярного игрового клиента)​

    0) Небольшое вступление (собственно о самом пациенте)​

    Гарена (англ. Garena, сокр. от Global Arena, до этого называлась GG client) представляет собой платформу для игр через интернет и мгновенного обмена сообщениями, чем-то похожую на Xfire. Распространяется на основе принципа «Free 2 Play», что позволяет не тратить на неё деньги либо тратить деньги на микроплатежи, оплачивая дополнительные возможности. Основной аудиторией являются игроки в DotA Allstars — пользовательскую карту игры Warcraft III The Frozen Throne. Garena набрала популярность среди игроков благодаря возможности играть без лицензионной версии игры с хорошим пингом, наличию защиты от программ-читов и ненадобности производить какие-либо настройки (например, Hamachi имеет аналогичные функции, но требует немало действий для начала игры).

    Источник (Более подробное описание)

    Так как игровой клиент распространяется на основе принципа «Free 2 Play», см выше, то в нем существует ряд ограничений, которые доступны только после покупки “Gold” статуса. Собственно о возможности снятия этих ограничений и будет рассказано в данной статье.

    1) План действий:​

    a) Уберем защиту от отладки
    b) Уберем проверку изменений модулей
    c) Уберем проверку изменений исполняемого файла
    d) Уберем таймер на вход в комнату
    e) Показ ping’a пользователей цифрами
    f) Уберем проверку на использование запрещенных программ (читов, например maphack’a)
    g) Уберем flood защиту из чата
    h) Уберем ограничение на запуск одной копии программы
    На этом я предлагаю остановится, так как цель данной статьи (показать основные принципы) считаю достигнутой, а все остальное вы уже сможете сделать и сами.

    2) Принятые обозначения:​

    Что то очень важное
    Обозначение разделов
    Обозначение чего то что следует выделить (ключевые слова)
    Первое упоминание о команде
    Справка по команде (функции)
    Адрес команды
    Переходы
    Команда
    Название API функций

    3) Кнопки на панели инструментов:​

    [​IMG]

    1. Reopen- Отладчик перезагрузит файл и остановится на точке входа. Hotkey ("Ctrl+F2")
    2. Run - Запуск программы на выполнение. Hotkey ("F9")
    3. Pause - Остановка выполнения программы. Hotkey ("F12")
    4. Step into - Трассируя программу в этом режиме отладчик будет заходить во все вызываемые функции и процедуры. Hotkey ("F7")
    5. Step over - Отладчик не будет заходить в функцию (он конечно это сделает, но без нас ;D а мы в свою очередь попадем на следующую за только что выполненной командой строку программы). Hotkey ("F8")
    6. Executable modules - Исполняемые модули программы. Hotkey ("ALT+E")
    7. Call stack - Отображение текущего стека вызова. Hotkey ("ALT+K")
    8. Breakpoints - Отображение списка точек останова. Hotkey ("ALT+B")

    4) Подготовка​

    a) Нам потребуется отладчик (1.3 МБ)
    b) Справочник по api функциям (16.1 МБ)
    Можно скачать уже распакованную версию (6.99 МБ)
    c) Сам пациент – клиент игровой платформы Garena (5.6 МБ)
    Зеркало (5.61 МБ)
    d) Так же желательно наличие поверхностных знания команд ассемблера

    5) Настройка отладчика​

    Запускаем отладчик, идем в меню “Options” -> “Debugging options”. В появившемся окне выбираем вкладку "Exceptions" (Исключения), устанавливаем все переключатели (отмечаем их галочкой). Правее есть кнопка “Add range”, жмем, в поле “First exceptions in range“ вводим “00000000” (8 нулей), в поле “Last exceptions in range“ вводим “FFFFFFFF” (8 букв “F”), жмем “OK”.
    [​IMG]

    Закрываем окно настроек отладчика нажатием “OK”. Теперь в случае возникновения исключения во время работы программы, она не будет прерываться и требовать нашего вмешательства ;D
    Для более глубокого понимания темы я попросил вас скачать справочную документацию по API функциям os windows. Настроим отладчик на использование данного справочника следующим образом:
    Выбираем меню “Help” -> “Select API help file”, указываем путь к win32.hlp (извлеченного из “MSHELP.exe”)
    Все, теперь все готово и можно приступать к основной части статьи

    6) Исследование программы

    a) Уберем защиту от отладки​


    Апдейт игрового клиента от 11.09.09 приподнес нам небольшой сюрприз в виде защиты от отладки.

    Сразу хочу сказать что с антиотладкой мне помог Flint_ta, за что ему огромное спасибо.

    Суть антиотладки заключается в загрузке драйвера, который бы скрывал процесс “garena.exe” от диспетчера задач и от оли собственно тоже, вызывается функция “CreateServiceW” из библиотеки “ADVAPI32.dll”, которая в свою очередь вызвана из “Gengine.dll”. Рассмотрим антиотладку более подробно:

    В оле уже загружена “Garena.exe”, но отладчик не запущен на выполнение, мы находимся на точке входа в программу, жмем на листинге правой кнопкой “Search for” -> “Name (label) in current module” или жмем “Ctrl+N”. Начинаем набор текста (активное окно – окно отладчика): “LoadLibrary”:

    Функция LoadLibrary отображает заданный исполняемый модуль в адресное пространство вызывающего процесса. Для загрузки с дополнительными параметрами, используется функция LoadLibraryEx.

    СинтаксисHMODULE LoadLibrary(
    LPCTSTR lpFileName
    );

    Параметры:

    lpFileName
    Указатель на символьную строку с нулем в конце, которая именует исполняемый модуль (или .dll или .exe файл). Указанное имя - это имя файла модуля и оно не связано с именем самого сохраняемого в библиотеке модуля, как это определено ключевым словом LIBRARY в (.def) файле определения модуля.

    Если строка определяет путь, но файл не существует в указанном каталоге, функция завершается ошибкой. Когда определяется путь, убедитесь, что использованы наклонные черты влево(обратные слэши (\)), а не прямые слэши (/).

    Если символьная строка не определяет путь, функция использует стандартную стратегию поиска файла. Дополнительную информацию см. в разделе Замечания.

    Возвращаемые значения:
    Если функция завершается успешно, возвращаемое значение - дескриптор модуля.


    Функция найдена “LoadLibraryW”, кликаем на строчку, вызываем контекстное меню, жмем “Set breakpoint on every reference”, только что мы поставили точку останова каждом вызове этой функции. Теперь можно и запустить отладчик, жмем “F9”. Грузится какая то библиотека:

    [​IMG]

    Название этой библиотеки мы можем увидеть в стеке (на рисунке отмечено синим прямоугольником). Скажу наперед, нас эта библиотека не интересует (чтобы не терять время мы сразу перейдем к нужной, если хотите, можете методом проб и ошибок выйти на нее ;D). И так нас интересует загрузка библиотеки “Gengine.dll”, если вы пошли методом проб и ошибок, то после её загрузки вы можете увидеть абсолютно чистую олю, без опкодов, таким образом вам сразу станет ясно, почему стоит уделить внимание именно этой библиотеке. Жмем “F9”, пока не окажемся тут 4F85DD:

    [​IMG]

    Сейчас происходит загрузка библиотеки “AvoidCrackPlugin.dll” (название в синем прямоугольнике). Но если вы нажмете “F9”, то увидите, что по этому же адресу 4F85DD происходит загрузка следующей библиотеки: “Gengine.dll”. Жмем “ALT+E” или идем в меню “View” -> “Executable modules”, после чего перед нами появляется список всех модулей используемых программой (“Garena.exe”). Нас, как уже было сказано выше, интересует библиотека “ADVAPI32.dll”. В колонке “Name” находим название “ADVAPI32”:

    [​IMG]

    Оля любезно сообщила нам что это системная библиотека, написав после её названия “(system)”. Двойной щелчек по строке с названием “ADVAPI32” и мы находимся непосредственно в ней. Жмем “Ctrl+N”, так как нас интересует список всех функций данного модуля. Начинаем набирать текст: “CreateService”:

    Функция CreateService создает сервис (службу)

    SC_HANDLE CreateService(

    SC_HANDLE hSCManager, // Указывает на указатель, возвращенный функцией OpenSCManager
    LPCTSTR lpServiceName, // Указывает на имя службы
    LPCTSTR lpDisplayName, // Указывает на имя, которое будет использовано пользовательским интерфейсом
    DWORD dwDesiredAccess, // Флаги определяющие права доступа к службе
    DWORD dwServiceType, // Тип создаваемого сервиса
    DWORD dwStartType, // Определяет способ запуска службы
    DWORD dwErrorControl, // Указывает на способ обработки возникающих ошибок
    LPCTSTR lpBinaryPathName, // Указатель на строку (заканчивающуюся нулём), которая содержит полный путь к исполняемому файлу сервиса
    LPCTSTR lpLoadOrderGroup, // Указатель на строку (заканчивающуюся нулём), которая содержит имя группы, членом которой является сервис.
    LPDWORD lpdwTagId, // Указатель на переменную, в которую будет записан уникальное значение тэга, которое идентифицирует группу, указанную в параметре lpLoadOrderGroup.
    LPCTSTR lpDependencies, // Указатель на массив (завершающийся двумя нулями) имён (разделённых нулями) сервисов или групп сервисов, которые система должна запустить до запуска этого сервиса.
    LPCTSTR lpServiceStartName, // Указатель на строку (завершающуюся нулём), которая содержит имя аккаунта, с правами которого будет запущен сервис.
    LPCTSTR lpPassword // Указатель на строку (заканчивающуюся нулём), которая содержит пароль к аккаунту, указанному в параметре lpServiceStartName.
    );


    Более подробно о функции можно почитать тут

    Функция найдена “CreateServiceW”, жмем на ней “F2”, Смотрим список бряков – все ок:

    [​IMG]

    После чего, жмем “F9” и мы оказываемся тут:

    [​IMG]

    Из рисунка отчетливо видно, что мы сейчас стоим на вызове той самой функции создания сервиса “ CreateServiceW ”, вызванной из модуля “GEngine”. Параметры вызова с которыми была вызвана функция вы можете увидеть в стеке. Переходим по адресу с которого был произведен вызов: 04874B88 (на рисунке – синий прямоугольник) . Для этого жмем “ALT+E”, Выбираем в колонке “Name” модуль “Gengine”, который собственно только что был загружен (“LoadLibraryW” по адресу 4F85DD в модуле “Garena”). Переходим в модуль “Gengine” по двойному щелчку, после чего жмем “Ctrl+G”, вводим адрес с которого произошел вызов (04874B88), после чего оказываемся тут:

    [​IMG]

    Что мы тут видим? По адресу 04874B88 происходит вызов “ADVAPI32. CreateServiceW”. Также мы можем увидеть имя драйвера создаваемого драйвера: “sys_GarenaPEngine.sys”. Нас интересуют переход выше вызова “ CreateServiceW ”, находящийся по адресу 04874B64. Поставим туда брейкпоинт (точку останова), жмем правой кнопкой по адресу перехода: 04874B64, вызываем контекстное меню (правая кнопка мыши) после чего, выбираем “Breakpoint” -> “Hardware, on execution”. Убираем бряк с адреса вызова функции “CreateServiceW” из модуля “ADVAPI32”, для этого идем в “View” -> “Breakpoints”, выделяем строку (она там будет 1), в колонке "Name" у которой будет написано “ADVAPI32”, жмем “Del”. Теперь перезапускаем программу в отладчике, жмем “F9”. Жмем “F9” на вызове “LoadLibraryW” в модуле “Garena” (дважды, так как сначала грузится “AvoidCrackPlugin.dll”) , после чего прерываемся на бряке. Что говорит оля по поводу перехода?

    [​IMG]

    Меняем флаг “Z” на противоположный, дважды щелкнув по нему:

    [​IMG]

    Смотрим что с переходом: “Jump is taken”. Отлично. Заменим условный переход по адресу: 04874B64 на безусловный “JE” заменим на “JMP”. Проходим по переходу с помощью “F8”. Тут надо сказать вам, почему мы не отпускаем программу в свободное плавание, нажав “F9”, а словно ожидая подвоха, трассируем по “F8”: Дело в том что я уже само собой проделал все это перед написанием данной статьи и могу вам сказать, что после того как мы выйдем из этого вызова, мы окажемся тут (4874448):

    [​IMG]

    Что же мы тут видим? А все очень просто, программа предпринимает еще одну попытку создания сервиса, по адресу 487444F видим переход, который может избавить нас от участи сидеть перед окном пустого отладчика. Меняем условный переход “JNZ SHORT 048744CB” на “JMP SHORT 048744CB”. Отлично. При желании можно немного потрассировать программу по “F8” и убедится, что теперь все в порядке. Но я надеюсь, вы поверите мне на слово. Итак, подведем итог, мы только что сделали 2 изменения в модуле “Gengine”, который является динамической библиотекой. Мы должны сохранить результат нашей работы. Жмем правую кнопку мыши на листинге, вызывая контекстное меню, выбираем:
    Copy to executable” -> “All modifications”, после чего нас спросят действительно ли мы хотим копировать все изменения сделанные в коде программы, жмем “Copy all”, в появившемся окне жмем правую кнопку, вызывая всплывающее меню, выбираем “Save file”, указываем имя файла и его местоположение (%Garena%\plugins\UI\GEngine.dll), после чего жмем “Сохранить”. Хочу обратить ваше внимание на то, что не лишним будет переименовать оригинальный файл “GEngine.dll”, на всякий случай ;D После чего уже сохранять изменный. Убираем все брейкпоинты, в том числе и hardware, для этого идем в меню "Debug" -> "Hardware breakpoints", удаляем их и перезапускаем клиента игровой платформы в отладчике. Запускаем на выполнение “F9”. Опс, что же мы видим?

    [​IMG]

    Garena сообщает нам о ошибке проверки файла. Что тут можно сказать? Не стоит ничего проверять и сейчас мы отучим garen’у делать это.

    Еще раз хочу сказать спасибо Flint_ta, за помощь с антиотладкой.

    b) Уберем проверку изменений модулей​


    Перезагружаем программу “Ctrl+F2”, что же происходит? При загрузке библиотеке garena проверяет контрольную сумму файла, так как мы файл изменили, то и контрольная сумма теперь другая, что же делать? В начале мы с вами уже были на загрузки “Gengine.dll”, помните? “LoadLibraryW” по адресу 4F85DD в модуле “Garena”. Именно оттуда мы начали свой путь. Идем по этому адресу “Gtrl+G”, вводим “4F85DD”, “OK”. Смотрим что у нас тут:

    [​IMG]

    Выше загрузки библиотеки, по адресу 4F85DA видим переход непосредственно на наш наг, информирующий о ошибке проверки файла (на рисунке выделен зеленым цветом). Выше по адресу: 4F85C8 видим переход, который переносит нас через “плохой переход”. После загрузки библиотеки по адресу: 4F85E5 также существует проверка условия, в случае если переход будет выполнен (на рисунке отмечен коричневым цветом), мы можем получить еще одно плохое сообщение, которое будет вызвано примерно тут:

    [​IMG]

    Делаем следующее:
    1) По адресу 4F85C8 меняем условный переход “JE SHORT 004F85DC” на безусловный “JMP SHORT 004F85DC ”, что позволит нам избавится от первого плохого сообщения.
    2) По адресу 4F85E5 занопаем переход (забьем командами “NOP” = ничего не делать). Этим мы избавимся от второго плохого сообщения.
    Собственно это все, теперь мы сохраняем сделанные изменения в файле “Garena.exe” (как? смотри выше).

    c) Уберем проверку изменений исполняемого файла​


    Собственно эта проверка не дает клиенту успешно соединится с сервером игры и авторизовать клиента.

    В далеком прошлом, когда еще не было антиотладки и все мапхакеры и прочие читеры жили припеваючи, была написана данная статья: "Снимаем таймер подключения в Garena Client". Именно по ней вы должны убрать проверку изменения исполняемого файла "Garena.exe" сомостоятельно. Зачем я тогда описал пункт "b"? Чтобы вам было удобнее и понятнее, так как были изменения в коде и виртуальные адреса сместились. Ну а проверка изменения исполняемого файла происходит из "AvoidCrackPlugin.dll", который был изменен еще в незапамятные времена, соответсвенно все адреса для этого модуля остались прежними и вам будет довольно удобно (я надеюсь) проделать все описанные в статье изменения. Для тех же у кого возникли трудности, в конце статьи вы найдете файл со всеми изменнеными нами файлами, которые вы сможете поковырять сами ;D
     
    #1 Dosia, 14 Aug 2009
    Last edited: 19 Sep 2009
    27 people like this.
  2. Dosia

    Dosia Member

    Joined:
    5 Jun 2009
    Messages:
    118
    Likes Received:
    81
    Reputations:
    6
    Низкоуровневое исследование post 2 of 4

    d) Уберем таймер на вход в комнату​


    Открываем отладчик, жмем “File” -> “Open” или "F3", указываем путь к “Garena.exe
    Отладчик остановился на оригинальной (настоящей) точке входа (OEP), файл ничем не упакован (это к слову).
    Жмем “F9” (Run) или воспользуемся кнопкой на панели инструментов. Отладчик запускает программу на выполнение.
    a) Дальше просто – вбиваем свой логин и пароль и пробуем зайти в какую – нибудь полную комнату (туда где больше 225 человек). Так как мы являемся простыми пользователями, то с большой долей вероятности получаем в ответ нежелательное сообщение (nag screen), говорящий примерно следующее: "Комната переполнена, не желаете ли потратить деньги и купить себе статус привилегированного пользователя?". Назовем это нежелательное сообщение nag1.
    Попробовав зайти в комнату еще раз и если не прошло 5 секунд, мы получим второе нежелательное сообщение: "Вы можете попытаться зайти в комнату не чаще одного раза в 5 секунд". Назовем это сообщение nag 2.
    Вот их то мы и должны будем убрать.

    Заходим в комнату, получаем nag1, переключаемся на отладчик. Внимание! сразу как только вы получили nag1 вы, не закрывая nag возвращаетесь в окно отладчика. Жмем “F12” (Pause) или воспользуемся кнопкой на панели инструментов. Также можно воспользоваться меню “Debug” -> “Pause”.Отладчик приостанавливает выполнение программы.
    Жмем "ALT+K", отладчик показывает текущий стек вызова. Будет что то вроде этого:

    [​IMG]

    Выше вызова (на рисунке фиолетовый прямоугольник):
    Code:
    0012E6B8   05028C70   AdPlugin.050288B0                     AdPlugin.05028C6B
    Видим вызов функции "DialogBoxParamW”, дважды кликнем на эту строку (на рисунке фиолетовый прямоугольник):
    Code:
    0012E6B8   05028C70   AdPlugin.050288B0                     AdPlugin.05028C6B
    Оказываемся по адресу 050288B0, перед нами процедура:

    [​IMG]

    Именно тут происходит вызов нашего nag1, собственно сам вызов происходит тут (на рисунке синий прямоугольник):

    Code:
    050288D8   FF15 10220305    CALL DWORD PTR DS:[<&USER32.DialogBoxPar>; USER32.DialogBoxParamW
    
    А 5 параметров, необходимых для её вызова (которые мы уже видели в Call stack) пушатся в стек выше (на рисунке фиолетовый прямоугольник):

    Code:
    050388CE   50               PUSH EAX
    050388CF   68 60880305      PUSH AdPlugin.05038860
    050388D4   51               PUSH ECX
    050388D5   6A 6D            PUSH 6D
    050388D7   52               PUSH EDX
    
    Казалось бы решение найдено - занопаем вызов функции и поставленная цель достигнута, но не тут то было ;D Дело в том, что я уже пробовал этот вариант, после него программа падает с ошибкой. Что же нам делать? Посмотрим еще раз на процедуру, в ней мы не видим никаких переходов, так что исправлять по сути нечего, нечего в этой процедуре, а в той из которой была вызвана эта, вполне вероятно можно будет что то исправить, давайте посмотрим. Так как наш nag1 уже вызван и ждет когда мы на него нажмем, то мы поставим брейкпоинт на следующий за вызовом нага (050288D8) адрес (050288DE), по которому находится команда "RETN 8".
    команда RETN (англ. RETURN – возврат) означает конец процедуры или функции и передает управление назад, на следующую инструкцию процедуры(функции), из которой был осуществлен вызов.
    Теперь мы снова запустим программу на выполнение, нажав "F9", после чего возвращаемся к окну garena, жмем "Отмена", прерываемся на бряке, смотрим комментарий оли:

    Code:
    Return to 05028C70 (AdPlugin.05028C70)
    Жмем "F8", переходим по адресу возврата (05028C70):

    [​IMG]

    Видим выше вызова 4 перехода (o_O):
    1) 05028C0A "JNZ SHORT AdPlugin.05028C87"
    2) 05028C1A "JNZ SHORT AdPlugin.05028C87"
    3) 05028C26 "JL SHORT AdPlugin.05028C87"
    4) 05028C33 "JNZ SHORT AdPlugin.05028C87"

    Но все они ведут на один и тот же адрес, нам нужно поправить какой то переход, чтобы он перенес нас через вызов nag1, скажу сразу не на первый (05028C0A), так как если вы поставите бряк на первый переход и запустите программу на выполнение, то тут же прерветесь на нем, переход не будет выполнен, очевидно какой то таймер использует этот участок кода. Поменяем второй переход (05028C1A), условный переход "JNZ SHORT AdPlugin.05028C87" мы
    заменим на безусловный "JMP SHORT AdPlugin.05028C87", для этого щелкнем на строке по адресу 05028C1A, жмем "space bar", после чего набираем "JMP SHORT AdPlugin.05028C87" и жмем "assemble" . После чего запустим программу на выполнение. Попробуем войти в комнату - увидим видоизмененной сообщение, теперь в нем нет рекламной вставки. Значит основная наша задача заключалась именно в том, чтобы убрать nag1(в который потом уже добавляется рекламная вставка). Теперь мы можем заняться именно "каркасом (основой)" nag1

    Это сообщение мы уберем другим способом:
    Не закрываем "недоделанный nag1". Переходим к окну отладчика, жмем "F12" ("Pause"). Теперь жмем “ALT+F9”, или идем в меню “Debug” -> “Execute till user code”, затем снова возвращаемся к окну игрового клиента и жмем “Отмена” в nag1, после чего мы оказываемся тут:

    [​IMG]

    Выше мы можем заметить вызов функции “MessageBoxIndirect”, кликнем на эту строку левой кнопкой мыши и вызовем правой кнопкой всплывающее меню, в нем выбираем пункт “Help on symbolic name”. Таким образом мы вызовем справку по данной API функции из предусмотрительно скаченного нами файла win32.hlp.
    Справка говорит нам что эта функция создает окно с заданными свойствами (текст, заголовок, иконка), не трудно догадаться что это и есть наш nag1, продолжим пошаговое выполнение программы, тут надо напомнить что существует несколько режимов выполнения: "Step into" и "Step over", их описание я дал во введении

    несколько раз жмем “F8” ("Step over)", до тех пор, пока не окажемся тут:

    Code:
    00465C32  \. C3             RETN
    Таким образом, если верить отладчику, наша функция показывающая nag1 начинающаяся по адресу: 00465B50 и заканчивающаяся адресом: 00465C32, передаст управление на адрес: 0049835C, см. скрин. Проверим это, жмем еще раз “F8”, и о чудо, мы оказываемся именно там. Смотрим выше, там находится вызов функции создающей nag1:
    [​IMG]

    Функция создающая наг не содержит других сообщений и призвана только сообщить нам что мы потерпели фиаско, таким образом можно очень просто избавится от nag1, забив вызов по адресу: 00498357 командами "NOP".
    выделяем строчку по указанному выше адресу и жмем клавишу “space bar” или вызываем всплывающее меню нажатием правой кнопки мыши и выбираем опцию “Assemble”.
    После чего в появившееся поле вбиваем команду “NOP”, жмем “assemble”. Мы только что убрали вызов функции создающей nag1, код содержащийся в функции никогда не будет исполнен.

    Теперь жмем “F9”, продолжая выполнение программы. Пытаемся зайти в комнату – после того как мы потерпели фиаско при входе не появилось назойливого nag1, перейдем к nag2:
    пытаемся войти в какую – нибудь популярную комнату, которая заведомо переполнена. Терпим неудачу, жмем еще раз … и вот он nag2. Для удалении этого нага воспользуемся тем же методом что и для устранения nag1. То есть не будем нажимать на nag2, а сразу перейдем к окну отладчика, нажмем “Pause” на панели отладчика, затем комбинацию клавиш “ALT+F9”, после чего возвращаемся к окну игрового клиента и жмем “OK”. После чего оказываемся тут:
    [​IMG]

    Выше видим вызов функции “MessageBox”, вызываем контекстное меню щелчком правой кнопки мыши, после чего выбираем пункт “Help on symbolic name”, видим что функция аналогична “ MessageBoxIndirect”, (которая применялась для создания nag1) и создает сообщение (nag2) с заданным текстом, заголовком и стилем окна.
    Жмем “F8” и доходим так до команды “RETN”:
    [​IMG]

    Видим что адрес возврата: 0046AC21, жмем “F8” оказываемся на адресе возврата. Выше видим вызов функции создания nag2:
    [​IMG]

    Тут надо сказать что просто занопать (забить командами “NOP”)вызов функции нам не подойдет, так как таймаут (5 сек) от этого никуда не денется и мы просто не будем получать сообщения о нем. Прокрутим окно отладчика чуть выше в поисках переходов, которые могут перенести нас через вызов функции создания нага:
    [​IMG]

    Как видим их всего 3:
    1) по адресу: 0046ABD3
    2) по адресу: 0046ABD8
    3) по адресу: 0046ABFC

    Третий мы можем сразу же отброисть , так как этот условный переход используется для создания цикла с условием, что видно из скрина выше (оля заботливо отметила этот участок скобкой)
    Второй переход перенесет нас на адрес 0046ABDD, что тоже не позволит нам избежать участи увидеть nag2.
    Смотрим что с первым… Первый условный переходпереносит нас через безусловный переход (переход номер 2, который будет обязательно выполнен без какого либо условия) на прямую «дорогу» к вызову функции создания nag2. Хм, что же делать нам не удается миновать функцию создания nag2. Исходя из того что программа не представляет нам другой возможности кроме как лицезреть это сообщение, можно сделать вывод что нам нужна другая процедура, в которой собственно и происходит сравнение текущего времени с временем последней попытки захода и в неблагоприятном для нас случае (прошло меньше 5 секунд) происходит вызов данной функции. Как нам попасть в эту процедуру?
    Очень просто! мы продолжаем трассировать программу по “F8”.
    Мы дошли до команды “RETN”:
    [​IMG]

    Жмем “F8”, оказываемся на адресе возврата: 00543CC1.
    Выше, по адресу: 00543CBC видим вызов процедуры из которой мы только что вышли:
    [​IMG]

    Теперь нам надо разобраться что же тут происходит, а точнее происходило выше:
    [​IMG]

    Все что нам важно я отметил красными прямоугольниками, рассмотрим все по порядку:
    По адресу 00543C66 видим вызов функции GetTickCount, выделяем строчку и вызываем справку по API, нажав “Ctrl+F1 “. Смотрим описание функции:
    Считывает вpемя (в миллисекундах), пpошедшее с момента запуска системы. Возвращаемое значение типа Longint.
    Вот где происходит получение значения времени, из которого вычитается предыдущее
    значение полученное на предидущем запуске.
    Смотреть адрес 00543C6E: SUB EAX,DWORD PTR DS:[622448]
    Тут из регистра EAX – в котором находится значение только что вызванной нами GetTickCount, вычитается результат выполнения GetTickCount (32-битное значение по адресу: 622448) на попытке входа в комнату предшедствуещего текущей попытке, после чего полученное значение помещается в регистр EAX.
    Смотрим дальше:
    00543C74 CMP EAX,1388
    CMP (англ: compare – сравнение) сравнение 1-го числа со вторым и установка флага
    “С”, в случае если числа одинаковы равным 0,в обратном случае равным 1.

    Значит тут время между предпоследней и последней попыткой входа в комнату сравнивается с числом 1388h. Зачем я дописал h? это значит hex = шестнадцатеричная система счисления. Возьмем калькулятор и переведем число 1388h в Dec (10 ричная система счисления) получим результат 5000. Именно 5000, так как время в миллисекундах.
    Смотрим дальше:
    00543С79 JNB SHORT 00543CDB
    Условный переход в случае если флаг C = 0 мы переходим по нему и пробуем войти в комнату, если же C =1 то мы получаем nag2.
    [​IMG]

    Проверим на практике: мы поставим на него точку останова (breakpoint), на которой оля будет прерывать выполнение программы. Жмем на адрес перехода (543C79), после чего жмем “F2” или вызываем всплывающее меню щелчком правой кнопки мыши и жмем “Breakpoint” -> “Toggle”. Теперь при переходе отладчика к этой инструкции, он будет на ней останавливаться.
    Пытаемся войти в какую – нибудь переполненную комнату.
    Останавливаемся на переходе, быстро жмем “F9” (командуем оле Run), так как нам нужно исчерпать данную попытку входа в комнату и перейти к следующей.После того как потерпели фиаско, то есть остались там же, ведь теперь нам не будут докучать предложениями о покупке привилегированного статуса, скорее пытаемся зайти опять ( у нас на это есть 5 секунд), после чего оля останавливается на указанной нами команде:
    [​IMG]

    Как видно на скрине, я успел за быстрее чем за 5 секунд совершить повторную попытку входа о чем нам говорит флаг “C”, который установлен в 1 и не даст мне совершить эту попытку, а отправит меня прямиков на nag2.
    Кликнем дважды (дабл клик) по флагу C, тем самым установив его в противоположное значение, смотрим что говорит оля по поводу перехода:
    Jump is taken
    Ура! теперь нажав “F9” мы не увидим nag2, а совершим очередную попытку входа в комнату. Но сделать так чтобы мы постоянно могли входить в комнату без смены флага “C” в ручную? Тут, как обычно, существует несколько вариантов:
    1. По адресу 543C75 заменить команду “CMP EAX,1388” на “CMP EAX,0” (выделить строку по адресу 543C75, нажать пробел, ввести команду “CMP EAX,0”, нажать “assemble”). Тогда программа будет проверять не прошло ли между предпоследней и последней попыткой входа в комнату 0 миллисекунд, если прошло, то флаг “C” будет установлен в 0, что даст нам возможность совершить попытку входа.
      [​IMG]
    2. По адресу 543C79 мы заменим команду условного перехода “JNB SHORT 00543CDB” зависящего от значения флага “C” на команду безусловного перехода, не зависящего от флагов “JMP SHORT 00543CDB” (выделить строку по адресу 543C79, нажать пробел, ввести команду “JMP SHORT 00543CDB”, нажать “assemble”). Результат будет тот же самый: таймаут на вход в комнату убран.

    Как сохранить внесенные в код изменения смотреть в конце статьи.
     
    #2 Dosia, 14 Aug 2009
    Last edited: 19 Sep 2009
    1 person likes this.
  3. Dosia

    Dosia Member

    Joined:
    5 Jun 2009
    Messages:
    118
    Likes Received:
    81
    Reputations:
    6
    Низкоуровневое исследование post 3 of 4

    e) Показ ping’a пользователей цифрами​


    Предполагается что “Garena.exe” уже загружена и запущена в вашем отладчике (мы юзаем олю), а также вы уже залогинились и готовы заходить в какую – нибудь свободную комнату (именно свободную или полупустую).
    Переходим к окну отладчика, вызываем контекстное меню нажатие правой кнопки мыши на дизассемблированном коде. Выбираем опцию “Search for” -> “All referenced text strings”:

    Оля нашла нам все строки которые встречаются в программе (незашифрованные). В появившемся окне перейдем к самой верхней строчке текста, это связано с тем, что наш отладчик ищет строки по порядку: сверху – вниз. Жмем правую кнопку мыши, снова вызывая контекстное меню, после чего выбираем опцию “Search for text”. В появившемся окне введем “|||” , что это? Именно так у обычных пользователей игровой платформы отображается пинг, то есть не цифрами, а вертикальными чертами (“|”,”||”,”|||”, и т.д.).
    [​IMG]

    Жмем “OK”, после чего оказываемся тут:
    [​IMG]

    Видим похожие строки, это явно то что мы искали. Кликнем два раза (ака дабл клик) на найденной нами строке и окажемся тут:
    [​IMG]

    Как мы можем видеть мы находимся на адресе: 4C012B где содержится команда “PUSH 5B19D4” которая помещает в стек значение находящееся по адресу 5B19D4, оля заботливо показала нам подсказку, что это текст “|||”. Осмотрим саму функцию в которой мы находимся: по адресу: 4C00FA идет сравнение EAX, с 190h (CMP EAX,190) после чего идет команда условного перехода (JGE SHORT 004C0122) на следующее сравнение (CMP EAX,258), в случае если перехода не произошло устанавливается количество палок соответствующее данному пингу ( в данном случае две), после чего идет команда RETN – возврат, становится понятно, что в зависимости от пинга именно тут проставляется необходимое колиство палок, но мы то хотим цифры, не так ли?
    Сделаем следующее: поставим брекйпоинт на начало данной функции: 4C0080 (щелкнем на строке находящейся по данному адресу, после чего жмем “F2”). Теперь заходим в комнату (выберите какую нибудь полупустую). Оп, окно отладчика всплывает, наша точка останова стработала.
    [​IMG]

    См. также строку состояния:
    [​IMG]

    Зачем мы тут остановились? чтобы вы могли самостоятельно потрассировать программу по “F8” до ближайшей команды “RETN 8”и посмотреть ход её выполнения.
    Как только вы остановились на команде “RETN 8”, жмем однократно “F8” и оказываемся на адресе возврата: 004C0251:
    [​IMG]

    Но самое интересное уже произошло выше:
    [​IMG]

    Начнем изучение кода:
    по адресу 4C024C мы имеем вызов процедуры которая установит пинг в виде вертикальных линий, следовательно, эта сточка, в ходе выполнения программы не должна быть выполнена. Смотрим выше в поисках переходов, позволяющих нам проскочить через “плохую” строчку. Имеем таковой по адресу: 4C023E, он переносит нас через вызов процедуры (по адресу 4C024C ) и последующий за ним безусловный переход (4C0251). Выше перехода (4C023C)видим сравнение “TEST BL,BL”. Тут надо сказать что опкод TEST Выполняет логическую операцию “И” над числами и по результату (не помещая его в получатель) устанавливает флаг Z. Если в BL будет 0, то переход “JNZ” не будет выполнен и мы будем видеть вертикальные линии вместо цифер. Также на скрине видно, что на это сравнение есть несколько условных переходов: “Jumps from 004C01F5, 004C0203, 004C0218, 004C0223”. С четырех адресов, найдем самый верхний по адресу: 4C01F5. Как я уже говорил в сравнении на которое мы можем попасть с этого условного перехода “JE SHORT 004C023C” проверяется значение регистра BL, значит оно где то устанавливается? Логично? Посмотрим чуть выше в поисках команды mov BL, (что нибудь) или вызова какой либо процедуры.
    Чуть выше первого перехода на сравнение, на котором мы сейчас находимся (4C01F5) по адресу: 4C01E5 видим команду MOV BL,AL, а выше нее (4C01E0) вызов процедуры по находящейся по адресу 004D2710, кликнем левой кнопкой мыши по адресу 4C01E0, где находится вызов нашей процедуры, после чего нажмем “Enter” и мы окажемся в процедуре. Сразу надо сказать что в этой процедуре устанавливается значение регистра AL, так как мы уже рассмотрели что после вызова данной процедуры находится команда MOV BL,AL , которая копирует содержимое регистра AL в регистр BL. А так же нам следует помнить что необходимо чтобы AL не был равен нулю, иначе на сравнении мы не перейдем по условному переходу. Ставим точку останова на начало данной процедуры (4D2710), после переходим к окну Garena и входим в комнату, останавливаемся на брейпоинте:
    [​IMG]

    Тут следует сказать почему мы немного углубились в изучение кода, а не пошли по более легкому пути и просто напросто исправили переход по адресу: 4C023E с условного JNZ SHORT 004C0256 на безусловный JMP SHORT 004C0256, что также решило бы проблему отображения цифрового пинга, как видно на скрине выше, эта процедура вызывается не с 1 фиксированного адреса, а с разных адресов, следовательно более правильно будет исправить именно значение возвращаемое этой функцией, нежели просто исправить переход. Это как функция проверки регистрация программы, в которой она проверяет зарегистрированная ли это версия и возвращает соответствующий результат, так вот, это функция может быть вызвана из разных мест программы, для того чтобы программа знала следует ли вводить ограничение на что – либо. И гораздо удобнее будет исправить значение возвращаемое этой функцией, нежели править все возможные переходы, проверяющие результат возвращенный функцией.
    Мы на брейкпоинте (4D2710), трассируем программу по “F8”, пока не найдем нечто похожее на MOV AL, (что - либо). Находим нечто похожее:
    [​IMG]

    Видим что по этому адресу (4D27F7) в регистр AL заносится значение находящееся по адресу EDX+44, оля любезно сообщила нам, что этот адрес 0100AE94, а значение находящееся по нему равно 0 (DS:[0100AE94]=00), также видим что текущее значение AL = B0.
    [​IMG]

    Жмем “F8”.
    [​IMG]

    AL = 0 – пинг вертикальными чертами. Изучаем оставшийся код до команды “RENT 4”, больше нигде AL не устанавливается, значит мы на верном пути. Жмем на адрес 4D27F7 – команду “MOV AL,BYTE PTR DS:[EDX+44]" заменим на команду “MOV AL,1” (кликаем на строку, жмем “space bar”,вводим команду “MOV AL,1”, жмем “assemble”), этим мы заставим программу думать что мы привилегированные пользователи.
    [​IMG]
    Как сохранить внесенные в код изменения смотреть в конце статьи.

    f) Уберем проверку на использование запрещенных программ​

    Переходим к окну отладчика, вызываем контекстное меню нажатие правой кнопки мыши на дизассемблированном коде. Выбираем опцию “Search for” -> “All referenced text strings”. В появившемся окне перейдем к самой верхней строчке текста, это связано с тем, что наш отладчик ищет строки по порядку: сверху – вниз. Жмем правую кнопку мыши, снова вызывая контекстное меню, после чего выбираем опцию “Search for text”. В появившемся окне введем “Path:%s” , что это? это путь к запрещенной программе, которую Garena передает на сервер, вместе с ip и логином заблокированного пользователя. Жмем “OK”, совпадение найдено, двойной щелчок на найденной строке и мы тут:
    [​IMG]

    Осмотрев код сразу становится понятно, что мы зашли по адресу. Чуть ниже можно заметить вызов функции “PostMessage”, оля даже смогла определить что параметром “Message” для нее будет “WM_QUIT”, что означает закрытие окна после уличения пользователя в использовании запрещенных программ.
    function PostMessage(Wnd: HWnd; Msg, wParam: Word; lParam: Longint): Bool;
    Напpавляет сообщение окну пpикладной задачи.

    Прокрутив листинг чуть выше можно заметить вызов следующих функций:
    GetWindowText, GetWindowThreadProcessId ,FindWindow полезным будет прочитать API help по ним, вызвав справку(как это сделать вы уже знаете). Позвольте вам разъяснить как идет проверка на наличие запрещенных программ:
    с помощью функции FindWindow идет поиск окон с заданными заголовками (аля maphack …), если таковое окно найдено, то все выше упомянутые (и некоторые другие, смотрите сами) функции будут выполнены с целью получения пути к исполняемому файлу запрещенной программы. И все это происходит в найденной нами процедуре.
    Найдем начало процедуры, прокрутив листинг чуть выше. Адрес 4DBF40 является началом процедуры, кликаем левой кнопкой мыши на строке и видим что оля знает откуда происходит вызов:
    [​IMG]

    Жмем правой кнопкой мыши на подсказке оли и выбираем команду “Go to CALL from 004DC1B5”. Оказываемся тут (004DC1B5):
    [​IMG]

    Выше видим условие(004DC1A4) и условный переход (004DC1A8), условный переход переносит нас через вызов процедуры поиска запрещенных программ, он же является условием выхода из цикла, начинающегося с адреса (004DC1A4) и заканчивающегося (004DC1CF), где стоит безусловный переход на проверку условия. Я думаю что здесь все понятно и наша задача сводится к тому, чтобы код начинающийся с адреса (004DC1B5) никогда не выполнялся. Для этого меняем условный переход по адресу (004DC1A8) “JNZ 004DC2F6” на безусловный “JMP 004DC2F6”.
    Как сохранить внесенные в код изменения смотреть в конце статьи.
     
    #3 Dosia, 14 Aug 2009
    Last edited: 19 Sep 2009
  4. struk666

    struk666 New Member

    Joined:
    11 May 2009
    Messages:
    20
    Likes Received:
    4
    Reputations:
    5
    статья супер! жаль не силен в програмировании.
    былобы великолепно еслиб выложили актуальною статью покупки голда... это единственное что ценится в гарене
    сниф в wpepro чтоб попроще... такое видео было на ютубе но для оч старой гарены...
    вот это был бы мега способ... а вообще програмеры в гарене рулят! Уважуха.
     
  5. struk666

    struk666 New Member

    Joined:
    11 May 2009
    Messages:
    20
    Likes Received:
    4
    Reputations:
    5
    ну все что тут изложено не слишком нужное...
    я просто намекнул что лучше копать в направлении голда.. это единственное что важно
     
  6. Zalp

    Zalp New Member

    Joined:
    3 Mar 2008
    Messages:
    20
    Likes Received:
    0
    Reputations:
    0
    а как на это реагирует проверка клиента на обновления???
     
  7. Dosia

    Dosia Member

    Joined:
    5 Jun 2009
    Messages:
    118
    Likes Received:
    81
    Reputations:
    6
    В смысле апдейтится ли клиент? Да, конечно, это по - прежнему полностью работоспособная программа.
     
  8. Dosia

    Dosia Member

    Joined:
    5 Jun 2009
    Messages:
    118
    Likes Received:
    81
    Reputations:
    6
    Именно это и было сделано в статье: описано получение частичных привилегий голд аккаунта, если прочитаеш статью, возможно у тебя получится получить и некоторые администраторские привилегии (появятся дополнительные меню).

    ЗЫ: Сорри за дабл постинг. Так уж вышло...
     
    1 person likes this.
  9. svesve

    svesve Elder - Старейшина

    Joined:
    15 Jun 2007
    Messages:
    574
    Likes Received:
    86
    Reputations:
    11
    ps после последнего апдейта гарены олька ругается при логине
    memory at address 7c812aeb is not readable try to change EIP .... bla bla bla

    постаили защиту от дебага?
     
    #9 svesve, 11 Sep 2009
    Last edited: 11 Sep 2009
  10. Dosia

    Dosia Member

    Joined:
    5 Jun 2009
    Messages:
    118
    Likes Received:
    81
    Reputations:
    6
    да, добавлена антиотладка, походу у статьи будет продолжение ...
     
    1 person likes this.
  11. AHJIoKeR

    AHJIoKeR New Member

    Joined:
    11 Sep 2009
    Messages:
    4
    Likes Received:
    0
    Reputations:
    0
    Да хотябы не продолжение, а начало изменить чтобы можно было GGC запустить в отладчике)
    Кстати, а скоро будет решение данной гадости?
     
    #11 AHJIoKeR, 12 Sep 2009
    Last edited: 12 Sep 2009
  12. svesve

    svesve Elder - Старейшина

    Joined:
    15 Jun 2007
    Messages:
    574
    Likes Received:
    86
    Reputations:
    11
    насколько я понимаю гарена палит трассировку и делает переход не на ту точку на которую надо )
    по моим скудным познаниям предполагаю что надо где то сменить переход или убрать проверку
     
  13. AHJIoKeR

    AHJIoKeR New Member

    Joined:
    11 Sep 2009
    Messages:
    4
    Likes Received:
    0
    Reputations:
    0
    to svesve
    мб ты решишь эту проблему?
     
  14. svesve

    svesve Elder - Старейшина

    Joined:
    15 Jun 2007
    Messages:
    574
    Likes Received:
    86
    Reputations:
    11
    я в дизассемблировании и отладки вообще не шарю )
     
  15. Dosia

    Dosia Member

    Joined:
    5 Jun 2009
    Messages:
    118
    Likes Received:
    81
    Reputations:
    6
    Низкоуровневое исследование post 4 of 4

    g) Уберем flood защиту из чата​

    Тут нам требуется знание API функций которые отвечают за получение содержимого элемента управления: GetWindowText GetDlgItemText
    Функция GetWindowText копирует текст строки заголовка определяемого окна (если оно имеет ее) в буфер. Если определяемое окно - элемент управления, текст элемента управления копируется.
    Параметры:
    hWnd, он же handle:Идентифицирует окно или элемент управления, содержащее текст;
    lpString:Указывает на буфер, который примет текст.
    nMaxCount:Устанавливает максимальное число символов для копирования в буфер. Если текст превышает это ограничение, он усекается.

    Функция GetDlgItemText Извлекает заголовок или текст, связанный с органом управления в диалоговом окне.
    В оле уже загружена “Garena.exe”, но отладчик не запущен на выполнение, мы находимся на точке входа в программу, жмем на листинге правой кнопкой “Search for” -> “Name (label) in current module” или жмем “Ctrl+N”. Начинаем набор текста (активное окно – окно отладчика): “GetWindowText”, функция найдена “GetWindowTextW”, кликаем на строчку, вызываем контекстное меню, жмем “Set breakpoint on every reference”, только что мы поставили точку останова каждом вызове этой функции. В строке состояния (нижний левый угол) оля отобразила нам количество установленных точек останова. На “GetDlgItemText” брейкпоинт ставить не будем, так как забегая вперед, могу сказать, что она нам не понадобится.
    Жмем “F9” – начинаем выполнение программы. Останавливаемся на брейпоинтах – убираем их нажав “F2” или вызвав контекстное меню и так до тех пор, пока мы не войдем в какую либо комнату, так как нас интересует только вызов этой функции при отправке сообщения из компонента в котором мы набираем текст (текстового поля) . И так мы сидим в комнате, набираем сообщение в окне чата, жмем кнопку “Отправить” , после чего сразу же всплывает окно отладчика, Трассируем программу по “F8”, оказываемся тут:
    Исходя из снятия предыдущих ограничений мне показался этот код очень интересным:
    по адресу: 41FC64 наблюдаем установку условного перехода командой “TEST AL,AL”, а прямо за ним (41FC66) и сам переход “JE” (на рисунке красный прямоугольник). Именно этот переход и играет решающую роль при проверке печаталось ли это сообщение ранее, если AL будет равен 0,то переход будет выполнен и наше сообщение увидят остальные пользователи, иначе нам сообщат что мы, похоже, флудеры. смотрим выше установки флага “Z”, ведь команда “TEST” устанавливает именно его, видим вызов по адресу: 41FC5F (синий прямоугольник на рисунке), кликаем левой кнопкой мыши на вызове, жмем “Enter” и мы внутри. Опять же слудует заметить что процедура вызывается из нескольких мест : “Local calls from 0041D7BC, 0041FC5F”, спасибо оле. Но мы помним что нам нужно найти где именно в этой процедуре устанавливается значение регистра AL, причем оно будет установлено в 1, в то время как нам требуется 0. Поставим точку останова на адрес этой процедуры, нажав “F2”, запускаем программу на выполнение – жмем “F9”. В окне гарены печатаем сообщение, которое будет повтором ранее отправленного нами (чтобы получить предупреждение о недопустимости флуда), после чего жмем “Отправить”. Успешно прервались, трассируем по "F8”, в поисках установки регистра AL (кода вроде: “MOV AL,1”). Трассировать пришлось не долго:
    [​IMG]

    На скрине видно, что по адресу: 41B290 происходит установка регистра AL равным 1, что является не приемлимым, так как нам нужен 0, кликнем по команде (“MOV AL,1”),нажмем “space bar”,исправим команду на “MOV AL,0” или “XOR AL,AL” (выполняет операцию логического исключающего ИЛИ над операндами: бит результата равен 1, если значения соответствующих битов операндов различны, в остальных случаях бит результата равен 0), жмем “assemble”. После исправленной команды регистр AL больше нигде не устанавливается (через несколько команд идет возврат управления и это отчетливо видно), так что можно смело жать “F9”. Ниже по адресу: 41B2B5 видим команду “XOR AL,AL” устанавливающую регистр AL равным 0 или попросту очищающим его, это происходит в случае если мы привилегированные пользователи, но теперь и в случае если мы обыкновенные юзеры в AL будет помещаться 0 ;D

    //Хочу обратить ваше внимание, что это не способ решения, можно было также исправить переходы и т.д. Но это более правильный метод.

    Тестим – все ок, но вот незадача, если мы печатаем текст слишком быстро, то нам сообщают что мы флудим.
    Если внимательно посмотреть на листинг, то можно было заметить:
    [​IMG]

    Но проверку с помощью таймера (пол секунды (500 милисекунд, как окажется чуть позже)) – 1 сообщение, на скрине красный прямоугольник) мы найдем другим способом:
    На листинге (дизассемблированный код) жмем “Ctrl+N”, набираем текст: “GetTickCount” (регистр символов не имеет значения). Эта функция нам уже встречалась и я давал её описание выше. Почему мы ищем именно её? потому что как правило именно с её помощью замеряют интервалы времени, нам ведь надо отмерить 1 секунду, не так ли? Кликнем по функции, жмем правую кнопку мыши, “Set breakpoint on every reference”, после чего продолжаем выполнение программы (если оно прервано), попутно убирая уже сработавшие бряки. Основной и еще какие то левые таймеры. Переходим к окну игрового клиента, печатаем текст (любой), жмем “Отправить”, прерываемся:
    [​IMG]

    Идем к началу функции (416B20) и видим что она вызывается по адресу 41FBE7, переходим по адресу “Gtrl+G” на листинге -> “41FBE7” -> “OK”. Вуаля, мы оказываемся именно там, где и планировалось. по адресу: 41FBE7 вызов функции проверки – прошел ли таймаут или мы слишком рано пытаемся отправить сообщение? Далее по адресу: 41FBEC видим проверку “TEST AL,AL”, значит функция опять устанавливает регистр AL, как и в предыдущем случае, потом идет условный переход (41FBEE), если AL = 0 то мы перейдем, и наше сообщение будет проверятся на повтор, но это мы уже исправли ;D
    Идем в функцию (416B20), изучаем код:
    сразу после вызова функции, по адресу видим сравнение регистра EAXс 1F4h = 500d вот она наша проверка, ниже по адресу 416B41 в AL перемещается значение регистра BL, после чего из стека считывается число в регистр EBX и идет RETN. Таким образом AL больше нигде не устанавливается. Теперь нас даже особо не интересует проверка по адресу: 416B37 где BL сравнивается с самим собой и если он равен 0 то перехода с адреса: 416B39 на адрес: 416B3F не случится. Мы можем:
    1) исправить значение устанавливаемое в регистр по адресу: 416B41MOV AL,BL” в “MOV AL,0” или “XOR AL,AL”.
    2) Исправить таймаут по которому идет сравнение по адресу: 416B2FCMP EAX,1F4” в “CMP EAX,0
    3) Исправить условный переход по адресу: 41FBEEJE SHORT 0041FC5A” на безусловный “JMP SHORT 0041FC5A”.
    Как сохранить внесенные в код изменения смотреть в конце статьи.

    h) Уберем ограничение на запуск одной копии программы​


    Тут мы поступим очень просто – будем трассировать программу по “F8” (благо делать это нам придется не долго). Запускаем гарену(без отладчика), нам нужна уже работающий экземпляр приложения, чтобы посмотреть на его реакцию. Грузим в олю гарену, после чего жмем “F8”, Трассируем по “F8” до адреса: 55F3D4, как только мы на этом адресе нажмем “F8”, чтобы перейти к следующей инструкции, окно уже запущенной без отладчика гарены получит фокус и/или начнет мигать. Следовательно по этому вызову приложение проверило, запущен ли один его экземпляр или нет. Переходим в функцию нажав “Enter” по адресу: 55F3D4, ставим точку останова (бряк) на первую команду в функции (как? рассматривалось ранее):
    [​IMG]

    После чего жмем “Ctrl+F2” – отладчик перезагрузит программу и мы снова окажемся на точке входа. Жмем “F9”, прерываемся на брейкпоинте и продолжаем трассировку программы по “F8”, при выполнении вызова по адресу: 42E5C1 показалось окно уже запущенного клиента, входим в вызов нажимая “Enter”, изучаем код:
    [​IMG]

    в стек помещаются параметры для последующего вызова функции “SendMessage”:
    function SendMessage(Wnd: HWnd; Msg, wParam: Word; lParam: Longint): Longint;
    Посылает сообщение оконной функции указанного окна. Возвpат из функции осуществляется только после обpаботки сообщения.

    Таким образом по этому вызову приложение посылает команду “всплыть” уже запущенному экземпляру, следовательно проверка на запуск второго экземпляра уже была проведена, но где? Перезагрузим программу (“Ctrl+F2”)и начнем трассировку (“F8”) с установленного нами бряка: по адресу 42D9C0 видим условный переход, который может передать управление на адрес 42E5C1, что у нас по адресу 42E5C1? Смотри выше – вызов процедуры которая установит фокус на окно уже запущенного экземпляра программы с помощью функции “ SendMessage”. Похоже мы нашли этот переход ;D
    Смотрим какая команда задает переход , это “TEST AL,AL” (42D9B9), выше вызов, скорее всего в нем то и устанавливается значение регистра AL. заходим в вызов нажав “Enter”:
    [​IMG]

    Видим что там происходит вызов функции OpenMutex:
    Функция возвращает HANDLE (дескриптор - указатель на структуру, файл ил процесс )существующего окна.
    Параметры:
    DWORD fdwAccess, // access flag
    BOOL fInherit, // inherit flag
    LPCTSTR lpszMutexName // address of mutex-object name //
    );

    Можно посмотреть на параметры которые были помещены в стек для вызова функции пройдя от адреса: 4369A0 (начало функции) до адреса: 4369AF (вызов OpenMutex) по “F8”.
    [​IMG]

    По адресу: 4369B7 видим “TEST EAX,EAX”, после него идет установка флага регистра AL командой SETNE, если результатом логического ”И” – “TEST” явился флаг “Z” = 0, то в AL будет помещено “01”, если “Z”=1 то AL будет установлен в “00” и после выхода из функции на мы не перейдем по условному переходу (42D9C0 ) и программа запустится.
    Проверим это, запустим программу на выполнение, предварительно поставив бряк на адресе: 4369B9, прервавшись мы поменяем значение флага “Z” на обратное, дважды щелкнув по нему. После чего команда “SETNE AL” как и планировалось установит значение AL в “00”.
    Таким образом, мы можем:
    1) Вместо команды “SETNE AL” (4369B9) установить “MOV AL,0
    2) Занопать (забить командами NOP) условный переход по адресу: 42D9C0
    Вариантов у нас много, но я указал основные.

    7) Как сохранить сделанные в коде изменения​

    Жмем правую кнопку мыши на листинге, вызывая контекстное меню, выбираем:
    Copy to executable” -> “All modifications”, после чего нас спросят действительно ли мы хотим копировать все изменения сделанные в коде программы, жмем “Copy all”, в появившемся окне жмем правую кнопку, вызывая всплывающее меню, выбираем “Save file”, указываем имя файла и его местоположение, после чего жмем “Сохранить”.

    8) Полезные ссылки:​

    Win32Asm Tutorial
    Win32Asm Tutorial #2
    Win32Asm Tutorial #3
    Intel Pentium Instruction Set Reference
    Снимаем таймер подключения в Garena Client

    В принципе это все материалы которые были использованы в ходе создания данной статьи.

    9) Хотелось бы сказать:​


    О найденных ошибках и неточностях просьба писать в ПМ, скажу сразу, что указанные на скринах адреса могут отличатся от адресов которые вы получите на практике, но на принцип нахождения и устранения ограничения это не влияет.

    Отчасти на написание статьи меня подтолкнуло большое количество существующих модифицированных клиентов игровой платформы “Garena” и большое количество просьб (лично ко мне от моих друзей) по её модификации, так как не все предпочитают использовать не понятно кем сделанные программы (этим я хочу сказать, что не так и сложно самому модифицировать программу), также хотелось бы сказать что возможно я бы и не написал статью, если не встретил нечто похожее (смотреть последнюю ссылку из раздела полезные ссылки), так же хочу добавить что в той статье рассматривается снятие ограничения на вход в комнату на примере более ранней версии клиента, так что адреса переходов другие, да и сам код программы поменялся, так что решение данной задачи отличается от приведенного.

    Кому интересно, можете найти полностью рабочую версию со всеми выше описанными изменениями (и многими другими, которые не попали в статью: функции админа (которые в прочем не все работают) и т.д.) тут (Последнее обновление: 10.02.10) Размер: Garena.rar (9.85 MB) (в связи с тем что данная версия гарены не последняя, в архиве находится вся папка Garena, чтобы не было проблем из - за различия файлов).
    //Обновление от 10.02.10: Убран автоапдейт

    1. rapidshare.ру
    2. dump.ру
    3. multiupload.ком

    Запускайте отладчик, смотрите что к чему, сравнивайте исходный файл игрового клиента и мою версию. Pass: antichat.ru.

    И самое главное! Помни, что информация приведена исключительно в образовательных целях. Не рекомендуется повторять выше описанные действия. Автор статьи не несет никакой ответственности за ваши возможные действия, после прочтения данного материала.

    © DoctorDraD aka Dosia
     
    #15 Dosia, 13 Sep 2009
    Last edited: 10 Feb 2010
    2 people like this.
  16. AHJIoKeR

    AHJIoKeR New Member

    Joined:
    11 Sep 2009
    Messages:
    4
    Likes Received:
    0
    Reputations:
    0
    Уберем таймер на вход в комнату
    -----
    Получаю наг1 перехржу в отладчик, f12,alt+f9, возвращаюсь в ггц жму отмена, кстати там нет "ОК", иду в отладчик а там все как после паузы стояло, так и стоит, единственно бряк создался, но на адрес:

    [​IMG]
    меня не кинуло. Где я ошибся?
     
    #16 AHJIoKeR, 13 Sep 2009
    Last edited: 13 Sep 2009
  17. Dosia

    Dosia Member

    Joined:
    5 Jun 2009
    Messages:
    118
    Likes Received:
    81
    Reputations:
    6
    Ты не ошибся, статья не была переработана, переработаю ориентировочно до 17.09.09, так как произошли изменения в коде программы, то сабж не совсем корректен. О переиздании сообщу.
     
    #17 Dosia, 14 Sep 2009
    Last edited: 15 Sep 2009
    1 person likes this.
  18. [EYFORIYA]

    [EYFORIYA] Member

    Joined:
    27 Apr 2009
    Messages:
    8
    Likes Received:
    9
    Reputations:
    0
    где полное описание найти изменений
    я так понял пинг стало видно в цифрах и защита от флуда отдыхает и лимит на комнаты тожэ естественно нету а еще чего кто заметил)
     
    4 people like this.
  19. AHJIoKeR

    AHJIoKeR New Member

    Joined:
    11 Sep 2009
    Messages:
    4
    Likes Received:
    0
    Reputations:
    0
    to [EYFORIYA]:
    а хз) я крякнутую скачал для того чтобы зглянуть работает ли она с новыми обновлениями, работает, но сообщение на голд выдает(наг1), так как изменились адреса, да и мессага тож), но юзать готовую не оч охото, сам процесс оч интересен!
    to Dosia:
    а можно еще убрать ограничение в хайлвлрумах, думаю это возможно?кста жду ночи=)
     
  20. svesve

    svesve Elder - Старейшина

    Joined:
    15 Jun 2007
    Messages:
    574
    Likes Received:
    86
    Reputations:
    11
    ТС респект однозначно, внимательно слежу за темой,очень интересно.
    Как говориться Пиши ЕсЧО