![]() |
Добро пожаловать, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
-=CHE@TER=- |
![]()
Сообщение
#1
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Итак, начнём.
Я тут увидел, что многие программы, которые я выкладываю на сайте - уже есть в XENTAX WIKI Grafs. Так что, я думаю, что имеет смысл делать распаковщики и выкладывать описания форматов, которых нет там. А то, как-то тупо получается - тут я выкладываю формат, который раскопал сам, в то время как он уже готовенький лежит там. Ну, вот этого формата я там точно не видел: QUOTE Формат: .WD Игра: Earth 2140 4 байта - количество файлов в архиве (обозначим их как TF) далее следует блок описания такого формата: 4 байта - абсолютное смещение файла относительно начала архива 4 байта - размер файла 8 байт - зарезервированно - всегда 0-ли (в том архиве, который мне давал когда-то Siberian GRemlin для написания распаковщика - "FONT.WD") 4 байта - какая-то контрольная сумма - у всех файлов разная 4 байта - смещение имени файла в списке имён (NOfs) - см. дальше Блок описания нужно повторить TF раз. 4 байта - размер списка имён Затем идёт сам список имён файлов: NAME1\0NAME2\0 и т.д. т.е. просто TF штук ASCIIZ-строк друг за другом. Если прочитать список имён в отдельную переменную-указатель, то через NOfs в качестве побайтового индекса, мы получим указатель на начало ASCIIZ-строки, с именем нужного нам файла. Имя файла может содержать относительный путь, с использованием символа слэш "/" в качестве разделителя. |
9k1d |
![]()
Сообщение
#2
|
Незарегистрирован ![]() |
|
-=CHE@TER=- |
![]()
Сообщение
#3
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Нет конечно.
То что расширение совпадается совсем не означает, что и содержание тоже. |
Siberian GRemlin |
![]()
Сообщение
#4
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Формат же разобран...
|
jTommy |
![]()
Сообщение
#5
|
Наблюдающий ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 197 Регистрация: 4-February 08 Из: деревня Москва Пользователь №: 6 Спасибо сказали: 19 раз(а) ![]() |
Я тут увидел, что многие программы, которые я выкладываю на сайте - уже есть в XENTAX WIKI Grafs. Так программы или описания? Там вроде ссылки только на универсальные распаковщики (и очень редко на специализированные). Так что твои программы пригодятся на этом сайте. |
-=CHE@TER=- |
![]()
Сообщение
#6
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Так программы или описания? Там вроде ссылки только на универсальные распаковщики (и очень редко на специализированные). Так что твои программы пригодятся на этом сайте. Не прошло и года... (*улыбается*)Смысл был в том, что если описание формата известно, то распаковщик может написать, _практически_ каждый (ну, кто программировать хоть на чём-то умеет). Другое дело, что заходить туда и писать распаковщики по их описаниям форматов - как-то... не знаю, глупо что-ли? Хотя я ими (описаниями) пользовался действительно продуктивно только один раз - при написании Blood Rayne 2 POD Encoder Decoder (а то часто там ошибки или вообще к жизни не относятся - например для первой части игры Blood вообще не учитывается, что файлы и FAT архива могут шифроваться - кому интересно на сайте у Ken Silverman лежит утилита KBARF с исходными кодами на Си, которая расшифровывает и распаковывает архивы, но, как оказалось, у меня была версия где тело файлов не шифровалось, так что пришлось эту утилиту немного модифицировать). Для первого Blood правильное описание выглядит так: QUOTE char {4} - Header ('R', 'F', 'F', 0x1A) Сам алгоритм расшифровки (там XOR с меняющимся ключом) можно посмотреть в уже упомянутой программе KBARF.uint16 {2} - version (0x2000 - no encryption; 0x0300, 0x0301 - encryption used) uint16 {2} - unused1 (padding) uint32 {4} - Directory Offset uint32 {4} - Number Of Files byte {16} - unused2 (padding) byte {x} - Files data |
Siberian GRemlin |
![]()
Сообщение
#7
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
|
-=CHE@TER=- |
![]()
Сообщение
#8
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
|
Siberian GRemlin |
![]()
Сообщение
#9
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Давай. Пригодится.
|
-=CHE@TER=- |
![]()
Сообщение
#10
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Блин, вру - и ни в одном глазу!
Поправил неточности в своём прошлом сообщении. Как различить, когда в архиве используется шифрование файлов, а когда нет - х.з. Видимо, это нужно те 16 байт смотреть... Думаю, они должны за это отвечать. |
-=CHE@TER=- |
![]()
Сообщение
#11
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Наверное тут будет самое место.
Очень подробное описание формата .TGA: tga_specs.pdf (64 Kb) Что интересно - прозрачность в 16 BPP (0 - есть, 1 - нет) не поддерживает ни PhotoShopt 7, ни XnView, даже PNGOut и тот, гад, в 16-ти цветовые переводит такие .TGA файлы. |
-=CHE@TER=- |
![]()
Сообщение
#12
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
- Ancient chinese secret!
© Lo Wang, Shadow Warrior (1997) Не могу пройти мимо и не упомянуть формат коллекций изображений .LIB из игры Blade & Sword (см. соответствующую тему на Extractor.ru). Как я уже написал там, структура похожа на ту, что использовалась в предыдущих играх, но заголовок изображений поменяли, а также зашифровали ширину и высоту. Итак, действующие лица в порядке появления (поля из заголовка lep-файла): Width, Height, Width_Add, Height_Add - типа DWORD (находятся в начале заголовка); Crypted, Width_Idx, Height_Idx - типа BYTE (находятся в самом конце заголовка); Div_List - массив DWORD из 10 элементов (от 0 до 9, прописан в исполняемом файле игры). А теперь представляю вам главного персонажа (барабанная дробь) - Её Величество Технология Особого Китайского Шифрования! CODE if (lep_head.Crypted) { lep_head.Width = (lep_head.Width / Div_List[lep_head.Width_Idx ]) + lep_head.Width_Add; lep_head.Height = (lep_head.Height / Div_List[lep_head.Height_Idx]) + lep_head.Height_Add; } |
-=CHE@TER=- |
![]()
Сообщение
#13
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Как различить, когда в архиве используется шифрование файлов, а когда нет - х.з. Разобрался до конца с форматом, поправил статью RFF Format и выслал изменения патчем для Ken Silverman. Он поправил свою утилиту на сайте, так что свою версию я из этой темы удалил. Нормальный распаковщик, поддерживающий шифрование (когда нужно) для таблицы размещения файлов и самих файлов можно, как и раньше, взять на его странице KBARF.Видимо, это нужно те 16 байт смотреть... Думаю, они должны за это отвечать. |
-=CHE@TER=- |
![]()
Сообщение
#14
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
На сайте про игру Total Overdose спрашивали, так что взялся я её посмотреть.
Пока ковырял архивы .NAZ, вдруг, понял, что мне это что-то напоминает. И точно, выяснилось, что там, как оказалось, обычный .ZIP в котором сигнатуру изменили и имена файлов пошифровали, плюс поменяли местами 4 поля в структуре перетащив их из начала в конец. Интересно что под отладчиком local .ZIP headers игра, вообще, не расшифровывает - похоже они забиты мусором, хотя размер и совпадает с тем что должно быть, так что приходится при конвертировании их восстанавливать вручную. Сделал конвертер в .ZIP отбросив поле с непонятными данными (по спецификации .ZIP там не менее 4 байт должно быть на одно поле, а тут 1 байт), так что не пугайтесь, что после конвертирования архив слегка похудеет. Ещё вспомнил что у нас есть конвертер архивов Alpha Prime в .ZIP - тоже поглядел что там и сделал конвертер. Оба конвертера теперь будут с открытыми исходными кодами. И если конвертер для Alpha Prime от Xplorer'а я могу спокойно заменить (без исходных кодов, плюс антивирус у меня почему-то на него ругается), то jTommy написал GUI распаковщик для Total Overdose и я не знаю - стоит его заменять или оставить в архиве. С одной стороны меня просто жаба давит в архив 4 Кб добавлять ещё 30 Кб старой программы. С другой стороны опять начнутся стоны, что старая программа работала, а новая непонятно как (ибо работу с консолью осилить не могут). Что думаете? P.S. Ни разу не хочу принизить огромный вклад Xplorer'а в общее дело - он молодец, но я за открытые исходные коды и не понимаю, если честно, чего там прятать - я про эту игрушку, вообще, только благодаря этому конвертеру и узнал. Даже про Total Overdose и то больше слышал. Вообще, Xplorer как-то странно программы писал. Ну, т.е. он делал какие-то вещи, которые, вроде, ничем обоснованы не были. Ну, ок, допустим, ты не хочешь, выкладывать исходные коды, потому что программа написана как попало и тебе за код стыдно (или ещё там чего). Ладно. Но зачем её шифровать (UPX, плюс стёртые заголовки, возможно ещё что-то)? Там же ни копирайтов нет, ни даже сообщений об ошибках. Чего там реально прятать было? Что кто-то подсмотрит алгоритм и выдаст конвертер за свой? Так, опять же, копирайтов нет - и так кто угодно авторство присвоить может. В общем, есть отдельные моменты которые мне непонятны и объяснить я их не могу. P.P.S. И, jTommy тоже, кстати, молодец, но он, видимо, не работал с .ZIP до этого, поэтому не сообразил что там архив или сообразил, но ему распаковщик проще написать было, чем заморачиваться с конвертированием. |
-=CHE@TER=- |
![]()
Сообщение
#15
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Обновил программы. Для Total Overdose ещё раз переписал программу, чтобы она была по аналогии с той что для Alpha Prime (не буду никакие блоки пропускать). Выяснилось также, что в .NAZ архивах старый формат ZIP Data Description block (без сигнатуры) - что удивительно, так это то что даже родной WinZIP не понимает такие блоки, хотя в документации об этом прямо сказано (см. комментарии в исходных кодах к naztozip - я там детально описал что к чему), поэтому при глубоком тестировании архива, возможны сообщения об ошибках, хотя сами файлы распаковываются без каких-либо проблем или предупреждений. Вообще, интересно, чем разработчики в оригинале файлы упаковывали, потому что помимо этого мне также непонятно что это за байт 0x88 / 0x89 в extra field (как я уже писал, там должно быть минимум 4 байта - два на id и два на размер).
|
-=CHE@TER=- |
![]()
Сообщение
#16
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Если кто пользуется программой pngout, то знает, что если запустить её без параметров, то она покажет справку по использованию, где помимо всего прочего будет и такая строка:
QUOTE /mincodes# Workaround for buggy decoders. 1:Zlib 1.2.1 bug, 2:buggy mobiles Я как-то никогда не обращал на неё внимание. А тут, пару лет назад, начали в комментариях к перепаковщику архивов для Санитаров Подземелий жаловаться, что с новыми (перепакованными) файлами игра не работает и валится с ошибкой, даже если ничего не менять, а только распаковать и сразу же запаковать назад. Я сначала было убрал упаковку вообще, благо игра позволяла это сделать флагами в TOC/FAT архива, но потом, всё же, попробовал её вернуть. Проблема была в том, что я всегда использовал последнюю версию zlib. Здраво решив, что здесь что-то не так, я поглядел исполняемый файл игры и, увидев там строчку "zlib 1.2.1", взял эту же версию библиотеки после чего файлы стали получаться один в один как в игре. Поставив проверку в исходных кодах чтобы не использовали другие версии zlib я благополучно об этом и забыл.Но, на всякий случай, если кто-то будет изменять другие игры и игра невоспринимает ничего кроме сжатых данных, а при перепаковке возникает ошибка - посмотрите не использует ли игра zlib версии 1.2.1. Если коротко, то из-за ошибки в 1.2.1 сжатые файлы можно распаковать другими версиями, но вот сама 1.2.1 может распаковать только то, что сжато ей же или, как в pngout, программами которые могут эту ошибку эмулировать. Ещё, как вариант, можно попробовать заменить код zlib, если он в отдельном .DLL файле. Цитата из zlib/ChangeLog (1.2.1.1 - это версия следующая сразу за 1.2.1): CODE Changes in 1.2.1.1 (9 January 2004) Интересно, что версия 1.2.1 вышла 2003.11.17, а исправленная 2004.01.09 - казалось бы, интервал всего в два месяца, но насколько эта версия успела широко разойтись.... - Fix a big fat bug in inftrees.c that prevented decoding valid dynamic blocks with only literals and no distance codes -- Thanks to "Hot Emu" for the bug report and sample file ... |
-=CHE@TER=- |
![]()
Сообщение
#17
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Понадобилось мне тут как-то создать длинный JPEG файл. Я знал, что там под ширину и высоту отводится 2 байта, поэтому более чем 65535x65535 (0xFFFF x 0xFFFF) там создать нельзя.
Но каково же было моё удивление, когда и 65535 у меня сделать не получилось - сохранил изображение в .BMP и попатался хоть чем-то сжать в .JPG, но всё что было под рукой отказывалось с таким файлом работать, причём ещё и без внятного сообщения об ошибке! Начал уменьшать высоту, пробуя после каждого уменьшения заново всунуть в JPEG и на 65500 изображение наконец-то упаковалось. Пошёл гуглить. Релевантной информации очень немного, даже стандарт на JPEG и Wikipedia пишут о 65535, так что самое внятное объяснение, которое удалось найти, выглядит так: QUOTE Symptom © Источник.A job fails with the error "Maximum supported image dimension is 65500 pixels(JPEG standard).." Cause This is caused by a combination of preview DPI setting and the height or width of the output file. The maximum pixel height/width of a JPEG is 65535 or 2^16-1. Many software implementations reduce this slightly to 65500 including libjpeg and libjpeg-turbo. This is a limitation of the JPEG standard. Resolution Error: JPEG Compression failed: Maximum supported image dimension is 65500 pixels(JPEG standard).. This is due to the preview file that is created regardless of input file type. The maximum allowed is a combination in the preview settings of your workflow of the DPI setting and the output size of your job. For example: if your preview DPI is set to 100 the max height/width would be 655" as 100x655=65500. This can be resolved by: * disabling the preview on the workflow * reducing the DPI so the preview image does not exceed 65500 pixels * selecting a fixed preview size from the dropdown. |
-=CHE@TER=- |
![]()
Сообщение
#18
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Закрывая тему по игре Total Overdose - на сайте опять просили написать утилиту для упаковки.
Меня откровенно ломало это делать, но подумалось, что есть способ проще, т.к. формат, по сути, почти что .ZIP - возможно, игра его и поддерживает. Заглянул внутрь исполняемого файла игры TOD.EXE и сделал поиск ".zip" - нашёл такие строки (я здесь по строкам разбил, но это ASCIIZ строки, где каждая заканчивается нулём): CODE /uk_sounds.naz Как видите, к каждому .NAZ идёт в паре .ZIP (видимо, если .NAZ не найден). Остальные архивы я нашёл внутри исполняемого файла одной строкой (это одна строка, с запятыми и пробелами):/uk_sounds.zip /it_sounds.naz /it_sounds.zip /de_sounds.naz /de_sounds.zip /fr_sounds.naz /fr_sounds.zip /es_sounds.naz /es_sounds.zip CODE blocks.naz, sounds.naz, videos00.naz, videos01.naz Что как бы говорит о том, что новые .NAZ файлы создавать бесполезно, т.к. игра не ищет по маске *.NAZ, а работает строго только с именами упомянутыми выше.И тут меня осенило, что, возможно, функция открывающая архивы одна, где внутри, уже по типу файла, определяет как его открывать: как .NAZ или как .ZIP. Тогда я сделал следующее: 1. Дешифровал все архивы .NAZ в .ZIP при помощи утилиты nastozip. 2. Убрал во временный каталог все оригинальные .NAZ файлы. 3. Переименовал все полученные .ZIP архивы в .NAZ (просто раширение сменил). 4. Запустил игру и... всё заработало будто так и было. Даже новую игру начал - никаких ошибок. Всё, конечно, не тестировал, но, подозреваю, что проблем быть не должно. Мораль сей басни такова: вот так лень победила желание что-то делать (конвертер из .ZIP обратно в .NAZ). Спасибо сказали:
|
-=CHE@TER=- |
![]()
Сообщение
#19
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Размышлял над тем где этот текст будет лучше разместить - решил, что в этой теме будет наиболее подходящее место. Речь пойдёт о недавно обновлённом конвертере Liberation Studio .WMV decrypter. Я хочу сразу написать о том что и как там было, по свежим следам, пока помню и не забыл какие-нибудь небольшие, но важные детали.
Так вот, когда я написал этот конвертер в 2009 году, то он поддерживал только первую и вторую часть игры "Алиса" - там было несложное шифрование заголовка. Но вот начиная с третьей части шифровать стали не заголовок, а данные со звуковыми и видео блоками, из-за чего файлы проигрывались с щелчками и треском в аудио дорожке и разноцветным мусором вместо видео. QUOTE Что мешало: Я почему-то, почти до последнего момента, считал, что шифровали не сами блоки, а заголовки к ним, как это было в некоторых подобных играх, где, например, в .AVI формате обнуляли в заголовках ширину, высоту и идентификатор кодека у сжатых данных. С 2009 года в комментариях, на почту, в обратную связь и так далее, время от времени приходили просьбы добавить поддержку третьей "Алисы" и "Жучка" (как выяснили умельцы, подменяя файлы, там такое же шифрование было). Я с 2009 года один-два раза в год пытался с этим шифрованием разобраться, но всё никак не мог. QUOTE Что помогло: В 2008 году я писал по работе видео проигрыватель, который работал как раз с DirectShow (компонент DirectX отвечающий за проигрывание видео файлов системными кодеками), так что знал что такое FilterGraph, SourceFilter, SinkFilter, что такое In Pin и Out Pin, как их соединять и так далее, а также знал о программе GraphEdit (DirectShow Graph Tool by Microsoft) и прочих таких вещах. Если бы это были для меня неизвестные технологии, то, скорее всего, осваивать их с нуля только чтобы написать конвертер я бы не стал, так что конвертер, вероятно, до сих пор не был бы написан. В общем, засунув исполняемый файл третьей "Алисы" в дизассемблер я увидел, что там строится FilterGraph и, примерно, понял что происходит. Смотрите, если запустить упомянутый выше GraphEdit и открыть (File -> Render Media File...) там любой .WMV файл, то увидим примерно следующую схему (содержимое FilterGraph): CODE +-------------+ |"Raw Video 0"| => [in0 "WMAudio Decoder DMO" out0] => [Audio input pin (rendered) "Default DirectSound Device" (clock)] |start_1.wmv | |"Raw Audio 0"| => [in0 "WMVideo Decoder DMO" out0] => [VMR input0 "Video Renderer"] +-------------+ Итак, что мы видим на этой схеме? Мы видим, что от входного файла "start_1.wmv" идут два потока: звуковой и видео. Сначала оба потока идут через соответствующие декодеры, а потом в фильтры, которые выводят уже декодированные (разжатые) потоки на экран и звуковую карту (воспроизводят). Несложно догадаться, что между первым блоком и декодеровщиками авторы игры всунули свои собственные фильтры, которые на ходу расшифровывают данные, а потом уже передают их декодерам. Это можно сделать заполнив FilterGraph после его создания вручную (но кому такое не надо, то используют специальный метод, куда можно подать только путь до входного файла или ссылку, а все фильтры и связи между ними за тебя DirectShow построит). То есть задача какая: понять где находятся эти фильтры и посмотреть как и что там внутри шифруется. И вот тут, вы не поверите, я 15 лет натурально страдал. Дело в том, что программа написана на ООП, да и сам интерфейс DirectX хотя там и есть процедурный способ вызова, но на уровне машинных команд он всё равно объектный. Указатели на указатели. Куда что указывает, откуда берётся - хрен поймёшь. Т.е. я вижу код, который создаёт FilterGraph и засовывает туда свои фильтры, но адресов тех фильтров не вижу, а те подпрограммы, куда я захожу, ни на что внятное не похожи. Гуглив так и сяк, я нашёл программу "DirectShowSpy.dll", которая после регистрации в системе (через "regsvr32.exe /i DirectShowSpy.dll" и не забудьте (!) потом удалить через ключ "/u" вместо "/i") пишет в файл "C:\DirectShowSpy.log" всякое разное и интересное, а также делает все FilterGraph в системе возможными для совместного использования с возможностью подключения (в GraphEdit это File-> Connect to Remote Graph...). И я даже при запуске игры и подключения к одному из таких FilterGraph вижу те самые SinkFilter, которые дешифруют, но при попытке посмотреть их свойства GraphEdit тупо падает. При попытке добавить фильтр Dump (см. ниже) всё тоже падает даже в GraphStudioNext (см. ниже). В общем я и так, и сяк, и об косяк, но никак не мог понять где же этот чёртов код, которые занимается дешифровкой. После очередного комментария на позапрошлой неделе на страничке с программой, я решил, что попробую ещё раз побиться об косяк. Все свои тесты я проводил на файле "start_1.wmv" с логотипом издателя GFI (Game Factory Interactive), при этом у меня был ещё один такой файл, но от второй "Алисы" с расшифрованным заголовком. Для удобства обозначим их так: start_1ok.wmv - расшифрованный от второй "Алисы" (ok) start_2no.wmv - зашифрованный от третьей "Алисы" (no) Увы, файлы разного размера и очень сильно отличаются. Да, если кто-то подумал что можно поставить бряк на чтение файлов в DirectShow, затем на обращение к памяти и посмотреть где идёт изменение памяти (расшифровка), то... я это тоже пробовал, но с тем как прочитанный буфер кидается из одного места памяти в другое (а там ещё FileMapping) - вы реально умрёте, пока доберётесь в отладчике до места расшифровки. Но на прошлой неделе мне в голову пришла гениальная мысль, которая всё и решила. Я снова загрузил нормальный файл в GraphEdit, затем добавил в FilterGraph фильтр под названием "Dump" (Graph -> Insert Filters... -> DirectShow Filters -> Dump). QUOTE Что мешало: При раскрытии дерева "DirectShow Filters" у меня падал GraphEdit. Падал он потому, что когда я купил новый телефон в 2013 году (Samsung S5610), то программа для этого телефона (Samsung Kies) начала в систему всякую херню ставить и я прервал установку Windows Media чего-то там. Поэтому у меня при построении списка всё накрывалось тазом. Пришлось искать и скачивать программу GraphStudioNext - которая почти как GraphEdit, только там больше функционала и она не падает. Главное в заголовке PE EXE опустить версию системы с 6.0 (Windows Vista) до 5.0 (Windows 2000), чтобы эта программа запускалась на Windows XP. И да, я пытался поставить Kies в песочнице, но так как там нужен драйвер для работы с сотовым телефоном, то программа, естественно, из песочницы, нифига телефон не видела. Ещё можно было таки нагадить в систему до конца Windows Media чего-то там, затем попробовать его удалить (если получится), но я решил оставить как есть. Дальше я удалил все фильтры у видео и сразу после Source фильтра соединил пин с Dump фильтром, указал файл и записал туда все кадры подряд (в файл они уходят без служебных заголовков, только сами данные). После чего я проделал тоже самое с аудио. А потом всё описанное, но уже с зашифрованным файлом. На всякий случай скажу очевидное: чтобы что-то куда-то писалось, нужно после построения фильтров и соединения пинов, запустить FilterGraph на проигрывание. Получились у меня условно такие файлы: vid_ok.dat - нормальное видео aud_ok.dat - нормальный звук vid_no.dat - шифрованное видео aud_no.dat - шифрованный звук И вот тут я понял, что, походу, конвертеру быть, ибо дампы видео и звука у нормального и шифрованного файла совпадали по размеру! Я тут же сделал сравнение видеофайлов: CODE fc /b vid_ok.dat vid_no.dat > vid_list.txt И получил всего 119 байт разницы на 216 Кб. При сравнении аудио файлов получилось 16 разных байт на 69 Кб. Когда я делал сравнение, то не ожидал что всё настолько просто. Я искренне думал, что файл заставки в третьей части "Алисы" был пережат (отсюда и отличающийся размер у .WMV), поэтому хотел посмотреть как сжатый поток начинается - по идее, что-то похожее должно быть (анимация-то в видео одинаковая), может быть, пойму как шифруются первые байты и уже от этого смогу найти полностью код шифрования. Я не мог поверить в свою удачу и начал анализировать изменённые байты (первые 5 байт видео): CODE 000001F4: 17 16 000007D8: BC BD 00000DE3: B3 B2 00001299: 28 29 0000181D: DC DD 00001E64: B8 B9 Сразу видно, что байт либо стал больше на единицу, либо на единицу же уменьшился. Так как непонятно когда прибавляется, а когда вычитается, то я предположил, что это был "byte xor 1" - проверил своё предположение по всем байтам - так и оказалось. А ещё, судя по всему, так как изменений было немного, то, вероятно, в каждом кадре менялся ровно 1 байт. Далее я перевёл первое смещение 0x1F4 в десятичное число и получил 500 - ровное число, скорее всего искусственное, введённое человеком (как 100, 200, 1337 и так далее), потому что в аудио данных первое смещение тоже было 0x1F4. Иными словами, мы теперь знаем, как выйти на код декодирования - нужно искать какой-то такой код: CODE data[500] ^= 1; /* Pascal: data[500] := data[500] xor 1; */ Проще всего найти по смещению, так что я начал искать последовательность байт "F4 01" в "Alice3.exe" и я их нашёл: CODE .0042BC9F: xor byte [ecx + 01F4h], 1 Весь код выглядел так (восстановленный из ассемблера): CODE if (size >= 500) { data[500] ^= 1; } Кто скажет что не так с проверкой - тот молодец. (*улыбается*) Подсказка: когда size == 500, то в массиве data[] есть индексы только с 0 до 499 включительно (итого: 500 элементов), иными словами data[500] - это выход за пределы памяти и потенциальное падение программы с ошибкой (авторам игры просто повезло, что у них таких блоков не оказалось). Но на этом мои мучения не закончились. Да, я теперь знаю метод шифрования, но как подобраться к тем кадрам? Логично для этого открыть документацию Advanced Systems Format (ASF) Specification. Формат .WMV, кто не знал, этот улучшенный и углубленный .ASF. И вот тут я уже бился головой, потому что непонятно как эти поля парсить: то ли они вложенные, то ли нужно те же самые данные иначе интерпретировать. Короче, я натурально страдал. Скачал даже исходные коды ffmpeg и пытался оттуда парсер .ASF/.WMV выдернуть, но там настолько всё запутано, что бросил это гиблое дело. Мне очень повезло, что я нашёл в итоге простой и понятный (хоть и с ООП, но от этого я быстро избавился) код для парсинга .ASF/.WMV на GitHub: ASF file parser by Maoxu Li. После чего я допилил парсер под свои нужды, добавил расшифровку и видео с логотипом было расшифровано и проигралось без ошибок! Проверял через Windows сборку MPlayer (юниксовая программа) - этот проигрыватель в консоль ошибки кидает, если с видео или аудио что-то не так при декодировании. Я тут же взял самый большой .WMV файл из игры, натравил на него программу и... старые ошибки исчезли, зато появились новые. После этого я нашёл файл поменьше, где тоже были ошибки (всё же 102 Мб не быстро расшифровывается, плюс потом откатывать из резервной копии, чтобы снова проверить - лишнее время) и начал выводить в консоль данные по блокам, которые расшифровывал. Выяснилось, что блоки, иногда, меньше, чем 500 байт. Причём в .ASF/.WMV количество пакетов делить на размер всей части файла с данными - получаем фиксированный размер одного пакета. Но так получается, что блоки, относящиеся целиком к одному кадру или кусочку звука, не умещаются в один такой пакет, поэтому дробятся на несколько. А вот в SinkFilter они приходят уже собранные в одно целое. В спецификации увидел, что есть такая штука как Media Object Number и он идёт по порядку: 0, 1, 2, 3 и так далее. Поставил проверку в функцию расшифровки, что если текущий номер объекта не равен предыдущему и размер больше 500 и не расшифрован, только тогда расшифровывать. Ошибок стало сильно меньше, но они всё равно остались. Начал логировать номер объекта и, ах, ты ж, долбанный, ты нафиг: 110, 111, 112, 112, 113, 113, 114, 114, 114, 25, 115, 116, 116, ... То что номера дублируются - это нормально, как я уже говорил, блоки могут разбиваться, если целиком в пакет не влезают. А вот 25 между 114 и 115 будет расшифровано (вернее зашифровано) хотя не должно. Получается блоки могут идти в любом порядке, плюс само поле Media Object Number занимает всего 1 байт, так что после 255 опять получаем 0 (в рамках достаточно длинного видео - легко). Однако я разобрался, что есть ещё поле Offset Into Media Object - это смещение текущего блока данных относительно начала объекта с номером Media Object Number. И смещение всегда ноль, если это новый объект. Иными словами - текущее смещение - это сумма всех уже пройденных и обработанных блоков в этом объекте. В итоге функция расшифровки получилась следующей: CODE static uint8_t obj_stat[256]; /*static uint32_t nTotal;*/ void wmv_decrypt(uint8_t *p, uint32_t len, uint8_t num, uint32_t ofs) { /* printf("%08X %04X %02X\n", ofs, len, num);*/ if (p) { /* patched Media Object */ if (!obj_stat[num]) { /* new Media Object (always started with zero offset) */ if (!ofs) { obj_stat[num] = 1; } } /* not patched Media Object */ if (obj_stat[num]) { if ((ofs + len) > 500) { /*nTotal++; printf("%02X %02X (%u)\n", p[500 - nOffset] ^ 1, p[500 - nOffset], nOffset + l);*/ p[500 - ofs] ^= 1; obj_stat[num] = 0; } } } } Я специально оставил в коде закрытый в комментарии отладочный вывод информации. Что такое nTotal? Помните, я выше писал, что у меня была разница в 119 байт у видео и 16 байт у звука? В сумме будет 135 (это для упомянутого файла start_1.wmv на котором тестировал) - я выводил это число после завершения программы, чтобы убедиться что у меня все байты были расшифрованы и не были зашифрованные лишние. А в SinkFilter у меня была бы просто проверка на 500 вместо всего вот этого! Другое дело, что непонятно как бы там потом данные снова в .WMV файл собрать без пережатия - я не уверен, что такие фильтры существуют, а писать свой - проще забить и забыть. В общем, да, так я и справился с этой игрой и форматом. 15 лет спустя. QUOTE Что мешало: Почему я сразу не нашёл код декодирования? Знаете, я, может, его и видел, но ожидал найти цикл по блоку данных с некоторыми вычислениями, а не проверку и один "xor 1", что, вообще, больше походило на переключение какого-то флага, чем на расшифровку. Вторая вещь - как я уже писал в самом начале, я думал что шифровали заголовок. Авторы игры, видимо, тоже что-то такое подозревали, так что решили усложнить жизнь - сделали отступ в 500 байт от начала данных, к тому же меняли всего 1 байт (если точнее - всего 1 бит в байте). Вроде бы и пустяк, а сколько головняка. Фух! Надеюсь описанное кому-нибудь пригодится. Спасибо всем, кто дочитал до этого момента и уж тем более разобрался в моей писанине - вы невероятны! (*улыбается*) |
![]() ![]() |
Упрощённая версия | Сейчас: 9th September 2024 - 14:24 |