понедельник, 11 июня 2012 г.

WoT Replay format

есть такая замечательная игра World of Tanks (0.7.3) Клиент игры умеет записывать реплеи боев. Во время боя создается файл (temp.wotreplay ???) так вот пока бой не закончен файл можно скопировать (потом пригодится :)) как только бой окончен начинаются чудеса: файл сжимается и переименовывается :(
Про просмотре hex редактором полученного файла в нем явно видно две части:
- 1ая текстовые данные о бое в JSON формате (данных о бое много: все ники игрков, команды, кланы, дамаг кадого, прибыль за бой и т. д.)
- 2ая явно выраженный архив.

посмотрев в отладчик можно заметить что 2ая часть это не просто архив, а зашифрованный (BLOWFISH) архив.

Собственно ключ (BF_KEY):
DE 72 BE A0 DE 04 BE B1 DE FE BE EF DE AD BE EF

процесс восстановления выглядит так blowfish - XOR (!!!) - zlib
расшиврованные данные надо ещё поксорить а потом расжать zlib'ом
В итоге получим файл идентичный тому временному файлу который записывался во время боя.

Что не может не радовать - так это то что расшиврованный / распакованный файл проигрывается клиентом успешно без лишних манипуляций :)

Посмотрев hex редактором на этот файл можно заметить заголовловок и дамп python объектов (pickle) которые представляют собой объекты игры и их сценарии поведения.

--------------------------------------------------------------------------------------------------
void BF_set_key(BF_KEY *key, int len, const unsigned char *data);
--------------------------------------------------------------------------------------------------
00CA77EE $-FF25 B853E600 JMP DWORD PTR DS:[<&LIBEAY32.#46>] ; LIBEAY32.BF_set_key
STACK:
0012EE20 008A961F RETURN to WORLDOFT.008A961F from <JMP.&LIBEAY32.#46>
0012EE24 0C3BA778 -> BF_KEY *key
0012EE28 00000010 -> int len
0012EE2C 08B51170 -> const unsigned char *data

[PASSWD]
08B51170 DE 72 BE A0 DE 04 BE B1 DE FE BE EF DE AD BE EF ▐r╛á▐ ╛▒▐■╛∩▐¡╛∩


--------------------------------------------------------------------------------------------------
void BF_decrypt(BF_LONG *data,const BF_KEY *key);
--------------------------------------------------------------------------------------------------
0222A9E9 E8 6D040000 CALL LIBEAY32.BF_decrypt

STACK:
0012EE1C 0012EE24 -> BF_LONG *data
0012EE20 0C3BA778 -> *data,const BF_KEY *key
0012EE24 B45E3A69 ---- 1st 64 bit(8 byte) to decrypt

19 комментариев:

  1. my russian is not good so used google translate, but what's the process? take the raw data, run it through blowfish decrypt with the key you gave, and then XOR it with what? can't decompress with zlib otherwise

    ОтветитьУдалить
  2. RUS
    реплей файл содержит сырые данные,которые зашифрованы(blowfish) и запакованы(zlib).
    Начало этих данных offset : найти текст {"frags": 0}}] + 8 байт.
    конец данных - конца файла.
    первые 8 байт расшифровываются функцией bf_decrypt, следующие 8 байт расшифровываются функцией bf_decrypt и XOR с предыдущими расшифрованными 8 байтами,
    и так до конца данных. после этого эти данные необходимо распаковать с помощью zlib (79 DA) После этого получится распакованный replay файл,
    который кстати успешно проигрывается клиентом игры.
    Код для распаковки возможно выложу чуть позже.

    ENG
    replay the file contains raw data that is encrypted (blowfish) and packaged (zlib).
    Beginning of the data offset: find text {"frags": 0}}] + 8 bytes.
    end of data - the end of the file.
    the first 8 bytes are decrypted function bf_decrypt, the following 8 bytes are decrypted bf_decrypt function and XOR with the previous decrypted 8 bytes,
    and so on until the end of the data. then these data should be unpacked with zlib (signature 79 DA) which has successfully played the game client.
    The example code to extract data the possible will publish later.

    ОтветитьУдалить
    Ответы
    1. "Начало этих данных offset : найти текст {"frags": 0}}] + 8 байт." - это не совсем верно, правильнее будет так:
      первые 4 байта - magic number
      дальше 4 байта - количество JSON блоков (1 реплей записан не до конца, 2 - до конца)
      дальше 4 байта размер первого JSON блока.
      затем первый json блок указанным размером,
      затем 4байта размер след json блока (если он есть)
      затем след json блок (если он есть)
      4 байта - 1 байт 5D (символ "]") затем 3 байта похоже на размер распакованных данных для проверки архива.
      4 байта размер RAW данных
      дальше данные
      таким образом

      Удалить
  3. Wot спасибо, дружище! Именно то, что нужно, а в бинарнике копаться лень.

    ОтветитьУдалить
  4. а можно ли как то в процессе игры вытащить координаты танков что на карте ? именно те что видимы ибо невидимых понятно сервер не отдает.

    ОтветитьУдалить
  5. а не подскажите в каком виде они представлены ? и каким образом можно вытащить ? помню был даже мод который на миникарте показывал в какую сторону противник смотрит, потом его запретили вроде. Заранее спасибо.

    ОтветитьУдалить
    Ответы
    1. нужно где то найти сам движок bigworld и SDK к нему, но тут есть неприятность он нифига не бесплатный и на паблике мне найти не удалось :(
      А дальше смотреть как он организует само 3D пространство. а там уже и на файлах реплеях можно потренироваться а потом уже и на самом клиенте танков в онлайне.

      Удалить
    2. Можно конечно и так в памяти процесса поискать что нить похожее, но шанс что либо найти таким образом ничтожно мал.

      Удалить
  6. Спасибо за ответ. Я просто покопался в файлах питоновских, декомпильнул, думал можно вытащить из удп пакета,не нашел, наверное обработка пакетов в движке реализована.

    ОтветитьУдалить
  7. Кстати, как я писал выше, мне удалось декомпильнуть питоновские скрипты, и смог сделать инжект, вставил простую функцию создания файла и записи тестовой строки в метод одного из класса, собрал pyc и подложил. Игра сьела все отработало. Однако, попытка записать в файл один из параметров класса, не проходит. Не могу понять почему или существует какая то питоновская защита для методов и членов класса (я в ООП не силен) или реализована защита или я просто не правильно делаю :) Решил озвучить чего добился, может у вас появятся идеи ? :)

    ОтветитьУдалить
    Ответы
    1. Это очень интересно. Можешь подробнее написать, какие pyc файлы декомпилял, чем декомпилял, что менял, как сработало или как не сработало. Можешь в личку _bakoff@rambler.ru_ Я тоже когда то пробовал декомпилить pyc файлы клиента но что тоне очень вышло.

      Удалить
  8. Спс за инфу.
    Столлман велел делиться :)

    ОтветитьУдалить
  9. Какие планы публикации готового скомпилированного декодера реплей файлов или хотя бы исходиков?

    ОтветитьУдалить
    Ответы
    1. Дружище, слушай. ты все бы сообщения в блоге почитал...
      Вот тут ссылка на реплей-анпакер:
      http://wotreplays.blogspot.ru/2012/06/replay.html

      Исходники думаю пока нет смысла выкладывать.

      Удалить
    2. А нет ли программы для обратной процедуры - т.е. упаковки реплея. Распакованный реплей не принимается wotreplays.ru, например.

      Удалить
    3. Есть конечно. исходный файл который создается клиентом игры как раз упакован и будет распакован лишь во время проигрывания реплея прямо в памяти, при этом файл на диске останется сжатым и без изменений. Нет ни каких трудностей зашифровать все обратно известным ключом BF потом все поксорить и зажать Zlib и получить в итоге исходный файл.

      Удалить