Ciscoman's notes (Записки цыщика c дипломом)

I'm Cisco Champion Community member for 2017!

I'm Cisco Champion Community member for 2017!
"Cisco Champions are passionate about Cisco and happy to share our knowledge, experience, and feedback."

суббота, 18 апреля 2009 г.

Перепаковка Cisco IOS или Исследования на тему юзабильности устаревшего оборудования Cisco

Статья была опубликована в журнале "Хакер" номер #124 за апрель 2009 года.

Эта версия оригинальная и не исправленная редакторами.

Статья, которая была создана изначально в целях систематизации своих изысканий, затем переросла в блогопост, ну и вот затем только в конечный вариант. Just4Fun.

Приветствую, дорогой читатель! Сегодня мы будем давать вторую молодость, а может даже жизнь старым маршрутизаторам Cisco.
Имеем исходные данные: старенькая кошка Cisco 2611 c двумя Ethernet(!) портами, 64 Мб RAM и 16 MB на flash. Эти параметры являются максимально возможными из поддерживаемых данной платформой (читай — увеличить объем DRAM памяти и flash физически не представляется возможным из-за отсутствия в природе комплектующих больших объемов). Исходя из данных Cisco IOS Feature Navigator (http://tools.cisco.com/ITDIT/CFN/jsp/index.jsp) последней версией IOS для данного маршрутизатора является 12.3(26), что естественного для столь старого продукта (End-of-Sale - апрель 2003, End-of-Life – апрель 2008). Однако, иногда хочется получить только все самое последнее и новое, а все самое новое и вкусное доступно только в версии 12.4 (точнее 12.4T). Посыл номер два, или дополнительные исходные данные: если внимательно следить за модельным рядом маршрутизаторов Cisco или просто хорошо ознакомиться с информацией о продуктах на официальным сайте, то можно обнаружить что серия 2600 включает в себя, например, маршрутизаторы 2611XM. Отличается эта серия от своего предшественника незначительно:
- Максимальный объем flash-памяти увеличен до 48 MB (в 2611 — 16 MB)
- Максимальный объем SDRAM-памяти увеличен до 128 MB (в 2611 — 64 MB)
- Интегрированные 10/100 Fast Ethernet порты (в 2611 — 10 Мбит/c Ethernet)
Для такой кошки Cisco IOS Feature Navigator сообщит, что последний IOS за версией 12.4(23).
Системные требования для IOS 12.4(21) с набором Enterprise Base или Advanced Security составляют 128 MB DRAM и 32 MB flash. Конечно, у нас нет 128 MB памяти, но попытка не пытка, да и пропускная способность портов у нас невысокая, что позволяет сделать предположение о том, что ОС возможно запустить на моем устройстве. Осталось предположения превратить в практику.
Идея проста - загнать бинарный образ операционной системы Cisco IOS 12.4(21) с набором фьючерсов Enterprise Base на старенький маршрутизатор 2611 c исходными данными, представленными выше и в последующем использовать его как тестовый стенд, ибо 10-ти мегабитные интерфейсы ограничивают его применение в дикой природе, или, как говорится, in production. Хотя с таким же успехом это устройство может надежно служить файрволлом корпоративной сети взамен какого-нибудь PIX, если, конечно, достаточно пропускной способности в 10 Мбит, но тогда встает вопрос — а есть ли такой функционал, который может вам потребоваться в IOS 12.4, но которого нет в 12.3? За подсказкой вновь отправляю к Cisco IOS Feature Navigator (http://tools.cisco.com/ITDIT/CFN/Dispatch). Утилита сравнения образов вам в помощь, но ответ скорее всего будет - нет. Отсюда вывод — не стоит меня корить в малой практичности данной статьи, так как изначально она в большей степени исследовательская (jus for fun), чем практическая.
Возвращаясь от лирических отступлений к делу, скажу, что у меня не возникла бы потребность в написании статьи, если бы не одна, а точее две небольших проблемы. О первой из них я уже упомянул — это объем DRAM памяти. К сожалению, я не повелитель паяльника и вольтметра, так что здесь поделать ничего не можем. Стоит только надеяться, что ОС не уйдет в core в самый ответственный момент из-за недостатка пямяти. Вторая проблема, которая застигла меня врасплох — это размер самого образа образа IOS 12.4 и тот факт, что он не помещается на флеш объемом 16 МB. Этот образ принципиально туда не помещается из за своего размера, точнее сам маршрутизатор глаголет, что данный образ не поместится, и неудивительно. Файл образа — c2600-entbasek9-mz.124-9.T1.bin , который я взял для эксперимента, занимает 16,4 MB, то есть 17 257 364 байт. Флеш же размером 16 MB ровно (show flash: сообщает, что всего 16777212 байт или 16384K). Даже если стереть флеш с опцией no-squeeze-reserve-space:
router#erase /no-squeeze-reserve-space flash:

это нам не поможет, хотя в свое время для образа c2600-ik9o3s3-mz.123-13.bin являлось решением проблемы (этот образ чуть меньше размера самой флеш и для его загрузки требуется отформатировать ее с опцией, запрещающей резервировать свободное место).
Таким образом, решения здесь может быть два - грузиться с tftp, например, что не всегда удобно, либо же похекать образ так, чтобы его размер стал меньше, грубо говоря перепаковать (что, собственно, и было отчасти сделано). Посылом номер три является эмулятор Dynamips. Причем он здесь? А притом, что именно он натолкнул меня на мысль о перепаковке образа. Если взглянуть на раздел «How to use?» на официальном сайте проекта (http://www.ipflow.utc.fr/index.php/Cisco_7200_Simulator), то можно обнаружить, что эмулятор использует распакованные образы для ускорения загрузки:


To boot quickly, the preferred method is to decompress the IOS image with the "unzip" utility. It avoids to run the self-decompressing process in the emulator.
chris@portchris2:~/dynamips-0.2.5$ unzip -p c7200-advipservicesk9-mz.124-9.T.bin > image.bin
warning [c7200-advipservicesk9-mz.124-9.T.bin]: 27904 extra bytes at beginning or within zipfile
(attempting to process anyway)
chris@portchris2:~/dynamips-0.2.5$ file image.bin
image.bin: ELF 32-bit MSB executable, cisco 7200, version 1 (SYSV), statically linked, stripped
You can ignore the warning, unzip has just skipped the self-decompressing code at the beginning of the image.
Now, you can boot the imagе


Значит, если есть запакованный образ, то можно попытаться использовать более оптимальные параметры(!) сжатия, которые позволят разместить образ на флеш. Обращаю внимание на одну важную деталь — так как мы не собираемся переписывать самораспаковывающися код, то есть заниматься дизассемблированием, да и ассемблер под 32х битные процессоры PowerPC я не знаю (да и под 64х битные тоже), то сам алгоритм сжатия менять мы не сможем. Самораспаковывающаяся часть просто не сможет распаковать архивы, сжатые другими методами. По поводу используемого в образе алгоритма сжатия можно взглянуть сюда: Cisco IOS Configuration Fundamentals Configuration Guide, Release 12.4 - Loading and Managing System Images, пункт Image Naming Conventions. Поле «тип» в имени образа как раз отвечает за его характеристики:

f - The image runs from flash memory.
m - The image runs from RAM.
r - The image runs from ROM.
l - The image is relocatable.
z - The image is zip compressed.
x -The image is mzip compressed.

В нашем случае образ имеет тип mz – работает в памяти и запакован как раз в zip-архив. Убедиться в этом просто — большинство архиваторов (WinZIP, WinRAR, 7zip) c легкостью открывают и распаковывают архив.

Не мудрствуя лукаво, пытаемся перепаковать архив заново с максимально возможной степенью сжатия. Сразу же отмечаем, что используемый метод — deflate и изменить его не получится. Я использовал 4 архиватора, чтобы сравнить их и получил следующий результат:

7-zip 4.65 со следующими параметрами:
Формат архива — zip
Уровень сжатия — Ультра
Метод сжатия — Deflate
Размер словаря — 32КB
Размер слова — 258

В результате был получен архив следующих размеров: 15,7 MB (16 489 764 bytes)

WinZIP 11.2 при использовании улучшенного метода Deflate выдал файл размером 16,0 MB (16 803 634 bytes)

WinRAR 3.80 формат архива — zip с наилучшими параметрами сжатия: 16,3 MB (17131 353 bytes)

PKZIP 9.00 от создателей формата совсем подвел, и по методу Deflate с максимальным сжатием произвел файл, размером 16,3 MB (17 094 474 bytes).

Итогом моего небольшого сравнительного тестирования стал выбор для экспериментов архива, как нетрудно догадаться, созданного 7zip. Далее требуется этот архив поместить вместо оригинального образа. Чтобы проделать это, нам понадобится шестнадцатеричный редактор типа WinHex, HT Editor или hview. Я предпочитаю WinHex, но нам понадобится еще и HT, чуть позже объясню почему.

Как вы можете видеть на скриншоте, скорее всего бинарный образ IOS есть ничто иное, как исполняемый файл в формате ELF (Executable and Linkable Formate). ELF-формат является основным исполняемым файлом в *nix-like системах, неудивительно встретить его здесь. По ELF-формату существует четкая спецификация, последняя версия которой 1.2, однако для наших целей будет достаточно, например, заголовочного файла из состава libc - elf.h. Обычный бинарный ELF файл представляет собой структуру следующего вида:

ELF Header
Program Header Table (optional)
Section 1
Section 2

Section n
Section Header Table

Не углубляясь в описание, дабы не повторяться, отправляю вас к спецификации.
Так как весь процесс исследования я проводил в MS Windows, то пришлось искать замену утилите readelf из состава binutils. Этой заменой и оказался шестнадцатеричный редактор HT (http:///hte.sf.net), который умеет читать и модифицировать структуры данных исполняемых файлов ELF. При попытке открыть подопытный образ c2600-entbasek9-mz.124-9.T1.bin, HT сразу меня обругал, что и привлекло мое внимание. Обратимся к elf.h, структура данных, отвечающая за ELF-заголовок выглядит так:

typedef struct {
Elf_Char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;


В нашем случае поле e_machine имеет значение 0x002b или 43, что соответствует процессору SPARC v9:

#define EM_SPARCV9 43 /* SPARC v9 64-bit */

Однако нам известно, что маршрутизатор 2611 использует процессор Motorolla MPC860, значит поле должно иметь значение 0x0014, что соответствует:

#define EM_PPC 20 /* PowerPC */

Скорее всего, это есть простейшая защита от дизассемблирования образа, однако нам это не сильно помешает. С помощью F6 открываем режим просмотра elf/header. Из него нам становятся известны следующие подробности:

- elf header size 0x34
- program header entry size 0x20
- program header count 1
- section header entry size 0x28
- section header count 6

Что в сумме нам дает размер 52+32+6*40=324 или 0x144.
То есть в файле всего 6 секций (соответственно 6 заголовков секций) и 1 заголовок программы. Вероятнее всего одна из секций предназначена для хранения архива с исполняемым образом IOS. Эту секцию можно вычислить либо по размеру (логично, что ее размер должен быть максимальным), либо по типу секции. Заголовок таблицы секций можно просмотреть, нажав F6 и выбрав elf/section headers, но для начала обратимся к описанию секции:

typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;

Поле sh_type и будет отвечать за искомый тип. К сожалению здесь меня ждал облом, большинство из секций имело тип SHT_PROGBITS, предназначенный для секций, значение которых определяется самой программой. Однако 4-я секция, имела тип отличный от предыдущих и имела значение 0x00000007, секция предназначена для каких-либо программных заметок. Первая (нулевая) секция также имеет отличный от предыдущих тип (SHT_NULL), исходя из этого становится ясно что она пустая и ни с чем не ассоциирована. В итоге приходится искать секцию с максимальным размером (поле sh_size), ее оказывается секция за номером пять, ее размер 0x1070e7c или 17239676 байт. Вернемся к hex-виду (F6 - hex) и перейдем по смещению (поле sh_offset) с помощью кнопки F5:


И что же мы здесь видим? Где же наш архив, который должен начинаться с сигнатуры PK, а точнее если следовать спецификации PKZIP-формата (http://www.pkware.com/documents/casestudies/APPNOTE.TXT) 0x04034b50 в обратном порядке? Как не странно эта сигнатура обнаруживается на 22 байта позже. Однако, если хорошо присмотреться, то отказывается, что сразу за значением 0xFEEDFACE идет размер распакованного образа 0x02AED904. Если внимательно поискать в Сети, то можно наткнуться на информацию из книги Cisco Networks Hacking Exposed издательства McGraw-Hill/Osborne. Наши русские парни Andrew A. Vladimirov, Konstantin V. Gavrilenko, Janis N. Vizulis and Andrei A. Mikhailovsky еще в 2006 году занимались разработкой бинарного патчинга IOS 12.3(6). Им удалось выяснить что после магического значения 0xFEEDFACE идут последовательно uncompressed image size, compressed image size, compressed image checksum, uncompressed image checksum. Помимо этого, им стало известно, что алгоритм вычисления контрольной суммы представляет собой модифицированный алгоритм контрольной суммы в Интернет, однако нам, к счастью, не придется их вычислять — как проверено позже на практике,маршрутизатор сам скажет нам какое значение должно иметь это поле, если конечно подсчитанная контрольная сумма и записанная в соответствующем поле не совпадут:

Error : compressed image checksum is incorrect 0xB99D8823
Expected a checksum of 0xF6F69877

*** System received a Software forced crash ***
signal= 0x17, code= 0x5, context= 0x800805f0
PC = 0x0, Vector = 0x0, SP = 0x0

Итак, перейдем к активным действиям. Для начала вырезаем из файла старую 4ю секцию, содержащую zip архив за исключением 20 байт, начиная с магического значения 0xFEEDFACE до сигнатуры zip не включая, то есть со смещения 0x44F8 по смещение 0x1075360 + 0x44F8. Затем по смещению 0x44F8 вставляем новый архив.

Соединим всю известную нам информацию воедино. Размер старой секции (№5), содержащей архив с образом IOS, загружаемым в память 0x1070e7c или 17239676 (включая 20 байт с 0xFEEDFACE по 0x504B0304 не включая). Размер новой секции, содержащей архив 0xFB9D38 или 16489784 (опять же включая те 20 байт). Разница между старым и новым значением составит 0xB7158 — 749912. То есть смещение 4й секции, физически расположенной в файле после 5й секции, требуется изменить с 0x1075360 на 0xFBE208.

Старые значения после магической записи 0xFEEDFACE:
unpacked image size: 0x02AED904 45013252
packed image size: 0x01070E66 17239654 (разница с размером 5й секции - на 22 байта меньше)
packed image checksum: 0xB58BE139
unpacked image checksum: 0xA29D4F6E
затем идет сигнатура: 0x504B0304

Новые значения после магической записи 0xFEEDFACE:
unpacked image size: 0x02AED904 (остался тот же)
packed image size: 0x00FB9D22 16489762 (разница с размером 5й секции - на 22 байта меньше)
packed image checksum: нам неизвестна, можно заменить на что-нибудь приметное, типа 0x48000000
unpacked image checksum: 0xA29D4F6E (остался тот же)

Новую контрольную сумму, как я уже говорил, сообщит сам маршрутизатор.
После всех манипуляций конечный образ был получен, однако размер его меня не впечатлил. К сожалению, по сравнению с изначальным размером 16,4 MB (17257364 bytes) я получил всего лишь 15,7 MB (16507472 bytes), то есть разница, которую я уже посчитал выше, составила 749912 байт. Конечно, это позволит загрузить образ на flash, но скорее всего придется применять опцию /no-squeeze-reserve-space. Однако, когда при копировании маршрутизатор запросит повторное стирание flash, подтверждать действие не нужно:

router#erase /no-squeeze-reserve-space flash:
Erasing the flash filesystem will remove all files! Continue? [confirm]
Erasing device... eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeeee ...erased
Erase of flash: complete
router#copy tftp://172.22.1.17/c2600-entbasek9-mz.124-9.T1-shad-pk.bin flash:
Destination filename [c2600-entbasek9-mz.124-9.T1-shad-pk.bin]?
Accessing tftp://172.22.1.17/c2600-entbasek9-mz.124-9.T1-shad-pk.bin...
Erase flash: before copying? [confirm]n
Loading c2600-entbasek9-mz.124-9.T1-shad-pk.bin from 172.22.1.17 (via Ethernet0/0): !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!![OK - 16507472 bytes]

Verifying checksum... CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC OK (0xE6ED)
16507472 bytes copied in 178.188 secs (92641 bytes/sec)
router#reload
Proceed with reload? [confirm]

Естественно, такая ситуация была бы только в том случае, если образ был бы сформирован правильно. Поэтому я не стал спешить, и для загрузки образа защел в режим rommon по Ctrl+Break, затем со своего компьютера загрузил образ по tftp напрямую в RAM:

rommon 1>tftpdnld -r

После загрузки маршрутизатор сказал:

TFTP flash copy: Error, image size (16507470) mismatches netsize (16507472).

Оказалось, что при редактировании размера 5й секции я ошибся на 2 байта (те самые 20 байт с 0xFEEDFACE + 2).

После второй попытки загрузки выяснилось, что контрольная сумма запакованного образа — 0xB0257B0D:

Error : compressed image checksum is incorrect 0xB99D8823
Expected a checksum of 0x48000000

*** System received a Software forced crash ***
signal= 0x17, code= 0x5, context= 0x800805f0
PC = 0x0, Vector = 0x0, SP = 0x0

Корректируем соответствующее поле после 0xFEEDFACE (Загружаем файл в HT по F3, переходим по смещению с помощью F5 и редактируем по F4, не забывая сохраняться по F2), затем снова грузимся.

rommon 4>reset -s

Дальше соответственно все ок, однако затем IOS вываливается, и отказывается работать по причине недостатка памяти:

System Bootstrap, Version 11.3(2)XA4, RELEASE SOFTWARE (fc1)
Copyright (c) 1999 by cisco Systems, Inc.
TAC:Home:SW:IOS:Specials for info
PC = 0xfff0a530, Vector = 0x500, SP = 0x680127c8
PC = 0xfff0a530, Vector = 0x500, SP = 0x680127b0
C2600 platform with 65536 Kbytes of main memory

PC = 0xfff0a530, Vector = 0x500, SP = 0x80004684

monitor: command "boot" aborted due to user interrupt
rommon 1 > tftpdnld -r

IP_ADDRESS: 172.22.1.199
IP_SUBNET_MASK: 255.255.255.0
DEFAULT_GATEWAY: 172.22.1.1
TFTP_SERVER: 172.22.1.17
TFTP_FILE: c2600-entbasek9-mz.124-9.T1-shad-pk.bin

Receiving c2600-entbasek9-mz.124-9.T1-shad-pk.bin from 172.22.1.17 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!!!!!
File reception completed.
program load complete, entry point: 0x80008000, size: 0xfbe0d8
Self decompressing the image : ################################################## ################################################## ################################################## ## [OK]

Smart Init is enabled
smart init is sizing iomem
ID MEMORY_REQ TYPE
000092 0X000B3280 C2600 Dual Ethernet
0X00098670 public buffer pools
0X00211000 public particle pools
TOTAL: 0X0035C8F0

If any of the above Memory Requirements are
"UNKNOWN", you may be using an unsupported
configuration or there is a software problem and
system operation may be compromised.
Rounded IOMEM up to: 3Mb.
Using 5 percent iomem. [3Mb/64Mb]



Cisco IOS Software, C2600 Software (C2600-ENTBASEK9-M), Version 12.4(9)T1, RELEASE SOFTWARE (fc2)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2006 by Cisco Systems, Inc.
Compiled Wed 30-Aug-06 15:43 by prod_rel_team
Image text-base: 0x800080E4, data-base: 0x81B46C00

SYSTEM INIT: INSUFFICIENT MEMORY TO BOOT THE IMAGE!

%Software-forced reload

00:00:16 UTC Fri Mar 1 2002: Unexpected exception to CPUvector 700, PC = 0x8069DE48, LR = 0x8069DD88

-Traceback= 0x8069DE48 0x8069DD88 0x80014B10 0x81B3BAA4 0x8170812C 0x817082A4 0x816E3D68 0x816E3DF4 0x816E3ED4 0x816E3E38 0x816E3ED4 0x816E3E38 0x816E3ED4 0x816E4A1C 0x8171AB4C 0x81729008

CPU Register Context:
MSR = 0x00029032 CR = 0x33000095 CTR = 0x806A2518 XER = 0x8000FE00
R0 = 0x00000000 R1 = 0x82EDD858 R2 = 0x82AF0000 R3 = 0x00000003
R4 = 0xFFFFFFFE R5 = 0x00000000 R6 = 0x00000003 R7 = 0x00009032
R8 = 0x82AF0000 R9 = 0x82820000 R10 = 0x82BBCC50 R11 = 0x00000000
R12 = 0x00004117 R13 = 0xFFF48A24 R14 = 0x80A82090 R15 = 0x00000000
R16 = 0x00000000 R17 = 0x00000000 R18 = 0x00000000 R19 = 0x00000000
R20 = 0x00000000 R21 = 0x00000000 R22 = 0x81B47998 R23 = 0x00000000
R24 = 0x81B47A48 R25 = 0x81708128 R26 = 0x81708128 R27 = 0x00002814
R28 = 0x00000000 R29 = 0x82C8F368 R30 = 0x00000000 R31 = 0x82AF0000

Writing crashinfo to flash:crashinfo_20020301-000016

Однако, здесь я не расстроился, и решил взяться за другой образ — c2600-advsecurityk9-mz.124-21.bin. После аналогичных манипуляций с байтами, даже при использовании 128 битного слова в 7zip, размер составил 15947076 (против изначального размера 16635336), что позволило загрузить его во flash. Помимо прочего, этот образ уже не ругался на недостаток памяти RAM и прекрасно чувствовал себя на этой платформе:

router#show version
Cisco IOS Software, C2600 Software (C2600-ADVSECURITYK9-M), Version 12.4(21), RELEASE SOFTWARE (fc1)


router#show memory summary
Head Total(b) Used(b) Free(b) Lowest(b) Largest(b)
Processor 82A44240 20244772 8718640 11526132 10171028 10098348
I/O 3CA3400 3525632 1650536 1875096 1875096 1875068


router#show flash:

System flash directory:
File Length Name/status
1 15947076 c2600-advsecurityk9-mz.124-21-shad-pk.bin
[15947140 bytes used, 830072 available, 16777212 total]
16384K bytes of processor board System flash (Read/Write)

Однако, у нас остается еще одна небольшая проблема. Если запустить проверку:

router#verify flash:c2600-advsecurityk9-mz.124-21-shad-pk.bin

Маршрутизатор обругает нас, сообщив, что Embedded hash и Calculated hash не совпадают. Исправить это очень просто — 16 байт контрольной суммы находится в самом конце бинарного файла образа. Обнаружить это можно даже с помощью простого поиска:





После исправления маршрутизатор сообщает, что контрольная сумма успешно подсчитана и совпадает:

Embedded Hash MD5 : 3DD2C6591FF4F033425147DE4540F9CD
Computed Hash MD5 : 3DD2C6591FF4F033425147DE4540F9CD
CCO Hash MD5 : 79020945BDFE2A354E012C8303136360

Embedded hash verification successful.
File system hash verification successful.

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

Постоянные читатели

Поиск по этому блогу