Программа Машинный Код Завершилась С Кодом 0 (0X0)

Программа Машинный Код Завершилась С Кодом 0 (0X0)

Реверс AGTH для воссоздания альтернативного GUI Хабрахабр. Так как тема реверс инжиниринга довольно популярна на хабре, решил поделиться своими наработками по этой теме. Мне, как и многим любителям визуальных новелл, знакома такая программа, как AGTH Anime Game Text Hooker. Программа Машинный Код Завершилась С Кодом 0 (0X0)' title='Программа Машинный Код Завершилась С Кодом 0 (0X0)' />Она позволяет извлекать текст из новелл для последующего переводабольшинство игр японские. Разработка этой программы, судя по всему, была прекращена ещ в 2. Оригинальная программа состоит из двух частей исполняемого файла и модуля перехвата выполненного в виде динамической библиотеки. Эту библиотеку программа внедряет в процесс игры и с е помощью получает оттуда текст. Реверсить и переписывать я буду лишь исполняемый файл, а модуль перехвата оставлю оригинальный. На это есть несколько причин. Помимо очевидной сложности модуля и присущей мне лени, необходимо обеспечить совместимость моей разработки с так называемыми H кодами. H код это набор данных нужный перехватчику для корректной установки хука в случае, когда дефолтные хуки неэффективны. Он содержит в себе адреса памяти, номера регистров и прочую информацию о местонахождении текста в игре. Для каждой отдельной игры этот код уникален и найден энтузиастами. Поэтому написать свой модуль так сказать по мотивам не выйдет. YDzITwcR69I/ULYNU-En6mI/AAAAAAAACHE/-y-_grd0mCA/s1600/ILDASM_InvisibleCrackMe_01.png' alt='Программа Машинный Код Завершилась С Кодом 0 (0X0)' title='Программа Машинный Код Завершилась С Кодом 0 (0X0)' />Нужно будет обеспечить полную совместимость по этим кодам, а это совсем другой уровень сложности. Да и никаких дополнительных преимуществ это не даст. Разбор протокола общения модуля перехвата и AGTH. Очевидно, что модуль перехвата в игре и AGTH как то взаимодействуют между собой, и для написания альтернативной оболочки нужно узнать как. Способов передать данные от одной программы к другой довольно много, начиная от оконных сообщений и заканчивая сокетами. Какой же способ использован на самом деле я узнал случайно. Программа Машинный Код Завершилась С Кодом 0 (0X0)' title='Программа Машинный Код Завершилась С Кодом 0 (0X0)' />Программа Машинный Код Завершилась С Кодом 0 (0X0)Просто зашел в свойства процесса agth. Process Explorer и решил посмотреть, какие строки содержит эта программа. В глаза сразу бросилась строка. Поток Поток Win64. Программа Что значит программа завершилась кодом 0 0х0 И что тут не так в. Программа. Если не вдаваться в особые подробности то программа на С это. Никакой ошибки нет. Это вспомогательные отладочные потоки Visual Studio, которые бегут в контексте вашего процесса даже скорее. Теперь у нас есть направление, в котором можно начинать поиски. Для отладки я буду использовать любимый многими отладчик Olly. Программа Машинный Код Завершилась С Кодом 0 (0X0)' title='Программа Машинный Код Завершилась С Кодом 0 (0X0)' />Dbg. Загрузим AGTH в Олю и сразу поставим бряки на Create. Named. Pipe функции внутри модуля kernel. Один из этих бряков должен сработать как только программа попытается создать именованный канал и из этой точки можно будет добраться до кода который с этими пайпами работает. Продолжим выполнение и со второго срабатывания бряка попадаем в нужное место. СCC, PascalDelphi, PHP, JavaJavaScript, Visual Basic, консультации по webразработке, удаленная помощь. О том, что это место нужное говорит нам наличие строки. Теперь перейдм по адресу 0x. AF3. A6. 4, который лежит на вершине стека и должен указывать на код сразу за вызовом Create. Named. Pipe. W. 0. B3. A4. 3 5. PUSH ESI 0x. AF3. A4. 4. EB 0. JMP SHORT agth. 0. AF3. A6. B. Тут уже можно разобрать с какими параметрами наш пайп создатся, а именно Create. Named. Pipe. W. Получится так Create. Named. Pipe. W. Хорошо, теперь нужно узнать, как происходит чтение данных, а точнее каков размер блока данных, передаваемого от игры к приложению. О том, что данные передаются блоками, а не непрерывным потоком байт, говорит наличие флага PIPE. Перейдм по адресу 0x. CC5. 08. 0 Вот и искомая функция Read. File, которая вызывается с параметрами 0. D9. B4 0. 00. 00. В общем то, нас интересует лишь параметр Bytes. To. Read, который равен 8. Вероятно это и есть размер структуры с текстом, которую передат игра в программу. В итоге собрано достаточно информации о том, как происходит взаимодействие с игрой AGTH реализует пайп сервер, который принимает данные кусками по 8. Теперь можно переходить к разбору того, что же эти байты означают. Разбор формата данных я решил сделать уже внутри своей программы. В ней я реализовал собственный сервер, воспользовавшись данными полученными ранее, и с его помощью получал сообщения от игры. Очень удобно можно завести структуру нужного размера и вычитывать данные прямо в не. По ходу разбора того, что значит та или иная группа байт, эту структуру можно модифицировать и в конце получить полное описание всех полей. Вот примерно так выглядит то, что приходит в программу из игры. Сразу бросаются в глаза строки User. Hook. Q и K. o. t. Первая имя функции, которое отображается в оригинальной программе, второе текст из игры в кодировке UTF 1. Также замечено число 7 синее выделение которое, как оказалось, всегда равно количеству символов строки игрового текста. Перебирая разные наборы данных выяснилось, что имя функции это null terminated строка с максимальной длинной в 2. То есть, в случае со скриншотом выше, все байты между зелным и синим выделением просто мусор. Осталось ещ 1. 6 байт данных в начале структуры. Первые две переменные определить было легко это Context и Subcontext, которые также можно видеть в окне оригинальной программы. Русификатор Для Modern Warfare 2 на этой странице. Третий параметр найти было чуть сложнее он всегда имел небольшие значения и менялся только при перезапуске игры. Им оказался Process. ID игры. Последний из четврки менялся постоянно и имел достаточно большие значения. Единственной зацепкой было то, что это значение всегда увеличивалось со временем и никогда не уменьшалось. Это и было временем, точнее результатом вызова функции Get. Tick. Count. В итоге получилась такая структура TAGTHRc. Pckt packed record Size. Of 8. 16. 8 bytes. Context Cardinal. Subcontext Cardinal. Process. ID Cardinal. Up. Time Cardinal. Text. Length Cardinal. Hook. Name array. Далее откроем список модулей, выберем kernel. Load. Library Это сделано потому, что как не крути, а финальная загрузка dll будет произведена с помощью вызова одной из этих функций и, если перехватить вызов можно, побродив по стеку, выйти на сам загрузчик. Продолжим выполнение программы. Затем запустим AGTH и укажем ему процесс игры agth PNИмя. В мом случае бряк сработал на функции Load. Library. W. Странно, я ожидал увидеть там адрес внедрнного в игру кода загрузчика. Что ж, посмотрим, что лежит рядом аргументом Load. Library. W. Перейдм по адресу 0x. EF8. 00. 22 и вот оно Это и есть искомый загрузчик, кстати, довольно хитрый всего 4 команды начиная с адреса 0x. EF8. 00. 14 идут данные. EF8. 00. 00 6. 8 1. E0. 0F8. 7E PUSH 7. EF8. 00. 1E UNICODE. Но мысль о том, что же будет после того как отработает Load. Library не давала мне покоя. Поэтому я решил глянуть, куда же все таки вернтся управление после вызова. Идм по адресу 0x. D3. 67. 7 и видим 7. D3. 67. 7 5. 0 PUSH EAX. D3. 67. 8 FF1. 5 F0. D7. 5 CALL DWORD PTR DS. Казалось бы вс хорошо, но меня не покидала мысль А откуда вообще на стеке оказался этот адрес, и где программа достала адрес строки, в которой путь к внедряемой dll лежит Ведь в коде загрузчика ничего подобного нет. Выходит кто то положил эти адреса на стек ещ до того как была вызвана первая инструкция загрузчика. И тут меня осенило удалнные потоки создаются с помощью функции Create. Remote. Thread, а она кроме указателя на функцию принимает ещ и параметр для этой функции. То есть она складывает на стек сначала адрес Rtl. Exit. User. Thread, чтобы поток, сделав RET, корректно завершился, а потом ещ и переменную параметр. Ещ раз вкратце Create. Remote. Thread складывает на стек адрес Rtl. Exit. User. Thread, путь к dll и запускает загрузчикзагрузчик складывает на стек аргументы для Set. Environment. Variable. W, адрес Load. Library. W и делает безусловный переход на Set. Environment. Variable. WSet. Environment. Variable. W забирает свои аргументы со стека и при возврате из не поток оказывается в начале Load. Library. WLoad. Library. W забирает со стека путь к dll и при возврате из не поток попадает на Rtl.

Программа Машинный Код Завершилась С Кодом 0 (0X0)
© 2017