Исследуем игру с аркадного автомата ч. 1

в 16:26, , рубрики: linux, аркадный автомат, взлом игр, информационная безопасность, отладка, метки: ,

Уф, вот меня и разбанили на хабре, и у меня есть для вас отличная статья, так что всем привет!

Исследуем игру с аркадного автомата ч. 1

Введение

Никогда не задумывались, что стоит в аркадных автоматах? Какие ОС, какие технологии используются для разработки игр? Как их защищают от копирования и модифицирования? Если да, то добро пожаловать в этот топик.

Внутренности

Итак, что же внутри нашего автомата?

  1. Обычный x86 компьютер с платой PIUIO и JAMMA
    Исследуем игру с аркадного автомата ч. 1
  2. Усилитель, кроссовер и эквалайзер
    image
  3. Панель со светодиодами
    image
  4. Панель управления с кнопками «TEST», «SERVICE» и крутилками эквалайзера
    image
  5. LCD или CRT экран

Нас же, конечно, в первую очередь интересует компьютер.

Есть несколько ревизий внутренностей последней версии компьютера:
Материнская плата: Gigabyte GA-945GCM-S2L / Asrock G41M-S3
Графический адаптер: Geforce 8400GS / Geforce 9300GS
Память: DDR2 / DDR3 512 MB
Процессор: Intel Celeron

Сама игра находится на винчестере. В комплекте USB-донгл SafeNet MicroDog.
image

Исследование

С чего же начать? Естественно, со снятия дампа винчестера. Это делается в линуксе одной командой:
dd if=/dev/sdX of=./dump.bin bs=1M
И идем пить чай, т.к. это займет минут 10-15. Винчестеры используются на 160 и 250 гигабайт.
Никогда ничего не делайте на работающем винчестере! Всегда нужно использовать образ!

Образ снят. Давайте запустим cfdisk на него.
image

Что же мы видим? Два раздела с файловой системой ext2, и подозрительно много неразмеченной области в начале диска. Файловая система сразу может навести на мысль, что внутри стоит что-то UNIX-подобное, с большой вероятностью это, конечно, Linux.

Давайте же запустим его в виртуалке. Я люблю qemu, поэтому использую его.
Исследуем игру с аркадного автомата ч. 1

И больше ничего. Дальше либо qemu завершается с ошибкой вроде:
qemu: fatal: Trying to execute code outside RAM or ROM at 0xa5ff00d8
либо просто зависает. Честно говоря, я знал, что у этой игры привязка к винчестеру, и стало очевидно, что алгоритм достаточно простой и не использует проверку целостности данных, а сразу передает управление расшифрованным данным, а в случае с виртуалкой, просто мусору.
Далее я, скорее больше ради интереса, а не в ожидании каких-то открытий, решил посмотреть, что же лежит на тех двух разделах с файловой системой ext2. А вот что:

Раздел 1
├── [4.0K]  game
│   └── [ 25G]  _00000.BIN
├── [4.3M]  i
├── [ 16K]  lost+found
├── [   0]  n
├── [8.5M]  p
├── [7.8M]  u
└── [ 22M]  x

game/_00000.BIN: data
i:               data
n:               empty 
p:               data
u:               data
x:               ELF 32-bit LSB  shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped

Раздел 2:
├── [ 16K]  lost+found
└── [144K]  PIUFESTAEX.INI

Ну вот, все данные на разделе 1, кроме файла «x», являются обычными данными, либо же шифрованы. Один только «x» как-то выделяется из этой массы — это shared библиотека, которая, вероятно, подгружается игрой (на самом же деле — нет).

Что же дальше? Ну, полезли в сам винчестер.

00000000  fa 33 c0 8e d0 bc 00 7c  8b f4 50 07 50 1f fb fc  |.3.....|..P.P...|
00000010  bf 00 06 b9 00 01 f3 a5  ea 1d 06 00 00 b6 00 b9  |................|
00000020  02 00 bf 05 00 bb 00 07  b8 01 02 57 cd 13 5f 73  |...........W.._s|
00000030  0c 33 c0 cd 13 4f 75 ed  be 8a 06 eb 3b b9 03 00  |.3...Ou.....;...|
00000040  bf 05 00 bb 00 20 53 07  bb 00 00 b8 20 02 57 cd  |..... S..... .W.|
00000050  13 5f 73 0c 33 c0 cd 13  4f 75 e8 be 8a 06 eb 18  |._s.3...Ou......|
00000060  b9 ff 3f be 00 08 33 ff  ad 83 e6 bf 26 33 05 ab  |..?...3.....&3..|
00000070  49 75 f5 ea 00 00 00 20  ac 3c 00 74 0b 56 bb 07  |Iu..... .<.t.V..|
00000080  00 b4 0e cd 10 5e eb f0  eb fe 44 69 73 6b 20 49  |.....^....Disk I|
00000090  2f 4f 20 45 72 72 6f 72  00 00 00 00 00 00 00 00  |/O Error........|
000000a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000180  28 43 29 32 30 30 34 20  41 4e 44 41 4d 49 52 4f  |(C)2004 XXXXXXXX|
00000190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001b0  00 00 00 00 00 00 00 00  9b f6 31 c9 00 00 00 00  |..........1.....|
000001c0  41 8f 83 fe ff ff cf ce  61 00 b1 a1 a9 03 00 fe  |A.......a.......|
000001d0  ff ff 83 fe ff ff 6f 56  36 04 80 60 1f 00 00 00  |......oV6..`....|
000001e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200  50 75 6d 70 20 49 74 20  55 70 3a 20 46 69 65 73  |Xxxx Xx Xx: Xxxx|
00000210  74 61 45 78 00 00 00 00  00 00 00 00 00 00 00 00  |xxXx............|
00000220  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000300  20 20 20 20 20 20 20 20  20 20 20 20 36 56 4d 51  |            6VMQ|
00000310  57 54 34 37 43 43 34 36  20 20 20 20 53 54 33 31  |WT47CC46    ST31|
00000320  36 30 33 31 38 41 53 20  20 20 20 20 20 20 20 20  |60318AS         |
00000330  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00000340  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400  0e a8 36 bd 22 ac ea 0e  a9 36 bb 22 82 66 80 70  |..6."....6.".f.p|
00000410  dc 7a 36 37 c8 5d 18 36  ae fa 83 3a 74 d8 35 29  |.z67.].6...:t.5)|
00000420  11 b9 2d 25 1f c8 7d 10  07 c8 7d 21 81 34 07 ae  |..-%..}...}!.4..|
...

(Вместо «X» были название производителя и название игры. Я их убрал, чтобы этот топик не гуглился по этим данным. Если хотите, узнать, что же там было, HEX-данные я не менял.)

Что это? Объясняю.
По адресу 0-1BE располагается MBR-загрузчик, самый наипростейший, который грузит с первого нашедшего диска stage2-загрузчик, который начинается с адреса 400. Интереснейшая строчка расположена на 300-32F, очень похоже на серийный номер винчестера, версию прошивки и модель. Да что тут гадать, так и есть ;)

Описание Данные
Серийный номер (20 байт) (12 пробелов)6VMQWT47
Версия прошивки (8 байт) CC46(4 пробела)
Название модели (40 байт) ST3160318AS(29 пробелов)

Я пошел по легкому пути: не стал разбирать алгоритм работы stage2-загрузчика, а просто чуть-чуть дописал кода в qemu, чтобы он брал данные винчестера из переменных окружения DRIVE_MODEL, DRIVE_SERIAL и DRIVE_VERSION. Также, qemu позволяет дампить память гостевой машины, что нам будет полезно.

valdikss@valaptop:~/ % DRIVE_SERIAL="            6VMQWT47" DRIVE_VERSION="CC46    " DRIVE_MODEL="ST3160318AS" qemu-system-i386 disk.img -monitor stdio
QEMU 1.4.1 monitor - type 'help' for more information
(qemu) dump-guest-memory mem.bin
(qemu) quit

Определить правильность расшифровки данных можно было чисто визуально: если ядро успешно распаковалось и запустилось, то на момент появится курсор на экране, если же и файловая система распаковалось правильно, то моргнет экран виртуальной машины, это будут пытаться запуститься иксы.
Как линуксоид, я сразу попытался переключиться на другую консоль с помощью комбинаций Alt+FN, и мне это удалось: на второй консоли был вывод иксов.
Образ в qemu успешно запустили, уже хорошо, что же дальше? Нам же нужно как-то получить файловую систему. Наверняка, вместе с ядром грузится initrd или initramfs, в которой либо и лежат все необходимые файлы, либо который расшифровывает и подключает rootfs. Что же делать? Вернемся к нашему дампу памяти и пройдемся по нему замечательной утилитой BinWalk:

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------------------
0               0x0             ELF 32-bit LSB core file Intel 80386, version 1 (SYSV)
141888          0x22A40         Copyright string: " 1999-2003 ANDAMIROang"
1649782         0x192C76        CramFS filesystem, little endian size 279239 CRC 0x42c70000, edition 20, 141723904 blocks, 1589959 files  
3848752         0x3ABA30        CramFS filesystem, little endian size 4947968 version #2 sorted_dirs CRC 0x9c99ddde, edition 0, 2433 blocks, 235 files  
17648271        0x10D4A8F       mcrypt 2.2 encrypted data, algorithm: blowfish-448, mode: CBC, keymode: 8bit
17752783        0x10EE2CF       mcrypt 2.2 encrypted data, algorithm: blowfish-448, mode: CBC, keymode: 8bit
17773455        0x10F338F       mcrypt 2.2 encrypted data, algorithm: blowfish-448, mode: CBC, keymode: 8bit
17966760        0x11226A8       Copyright string: " (C) 1996-2009 the UPX Team. All Rights Reserved. $l Rights Reserved. $"
18179243        0x11564AB       Copyright string: " (C) 2009 Free Software Foundation, Inc.ion, Inc."
18236316        0x116439C       ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV)
18261064        0x116A448       LZMA compressed data, properties: 0xBD, dictionary size: 16777216 bytes, uncompressed size: 33554432 bytes
18261104        0x116A470       LZMA compressed data, properties: 0xB8, dictionary size: 16777216 bytes, uncompressed size: 33554432 bytes
21033884        0x140F39C       ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV)
21061669        0x1416025       ELF 32-bit LSB no file type, no machine, (GNU/Linux)
21088103        0x141C767       ELF
21152544        0x142C320       LZMA compressed data, properties: 0x6C, dictionary size: 16777216 bytes, uncompressed size: 838860800 bytes
21435292        0x147139C       ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV)
21525404        0x148739C       ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV)
21537692        0x148A39C       ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV)
21554076        0x148E39C       ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV)
21615281        0x149D2B1       Copyright string: " (C) 2006 Free Software Foundation, Inc.ion, Inc."
21672860        0x14AB39C       ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV)
21926836        0x14E93B4       ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV)
110031566       0x68EF2CE       gzip compressed data, was "cursor.pcf", from Unix, last modified: Fri Feb 13 07:15:31 2004
116417852       0x6F0653C       CramFS filesystem, little endian size 4947968 version #2 CRC 0x86f06160, edition 16777216, 18 blocks, 0 files  
121710143       0x741263F       LZMA compressed data, properties: 0x87, dictionary size: 1048576 bytes, uncompressed size: 256 bytes
121721756       0x741539C       ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV)
122005647       0x745A88F       LZMA compressed data, properties: 0x87, dictionary size: 1048576 bytes, uncompressed size: 256 bytes
122594740       0x74EA5B4       LZMA compressed data, properties: 0x7E, dictionary size: 16777216 bytes, uncompressed size: 33554432 bytes
122614684       0x74EF39C       CramFS filesystem, little endian size 4947968 version #2 sorted_dirs CRC 0x9c99ddde, edition 0, 2433 blocks, 235 files  
129803164       0x7BCA39C       CramFS filesystem, little endian size 4947968 version #2 sorted_dirs CRC 0x9c99ddde, edition 0, 2433 blocks, 235 files

Ох, как же много всего!
На самом деле, все срабатывания LZMA ложные, т.к. у него нет magic number, половина ELFов тоже фейковые. А вот CramFS с 235 файлами очень похож на реальный, и, с большой вероятностью, он используется в качестве initrd.
Вытащить из памяти правильный CramFS не составляет труда. После того, как CramFS лежит у вас на винчестере в виде файла, попытаемся его распаковать. Я использовал cramfs-2.0 из пакета firmware-mod-kit.

valdikss@valaptop:~/ % cramfsck -x root cram1.bin
cramfsck: crc error

Ну а что вы ожидали? Думали, все так просто будет?
Если пропатчим проверку контрольной суммы в cramfsck, мы сможем «успешно» распаковать файловую систему:

Дерево файловой системы

├── [4.0K]  bin
│   ├── [   7]  ash -> busybox
│   ├── [130K]  busybox
│   ├── [   7]  cat -> busybox
│   ├── [   7]  chmod -> busybox
│   ├── [   7]  cp -> busybox
│   ├── [   7]  df -> busybox
│   ├── [   7]  dnsdomainname -> busybox
│   ├── [   7]  echo -> busybox
│   ├── [   7]  false -> busybox
│   ├── [   7]  hostname -> busybox
│   ├── [   7]  kill -> busybox
│   ├── [   7]  ln -> busybox
│   ├── [   7]  ls -> busybox
│   ├── [   7]  mkdir -> busybox
│   ├── [   7]  mknod -> busybox
│   ├── [   7]  mount -> busybox
│   ├── [   7]  mv -> busybox
│   ├── [   7]  netstat -> busybox
│   ├── [   7]  ping -> busybox
│   ├── [   7]  ps -> busybox
│   ├── [   7]  pwd -> busybox
│   ├── [   7]  rm -> busybox
│   ├── [   7]  sh -> busybox
│   ├── [   7]  sleep -> busybox
│   ├── [   7]  sync -> busybox
│   ├── [   7]  true -> busybox
│   ├── [   7]  umount -> busybox
│   ├── [   7]  uname -> busybox
│   └── [   7]  vi -> busybox
├── [4.0K]  dev
│   ├── [   0]  console
│   ├── [   0]  null
│   ├── [   0]  tty1
│   └── [   0]  tty2
├── [4.0K]  etc
│   ├── [4.0K]  init.d
│   │   ├── [  90]  mnttab
│   │   ├── [ 754]  once
│   │   ├── [ 412]  rcS
│   │   └── [ 244]  run
│   ├── [ 151]  inittab
│   └── [4.0K]  X11
│       └── [  23]  xorg.conf -> /usr/lib/xorg/xorg.conf
├── [4.0K]  lib
│   ├── [111K]  ld-2.10.1.so
│   ├── [  12]  ld-linux.so.2 -> ld-2.10.1.so
...
│   ├── [ 78K]  libz.so.1.2.3
│   └── [4.0K]  modules
│       └── [ 25K]  atkbd.ko
├── [4.0K]  mnt
│   ├── [4.0K]  0
│   │   └── [   0]  invalid
│   ├── [4.0K]  1
│   │   └── [   0]  invalid
│   └── [4.0K]  hd
├── [1.1M]  piu
├── [4.0K]  proc
├── [4.0K]  sbin
│   ├── [  14]  halt -> ../bin/busybox
│   ├── [  14]  ifconfig -> ../bin/busybox
│   ├── [  14]  init -> ../bin/busybox
│   ├── [  14]  insmod -> ../bin/busybox
│   ├── [  14]  lsmod -> ../bin/busybox
│   ├── [  14]  mdev -> ../bin/busybox
│   ├── [  14]  poweroff -> ../bin/busybox
│   ├── [  14]  reboot -> ../bin/busybox
│   └── [  14]  route -> ../bin/busybox
├── [4.0K]  SETTINGS
├── [4.0K]  sys
├── [   4]  tmp -> /var
├── [4.0K]  usr
│   ├── [4.0K]  bin
│   │   ├── [ 18K]  amixer
│   │   ├── [  17]  du -> ../../bin/busybox
│   │   ├── [  17]  env -> ../../bin/busybox
│   │   ├── [  17]  free -> ../../bin/busybox
│   │   ├── [  17]  less -> ../../bin/busybox
│   │   ├── [4.4K]  mountrd
│   │   ├── [4.6K]  mount_tab
│   │   ├── [  17]  telnet -> ../../bin/busybox
│   │   ├── [ 25K]  usbdaemon
│   │   ├── [   4]  X -> Xorg
│   │   ├── [ 14K]  xinit
│   │   └── [1.7M]  Xorg
│   ├── [4.0K]  lib
│   ├── [4.0K]  sbin
│   │   └── [  17]  setlogcons -> ../../bin/busybox
│   ├── [4.0K]  share
│   │   ├── [4.0K]  alsa
│   │   │   ├── [8.8K]  alsa.conf
│   │   │   ├── [4.0K]  cards
│   │   │   │   ├── [ 669]  AACI.conf
│   │   │   │   ├── [ 687]  aliases.alisp
│...
│   │   │   │   ├── [ 839]  VXPocket.conf
│   │   │   │   └── [1.3K]  YMF744.conf
│   │   │   ├── [4.0K]  init
│   │   │   │   ├── [1.8K]  00main
│   │   │   │   ├── [6.9K]  default
│   │   │   │   ├── [1.4K]  hda
│   │   │   │   ├── [ 391]  help
│   │   │   │   ├── [ 932]  info
│   │   │   │   └── [ 11K]  test
│   │   │   └── [4.0K]  pcm
│   │   │       ├── [ 805]  center_lfe.conf
...
│   │   │       └── [ 978]  surround71.conf
│   │   └── [4.0K]  X11
│   │       └── [4.0K]  xkb
│   │           ├── [4.0K]  compiled
│   │           │   └── [ 11K]  server.xkm
│   │           └── [4.0K]  rules
│   │               ├── [ 34K]  base
│   │               ├── [ 31K]  evdev
│   │               └── [   4]  xorg -> base
│   └── [   4]  var -> /var
└── [4.0K]  var

Вот и, вроде бы, все, думаете вы? Тестовые файлы, вроде /etc/init.d/run, вроде-бы, нормальные. Но вот ни один исполняемый файл и ни одна библиотека не запускаются. Сначала я думал, что игра использует либо модифицированное ядро, либо модифицированный libc. Патчил исполняемые файлы, смотрел, как примерно они отличаются от hello world, т.к. все они либо завершались с segmentation fault, либо, что еще хуже, c illegal hardware instruction.
Скомпилировал себе эталонный «hello world», т.к. уже с самого начала, с вызова __libc_start_main, оно улетало куда-то не туда. Затем грешил на релоки, т.к. некоторые были как будто бы побиты, и я предположил, что, возможно, модификация в этом, но нет, после правки релоков игра хоть и стала стараться запускаться, но все не то. Размышлял над этим около 3 дней. Пришел к выводу, что исполняемые файлы каким-то образом бьются в CramFS, а текстовые остаются в оригинальном виде. И был прав!

/etc/init.d/run

echo run
export __GL_SYNC_TO_VBLANK=1
export force_s3tc_enable=true
export LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/hd/lib
cd /mnt/hd/game
xinit /piu /mnt/hd/game/ -- -br -quiet -logverbose 0 -verbose 0 -depth 24 -audit 0 -bs -tst -xinerama
#/bin/sh

/etc/init.d/once

until /usr/bin/mount_tab /etc/init.d/mnttab; do sleep 1; done
/usr/bin/mountrd
insmod /usr/lib/modules/nvidia.ko
insmod /usr/lib/modules/drm.ko
insmod /usr/lib/modules/fb.ko
insmod /usr/lib/modules/font.ko
insmod /usr/lib/modules/softcursor.ko
insmod /usr/lib/modules/bitblit.ko
insmod /usr/lib/modules/fbcon.ko
insmod /usr/lib/modules/drm_kms_helper.ko
insmod /usr/lib/modules/cfbcopyarea.ko
insmod /usr/lib/modules/cfbimgblt.ko
insmod /usr/lib/modules/cfbfillrect.ko
insmod /usr/lib/modules/i915.ko
mkdir /dev/dri
ln -s /dev/card0 /dev/dri/card0
/usr/bin/usbdaemon
amixer set Master 80% unmute
amixer set PCM 75% unmute
amixer set Front 90% unmute
insmod /lib/modules/atkbd.ko

/etc/init.d/run

setlogcons 2
mount -n -t tmpfs -o size=128k var /var
mkdir /var/log
mkdir /var/run
mkdir /var/run/microdog
mount -t sysfs sysfs /sys
mount -t proc proc /proc
mount -t usbfs none /proc/bus/usb
mount -t tmpfs mdev /dev
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
mkdir /dev/snd
cp -a /dev/controlC* /dev/snd
cp -a /dev/pcmC* /dev/snd
cp -a /dev/timer /dev/snd

Т.к. на руках у меня был оригинальный CramFS, и, вспомнив, что я могу попасть в консоль ОС в виртуальной машине просто нажав Alt+F2, я решил попробовать заменить оригинальный /etc/init.d/run, заменив вызов xinit на /bin/sh. Но нам же нужно каким-то образом засунуть модифицированный CramFS обратно в образ. Поискав строку «Compressed RamFS» в образе винчестера, я был несколько удивлен, что он лежит незашифрованным! Только, конечно, не просто так, а с «паддингом», весь файл на винчестере разбит на блоки по 32КБ данных и 512 байт пустоты. Ну, это, вроде бы, не проблема!

Так уж получилось, что изменил я не только /etc/init.d/run, но и /etc/init.d/once, закомментировав вызовы mount_tab, mountrd и usbdaemon, и как-то не особо и обратил внимание на цикл в вызове mount_tab.

Итак, отредактировали /etc/init.d/run, собрали CramFS, записали ее в образ, И-и-и!… ничего. Ладно, собрал ФС с оригинальным /etc/init.d/run, и начал искать отличия в файлах. Как оказалось, их было много, я долго пытался понять, в чем же дело, оказывается, cramfs-2.0 из firmware-mod-kit собирает чуточку иначе. Хорошо, скачал обычный cramfs-tools из репозиториев, собрал им, и вдруг увидел, что, помимо контрольной суммы, различается последний байт у файлов. У оригинального файла 0x80, а у собранного мной, конечно же, 0x00. Удивленный таким положением дел, заменил в своем файле последний байт, засунул его в образ винчестера и УРА! Образ запустился с моей модифицированной ФС, и я получил консоль. Никакой сложности простое копирование файлов не создало, запускные файлы теперь действительно запускались на моей linux-системе, и именно на этом шаге я понял, что, действительно, CramFS специальным образом изменяет исполняемые файлы.

Бегло посмотрев на mount_tab, mountrd и usbdaemon в IDA PRO, на тот момент я был уверен, что mount_tab просто монтирует файловую систему в нужные места (те два раздела на винчестере, первый в /mnt/game, а второй в /SETTINGS), mountrd сканирует AGP и PCI шины, расшифровывает, загружает в память и монтирует в /usr/lib один из файлов «p», «i» или «u», лежащих на первом разделе, которые содержат драйвера для видеокарты, а usbdaemon обеспечивает работу с USB-донглом посредством UNIX-сокетов.

Ложная радость

Сижу, исследую запускной файл игры, который вытащил копированием, и у меня начали закрадываться подозрения. Какой-то он не такой, упоминания это версии игры, которую я исследую, нет, и вообще, как-то что-то не то. Понял, что этот файл принадлежит другой версии игры, и выдвинул предположение, что, видимо, после проверки USB-донгла он откуда-то берет и расшифровывает другой файл. Все оказалось куда смешнее.
Помните тот цикл при вызове mount_tab? При первом запуске он действительно просто монтирует файловые системы, но при повторном запуске он читает с винчестера некоторое количество данных со смещения 0x1F80200 или 0x2080200, в зависимости от заголовка по первому смещению, расшифровывает эти данные, и прямо в памяти подменяет запускной файл игры в CramFS на правильный. Вот этот ход мне действительно понравился! Я был в ярости, но, в то же время, горд находчивостью разработчиков.

Заключение

Статья получилась несколько скомканной и состоит скорее из моих мыслей, догадок и наблюдений. Надеюсь, ее было интересно читать. Часть 2 будет чисто техническая, и, возможно, будет содержать разбор файловой системы игры и отвязывание ее от USB-донгла.
Вот вам видео, напоследок.

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

Автор: ValdikSS

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js