From 5429755609503b5da8d0c46e1d489998b2f4d93f Mon Sep 17 00:00:00 2001 From: Kirill Zhumarin Date: Tue, 18 Aug 2026 03:09:41 +0300 Subject: [PATCH] Expand and refine software catalog --- AGENTS.md | 28 +- README.md | 6 +- .../armdebugger/files/ArmDebugger-079m2.zip | 3 + .../debugging/armdebugger/index.yaml | 41 ++- .../files/ATCGSN.Debug-1.2.0.0.zip | 3 + .../debugging/atcgsn-debug/index.yaml | 16 + .../cgsn-debugger/files/CGSN-Debugger-1.3.zip | 3 + .../debugging/cgsn-debugger/index.yaml | 21 ++ .../files/SiemensDebugger-1.7.2.16.zip | 3 + .../debugging/siemens-debugger/index.yaml | 16 + .../smelter/files/ocx-control-1.1.zip | 3 + .../firmware/smelter/files/smelter-9.65.zip | 3 + .../smelter/files/smelter-language-files.zip | 3 + .../development/firmware/smelter/index.yaml | 58 ++++ catalog/development/firmware/wsff/index.yaml | 5 +- catalog/development/modding/index.yaml | 4 + .../modding/layoutme/files/layoutme-2.59.zip | 3 + .../development/modding/layoutme/index.yaml | 37 +++ .../development/patching/ffpatch/index.yaml | 24 -- .../patching/filescomparer/index.yaml | 22 -- .../development/patching/hex2vkp/index.yaml | 21 -- catalog/development/patching/index.yaml | 4 - .../ffpatch/files/ffpatch.zip | 0 .../development/utilities/ffpatch/index.yaml | 17 + .../filescomparer/files/fc_v1.2.zip | 0 .../utilities/filescomparer/index.yaml | 18 + .../hex2vkp/files/hex2vkp.zip | 0 .../development/utilities/hex2vkp/index.yaml | 23 ++ catalog/development/utilities/index.yaml | 4 + .../slfc/files/slfc-chaos.zip | 0 .../slfc/files/slfc-vi-soft.zip | 0 .../{patching => utilities}/slfc/index.yaml | 9 +- catalog/drivers/pl-2303/index.yaml | 4 +- catalog/explorers/index.yaml | 5 + .../explorers/simoco/files/SiMoCo-2.2.9.zip | 3 + catalog/explorers/simoco/img/simoco.jpg | Bin 0 -> 51102 bytes catalog/explorers/simoco/index.yaml | 58 ++++ catalog/files.yaml | 52 ++- catalog/flashers/v-klay/index.yaml | 42 +-- catalog/flashers/x65flasher/index.yaml | 17 +- catalog/service/joker/files/JokerV0343.zip | 3 + catalog/service/joker/index.yaml | 31 +- .../files/SiemensEEPROMtool315.zip | 3 + .../service/siemens-eeprom-tool/index.yaml | 15 +- .../files/SWriteMapR65-1.04.zip | 3 + catalog/service/swrite-map-r65/index.yaml | 18 + catalog/service/winswup/index.yaml | 42 +-- catalog/service/x65-papua-utils/index.yaml | 62 +--- .../fardes/files/fardes-1.63-des-2.67.zip | 3 + .../fardes/files/fardes-1.63-des-3.0.0.zip | 3 + catalog/utilities/fardes/index.yaml | 45 +++ catalog/utilities/midletsigner/index.yaml | 28 +- catalog/utilities/vmo2wav/index.yaml | 9 +- package.json | 1 + schema/index.schema.json | 3 + scripts/repackArchive.ts | 308 ++++++++++++++++++ 56 files changed, 909 insertions(+), 247 deletions(-) create mode 100644 catalog/development/debugging/armdebugger/files/ArmDebugger-079m2.zip create mode 100644 catalog/development/debugging/atcgsn-debug/files/ATCGSN.Debug-1.2.0.0.zip create mode 100644 catalog/development/debugging/atcgsn-debug/index.yaml create mode 100644 catalog/development/debugging/cgsn-debugger/files/CGSN-Debugger-1.3.zip create mode 100644 catalog/development/debugging/cgsn-debugger/index.yaml create mode 100644 catalog/development/debugging/siemens-debugger/files/SiemensDebugger-1.7.2.16.zip create mode 100644 catalog/development/debugging/siemens-debugger/index.yaml create mode 100644 catalog/development/firmware/smelter/files/ocx-control-1.1.zip create mode 100644 catalog/development/firmware/smelter/files/smelter-9.65.zip create mode 100644 catalog/development/firmware/smelter/files/smelter-language-files.zip create mode 100644 catalog/development/firmware/smelter/index.yaml create mode 100644 catalog/development/modding/index.yaml create mode 100644 catalog/development/modding/layoutme/files/layoutme-2.59.zip create mode 100644 catalog/development/modding/layoutme/index.yaml delete mode 100644 catalog/development/patching/ffpatch/index.yaml delete mode 100644 catalog/development/patching/filescomparer/index.yaml delete mode 100644 catalog/development/patching/hex2vkp/index.yaml delete mode 100644 catalog/development/patching/index.yaml rename catalog/development/{patching => utilities}/ffpatch/files/ffpatch.zip (100%) create mode 100644 catalog/development/utilities/ffpatch/index.yaml rename catalog/development/{patching => utilities}/filescomparer/files/fc_v1.2.zip (100%) create mode 100644 catalog/development/utilities/filescomparer/index.yaml rename catalog/development/{patching => utilities}/hex2vkp/files/hex2vkp.zip (100%) create mode 100644 catalog/development/utilities/hex2vkp/index.yaml create mode 100644 catalog/development/utilities/index.yaml rename catalog/development/{patching => utilities}/slfc/files/slfc-chaos.zip (100%) rename catalog/development/{patching => utilities}/slfc/files/slfc-vi-soft.zip (100%) rename catalog/development/{patching => utilities}/slfc/index.yaml (56%) create mode 100644 catalog/explorers/index.yaml create mode 100644 catalog/explorers/simoco/files/SiMoCo-2.2.9.zip create mode 100644 catalog/explorers/simoco/img/simoco.jpg create mode 100644 catalog/explorers/simoco/index.yaml create mode 100644 catalog/service/joker/files/JokerV0343.zip create mode 100644 catalog/service/siemens-eeprom-tool/files/SiemensEEPROMtool315.zip create mode 100644 catalog/service/swrite-map-r65/files/SWriteMapR65-1.04.zip create mode 100644 catalog/service/swrite-map-r65/index.yaml create mode 100644 catalog/utilities/fardes/files/fardes-1.63-des-2.67.zip create mode 100644 catalog/utilities/fardes/files/fardes-1.63-des-3.0.0.zip create mode 100644 catalog/utilities/fardes/index.yaml create mode 100644 scripts/repackArchive.ts diff --git a/AGENTS.md b/AGENTS.md index 5726bb5..61a9e77 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -50,11 +50,12 @@ description: Описание категории на русском языке. Markdown. 6. `homepage` — необязательный URL домашней страницы. 7. `source` — необязательный URL исходного кода. -8. `author` — необязательное имя автора или название организации-разработчика. -9. `screenshots` — обязательный массив путей; используй `[]`, если изображений +8. `forum` — необязательный URL темы программы на форуме. +9. `author` — необязательное имя автора или название организации-разработчика. +10. `screenshots` — обязательный массив путей; используй `[]`, если изображений нет. -10. `versions` — обязательный непустой массив версий. -11. `additional_files` — необязательный массив файлов, не привязанных к версии. +11. `versions` — обязательный непустой массив версий. +12. `additional_files` — необязательный массив файлов, не привязанных к версии. Новые версии добавляй в начало `versions`, от новых к старым. Каждая версия имеет такой вид: @@ -87,6 +88,11 @@ description: Описание категории на русском языке. SHA-256 не добавляй в индекс программы: они хранятся только в автоматически создаваемом `catalog/files.yaml`. +`description` файла добавляй только для существенной информации: отличия от +других вариантов, особого назначения или дополнительных материалов в архиве. +Не повторяй в нём название программы, номер версии, имя файла или тип +«программа», «дистрибутив», «исполняемый файл». + ### Короткое описание `summary` выводится рядом с названием программы в списке категории. Напиши @@ -109,12 +115,17 @@ additional_files: - Названия категорий, описания программ, версий и файлов пиши на русском языке. Официальные названия продуктов и технологий не переводи. +- Если доступно авторское описание, сохраняй его лексику, тон, порядок мыслей и + характерные формулировки. Не переписывай текст в нейтральном справочном стиле + и не заменяй авторские термины своими. Исправляй только оформление Markdown, + явные опечатки и очевидные грамматические ошибки. - Сохраняй полноту исходного описания. Не сокращай перечень возможностей до общего пересказа и не удаляй значимые технические подробности. - Содержимое каждого `description` интерпретируется как Markdown. Для длинного описания со списком используй литеральный блок `|-` и Markdown-списки; для обычного абзаца, перенесённого на несколько строк, используй `>-`. Не вставляй HTML-разметку. +- Каждый пункт Markdown-списка начинай с заглавной буквы. - Не выдумывай даты, ссылки, возможности или платформы. Неизвестное необязательное поле лучше не добавлять. - Сначала пытайся определить версию по странице, имени файла, README и @@ -134,8 +145,13 @@ additional_files: - Дистрибутивы и отдельные исполняемые файлы храни в ZIP, совместимом со встроенным распаковщиком Windows XP: методы Store или Deflate, без шифрования и Zip64. Не добавляй RAR, 7z и незапакованные EXE. -- При перепаковке сохраняй имена, содержимое и время изменения файлов внутри - архива. +- RAR, 7z, ZIP и отдельные EXE перепаковывай только командой + `pnpm repack-archive <путь>`. Она создаёт рядом проверенный ZIP и сохраняет + имена, содержимое и время изменения файлов. По умолчанию исходник остаётся; + `--replace` используй только когда его нужно удалить после успешной проверки. + Для другого пути назначения используй `--output <путь>`. +- После перепаковки замени путь в `index.yaml` и выполни + `pnpm fill-metadata`, чтобы обновить `catalog/files.yaml`. - Архивы должны проходить через Git LFS согласно `.gitattributes`. Остальные файлы хранятся в обычном Git. diff --git a/README.md b/README.md index db21074..3886adb 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ description: |- Полное описание в Markdown. homepage: https://example.org source: https://github.com/example/project +forum: https://example.org/forum/topic author: Автор screenshots: - img/screenshot.png @@ -78,9 +79,12 @@ additional_files: pnpm install pnpm fill-metadata pnpm fill-metadata:check +pnpm repack-archive path/to/archive.rar pnpm tree pnpm typecheck ``` `fill-metadata` пересобирает `catalog/files.yaml`. `tree` принимает путь и флаги -`--paths`, `--versions`. +`--paths`, `--versions`. `repack-archive` создаёт совместимый с Windows XP ZIP и +проверяет содержимое и timestamps; флаг `--replace` удаляет исходник только +после успешной проверки. diff --git a/catalog/development/debugging/armdebugger/files/ArmDebugger-079m2.zip b/catalog/development/debugging/armdebugger/files/ArmDebugger-079m2.zip new file mode 100644 index 0000000..2a80ce3 --- /dev/null +++ b/catalog/development/debugging/armdebugger/files/ArmDebugger-079m2.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f02c880d1631a3d56938c962019c494fb7c50effabdf85095a316a84c310b9c +size 539301 diff --git a/catalog/development/debugging/armdebugger/index.yaml b/catalog/development/debugging/armdebugger/index.yaml index b6358b6..37f1f05 100644 --- a/catalog/development/debugging/armdebugger/index.yaml +++ b/catalog/development/debugging/armdebugger/index.yaml @@ -1,30 +1,41 @@ format: 1 type: program name: ArmDebugger -summary: Отладчик ARM/Thumb-кода для телефонов Siemens 65/70/75-й серии. +summary: Дебаггер для телефонов Siemens 65/70/75-й серии. description: |- Отладчик для телефонов Siemens 65/70/75-й серии. - Возможности: - - автоматическая генерация CGSN-патча по слитому фулфлешу; - - просмотр содержимого памяти телефона в HEX-дампе; - - ARM/Thumb-дизассемблер с inline-ассемблером; - - пошаговая трассировка программы или процесса; - - установка точек мониторинга на любой адрес флеш-памяти и на запись в - диапазон RAM; - - редактирование памяти, в том числе флеш-области, с использованием замещения - flash-страниц; - - поиск байтов, строк и ссылок в памяти; - - интеграция с Keil ARM Tools; - - дамп памяти в файл, вызов функций flash с параметрами и hex/bin/dec - калькулятор. + - Автоматическая генерация CGSN-патча по слитому фулфлешу + - Просмотр содержимого памяти телефона в HEX-дампе + - ARM/Thumb дизассемблер с inline-ассемблером + - Пошаговая трассировка программы или процесса + - Установка точек мониторинга на любой адрес флеш-памяти и на запись в + диапазон RAM + - Возможность редактирования памяти, в том числе флеш-области (используется + замещение flash-страниц) + - Поиск байтов/строк в памяти, ссылок + - Интеграция с Keil ARM tools + - Дополнительные функции: дамп памяти в файл, вызов функций flash с + параметрами, hex/bin/dec калькулятор + + [Инструкция по работе с ArmDebugger](/docs/reverse-engineering/arm-debugger). homepage: https://web.archive.org/web/20130813164842/http://chaos.allsiemens.com/software.html +forum: https://web.archive.org/web/20160806060433/http://forum.allsiemens.com/viewtopic.php?t=20735 author: Chaos screenshots: [] versions: + - version: "0.7.9m2" + released: "2012-04-07" + description: >- + Модификация Dimadze для BenQ-Siemens: работа с MallocAddress, мониторинг + внешней и виртуальной RAM, дополнительные паттерны Nucleus и подсветка + указателей. + files: + - path: files/ArmDebugger-079m2.zip + platform: win32 - version: "0.7.9" released: "2006-12-28" files: - path: files/ArmDebugger-079.zip - description: Отладчик, краткое руководство и примеры для Keil ARM Tools + description: В комплекте краткое руководство и примеры для Keil ARM Tools platform: win32 diff --git a/catalog/development/debugging/atcgsn-debug/files/ATCGSN.Debug-1.2.0.0.zip b/catalog/development/debugging/atcgsn-debug/files/ATCGSN.Debug-1.2.0.0.zip new file mode 100644 index 0000000..0104a91 --- /dev/null +++ b/catalog/development/debugging/atcgsn-debug/files/ATCGSN.Debug-1.2.0.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:745857e73e9dc6632b9586840fbe0e706230dfa9016c7cba4c7bc574de5463b8 +size 368471 diff --git a/catalog/development/debugging/atcgsn-debug/index.yaml b/catalog/development/debugging/atcgsn-debug/index.yaml new file mode 100644 index 0000000..c8d6913 --- /dev/null +++ b/catalog/development/debugging/atcgsn-debug/index.yaml @@ -0,0 +1,16 @@ +format: 1 +type: program +name: ATCGSN.Debug +summary: Дебаггер телефонов Siemens на платформе EGOLD через AT+CGSN. +description: >- + Дебаггер для чтения и изменения памяти работающего телефона Siemens на + платформе EGOLD через расширенную команду AT+CGSN и установленный в прошивку + патч. +homepage: https://web.archive.org/web/20050901015815/http://alexsid.antex.ru/index.php?main=techinfo.php +author: ACiD[mrp] +screenshots: [] +versions: + - version: "1.2.0.0" + files: + - path: files/ATCGSN.Debug-1.2.0.0.zip + platform: win32 diff --git a/catalog/development/debugging/cgsn-debugger/files/CGSN-Debugger-1.3.zip b/catalog/development/debugging/cgsn-debugger/files/CGSN-Debugger-1.3.zip new file mode 100644 index 0000000..32e5482 --- /dev/null +++ b/catalog/development/debugging/cgsn-debugger/files/CGSN-Debugger-1.3.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d9e849b4968d69f1352c8eb80b1593c84abf6ed8c091c188408bcc292f1eab95 +size 387740 diff --git a/catalog/development/debugging/cgsn-debugger/index.yaml b/catalog/development/debugging/cgsn-debugger/index.yaml new file mode 100644 index 0000000..df99a38 --- /dev/null +++ b/catalog/development/debugging/cgsn-debugger/index.yaml @@ -0,0 +1,21 @@ +format: 1 +type: program +name: CGSN Debugger +summary: Дебаггер телефонов Siemens на платформе EGOLD через патч AT+CGSN. +description: |- + Дебаггер для работы с внутренней памятью RAM, ROM и Flash телефонов Siemens + на платформе EGOLD через соответствующую версию патча AT+CGSN. + + - Чтение участка памяти в файл; + - Запись и заполнение памяти; + - Поиск данных в пределах сегмента; + - Мониторинг выбранного участка памяти; + - Вызов процедуры по заданному адресу с установкой значений регистров. +homepage: https://web.archive.org/web/20050901015815/http://alexsid.antex.ru/index.php?main=techinfo.php +author: KonstanT +screenshots: [] +versions: + - version: "1.3" + files: + - path: files/CGSN-Debugger-1.3.zip + platform: win32 diff --git a/catalog/development/debugging/siemens-debugger/files/SiemensDebugger-1.7.2.16.zip b/catalog/development/debugging/siemens-debugger/files/SiemensDebugger-1.7.2.16.zip new file mode 100644 index 0000000..7df4006 --- /dev/null +++ b/catalog/development/debugging/siemens-debugger/files/SiemensDebugger-1.7.2.16.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:46893fd85a864b5fd163c5a55677b544adbe1e376dd5c57058e51f8608958e8d +size 442087 diff --git a/catalog/development/debugging/siemens-debugger/index.yaml b/catalog/development/debugging/siemens-debugger/index.yaml new file mode 100644 index 0000000..ca1d35e --- /dev/null +++ b/catalog/development/debugging/siemens-debugger/index.yaml @@ -0,0 +1,16 @@ +format: 1 +type: program +name: Siemens Debugger +summary: Дебаггер телефонов Siemens на платформе EGOLD через BFB Mode. +description: >- + Дебаггер для телефонов Siemens на платформе EGOLD с открытым BFB. Для работы + требуется патч, открывающий BFB Mode и отключающий проверку CRC; примеры + патчей для разных моделей входят в комплект. +homepage: https://web.archive.org/web/20050901015815/http://alexsid.antex.ru/index.php?main=techinfo.php +author: ACiD[mrp] +screenshots: [] +versions: + - version: "1.7.2.16" + files: + - path: files/SiemensDebugger-1.7.2.16.zip + platform: win32 diff --git a/catalog/development/firmware/smelter/files/ocx-control-1.1.zip b/catalog/development/firmware/smelter/files/ocx-control-1.1.zip new file mode 100644 index 0000000..929194c --- /dev/null +++ b/catalog/development/firmware/smelter/files/ocx-control-1.1.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:926cc3c943ec030395840c69642a6c280226d011e8fbc8802cd30698e9f057b0 +size 1070964 diff --git a/catalog/development/firmware/smelter/files/smelter-9.65.zip b/catalog/development/firmware/smelter/files/smelter-9.65.zip new file mode 100644 index 0000000..6926ad3 --- /dev/null +++ b/catalog/development/firmware/smelter/files/smelter-9.65.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91dc68718aead4dd21b7c6e14d9960d45c892e079d0fb543deb99761f5e2959a +size 508512 diff --git a/catalog/development/firmware/smelter/files/smelter-language-files.zip b/catalog/development/firmware/smelter/files/smelter-language-files.zip new file mode 100644 index 0000000..fefa988 --- /dev/null +++ b/catalog/development/firmware/smelter/files/smelter-language-files.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f8d51d6670baa57668faf770d23ffd280c7b99b6e609790ad44fb7d8bfaece1 +size 55580 diff --git a/catalog/development/firmware/smelter/index.yaml b/catalog/development/firmware/smelter/index.yaml new file mode 100644 index 0000000..41e9daa --- /dev/null +++ b/catalog/development/firmware/smelter/index.yaml @@ -0,0 +1,58 @@ +format: 1 +type: program +name: Smelter +summary: "Исследователь FullFlash телефонов Siemens: EEPROM, ленгпак, меню и ресурсы прошивки." +description: |- + Эта программа предназначена для исследования фуллфлеша телефона. Она + вытаскивает из фф информацию о еепромах, ленгпаке, меню, картинках, мелодиях, + файлах и многом другом, после чего показывает их в удобном виде. Программа + заточена под 55-ю серию, но, по идее, должна грамотно работать и с + фуллфлешами других телефонов. Изначально предназначена для флешекопателей, но + может быть полезна и неискушенным пользователям. + + Возможности: + + - Вывод найденной в фф информации; + - Просмотр, загрузка и выгрузка блоков EEPROM, расшифровка содержимого + отдельных блоков, создание резервных копий и определение IMEI; + - Просмотр и редактирование ленгпака, загрузка и сохранение всего ленгпака или + его области; + - Исследование системы меню и поиск точек входа элементов; + - Просмотр и выгрузка картинок из фф; + - Просмотр, прослушивание, загрузка и выгрузка мелодий; + - Просмотр содержимого флекс-мемори и выгрузка файлов; + - Графический просмотр фф по блокам; + - Просмотр адресной книги x45–x65; + - Поиск байт с маской и выравниванием, поиск текста; + - Создание VKP-патча из изменений фф и запуск V_Klay; + - Сохранение списков в текстовый формат и IDC-файлы для IDA, поиск по спискам + и интеграция с WinHex или HexWorkshop; + - Мультиязычный интерфейс; + - Просмотр фф, стандартный калькулятор Windows и отдельный Calc166; + - Поиск стандартных функций по заданным в ini-файле сигнатурам; + - Генерация стандартных патчей по заданным в ini-файле сигнатурам; + - Нахождение бут-ключей и создание лоадера для V_Klay; + - Брут-форсовый поиск PhoneID; + - Поиск мастер-кодов для разлочки; + - Включение дополнительных менюшек в WinSwup; + - Создание сертификатов и подписывание мидлетов без Java; + - Дизарм, МикроАсм, работа с библиотекой функций и скриптами; + - Проверка и стрипание эльфов. + + Для корректной работы программы необходимы OCX-компоненты из комплекта OCX + Control, размещённого в дополнительных файлах. +homepage: https://web.archive.org/web/20130401035858/https://avkiev.kiev.ua/Siemens/Smelter/Smelter_ru.htm +author: avkiev +screenshots: [] +versions: + - version: "9.65" + released: "2008-04-20" + files: + - path: files/smelter-9.65.zip + description: В комплекте базы, скрипты и документация + platform: win32 +additional_files: + - path: files/smelter-language-files.zip + description: Языковые файлы для перевода интерфейса + - path: files/ocx-control-1.1.zip + description: Обязательные библиотеки ActiveX и OCX Control 1.1 для их регистрации diff --git a/catalog/development/firmware/wsff/index.yaml b/catalog/development/firmware/wsff/index.yaml index 1711e82..868d6b2 100644 --- a/catalog/development/firmware/wsff/index.yaml +++ b/catalog/development/firmware/wsff/index.yaml @@ -2,9 +2,7 @@ format: 1 type: program name: WSFF summary: Программа для анализа и распаковки сервисных прошивок Siemens WinSwup. -description: |- - Утилита для анализа структуры и распаковки баз сервисных прошивок Siemens - WinSwup. +description: Программа для анализа и распаковки WinSwup-баз. homepage: https://web.archive.org/web/20130825050857/http://papuas.allsiemens.com/ author: Papuas screenshots: [] @@ -13,5 +11,4 @@ versions: released: "2006-02-10" files: - path: files/WSFF4.zip - description: Программа WSFF4 platform: win32 diff --git a/catalog/development/modding/index.yaml b/catalog/development/modding/index.yaml new file mode 100644 index 0000000..745144e --- /dev/null +++ b/catalog/development/modding/index.yaml @@ -0,0 +1,4 @@ +format: 1 +type: category +name: Моддинг +description: Изменение интерфейса и ресурсов прошивок телефонов. diff --git a/catalog/development/modding/layoutme/files/layoutme-2.59.zip b/catalog/development/modding/layoutme/files/layoutme-2.59.zip new file mode 100644 index 0000000..9a0cc73 --- /dev/null +++ b/catalog/development/modding/layoutme/files/layoutme-2.59.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c4bd6dfe0f4afdb0f54a806c7027502834120e9d7067ac9279bfed5ae4cb82a +size 41012 diff --git a/catalog/development/modding/layoutme/index.yaml b/catalog/development/modding/layoutme/index.yaml new file mode 100644 index 0000000..70ef4e2 --- /dev/null +++ b/catalog/development/modding/layoutme/index.yaml @@ -0,0 +1,37 @@ +format: 1 +type: program +name: LayoutMe +summary: Редактор клавиатурных раскладок в FullFlash телефонов Siemens. +description: |- + Данная программа предназначена для редактирования клавиатурных раскладок + телефонов Siemens. Программа позволяет избавиться от надоедливых каракулей в + конце символьных последовательностей, русифицировать раскладки, а также + создавать экзотические раскладки вида АБЦ2ABC и тому подобных. + + Возможности: + + - Редактирование раскладки в фуллфлеше; + - Загрузка и выгрузка раскладки в автономный файл `*.lay`; + - Сохранение изменённого фуллфлеша или патча VKP; + - Интеграция с V_Klay; + - Поддержка WAP-раскладки; + - Русификация ввода во встроенном mail-клиенте с использованием KOI-8; + - Контроль количества используемых и доступных символов; + - Автоопределение модели и версии прошивки. + + Поддерживаемые прошивки: C45_3803, C45_5001, ME45_2803, ME45_3003, + S45i_0403, SL45_5601, 2118_3108, A50_1091, A50_1105, A50_1191, A50_1201, + MT50_1791, M50_1791, M50_1991, A55_0901, C55_2491, M55_1002, M55_1091, + M55_1191, M55_1192, M55_9191, S55_2091, S55_9191, SL55_1491, SL55_1691, + A52_0701, A60_1095, C60_2391, C60_2591, C60_2691, C60_2791, MC60_1095, + CF62_0791 и CF62_1191. +homepage: https://web.archive.org/web/20130401035858/http://avkiev.kiev.ua/Siemens/LayoutMe/LayoutMe.htm +author: avkiev +screenshots: [] +versions: + - version: "2.59" + released: "2004-10-27" + files: + - path: files/layoutme-2.59.zip + description: В комплекте документация и типовые раскладки X45/X55 + platform: win32 diff --git a/catalog/development/patching/ffpatch/index.yaml b/catalog/development/patching/ffpatch/index.yaml deleted file mode 100644 index 21a08e1..0000000 --- a/catalog/development/patching/ffpatch/index.yaml +++ /dev/null @@ -1,24 +0,0 @@ -format: 1 -type: program -name: FFPatch -summary: Программа для сравнения образов FullFlash и работы с патчами VKP. -description: |- - Программа для сравнения двух файлов fullflash, сохранения найденных отличий - в виде патча VKP и поиска уже установленных патчей в образе flash-памяти. - - Возможности: - - сравнение оригинального и текущего fullflash; - - формирование файла различий в формате VKP; - - поиск одного или нескольких патчей VKP в fullflash; - - добавление патчей отдельными файлами или целым каталогом; - - исключение заданных диапазонов адресов из поиска и сравнения; - - сохранение настроек фильтрации адресов. -homepage: https://web.archive.org/web/20130813164842/http://vi-soft.com.ua/ -author: Александр Яблочкин -screenshots: [] -versions: - - version: "0.4.2" - files: - - path: files/ffpatch.zip - description: Программа FFPatch и руководство пользователя - platform: win32 diff --git a/catalog/development/patching/filescomparer/index.yaml b/catalog/development/patching/filescomparer/index.yaml deleted file mode 100644 index 861bcfd..0000000 --- a/catalog/development/patching/filescomparer/index.yaml +++ /dev/null @@ -1,22 +0,0 @@ -format: 1 -type: program -name: FilesComparer -summary: Программа для побайтового сравнения файлов и образов FullFlash. -description: |- - Программа для сравнения файлов и образов flash-памяти. - - Возможности: - - сравнение файлов одинакового и разного размера; - - ограничение сравнения начальным и конечным адресами; - - передача параметров через командную строку; - - выравнивание результатов по байтам; - - работа под DOS и Windows. -homepage: https://web.archive.org/web/20130813164842/http://vi-soft.com.ua/ -author: SaiNT -screenshots: [] -versions: - - version: "1.2" - files: - - path: files/fc_v1.2.zip - description: Программа FilesComparer 1.2 - platform: win32 diff --git a/catalog/development/patching/hex2vkp/index.yaml b/catalog/development/patching/hex2vkp/index.yaml deleted file mode 100644 index 33a15a9..0000000 --- a/catalog/development/patching/hex2vkp/index.yaml +++ /dev/null @@ -1,21 +0,0 @@ -format: 1 -type: program -name: Hex2VKP -summary: Конвертер Intel HEX в формат патчей VKP для V_KLay. -description: |- - Консольный конвертер из формата Intel HEX в формат патчей VKP программы - V_KLay. - - Intel HEX применяется для загрузки данных в микроконтроллеры и может быть - создан компиляторами для C166, включая Keil и Tasking C. Hex2VKP преобразует - результат компиляции в патч VKP для последующей записи через V_KLay. Ключ - `-F` создаёт секцию отмены патча `UNDO PATCH`. -homepage: https://web.archive.org/web/20130813164842/http://vi-soft.com.ua/ -author: Redkin -screenshots: [] -versions: - - version: "0.1a" - files: - - path: files/hex2vkp.zip - description: Программа Hex2VKP, исходный код, настройки и руководство - platform: win32 diff --git a/catalog/development/patching/index.yaml b/catalog/development/patching/index.yaml deleted file mode 100644 index 3836672..0000000 --- a/catalog/development/patching/index.yaml +++ /dev/null @@ -1,4 +0,0 @@ -format: 1 -type: category -name: Патчинг -description: Сравнение прошивок, поиск изменений и создание патчей VKP. diff --git a/catalog/development/patching/ffpatch/files/ffpatch.zip b/catalog/development/utilities/ffpatch/files/ffpatch.zip similarity index 100% rename from catalog/development/patching/ffpatch/files/ffpatch.zip rename to catalog/development/utilities/ffpatch/files/ffpatch.zip diff --git a/catalog/development/utilities/ffpatch/index.yaml b/catalog/development/utilities/ffpatch/index.yaml new file mode 100644 index 0000000..1bcc3c0 --- /dev/null +++ b/catalog/development/utilities/ffpatch/index.yaml @@ -0,0 +1,17 @@ +format: 1 +type: program +name: FFPatch +summary: Программа для сравнения образов FullFlash и работы с патчами VKP. +description: >- + Для Windows. Сравнивает 2 файла (fullflash), результат сравнения можно + сохранять в виде vkp-файла. Также при помощи этой программы можно производить + поиск установленных патчей в файле фуллфлеша. +homepage: https://web.archive.org/web/20130813164842/http://vi-soft.com.ua/ +author: Александр Яблочкин +screenshots: [] +versions: + - version: "0.4.2" + files: + - path: files/ffpatch.zip + description: В комплекте руководство пользователя + platform: win32 diff --git a/catalog/development/patching/filescomparer/files/fc_v1.2.zip b/catalog/development/utilities/filescomparer/files/fc_v1.2.zip similarity index 100% rename from catalog/development/patching/filescomparer/files/fc_v1.2.zip rename to catalog/development/utilities/filescomparer/files/fc_v1.2.zip diff --git a/catalog/development/utilities/filescomparer/index.yaml b/catalog/development/utilities/filescomparer/index.yaml new file mode 100644 index 0000000..3417f79 --- /dev/null +++ b/catalog/development/utilities/filescomparer/index.yaml @@ -0,0 +1,18 @@ +format: 1 +type: program +name: FilesComparer +summary: Программа для побайтового сравнения файлов и образов FullFlash. +description: >- + Для DOS. Сравниватель файлов/флешей может сравнивать не только равные по + размеру файлы, но и неравные, а также выполнять сравнение с начального по + конечный адреса, которые задает сам пользователь. Параметры можно задавать из + командной строки. Возможность выравнивания результатов по байтам. Под DOS & + Windows. +homepage: https://web.archive.org/web/20130813164842/http://vi-soft.com.ua/ +author: SaiNT +screenshots: [] +versions: + - version: "1.2" + files: + - path: files/fc_v1.2.zip + platform: win32 diff --git a/catalog/development/patching/hex2vkp/files/hex2vkp.zip b/catalog/development/utilities/hex2vkp/files/hex2vkp.zip similarity index 100% rename from catalog/development/patching/hex2vkp/files/hex2vkp.zip rename to catalog/development/utilities/hex2vkp/files/hex2vkp.zip diff --git a/catalog/development/utilities/hex2vkp/index.yaml b/catalog/development/utilities/hex2vkp/index.yaml new file mode 100644 index 0000000..a2e07ea --- /dev/null +++ b/catalog/development/utilities/hex2vkp/index.yaml @@ -0,0 +1,23 @@ +format: 1 +type: program +name: Hex2VKP +summary: Конвертер Intel HEX в формат патчей VKP для V_KLay. +description: |- + Для Windows, с консольным интерфейсом. Hex2VKP — конвертер из Intel HEX + формата в формат программы V_Klay — .VKP. + + HEX (.H86) — это формат от фирмы Intel, специально предназначенный для + загрузки данных в микроконтроллеры. Многие компиляторы для C166 (в том числе + Keil и Tasking C) умеют выдавать результаты в этом формате. Таким образом, + заливка патчей в телефон становится проще. Все, что вам остается сделать + после компиляции патча, — это сконвертировать его данным тулом в формат .VKP и + залить в телефон программой V_KLay. +homepage: https://web.archive.org/web/20130813164842/http://vi-soft.com.ua/ +author: Redkin +screenshots: [] +versions: + - version: "0.1a" + files: + - path: files/hex2vkp.zip + description: В комплекте исходный код, настройки и руководство + platform: win32 diff --git a/catalog/development/utilities/index.yaml b/catalog/development/utilities/index.yaml new file mode 100644 index 0000000..9986f30 --- /dev/null +++ b/catalog/development/utilities/index.yaml @@ -0,0 +1,4 @@ +format: 1 +type: category +name: Утилиты +description: Сравнение и анализ прошивок, поиск функций и создание патчей VKP. diff --git a/catalog/development/patching/slfc/files/slfc-chaos.zip b/catalog/development/utilities/slfc/files/slfc-chaos.zip similarity index 100% rename from catalog/development/patching/slfc/files/slfc-chaos.zip rename to catalog/development/utilities/slfc/files/slfc-chaos.zip diff --git a/catalog/development/patching/slfc/files/slfc-vi-soft.zip b/catalog/development/utilities/slfc/files/slfc-vi-soft.zip similarity index 100% rename from catalog/development/patching/slfc/files/slfc-vi-soft.zip rename to catalog/development/utilities/slfc/files/slfc-vi-soft.zip diff --git a/catalog/development/patching/slfc/index.yaml b/catalog/development/utilities/slfc/index.yaml similarity index 56% rename from catalog/development/patching/slfc/index.yaml rename to catalog/development/utilities/slfc/index.yaml index 37504da..246138f 100644 --- a/catalog/development/patching/slfc/index.yaml +++ b/catalog/development/utilities/slfc/index.yaml @@ -3,12 +3,11 @@ type: program name: SLFC summary: Консольная программа для сравнения образов FullFlash и создания VKP-патчей. description: |- - Консольная программа для сравнения двух файлов fullflash и создания патча в - формате VKP. + Для Windows, с консольным интерфейсом. Сравнивает 2 файла (fullflash), + результат сравнения можно сохранять в виде vkp-файла. - Совпадающие байты можно учитывать по правилу: если их не больше трёх, они - включаются в патч; более длинная совпадающая последовательность считается - окончанием блока изменений. + Совпадающие байты можно обойти так: если их `<=3`, то включать в патч, если + больше, тогда уже считать, что блок изменений закончился. homepage: https://web.archive.org/web/20130813164842/http://chaos.allsiemens.com/software.html author: Chaos screenshots: [] diff --git a/catalog/drivers/pl-2303/index.yaml b/catalog/drivers/pl-2303/index.yaml index d03cd64..88adeaf 100644 --- a/catalog/drivers/pl-2303/index.yaml +++ b/catalog/drivers/pl-2303/index.yaml @@ -3,7 +3,8 @@ type: program name: PL-2303 Driver (Patched) summary: Модифицированный драйвер дата-кабелей PL-2303 с поддержкой скорости до 1625000 бит/с. description: >- - Модифицированный Chaos драйвер для дата-кабелей на чипсете Prolific PL-2303. В отличие от штатного драйвера он позволяет флешерам обмениваться данными с телефоном на скорости до 1625000 бит/с. + Пропатченный драйвер для дата-кабелей на чипсете Prolific PL-2303, + позволяющий работать с флешером на скорости 1625000 бит/с. homepage: https://web.archive.org/web/20130813164842/http://chaos.allsiemens.com/software.html author: Prolific Technology Inc.; модификация — Chaos screenshots: [] @@ -11,5 +12,4 @@ versions: - version: "2.0.5.26" files: - path: files/PL-2303_patched.zip - description: Драйвер PL-2303 с поддержкой скорости до 1625000 бит/с platform: win32 diff --git a/catalog/explorers/index.yaml b/catalog/explorers/index.yaml new file mode 100644 index 0000000..9fea5ad --- /dev/null +++ b/catalog/explorers/index.yaml @@ -0,0 +1,5 @@ +format: 1 +type: category +name: Эксплореры +order: -15 +description: Программы для управления содержимым телефонов с компьютера. diff --git a/catalog/explorers/simoco/files/SiMoCo-2.2.9.zip b/catalog/explorers/simoco/files/SiMoCo-2.2.9.zip new file mode 100644 index 0000000..29bfa98 --- /dev/null +++ b/catalog/explorers/simoco/files/SiMoCo-2.2.9.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:289a26e6f137447fafdaadf03ad83c25e01199254010adaa13b4dbc506335456 +size 1064761 diff --git a/catalog/explorers/simoco/img/simoco.jpg b/catalog/explorers/simoco/img/simoco.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ba689b94a6d7c34878a8702278a3367326ee6473 GIT binary patch literal 51102 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 + +Creates a Windows XP-compatible ZIP next to the source file. + + -o, --output write to a specific ZIP path + --replace delete the source after successful verification + --help show this help message`); +} + +function parseArguments(args: string[]): Options { + let output: string | undefined; + let replace = false; + const positional: string[] = []; + + for (let index = 0; index < args.length; index += 1) { + const argument = args[index]; + if (argument === "--help" || argument === "-h") { + usage(); + process.exit(0); + } else if (argument === "--replace") { + replace = true; + } else if (argument === "--output" || argument === "-o") { + output = args[index + 1]; + if (output === undefined) { + throw new Error(`${argument} requires a path`); + } + index += 1; + } else if (argument.startsWith("-")) { + throw new Error(`Unknown option: ${argument}`); + } else { + positional.push(argument); + } + } + + if (positional.length !== 1) { + throw new Error("Expected one archive or EXE path"); + } + + const source = path.resolve(positional[0]); + const extension = path.extname(source).toLowerCase(); + if (!supportedExtensions.has(extension)) { + throw new Error(`Unsupported source type: ${extension || "no extension"}`); + } + + const destination = path.resolve( + output ?? path.join(path.dirname(source), `${path.basename(source, extension)}.zip`), + ); + if (path.extname(destination).toLowerCase() !== ".zip") { + throw new Error("Output path must have the .zip extension"); + } + if (source === destination) { + throw new Error("Source and output paths are the same; use --output for ZIP input"); + } + + return { source, output: destination, replace }; +} + +async function run( + command: string, + args: string[], + cwd?: string, +): Promise<{ stdout: string; stderr: string }> { + return execFileAsync(command, args, { + cwd, + encoding: "utf8", + maxBuffer: 16 * 1024 * 1024, + }); +} + +async function sha256(filePath: string): Promise { + const hash = createHash("sha256"); + for await (const chunk of createReadStream(filePath)) { + hash.update(chunk); + } + return hash.digest("hex"); +} + +async function collectTree(root: string): Promise> { + const result = new Map(); + + async function visit(directory: string): Promise { + const entries = await readdir(directory, { withFileTypes: true }); + entries.sort((left, right) => left.name.localeCompare(right.name, "en")); + + for (const entry of entries) { + const absolutePath = path.join(directory, entry.name); + const relativePath = path.relative(root, absolutePath).split(path.sep).join("/"); + const fileStat = await lstat(absolutePath, { bigint: true }); + const mtime100ns = fileStat.mtimeNs / 100n; + + if (fileStat.isDirectory()) { + result.set(relativePath, { type: "directory", mtime100ns }); + await visit(absolutePath); + } else if (fileStat.isFile()) { + result.set(relativePath, { + type: "file", + mtime100ns, + size: fileStat.size, + sha256: await sha256(absolutePath), + }); + } else { + throw new Error(`Unsupported special file: ${relativePath}`); + } + } + } + + await visit(root); + return result; +} + +function compareTrees( + original: Map, + verified: Map, +): void { + if (original.size === 0) { + throw new Error("Source contains no files or directories"); + } + if (original.size !== verified.size) { + throw new Error("ZIP contents differ from the source"); + } + + for (const [entryPath, expected] of original) { + const actual = verified.get(entryPath); + if (actual === undefined) { + throw new Error(`Missing entry after repacking: ${entryPath}`); + } + if ( + actual.type !== expected.type || + actual.mtime100ns !== expected.mtime100ns || + actual.size !== expected.size || + actual.sha256 !== expected.sha256 + ) { + throw new Error(`Entry differs after repacking: ${entryPath}`); + } + } +} + +async function validateCompatibility(zipPath: string): Promise { + const { stdout } = await run("zipinfo", ["-v", zipPath]); + if (/zip64/i.test(stdout)) { + throw new Error("Zip64 is not compatible with Windows XP Explorer"); + } + + const versions = [...stdout.matchAll( + /minimum software version required to extract:\s*([0-9.]+)/g, + )]; + if (versions.some((match) => Number(match[1]) > 2)) { + throw new Error("ZIP requires an extractor newer than version 2.0"); + } + + const methods = [...stdout.matchAll(/compression method:\s*([^\r\n]+)/g)]; + if ( + methods.length === 0 || + methods.some((match) => !/^(deflated|none \(stored\))$/.test(match[1].trim())) + ) { + throw new Error("ZIP uses a method other than Store or Deflate"); + } + + const security = [...stdout.matchAll(/file security status:\s*([^\r\n]+)/g)]; + if ( + security.length === 0 || + security.some((match) => match[1].trim() !== "not encrypted") + ) { + throw new Error("Encrypted ZIP entries are not allowed"); + } +} + +async function ensureOutputDoesNotExist(output: string): Promise { + try { + await lstat(output); + throw new Error(`Output already exists: ${output}`); + } catch (error) { + const code = error instanceof Error && "code" in error ? error.code : undefined; + if (code !== "ENOENT") { + throw error; + } + } +} + +async function main(): Promise { + const options = parseArguments(process.argv.slice(2)); + const sourceStat = await stat(options.source); + if (!sourceStat.isFile()) { + throw new Error(`Source is not a regular file: ${options.source}`); + } + await ensureOutputDoesNotExist(options.output); + + const temporaryRoot = await mkdtemp(path.join(tmpdir(), "repack-archive-")); + const originalDirectory = path.join(temporaryRoot, "original"); + const verifiedDirectory = path.join(temporaryRoot, "verified"); + const temporaryZip = path.join(temporaryRoot, "output.zip"); + await mkdir(originalDirectory); + await mkdir(verifiedDirectory); + + try { + if (path.extname(options.source).toLowerCase() === ".exe") { + await run("cp", ["-p", "--", options.source, originalDirectory]); + } else { + await run("7z", ["t", options.source, "-bso0", "-bsp0"]); + await run("7z", [ + "x", + options.source, + "-y", + `-o${originalDirectory}`, + "-bso0", + "-bsp0", + ]); + } + + const originalTree = await collectTree(originalDirectory); + await run( + "7z", + [ + "a", + "-tzip", + "-mm=Deflate", + "-mx=9", + "-mtc=on", + "-mtm=on", + "-mta=on", + temporaryZip, + ".", + "-bso0", + "-bsp0", + ], + originalDirectory, + ); + await run("touch", ["-r", options.source, temporaryZip]); + await run("7z", ["t", temporaryZip, "-bso0", "-bsp0"]); + await validateCompatibility(temporaryZip); + + await run("7z", [ + "x", + temporaryZip, + "-y", + `-o${verifiedDirectory}`, + "-bso0", + "-bsp0", + ]); + compareTrees(originalTree, await collectTree(verifiedDirectory)); + + await mkdir(path.dirname(options.output), { recursive: true }); + try { + await copyFile(temporaryZip, options.output, constants.COPYFILE_EXCL); + await run("touch", ["-r", options.source, options.output]); + } catch (error) { + await rm(options.output, { force: true }); + throw error; + } + + if (options.replace) { + await rm(options.source); + } + + console.log(`Created ${options.output}`); + console.log("Verified contents, SHA-256, timestamps, and Windows XP compatibility."); + if (options.replace) { + console.log(`Removed ${options.source}`); + } + } finally { + await rm(temporaryRoot, { recursive: true, force: true }); + } +} + +try { + await main(); +} catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.error(`Error: ${message}`); + process.exitCode = 1; +}