IPB

Добро пожаловать, гость ( Вход | Регистрация )

История благодарностей участнику -=CHE@TER=- ::: Спасибо сказали: 314 раз(а)
Дата поста: В теме: За сообщение: Спасибо сказали:
Aug 19 2024, 17:13 Описание форматов файлов
Размышлял над тем где этот текст будет лучше разместить - решил, что в этой теме будет наиболее подходящее место. Речь пойдёт о недавно обновлённом конвертере 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 Audio 0"| => [in0 "WMAudio Decoder DMO" out0] => [Audio input pin (rendered) "Default DirectSound Device" (clock)]
|start_1.wmv  |
|"Raw Video 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 бит в байте). Вроде бы и пустяк, а сколько головняка.

Фух! Надеюсь описанное кому-нибудь пригодится.
Спасибо всем, кто дочитал до этого момента и уж тем более разобрался в моей писанине - вы невероятны! (*улыбается*)
Siberian GRemlin,
Feb 22 2024, 14:21 Chemax Siberian GRemlin,
Feb 12 2024, 18:07 Chemax
В 2022 году домен CheMax.ru был разделегирован, так что история данной программы на этом закончилась, поэтому можно подвести уже окончательный итог.
Для начала отвечу на самое первое сообщение этой темы (понимаю, что уже не актуально, ну да ладно):
QUOTE(Кантемир @ Mar 18 2007, 18:00) [snapback]536[/snapback]
Просто хочу оболочку и возможности сохранить, а база кодов с нула хочу написать
и добавить секреты.
Блин как редактировать база данных?
А может ктонибудь создать прогу на подобия это? Просто там в chemaxе нельзя ни редактировать ни с нула.
Нет, это невозможно. Дело в том, что описания кодов хранятся зашифрованные в текстовом файле "Cheats.dat", в то время как соответствующие этим текстам имена игр и смещения до них в этом файле, намертво прошиты в "Chemax.exe", который ещё и ASPack'ом упакован (защищён от изменений). Поэтому, максимум, что можно сделать, это изменить коды к существующим играм так, чтобы они не выходили за отведённое им место (меньше текста можно - лишнее пробелами заменить, больше - нельзя).
Сама программа и некоторые её старые и новые версии, помимо веб-архива, доступны ещё здесь: CheMax.
И тут, поковыряв старые и новые версии этой программы, я выяснил интересную штуку про ключи шифрования. Оказывается, ключ "a@g5eDu(*5" использовался только для русской версии. В английской версии ещё с 2004 года использовался ключ "qZ8&5N3eS0" на который перевели и русскую между 2013 и 2018 годом - видимо, автору надоело пересобирать исполняемый файл с разными ключами при выпуске новых версий. Так что, признаю, моё предположение о том что ключ поменяли, потому что я его в этой теме публично засветил, было неверное.
Попробую при следующем обновлении сайта добавить программу для расшифровки любой базы данных (с автоматическим определением ключа расшифровки), а также два текстовых файла со смещениями и именами игр в последних версиях "Cheats.dat" (RUS 21.4 и ENG 20.8) для тех, кто захочет распотрошить базу данных (распаковал и распарсил исполняемые файлы "CheMax.exe"). Увы, это, конечно, не вернёт потерянных трейнеров и других полезных утилит, которые накрылись вместе с сайтом программы.
Функция для расшифровки любой базы данных выглядит так (возвращает не нулевое значение, если буфер удалось расшифровать):

CODE
uint32_t CheMaxDecrypt(uint8_t *p, uint32_t size) {
uint8_t key[10];
uint32_t i, k;
  i = 0;
  /* sanity check */
  if (p && size && ((*p == 0x81) || (*p == 0x91))) {
    /* detect key */
    if (*p == 0x81) {
      memcpy(key, "a@g5eDu(*5", sizeof(key));
    } else {
      memcpy(key, "qZ8&5N3eS0", sizeof(key));
    }
    /* decrypt database with key */
    for (i = 0; i < size; i++) {
      k = i % sizeof(key);
      p[i] += ((p[i] > key[k]) ? 0 : 255) - key[k];
    }
    i = 1;
  }
  return(i);
}

На этом, вероятно, уже точно всё - тему можно считать закрытой.
Siberian GRemlin,
Feb 10 2024, 15:29 Новости сайта
Нашему проекту 7-го февраля 18 лет исполнилось - достигли совершеннолетия, можно сказать.
Недавно гуглил со ссылками на наш сайт и вот чего нашёл (2021 год, кстати, на том канале это видео с наибольшим количеством просмотров):
Need for Speed Most Wanted | How to Extract Soundtrack from Game File | 2021 Tutorial
Аж смахнул скупую мужскую слезу - столько лет прошло, а нашей программой до сих пор пользуются.
Какие же мы офигенные все - даже столько лет спустя. (*улыбается*)
Не зря мы столько сил и времени вложили в эту программу.
Я у себя на домашней страничке уже добавил в статью про конвертер для NFS, но хочу повториться (нисколько не умаляя труда каждого из нас), что большая часть кода для NFS Multimedia Converter была написана товарищем jTommy - по сути, если бы он тогда не взялся за это, то ничего бы не было.
Было очень классно - огромное вам всем спасибо, друзья, за то что есть что вспомнить!
Siberian GRemlin,
Sep 20 2022, 10:55 Описание форматов файлов
Закрывая тему по игре Total Overdose - на сайте опять просили написать утилиту для упаковки.
Меня откровенно ломало это делать, но подумалось, что есть способ проще, т.к. формат, по сути, почти что .ZIP - возможно, игра его и поддерживает.
Заглянул внутрь исполняемого файла игры TOD.EXE и сделал поиск ".zip" - нашёл такие строки (я здесь по строкам разбил, но это ASCIIZ строки, где каждая заканчивается нулём):
CODE
/uk_sounds.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
Как видите, к каждому .NAZ идёт в паре .ZIP (видимо, если .NAZ не найден). Остальные архивы я нашёл внутри исполняемого файла одной строкой (это одна строка, с запятыми и пробелами):
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).
Siberian GRemlin,
Aug 30 2022, 09:27 My Big Sister (PS Vita) [Adventure Game Studio (AGS)]
А! Вот оно что. Проверил отдельно "agstract.exe" - он нормально работает. Значит, действительно, проблема в MSYS2 и том, что он файл найти не может. Нужно посмотреть какой каталог текущий, возможно, что, наоборот, не /bin/, а какой-то другой. Набери в MSYS2 команду "ls" (без ковычек, это что-то типа "dir" в Windows) и посмотри какие файлы будут выведены на экран - в каком каталоге ты сейчас находишься туда и перемести свой "game.exe". Или через команду "cd" (работает также, как и в Windows) перейди в нужный и оттуда уже вызывай. Конкретно MSYS2 у меня не стоит, но описанная схема в общем и целом для подобных иксовых программ должна работать.
necros2k7,
May 14 2021, 18:08 C# есть такие???
Я последний раз что-то делал на шарпах году... эээ... в 2005 наверное. С тех пор к ним не притрагиваюсь.
По идее можно на MSDN посмотреть, вот, например, описание FileStream и работы с файлами: FileStream Class (System.IO).
Rash_forever,
Dec 25 2020, 15:27 Жёсткий диск
QUOTE(Siberian GRemlin @ Dec 25 2020, 13:30) [snapback]4624[/snapback]
Windows 7, NTFS. Я тоже сперва подумал, что проблема в «Total Commander», выделил те 65536 файлов в папке и удалил, но остальные файлы не появились – папка пустая.
Саму папку пробовал удалять?

QUOTE
«R.Saver» видит 65536 удалённых файлов, но не последних, а первых. Методом сложения пустого места и размера всех файлов на диске получилось, что недостаёт 4 гигов.

chkdsk /f ошибок на этом диске не находит.
Тогда у меня вопрос, а как ты изначально узнал, что создалось более 65536 файлов? Потому что если chkdsk ошибок не находит, то MFT должна быть в порядке. Я сейчас у себя на диске NTFS посмотрел:
102840639488 - всего байт (T)
805502976 - свободно байт (F)
101681394989 - сумма размера всех файлов на диске (S)
При этом если посчитать T - F:
102840639488 - 805502976 = 102035136512 - типа, сколько должно быть занято (E)
Однако же:
102035136512 (E) - 101681394989 (S) = 353 741 523 ~ 337 Mb разница
Но у меня и диск небольшой - около 100 Гб. Так что вполне возможно у тебя, если диск огромный, то 4 Гб на разницу и уходит.
Там же размер не побайтно считается, а по рамеру кластера (average - среднее, а не точное значение):
QUOTE
On the typical hard disk partition, the average amount of space that is lost in this manner can be calculated by using the equation (cluster size)/2 * (number of files).
Попробуй на другом диске также посчитать, как ты здесь посчитал (хорошо, если он такого же объёма и заполненности, чтобы порядок примерно одинаковый был) и сравнить результаты.

QUOTE(Siberian GRemlin @ Dec 25 2020, 13:30) [snapback]4624[/snapback]
chkdsk /f /r на четвёртом этапе сжирает всю оперативку, что ОС кричит караул. Если не вырубать его, а оставить в таком состоянии, то он обрабатывает примерно по 1 файлу в секунду, иногда со стопорами и скачками на несколько тысяч. За пару часов он проверил около 10%, после чего я его вырубил.
Если ты хочешь поверхность проверить, то это лучше делать загрузившись с диска, а не в системе.

На всякий случай тут пару ссылок нашёл, но там везде chkdsk проблемы находил, и решения без форматирования, к сожалению, там нет:
_ttps://answers.microsoft.com/en-us/windows/forum/windows_7-performance/is-there-a-way-to-delete-orphaned-files/9bfc5c27-5243-4488-be07-ad8a62760326
_ttps://answers.microsoft.com/en-us/windows/forum/all/chkdsk-f-gives-result-of-orphaned-files/4f7d04bd-1eb8-4fe7-829a-335ec18dc94d
_ttps://answers.microsoft.com/en-us/windows/forum/all/ntfs-corruption/71208334-5734-4e96-9e3a-9582f547feee
_ttps://drobocommunity.m-ize.com/t/unindexed-file-chkdsk-wont-complete-run/3211
Siberian GRemlin,
Jul 2 2020, 19:03 Delphi, Asm, C, WinAPI, PHP, ...
Это слегка не так работает.
%d - вывести digit
%ld - вывести long digit (для архитектур, где размер int больше long, например int 16, а long 32)
%lld - вывести long long digit (как правило int 64)

%0lld - тоже самое что и %lld (символ один и не указан размер)
%03lld - тоже самое, что %03d (выравнять тремя нулями слева, если число меньше), но для int64

CODE
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int main(void) {
ULARGE_INTEGER x;
  x.QuadPart = 1;
  printf("%0lld\n", x.QuadPart); // будет просто 1
  printf("%03lld\n", x.QuadPart); // будет 001
  return(0);
}

В сях нет стандартных функций для разделения тысяч, чтобы из 1234567 сделать 1,234,567 или 1 234 567. Боюсь тебе придётся вручную искать код который это делает. Попробуй поискать по работе со строками и символом 0x2C (запятая). Ставлю на то, что как раз твои строки и работают с числами - смотри где они используются.
"%03lld" нужно чтобы у тебя числа менее тысячи добивались нулями: 3007 => 3,007, а не 3,7.
"%0lld" - это остаток в левой части, в примере 3007 - это будет тройка, т.к. её добивать нулями не нужно.
Siberian GRemlin,
Apr 10 2020, 18:20 Command & Conquer: Red Alert [Hidden Easter Egg]
Не думал, что вернусь к этой теме, но... Сделал сегодня атаку по словарю с комбинацией из двух слов - и таки что вы думаете? (*улыбается*)
QUOTE
Hidden commandline argument for hash 0xD95C68A2: FROMINSTALL
Hidden word for network chat to see developers easter egg for hash 0x72A47EF6: FELTPLAYWORK
Насчёт первого хеша я уверен на 100%, а насчёт второго практически (я ещё не закончил брутфорс - там 6 часов на том компьютере с 4 ядрами, к которому у меня сейчас доступ есть, при этом я распараллелил процесс и там все ядра заняты - задача на 4 потока разбита). Подробности как закончу напишу - я, вообще-то, демо-версия C&C:RA брутфорсю (там есть новые ключи и тоже от них хеши). Кстати, я обновил статью про The Neverhood у себя на домашней страничке - там теперь человеческие хеши (плюс разобрался что коды делают, кроме одного) - вчера тоже из двух слов перебирал (35 минут ушло в силу того что там алгоритм легче и можно вместо слов уже посчитанные хеши объединять, что в разы быстрее), не все, но большую часть кодов удалось чем-то адекватным заменить.
Siberian GRemlin,
Feb 20 2020, 14:11 Clock Tower (PS1)
Да всё нормально.
Ещё раз подчёркиваю: я не против помочь и хочу помочь, но я никак не могу понять в чём проблема зайти в нужную тему (ссылку я уже давал не один раз), и написать там вопрос? Нажать на ссылку и перейти в тему, нажать там на кнопку "Ответить", написать вопрос, нажать "Отправить"?
Это же не сложно? Или я чего-то не знаю?
Я правда не могу понять что происходит. В чём проблема-то?
Просто уже целая неделя прошла, за это время можно было 1 раз написать сообщение в нужной теме и проблемы бы не было.

Объясняю свою позицию: я хочу чтобы на форуме всё было более или менее упорядоченно. Чтобы если понадобится что-то найти по программированию, то это всё будет в одной теме. Если по ресурсам - то для этого есть подфорум. По программам - свой подфорум. И так далее. Ну вот в жизни, если хочешь сварить суп и не можешь найти крышку от кастрюли, то ты же не пойдёшь её в спальню или ванную искать, а будешь её искать на кухне, верно?

Ещё раз: я хочу помочь и я готов помочь. Но задай, пожалуйста, вопрос в нужно месте.
Или объясни почему это так сложно задать его именно там?
Я вот свою мотивацию объяснил и аргументировал. В этом тоже нет ничего сложного (на мой взгляд).
Спасибо.
Rash_forever,
Feb 19 2020, 11:31 Clock Tower (PS1)
QUOTE(-=CHE@TER=- @ Jan 27 2020, 14:28) [snapback]4482[/snapback]
А если есть вопросы по программированию, то их лучше >>>в другой теме<<< задавать.
Rash_forever,
Feb 18 2020, 13:51 Clock Tower (PS1)
Хороший вопрос. Если человек спрашивает, значит пытается разобраться - это здорово!
Но, главное в программировании, да и, наверное, во многих других областях - это внимание к деталям.
Я парой сообщений выше давал ссылку на форум Extractor.ru с примером похожей программы и комментариями, где этот момент был объяснён.
Но я могу объяснить гораздо подробнее и понятнее, с примером, если подобный вопрос, как я уже писал парой сообщений выше, будет задан в другой теме, ссылку на которую я, опять таки, в том же сообщении уже давал.
Вот. Внимание к деталям - это очень важно.
Спасибо!
Rash_forever,
Jan 31 2020, 16:15 Clock Tower (PS1)
Вот это я пролетел. Дичайше извиняюсь - промахнулся с форматом. Я почему-то подумал что размер 16, когда он 32. Исправил свою программу выше - теперь она должна правильно распаковывать:

CODE
  uint16_t size;
  uint16_t flags;  /* unknown 0, 1 or 3 */

Заменил на (16 + 16 = 32):

CODE
  uint32_t size;

Потому что размер не 2 байта, а 4. Мне почему-то подумалось, что раз файл небольшой, значит и данные там не должны за 2 байта выходить. А есть больше из-за чего файлы извлекались не целиком.
Теперь точно должно правильно работать, потому что я проверил: сумма всех извлечённых файлов + размер заголовка = целиком размеру D1A.BIN.
Прошу прощение за причинённые неудобства.
Rash_forever,
Jan 27 2020, 14:28 Clock Tower (PS1)
Да почему - нормальные вопросы. На Extractor.ru была 15 лет назад тема по программированию, где я написал похожую программу с подробными комментариями. Правда там были архивы .PAK от Quake II, но главное не это, а понимание за что какие команды языка отвечают. Я ту программу недавно переписал, чтобы была более аккуратная и понятная. Думаю как отправная точка для разбора и понимания программы от Clock Tower (она куда проще) - это то что нужно.
А если есть вопросы по программированию, то их лучше в другой теме задавать (кстати, тоже рекомендую её почитать, а всё что относится к PHP, Assembler и настройке веб-серверов можешь спокойно там пропускать). Если правда этим интересуешься и есть желание разобраться, то тебе с удовольствием ответят.
Rash_forever,
Jan 19 2020, 14:52 Clock Tower (PS1)
QUOTE(Rash_forever @ Jan 19 2020, 11:18) [snapback]4478[/snapback]
огромное спасибо ему правда не пойму как он узнал это без проги по просмотру тайловой графики!
Нашему проекту CTPAX-X в феврале будет 14 лет, а занимаемся мы всем этим гораздо больше времени. Когда много с разбором незнакомых файловых форматов работаешь, то уже глаз намётан. Здесь нет ничего удивительного - с опытом и временем каждый это может. Другое вопрос, конечно да, количество времени, которое на это уйдёт. Но спасибо за тёплые слова!

QUOTE(Rash_forever @ Jan 19 2020, 11:18) [snapback]4478[/snapback]
Т.Е. 1 картинка начало палитры от смещения от заголовка, 2-я картинка +32 байта от начала палитры чет намудрил blink.gif мож поймет то))))
Я формат описывал по прикидке, не особо проверяя точность значений (т.е. программу для чтения и проверки не писал). Поэтому, возможно, что-то упустил, откуда и вылезают эти +32 байта. Я поэтому и написал "подозреваю что формат примерно такой" - если бы знал точно, то так бы и написал, что формат 100% вот такой. Сам не люблю, когда читаешь документацию, где пишут что всё точно-точно вот так, а ты потом смотришь, но в файле на диске всё местами сильно не так, как описано. А так хотя бы честно предупреждают что оно примерно где-то так, так что есть на что опираться и от чего оттолкнуться при изучении, но считать за точное описание не стоит.
Rash_forever,
Nov 19 2019, 22:51 Полезные ссылки
ICY Hexplorer
Интересный hex-редактор. Автор уверяет, что даже под Windows 98 может работать.
Там есть дизассемблер (правда только 32-х битный, хотя в описании написано, что он 16-ти битный), просмотрщик рисунков (можно битность указать), поиск, контрольные суммы, вставка и замена текста, создание и разбор структур, макросы и ещё много чего. Правда обновлялось последний раз в 2011 году, но идёт с исходными кодами на C++.

Главное после запуска сразу зайти в настройки View -> Options... и выбрать там:

Font: [Oem Fixed Font]
Это если нужно, чтобы русский текст кодировки 866 DOS нормально отображался.

Colors: White background, special signs marked
Это чтобы не сломать глаза на цветовой теме по умолчанию.

[v] Show offsets
Это чтобы смещение показывало.

Кстати, дизассемблер и поиск рисунков будут работать с той позиции, где курсор стоит, поэтому сначала нужно щёлкнуть мышкой на каком-то байте, а уже потом вызывать, например, View -> Disassembler.

Структуры тоже удобно смотреть. Например, открываем в программе любой .BMP файл, затем щёлкаем мышкой на первом байте и выбираем Structures -> BMP Header после чего в появившемся окне можно щёлкать мышкой по полям структуры и они будут сразу же в файле подсвечиваться. Можно добавлять свои структуры и неизвестный формат разбирать без написания утилиты для разбора. Неудобно только, что программа показывает значения полей только в десятичном виде - иногда и в шестнадцатеричном нужно. А, я туплю, в файле-то оно и так в шестнадцатеричном подсвечивать будет. (*улыбается*) И всё же хотелось бы видеть что-нибудь типа 00123456, а не 56 34 12 00.

Добавлено:
А-а-а-а-а!!! Решил попробовать собрать из исходных кодов. Компилируется, но на файле hash/SHA.cpp зависло. Минута, другая, сижу жду. Открыл диспетчер задач, а там процесс cc1plus.exe жрёт и жрёт оперативную память. Наконец память закончилась и всё упало. Заглянул в этот файл - вместе с заголовочным SHA.h там не так уж и много кода, но всё объектно ориентированное. С 2002 года пользуюсь этим компилятором, кучу разных проектов собирал... Нет, понятно, что в более новой версии этот косяк уже поправили, но у меня появилась ещё одна наглядная причина объяснить почему классы, объекты и прочая абстракция - совершенно лишние и ненужные сущности.
Rash_forever,
Sep 6 2019, 10:40 Полезные ссылки
x86 Instruction Set Reference
Хороший и простой справочник по командам языка Assembler архитектуры x86.
Любую команду там можно быстро подсмотреть без всякой лишей зауми и воды, которая только отвлекает.
Также можно всё это стянуть с GitHub и даже без подключения к Интернету пользоваться.
Rash_forever, Siberian GRemlin,
Aug 9 2019, 18:27 Clock Tower (PS1)
Выложенный файл можно распаковать на отдельные составляющие вот так:

binunpak.c
[codebox]#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <stdint.h>

#pragma pack(push, 1)
typedef struct {
uint32_t offs;
uint32_t size;
uint32_t zero; /* always zero? */
uint16_t number; /* number in group */
uint16_t last; /* last in group: 1 - yes; 0 - no */
} bin_item;
#pragma pack(pop)

int main(void) {
uint32_t i, j, k, count;
bin_item *list;
FILE *fl, *f;
char s[16];
void *p;
fl = fopen("D1A.BIN", "rb");
if (!fl) { return(1); }
fread(&count, 4, 1, fl);
fseek(fl, 16, SEEK_SET);
list = (bin_item *) malloc(count * sizeof(list[0]));
if (!list) {
fclose(fl);
return(2);
}
/* relative offset */
k = 16 + (count * sizeof(list[0]));
fread(list, sizeof(list[0]), count, fl);
for (i = 0; i < count; i++) {
sprintf(s, "%03u-____.DAT", i);
p = malloc(list[i].size);
if (p) {
fseek(fl, list[i].offs + k, SEEK_SET);
fread(p, list[i].size, 1, fl);
memcpy(&s[4], p, 4);
for (j = 0; j < 4; j++) {
/* alpha or number */
if (isalnum(s[4 + j])) { continue; }
s[4 + j] = '_';
}
f = fopen(s, "wb");
if (f) {
fwrite(p, list[i].size, 1, f);
fclose(f);
}
free(p);
}
printf("%s\n", s);
}
free(list);
fclose(fl);
printf("\ndone\n\n");
return(0);
}[/codebox]
Как я понял, там всё: изображения, звуки, музыка, архитектура комнаты и прочее.
Картинки, походу, в TIG0 файлах, но что это за формат я не в курсе.
Подозреваю, что у TIG0 примерно такой формат:
char[4] - TIG0 - сигнатура
uint32_t - смещение до палитры
uint32_t - смещение до палитры (опять, не знаю почему их два)
uint16_t - количество записей в первой таблице
uint16_t - количество записей во второй таблице
uint16_t - количество записей в третьей таблице
uint16_t - всегда ноль (выравнивание? количество записей в четвёртой? таблица опциональна?)
далее идут две таблицы каждая запись в которой 8 байт:
uint16_t - неизвестно
uint16_t - неизвестно (иногда равно предыдущему значению)
uint32_t - всегда ноль (?)
каждая запись в третьей таблице 12 байт:
uint32_t - смещение?
uint16_t - ширина?
uint16_t - высота?
uint32_t - номер?
Потом идёт палитра (см. смещение из заголовка) и уже сами изображения.
Палитра, как я вижу, 768 байт (по 3 байта на цвет, но прядок (RGB, BGR и т.д.) не проверял).
Кстати говоря, изображение, всё же, на мой взгляд, 8 бит, а не 4, ибо 768/3 = 256 цветов.

Ах, да, crystaltile2 запустить не смог - оно почему-то падает с ошибкой обращения к нулевому (?) адресу.
Rash_forever,
Dec 14 2018, 16:20 MP3
Я тут что подумал - Grom PE лет 10 назад давал ссылку на MP3packer.
См. там файл "mp3packer.html" - это основная страница, ибо сайт уже неживой.
Есть зеркало тут.
Чем это программа хороша (цитата с зеркала): "Provides the ability to losslessly turn VBR files into larger CBR files to humor players which can't handle VBR". Я очень давно последний раз её запускал - вполне возможно, что она может и обычный CBR поднять losslessly с 56 до 128. Понимаю, что место сожрёт, но, во-первых, твой установщик со звуковыми файлами не будет больше занимать (конвертируешь при установке перевода), а, во-вторых, качество не пострадает.
Потому что судя по постфиксу "-ttv-" разработчики игры эти библиотеки с какой-то зависимостью (я так понимаю) компилировали и их так просто, наверное, хрен заменишь. К тому же это вряд ли проблема именно LAME кодека - он должен нормально работать. Скорее всего, действительно, они продолжительность от битрейта считают (рукалицо - HD переиздание такое переиздание), поэтому если даже ты её найдёшь и исправишь чтобы русские файлы работали, то отвалятся все остальные - звуки, музыка и что там ещё есть.
Как-то так попробуй (mp3packer будет в пустое место свои копирайты строкой шарашить):
mp3packer.exe -b 128 b1a.mp3
Siberian GRemlin,
Nov 4 2018, 23:21 No-CD для Little Bill Thinks Big
Я долго ломал мозг пользуясь вот этой ссылкой: Lingo bytecode.

1) Копируешь всё с CD диска в каталог.
2) Через subst Z: <каталог> создаёшь виртуальный диск.
3) Меняешь в реестре букву диска на Z.
4) После этого патчишь:
Joy.cxt
0001D046: 0F 0E
0001D088: 10 0E
Теперь оно будет работать без CD. Проверка отломана не очень красиво, ибо она меняет код "если CD-ROM" на "если не CD-ROM", а также "свободного места на диске больше нуля" на "свободного места не ноль".

Хочешь чтобы работало без проверки CD и без виртуального диска тупо из каталога? Кури доки по ссылке выше и ковыряй байт-код. Меня откровенно ломает в этом рыться.

CODE
4C 05; local
44 0E; push local literal to stack (0E="type")
43 02; arg(2)
57 B1; call
44 0F; push local literal to stack (0F="CD-ROM")
0F  ; a = b
95 00 13 (jmp1 if false)

<...>

4C 06; local var
44 10; push local literal to stack (10="size")
43 02; arg(2)
57 B1; call
03  ; push 0
10  ; a > b (size > 0)
95 00 41; jmp2 if false


Индексы строк проверки, если, вдруг, понадобятся (ищи по 44 XX, где XX номер литерала для складывания на стек):
CODE
00=Projector
01=You need to insert the Little Bill Thinks BIG CD-ROM to play!
02=Windows
03=DirectSound
04=windows
05=Animal Joy
06=SOFTWARE\Scholastic Inc\Little Bill Things BIG
07=CDLet
08=Error
09=HKEY_LOCAL_MACHINE
0A=:\DATA\LB_MAIN.DXR
0B=:\DATA\CASTS
0C=:\DATA\VIDS
0D=:\DATA\TALKING
0E=type
0F=CD-ROM
10=size
11=FileXtra4
12=Little Bill Thinks Big:DATA:LB_MAIN.DXR
13=Little Bill Thinks Big:DATA:CASTS
14=Little Bill Thinks Big:DATA:VIDS
15=Little Bill Thinks Big:DATA:TALKING
Siberian GRemlin,
Oct 6 2018, 14:06 Работа с отладчиком
Несколько корректировок.

QUOTE(-=CHE@TER=- @ Jun 14 2018, 17:15) [snapback]4362[/snapback]
5) Т.к. ты брезгуешь нормальными системами, то запускаешь Ольку от имени Администратора, плюс помни, что первый вылет в ней будет не на OEP, а где-то в дебрях системы, ибо Windows Vista и выше - гоумно. Так что делай сразу F9, чтобы оно до OEP дошло.
Это можно обойти, чтобы сразу на OEP вставало, если в опциях выбрать игнорировать последнее исключение (Debugging Options - Exceptions - Add last exception, не забыть галку на Ignore also following custom exception or ranges чтобы список работал).

QUOTE(-=CHE@TER=- @ Jun 21 2018, 20:03) [snapback]4366[/snapback]
А ещё F8 на инструкции loop сразу пройдёт весь цикл, в то время как F7 будет переходить на начало при каждом шаге.
Спутал с отладчиком DOSBox. Во всяком случае в классической Ольке это не работает так.

QUOTE(-=CHE@TER=- @ Jun 21 2018, 20:03) [snapback]4366[/snapback]
Если файл не изменялся, то при перезапуске бряки не будут пропадать, кроме случаев когда бряк стоит на памяти которая была динамически выделена или внутри .DLL.
x64dbg допилили, так что там бряки внутри .DLL не пропадают - удобно. Вроде бы, даже файл на диске изменять можно. Насчёт остального не проверял.

А ещё, рассказываю, как и обещал когда-то, одно ноу-хау, о том как можно быстро найти код распаковки/расшифровки чего-либо, если отлаживать с самого начала программу очень долго и муторно.

Чтение файлов в Windows, как правило, идёт через CreateFile + ReadFile. Исключение - когда файл мапится в память (тогда придётся перехватывать ещё mapping-функции и высчитывать адрес нужного блока памяти для смены прав). Поэтому можно поступить так:
1) Делаем wrapper-оболочку-прослойку между игрой и системной kernel32.dll:
game.exe -> kernelxx.dll -> kernel32.dll
2) В kernelxx перехватываем работу с CreateFile и сравниваем с именем файла, который нам нужен. Если наш - сохраняем дескриптор открытого файла.
3) В ReadFile смотрим какой файл читается - если нужный (сравнили с дескриптором), то ставим (после того как оригинальная функция отработала!) на весь буфер бряк программно - запрещаем обращение к этой памяти:
VirtualProtect(lpBuffer, nNumberOfBytesToRead, PAGE_NOACCESS, @tmp);
4) Теперь если где-то программа обратится к этому куску памяти, то отладчик сразу остановится на этом месте, т.к. выбьет ошибку. Можно вместо этого вызвать DebugBreak(); тогда в этом месте управление передастся отладчику и можно будет дальше смотреть кто и что с этим буфером делает (это если с ним сразу работают, а не через 10 минут после загрузки, когда понадобился).
5) Обращаю внимание, что изменить в отладчике права на обращения к памяти нельзя, а т.к. код распаковки будет постоянно это делать, то будут постоянно лезть ошибки - т.е. нашли адрес кода распаковки, bp <адрес> и перекомпилили библиотеку, чтобы больше запрета на обращение к памяти не было. Тут можно попробовать, наверное, PAGE_GUARD (см. документацию - оно как раз один раз срабатывает и возвращает старые права на память после этого), вместо PAGE_NOACCESS, но я уже не помню почему от PAGE_GUARD отказался (не срабатывало, вроде бы).

Вот пример такой библиотеки (я его слегка поменял и уменьшил, чтобы было нагляднее, но не тестировал, так что возможны ошибки в работе, хотя всё и компилируется без проблем под Delphi 7):
[codebox]library KERNELXX;

uses Windows;

const
MyFileName = 'filename.ext';

var
MyHandle: THandle = INVALID_HANDLE_VALUE;

function CreateFileA(
lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: DWORD;
lpSecurityAttributes: PSecurityAttributes;
dwCreationDisposition, dwFlagsAndAttributes: DWORD;
hTemplateFile: THandle
): THandle; stdcall;
var s: ansistring;
begin
result:=Windows.CreateFileA(
lpFileName, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile
);
s:=lpFileName;
if (
(result <> INVALID_HANDLE_VALUE) and (Length(s) >= Length(MyFileName)) and
(Windows.lstrcmpiA(PAnsiChar(Copy(s, Length(s) - Length(MyFileName) + 1,
Length(MyFileName))), PAnsiChar(MyFileName)) = 0)
) then
begin
MyHandle:=result;
end;
end;

function ReadFile(hFile: THandle; Var Buffer; nNumberOfBytesToRead: DWORD;
var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
var
d: DWORD;
p: pointer;
begin
result:=Windows.ReadFile(
hFile, Buffer, nNumberOfBytesToRead,
lpNumberOfBytesRead, lpOverlapped
);
if (result = true) then
begin
if (hFile = MyHandle) then
begin
p:=@Buffer;
Windows.VirtualProtect(p, nNumberOfBytesToRead, PAGE_NOACCESS, @d);
// DebugBreak();
end;
end;
end;

function CloseHandle(hObject: THandle): BOOL; stdcall;
begin
result:=Windows.CloseHandle(hObject);
if (hObject = MyHandle) then MyHandle:=INVALID_HANDLE_VALUE;
end;

procedure RtlUnwind; stdcall; external 'kernel32.dll' name 'RtlUnwind';

exports
CreateFileA,
ReadFile,
CloseHandle,
SetFilePointer,
GetFileSize,
CreateDirectoryA,
GetCommandLineA,
RtlUnwind,
GetVersion;

end.[/codebox]
Обращаю внимание на несколько важных вещей связанных с этим кодом:
1) В exports должны быть все функции, которые экспортирует игра/программа, иначе она тупо не запустится.
2) Блок exports обязательно должен идти после перехваченных функций, иначе перехватчики не будут работать (будет вызов оригинальных функций напрямую).
3) Если нужно вызвать оригинальный код из kernel32 (или другого юнита), то это нужно делать добавив имя такого юнита перед именем функции, как у объекта класса:
Windows.CreateFileA(...)
Потому что вызов:
CreateFileA(...)
создаст бесконечную рекурсию.
4) Ну и, конечно, не забудьте заменить в исполняемом файле игры/программы все строки "KERNEL32.DLL" на "KERNELXX.DLL", чтобы использовалась эта библиотека.
5) Можно не только работу с файлами перехватывать, но и работу с памятью, сетью, реестром (advapi32.dll - я обычно это делаю, чтобы при отладки игры мне в реестр не гадили) и так далее.

Мне идея такой библиотеки пришла в голову в 2015 году (обычные wrapper-то я ещё раньше делал - в старой версии патча для Турка) и безумно выручила - я как раз по заказу писал конвертер графики для какой-то игры (уже не помню точно для какой, но на сайте конвертер есть) и не мог никак до функции конвертирования добраться - в меню загружались обычные .BMP, а мне нужен был собственный формат игры, который только в игре загружался и только в определённый момент (когда этот объект был виден на экране). Там проблема, если правильно помню, была в том, что если ставить бряк на обращение к памяти (memory on access), то Олька почему-то начинает о-о-очень медленно работать, так что было практически невозможно дойти с момента загрузки до момента, когда нужный спрайт появлялся на экране (декодировался - шло обращение к памяти).
Siberian GRemlin,
Oct 5 2018, 19:44 The Settlers (все части)
Проверил. Закинул твой файл в демку, меню стало на русском, прошёл первое обучение, там тоже всё на русском, проблем не заметил. Русский Windows XP SP3 + все дополнения (официальные, POS Ready не ставил).
Может на другом ПК что-то перекосило, вот русский шрифт и не грузится?
А ещё заглянул в упомянутый тобой guiengine2.dll от demo в IDA, там в IGuiEngine::Init такой код:
CODE
<...>
  nCharSet = 0; // ANSI_CHARSET
  switch (a7) {
    case 16:
      nCharSet = 204; // RUSSIAN_CHARSET
      break;
    case 5:
    case 11:
    case 13:
      nCharSet = 238; // EASTEUROPE_CHARSET
      break;
    default:
      break;
  }
  v9 = &h;
  pFntData = (BYTE *)&unk_18809900;
  do {
    if (*v9) { DeleteObject(*v9); }
    v11 = CreateFontA(
            *((_DWORD *)pFntData - 8),
            *((_DWORD *)pFntData - 7),
            0,
            0,
            *((_DWORD *)pFntData - 6),
            0,
            0,
            0,
            nCharSet,
            0,
            0,
            *pFntData != 0 ? 4 : 0,
            0,
            (LPCSTR)pFntData + 2);
    *v9 = v11;
    if (!v11) { BBSupportTracePrintF(0, aGuiEngineCan_2); }
    pFntData += 84;
    v9++;
  } while ( (signed int)pFntData < (signed int)&unk_18809F3C );
<...>

Как я понимаю ANSI_CHARSET = RUSSIAN_CHARSET, если в системе установлен русский язык.
Можно попробовать либо 238 на 204 заменить, либо сделать так, чтобы всегда 204 было.
А ещё можно посмотреть откуда лезет параметр a7 входной со значениями 5, 11 или 13 - может в ресурсах где-то язык задаётся, а потом этот номер в эту функцию уходит.
Siberian GRemlin,
Oct 3 2018, 18:31 The Settlers (все части)
Там, действительно, какая-то модификация LZW, пришлось на ассемблере выдирать.
unlibs4.zip
Я так задолбался выдирая распаковку (там же ср@ные классы, где регистр ecx указывает на структуру, в которой хрен пойми что лежит - т.е. ты не можешь вот так просто взять и выдрать код распаковки), что на расшифровку забил. В demo ничего не шифровали, так что сделай при распаковке перенаправление вывода в файл (unlibs4.exe filename.lib > output.txt) и смотри, есть ли там "Warning: encrypted file, but decryption not supported - saving as is." и, если есть, то выложи куда-нибудь самый мелкий такой архив посмотреть.

CODE
#pragma pack(push, 1)
typedef struct {
  DWORD headsize; // размер заголовка со всеми таблицами
  DWORD revision; // должно быть равно 0x1000 иначе игра считает архив битым
  DWORD dnamelen; // длина блока с именами директорий
  DWORD dcounter; // количество директорий в блоке
  DWORD fnamelen; // длина блока с именами файлов
  DWORD fcounter; // количество файлов
} headinfo;

// после этого идут char[dnamelen] и char[fnamelen]
// затем описание файлов fcounter раз:

typedef struct {
  DWORD floffs; // смещение файла, минимальное 1 (.LIB всегда должен начинаться с нулевого байта)
  DWORD pksize; // упакованный размер
  DWORD unsize; // распакованный размер (0 если не упакован)
  DWORD dindex; // номер директории в массиве строк выше
  DWORD xflags; // флаги: 1 - упакован; 2 - зашифрован (расшифровывать, ПЕРЕД, распаковкой)
  DWORD crcsum; // контрольная сумма (16 бит), может быть ноль (только для запакованных?)
} fileinfo;
#pragma pack(pop)
Распаковка идёт так:
1) Проверка контрольной суммы, если она не ноль.
2) Если контрольная сумма совпала или ноль, то расшифровать если (xflags & 2).
3) Если задан флаг (xflags & 1), то распаковать.
В принципе, игра не использует файлы из архива, если нужные уже есть на диске в соответствующем подкаталоге - т.е. достаточно распаковать и всё, можно переводить.

P.S. Как экзамен-то сдал? (*улыбается*)
P.P.S. Если не сложно, можешь чего-нибудь на копилку закинуть - мы на этой неделе как раз оплачивать хостинг будем. Спасибо.
Siberian GRemlin,
Aug 9 2018, 15:43 Работа с отладчиком
Ещё добавлю - Олька в оригинале устарела (но для начала и обучения азам - самое-то, ибо ещё не сильно навороченная).

А после можно смело переходить на вот это: x64dbg.

Пусть не смущает название - там и x32 отладчик есть. Выглядит точь-в-точь как Олька, только функций больше и их по разным местам растащили (например, задавать командную строку запускаемой программе теперь нужно в меню "File", заместо "Debug"), там даже command bar уже встроен (правда пара команд изменилась, ибо что-то я сходу не нашёл как там AT (перейти на адрес кода в дизассемблере) делается).
Так что можно даже x64 приложения дебажить - всё что изменится, это название регистров.
На примере регистра eax:
CODE
(=============================== 64 bit =======================) - rax
                             (============== 32 bit ===========) - eax
                                               (=== 16 bit ====) - ax
                                               ( 8 bit | 8 bit ) - ah | al
Такая же фигня с ebx, ecx и edx - они теперь все будут с "r" начинаться и размером в 64 бита. А, ну и всякие "push 0" положат на стек уже не 4 байта (32 бита), а 8 (64 бита). Короче, думаю, разобраться что к чему не сложно будет.

И ещё, меня тут в личке спрашивали что делать с играми, у которых оконного режима нет.
Есть три варианта:
1) Запустить игру в окне при помощи D3DWindower, DxWnd или подобных утилит.
2) Если есть дополнительный выход на видеокарте и возможность (в наличии второй монитор) - подключить второй монитор и вытащить окно отладчика туда.
3) Запусть игру под отладчиком и подцепиться к отладчику с другого компьютера (удалённо). Сразу скажу, что я такого никогда не делал, хотя знаю что можно (может, конечно, не все отладчики такое поддерживают), так что помочь не смогу если кто совета спросит - гугл в помощь.

P.S. Перетащу-ка я эту тему в подфорум "Статьи" - там ей самое место.
Siberian GRemlin,

7 Страниц V  1 2 3 > » 
Упрощённая версия Сейчас: 4th December 2024 - 22:14