image

В предыдущей статье мы разобрали, как реверс-инжиниринг может помочь в получении каких-либо преимуществ перед остальными пользователями. Сегодня мы поговорим ещё об одном применении обратной разработки — исправлении багов в отсутствии исходных кодов приложения. Причин заниматься подобными вещами может быть целое море — разработка программы давным-давно заброшена, а её сорцы автор так и не предоставил общественности / разработка ведётся совершенно в другом русле, и авторам нет никакого дела до возникшего у вас бага / etc, но их объединяет общая цель — исправить сломанный функционал, который постоянно вам досаждает.

Что ж, ближе к делу. Есть такая широко известная в узких кругах программа под названием «Govorilka». Как объясняет её автор, это ничто иное, как «программа для чтения текстов голосом». По сути, так оно и есть. При помощи неё было озвучено множество популярных и не очень видео, рапространившихся по всей сети. Программа имеет консольную версию под названием «Govorilka_cp», которую удобно вызывать из своих собственных приложений, что, собственно, я и сделал в одном из своих проектов.

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

Учитывая, что говорилка не обновлялась уже несколько лет, а сам автор оставил вот такое «послание» на своём сайте

image

, я понял, что надеяться мне не на кого, и решать проблему придётся самому.

Как протекал процесс, и что из этого вышло, читайте под катом (осторожно, много скриншотов).

Прежде чем загружать говорилку в OllyDbg, давайте посмотрим, не защищена ли она каким-нибудь протектором. Берём в руки DiE и видим следующую картину:

image

Судя по его выводу, программа запакована ASPack'ом. Для убедительности воспользуемся ещё одним анализатором — PEiD:

image

Надеясь, что два анализатора не могут ошибаться одновременно, приходим к выводу, что говорилка действительно накрыта ASPack'ом. Ну, ничего, давайте его снимем.

Избавление исполняемого файла от ASPack'а можно разделить на три основных этапа:
  • Поиск OEP (Original Entry Point — адрес, с которого бы начинала выполняться программа, если бы не была упакована)
  • Снятие дампа
  • Восстановление IAT

Начнём, разумеется, с поиска OEP. Один из самых простых способов обнаружить оригинальную точку входа — поставить хардварный бряк на ESP-4, потому что большинство паковщиков после своей работы восстанавливают стек. Запускаем говорилку в OllyDbg, открываем Command Line при помощи Alt-F1 (окно стандартного плагина, который поставляется вместе с самим отладчиком), вводим команду hr esp-4, нажимаем F9 и останавливаемся вот на таком месте:

image

Теперь нам надо пробежаться до ближайшего return'а при помощи Ctrl-F9, нажать F8 и… оказаться на OEP, которая в данном случае находится по адресу 0x0045A210:

image

Пришло время снимать дамп. Скачиваем и устанавливаем плагин для OllyDbg под названием OllyDump, перезапускаем отладку при помощи Ctrl-F2, снова останавливаемся на OEP и выбираем пункт меню «Dump debugged process», который находится в Plugins -> OllyDump:

image

Нажимаем кнопку «Dump», выбираем имя выходного исполняемого файла и… получаем вот это при попытке его запустить:

image

Значит, что-то не так с импортами. Ничего, восстановим их вручную.

Дампим процесс говорилки ещё раз, но на этот раз снимаем галочку с CheckBox'а «Rebuild Import». Скачиваем ImpREC, выбираем процесс говорилки из списка, вводим адрес 5A210 в поле для OEP — 0x0045A210 — image base (0x400000) = 0x5A210 и нажимаем на кнопку «IAT AutoSearch»:

image

Делаем, как сказали, и наблюдаем следующую картину:

image

Очевидно, это ненормально. Пробуем указать RVA и size, которыми нам предлагала воспользоваться в случае неудачи сама программа, и нажать на кнопку «Get Imports» снова:

image

Что-то явно идёт не так, как ожидается. Давайте попробуем найти границы IAT вручную. Ищем в дизассемблированном листинге вызов любой WinAPI-функции. Например, вот этот:

image

Прыгаем на него (left click -> Enter) и видим, куда обращаются все JMP'ы:

image

Переходим по любому из указанных в данном месте адресов (right-click -> Follow in Dump -> Memory address), выбираем соответствующее представление (right-click по окну Memory Dump'а -> Long -> Address) и видим следующее:

image

Пробегаемся глазами до начала списка адресов функций:

image

Нажимаем двойным кликом мыши на ntdll.RtlDeleteCriticalSection и ищем конец списка:

image

Указываем адрес начала IAT (0005F168) и size (0000066C), снова нажимаем на кнопку «Get Imports» и получаем следующий результат:

image

Уже лучше, но всё равно остались невалидные импорты, причём самое странное, что мы вроде бы всё сделали правильно… Давайте воспользуемся другим приложением для восставления IAT — Scylla:

image

Да что такое происходит? А давайте попробуем проделать то же самое в другой системе — например, в Windows 7 x32 (до этого эксперименты проводились в Windows 8 x64).

Чудесным образом мы получили валидные импорты:

image

Честно говоря, не уверен, что это — баг ImpRec'а и Scylla, особенность Windows 8 x64 или что-то ещё, но главное, что мы восстановили IAT. Точнее, для этого нам надо нажать на кнопку «Fix Dump», выбрать сделанный ранее дамп и попробовать запустить получившийся исполняемый файл. Да, при запуске говорилки без аргументов она работает, как и положено, а вот в случае передачи каких-либо фраз для озвучивания она падает, как и в запакованном варианте.

Итак, ASPack снят. Что дальше? А дальше, собственно, нам предстоит разобраться с возникающим на некоторых компьютерах багом.

Первым делом давайте посмотрим на стандартное окно Windows, сообщающее о краше приложения:

image

Вам должно быть заметно, что Exception Offset равен 0x000591D4. Загружаем говорилку в OllyDbg, ставим софтварный бряк на этот адрес (точнее, на image base + 0x000591D4 — в моём случае это 0x004591D4), нажимаем F9 и получаем следующее:

image

Как вы видите, значение регистра ESI на момент выполнения операции чтения по адресу ESI+38 равно нулю, что, разумеется, приводит к крашу приложения. Двумя инструкциями выше заметно, что в ESI значение попадает из регистра EAX. Значение регистра EAX до этого в данной процедуре не меняется, так что смотрим по Call Stack'у, откуда нас позвали:

image

Прыгаем туда (right click -> Show Call) и видим, что прямо перед вызовом процедуры находится команда MOV EAX,DWORD PTR DS:[45EC5C]:

image

Как видно из предыдущего скриншота, по адресу 0x45EC5C также находится ноль. Ставим хардварный бряк на запись по этому адресу (right click -> Breakpoint -> Hardware, on write -> Dword), запускаем приложение ещё раз и обнаруживаем, что никакой записи по данномуадресу не происходит. Давайте проанализируем, как себя ведёт приложение в случае успешной работы в другой системе. Запись по адресу 0x45EC5C в этом случае действительно происходит:

image

, в результате чего ESI+38 даёт какое-то осмысленное значение. Давайте узнаем, как мы попали в это место. Call Stack на момент выполнения данной инструкции пустой, так что у меня возникло впечатление, что это основная процедура программы. Чтобы понять, в каком именно месте приложение стало вести себя по-другому, давайте запустим Trace over (Ctrl-F12) на обеих системах (там, где приложение падает, и там, где оно работает).

В случае системы, где приложение постоянно падает, оно достигло бряка на доступе к ESI+38, где и упало. Последняя строчка кода в trace log'е была CALL'ом по адресу 0x004597C8:

image

, в то время как в системе, где приложение работает нормально, после вызова данной процедуры (0x004597C8) происходит выполнение других инструкций, на одной из которых и срабатывает хардварный бряк на запись по адресу 0x45EC5C:

image

Возможно, что-то идёт не так в процедуре 0x004597C8. Ставим софтварный бряк на её вызов (0x0045AD5B) и обнаруживаем, что его установка ведёт к тому, что на той системе, где всё работало нормально, теперь не срабатывает хардварный бряк на запись по адресу 0x45EC5C, в результате чего приложение падает, как и в случае другой системы. С хардварными бряками на выполнение всё обстоит так же.

Экспериментальным путём было выяснено, что установка бряков на нескольких предшествующих 0x0045AD5B инструкциях ведёт к такому же результату. Установить бряк с последующей нормальной работой приложения получилось лишь на данной инструкции:

image

Возможно, установкой бряков в данных местах мы мешали замерам времени, которые как раз и осуществляются при помощи вызовов функции GetTickCount.

Запускаем Trace into (Ctrl-F11), начиная с данной инструкции, и обнаруживаем, что различия в выполнении начинаются вот с этого места:

; если приложение выполняется в системе, где оно падает
004597EC Main     MOV EAX,DWORD PTR DS:[45EC98]             ; EAX=F2B47801
004597F1 Main     ADD EAX,64                                ; EAX=F2B47865
004597F4 Main     CDQ                                       ; EDX=FFFFFFFF
004597F5 Main     CMP EDX,DWORD PTR SS:[ESP+4]
004597F9 Main     JNZ SHORT Govorilk.00459807
00459807 Main     POP EDX                                   ; EDX=F2B47802

; если приложение выполняется в системе, где оно нормально работает
004597EC Main     MOV EAX,DWORD PTR DS:[45EC98]
004597F1 Main     ADD EAX,64                                ; EAX=064A1501
004597F4 Main     CDQ
004597F5 Main     CMP EDX,DWORD PTR SS:[ESP+4]
004597F9 Main     JNZ SHORT Govorilk.00459807
004597FB Main     CMP EAX,DWORD PTR SS:[ESP]

Отсюда заметно, что результат выполнения инструкции CMP EDX,DWORD PTR SS:[ESP+4] влияет на дальнейшую работу процедуры. В случае системы, где оно работает, флаг Z регистра флагов был выставлен на момент выполнения данной инструкции, в то время как в случае той системы, где приложение падает, данный флаг не был выставлен:

image

Давайте посмотрим, что же на это влияет. Итак, что у нас здесь происходит?

  • Вызывается функция GetTickCount, результат её вызова записывается в регистр EAX
  • Обнуляется содержимое регистра EDX
  • Содержимое регистров EDX (0x0) и EAX (результат выполнения функции GetTickCount) заносятся на стек
  • В регистр EAX помещается значение из адреса 0x45EC98
  • К нему прибавляется 0x64
  • Выполняется инструкция CDQ
  • И, наконец, сравнивается содержимое регистра EDX и значение по адресу ESP-4, где хранится предыдущее значение данного регистра, т.е. 0x0

Поставив хардварный бряк на запись по адресу 0x45EC98, можно увидеть, что туда также помещается результат выполнения функции GetTickCount:

image

Кстати, а почему GetTickCount возвращает такое большое значение? Ведь система выключалась мной ещё сегодня утром. На самом деле, тут играет свою роль hybrid boot и shutdown в Windows 8. Почитать об этом больше можно, например, тут.

Но вернёмся к основной теме нашего обсуждения. В чём же тут тогда проблема? Давайте внимательно посмотрим на содержимое регистров общего назначения в этом куске кода на обеих системах. Вам должно броситься в глаза, что после выполнения инструкции CDQ на системе, где приложение работает корректно, регистр EDX принимает значение 0x0, а в системе, где программа падает, 0xFFFFFFFF, что видно, например, на предыдущем скриншоте. Внимательно читаем описание инструкции CDQ:

Converts signed DWORD in EAX to a signed quad word in EDX:EAX by extending the high order bit of EAX throughout EDX

А теперь взглянем на сигнатуру функции GetTickCount:

DWORD WINAPI GetTickCount(void);

Как видите, она возвращает DWORD, который «раскрывается» в unsigned long, т.е. беззнаковый тип.

Уж не знаю, баг это разработчика или компилятора, но на такое поведение автор явно не рассчитывал, ведь в текущей ситуации говорилка будет падать на системах, которые работают дольше 24.8 и меньше 49.7 дней. Почему именно так? Нижняя граница определяется максимальным значением, которое может поместиться в знаковую 4-байтовую переменную — 2147483647:

2147483647 / 1000 / 60 / 60 / 24 = 24.8551348032

Верхняя же граница определяется самой функцией GetTickCount, о чём сказано в документации (собственно, она определяется максимальным значением, которое может поместиться в беззнаковую 4-байтовую переменную):

The elapsed time is stored as a DWORD value. Therefore, the time will wrap around to zero if the system is run continuously for 49.7 days

Ну что, пора исправить это допущение. Один из вариантов исправления проблемы — каким-то образом «подменить» вызов функции GetTickCount своим кодом, в котором мы будем «уменьшать» возвращаемое из неё значение настолько, чтобы оно поместилось в знаковую 4-байтовую переменную.

Вариантов решения данной задачи несколько, но давайте напишем code cave. Ищем свободное место (проще всего найти его в «конце» окна CPU) и помещаем туда следующий код:

; Сохраняем состояние регистров общего назначения на стеке
0045BAAA      60               PUSHAD
; Сохраняем состояние регистра флагов на стеке
0045BAAB      9C               PUSHFD
; Получаем значение EIP
0045BAAC      E8 00000000      CALL Govorilk.0045BAB1
0045BAB1      5E               POP ESI
; Вызываем функцию GetTickCount
0045BAB2      FF96 2F380000    CALL DWORD PTR DS:[ESI+382F]
; Сохраняем результат её выполнения на по адресу ESP-4
0045BAB8      894424 FC        MOV DWORD PTR SS:[ESP-4],EAX
; Восстанавливаем состояние регистра флагов
0045BABC      9D               POPFD
; Восстанавливаем состояние регистров общего назначения
0045BABD      61               POPAD
; Помещаем в регистр EAX результат выполнения функции GetTickCount
0045BABE      8B4424 D8        MOV EAX,DWORD PTR SS:[ESP-28]
; Выполняем операцию битового "AND" над значением, хранящемся в регистре EAX
0045BAC2      25 FFFFFF0F      AND EAX,0FFFFFFF
0045BAC7      C3               RETN

Значение 382F получилось в результате вычисления разницы между адресом в IAT, по которому хранится адрес функции GetTickCount (0x0045F2E0), и текущим адресом (0x0045BAB1).

Получить значение регистра EIP напрямую не получится — к нему нельзя обращаться ни на чтение, ни на запись.

Теперь переходим на место, где осуществляется JMP на функцию GetTickCount

image

и заменяем адрес, на который прыгает JMP, на адрес начала нашего code cave'а (в моём случае это 0x0045BAAA):

image

Сохраняем изменённый исполняемый файл (right-click по окну CPU -> Copy to executable -> All modifications -> Copy all -> right-click на появившемся окне -> Save file) и проверяем его работоспособность. Да, он действительно работает, однако при запуске говорилки теперь выдаётся знакомое практически всем пользователям Windows окно UAC. Почему именно это происходит можно почитать, например, тут, а для решения проблемы в нашем случае достаточно всего лишь дать нашему исполняемому файлу оригинальное название — «Govorilka_cp.exe».

Послесловие


Как видите, использовать реверс-инжиниринг можно не только для читерства или поиска уязвимостей, но и для вполне полезных целей. Старайтесь исправлять проблемы, а не забивать на них — вполне возможно, что в процессе исправления очередной ошибки вы откроете для себя что-то новое. А я в свою очередь снова надеюсь, что статья оказалась кому-нибудь полезной.

Также я выражаю огромную благодарность человеку с ником tihiy_grom — без него этой статьи просто не было бы.

Комментарии (53)


  1. AllexIn
    09.05.2015 22:44
    +26

    Хех. Припоминаю ситуацию, когда работал реверс-инженером в фирме по локализации. Исходников проекта не было.
    И вот, уже пора сдавать проект. И менеджер заказчика решил выпендриться и в списке багов написал баг, который изначально в игре присутствует и к локализации никакого отношения не имеет.
    Ну чтож. Вызов приняли. Выковыряли скрипты, аккуратно разобрались в логике работы и исправили баг. Было весело. :)
    P.S. Не знаю зачем я это всё написал. :(


  1. EminH
    09.05.2015 23:46
    -1

    Я понимаю, в таких темах к терминологии придираться не comme il faut, но как обьяснить происхождение термина «бряк», от оригинала как по произношению так и по написанию он довольно далек. Тем паче, что вполне можно найти аналог и из незаимствованных слов


    1. Antelle
      10.05.2015 00:03
      +12

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


      1. priv8v
        12.05.2015 10:18
        +1

        бряк — наше все, сколько себя помню бряк именовали именно бряком и никак иначе


        1. vlivyur
          13.05.2015 10:48

          Брык.


          1. priv8v
            13.05.2015 10:59
            +1

            Ни разу не встречал такого написания или не помню просто. Даже гугл плохо помнит: по «ставим брык» нашел 1 (один) результат, а по «ставим бряк» — 4 570


            1. MacIn
              13.05.2015 23:24
              +2

              Останов.
              Устаревшее, но используется до сих пор. «точка останова» (breakpoint).
              Ха, даже в вики есть: ru.wikipedia.org/wiki/%D0%A2%D0%BE%D1%87%D0%BA%D0%B0_%D0%BE%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%B0


              1. priv8v
                14.05.2015 10:00

                Ну это понятно, что есть «нотариально заверенный перевод», но изначально здесь речь зашла о том «откуда есть пошел бряк» и вообще вокруг него. Бряк устоявшееся сленговое понятие, значение которого понятно всем, кто в теме. Точки останова — уровень книг и MSDN. Бряк — разговорный стиль скорее.

                Ну с бряком-то вроде разобрались, а вот «булевая» vs «булевская» вопрос не раскрыт ;)


                1. Mrrl
                  14.05.2015 11:24
                  +1

                  А может быть, «булева»? По аналогии с алгеброй, функцией и т.п.


                  1. priv8v
                    14.05.2015 11:40

                    Да может и так, я исследования не проводил, а субъективно эти три написания встречаются примерно одинаково.


                  1. PsyHaSTe
                    18.05.2015 08:21
                    -1

                    Булева — это типичное сокращенное прилагательное от «булевая», так же, как «красна» от «красная», «симпатична» от «симпатичная», и т.п.


                    1. Mrrl
                      18.05.2015 09:14
                      +1

                      Тем не менее, математики говорят именно «булева алгебра», а не «булевая алгебра». И это вполне естественно: поскольку Джордж Буль, в честь которого она названа — имя собственное, то «булева» — никакое не прилагательное, а притяжательное местоимение: «принадлежащая Булю». И, соответственно", никакого слова «булевая» в русском языке нет.


                      1. Mrrl
                        18.05.2015 09:18

                        А вот слово «булевская» вполне возможно — есть же слова «петровский», «екатерининский», «андреевский»…


                1. MacIn
                  14.05.2015 17:24
                  +1

                  Логическая :)


  1. totuin
    09.05.2015 23:51
    -18

    Вот чем мне нравится язык SmallTalk что никакой реверс — инженеринг в его случае не поможет. Соответственно невозможно создать ни кряк, ни взломщик. Правда багу при отсутствии исходников то же невозможно исправить. А недавно так нужно было…


    1. totuin
      10.05.2015 01:44
      -3

      Ну естественно «настоящие хакеры» испугались упоминания языка программу на котором нельзя сломать, и быстренько заминусовали. Теперь уже дело чести написать пост об этом незаслуженно неизвестном в России языке программировании, который с моей точки зрения является наиболее удобным и гибким воплощением ООП.


      1. Vindicar
        10.05.2015 02:16
        +5

        А вот напишите. Мне интересно. У компилятора что, какие-то особенные волшебные опкоды получаются, которые ни один дебаггер не знает?

        P.S.: не голосовал.


        1. totuin
          10.05.2015 02:23
          -5

          Как раз сейчас этим и занимаюсь. В основном проекте нарисовался небольшой перерыв — появилась возможность. К понедельнику думаю сделаю.
          По Вашему вопросу. Декомпилировать получится только виртуальную машину, соответственно изменить исходный код получится только её. Исходный код программы находится в отдельном образе — хранилище классов, и он представляет собой бинарник, структуру которого я думаю знают только в Sincome. И вот его уже никакой декомпиляцией не измениш.


          1. bioskiller
            10.05.2015 05:29
            +6

            По вашей логике, любой язык который использует ВМ невозможно исследовать. А при этом, люди Another World разобрали, а там как раз была ВМ и так же не было исходных кодов.


            1. totuin
              10.05.2015 05:33
              -4

              Возможно, но честно говоря я не слышал о такой возможности. Я работаю со Smalltalk — ом уже почти 10 лет, но ни разу не слышал о возможности дебажить упакованный образ. Там в принципе даже не команды ассемблера, а байт- код, инструментов для просмотра которого насколько я знаю не существует.


              1. bioskiller
                10.05.2015 05:36
                +18

                Ну вот мы и пришли к правильной формулировке вашего комментария — «Я не слышал о такой возможности»


              1. adic3x
                10.05.2015 13:58
                +2

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

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

                Другой вопрос в сложности всего этого (какая там защита) и необходимости (если на нем не пишут ничего важного — то зачем взламывать?).

                P. S. я абсолютно не знаком с данной средой.


                1. vk2
                  10.05.2015 15:18
                  +1

                  Замечу, что в комплекте этой среды дополнительно идет отладочная VM, в которой полно ассертов, логов и т.д., но главное, что она еще собрана с полной отладочной информацией (специально, чтобы разработчик мог нормальный стектрейс представить авторам).

                  Понятно, что это означает для исследователя.


          1. bioskiller
            10.05.2015 05:32
            +5

            Я вам даже подскажу кто знает структуру того тайного бинарника с исходным кодом. Это сама ВМ.


            1. totuin
              10.05.2015 05:37
              -7

              Не думаю что в Sincome не озаботились возможностью разборки своей BM. Ребята работают в основном с банковской сферой, так что там думаю все серьёзно. Но хотя можете при желании попробовать.


              1. bioskiller
                10.05.2015 05:40

                Ну это вполне объясняет отсутвие широкой информации о данной ВМ. Такие вещи обычно в общий доступ не идут.


                1. totuin
                  10.05.2015 05:43

                  Я как раз сейчас пишу пост об этом языке, и там расскажу его историю. Вообще то этот язык как бы не старше большинства из существующих. Первая реализация — 71 год.


                  1. bioskiller
                    10.05.2015 05:47
                    +1

                    Пишите конечно. Но наличие GNU Smalltalk подразумеват наличие исходных кодов. Так что мы приходим к тому, что скорее всего отсутствует спецификация конкретно ВМ Sincome.


              1. vk2
                10.05.2015 11:12
                +5

                По-моему, вы демонизируете Смоллток :-)

                Посмотрите класс CompiledCode, Compiler, Decompiler, InstructionStream и прочие. Учитывая рефлексию как неотъемлемое свойство смоллтока, можно получить просто огромное количество информации на достаточно низком уровне. В отданном экзешнике многих этих классов, вероятно, не будет (если он умен, чтобы их стрипнуть), но их достаточно, чтобы изучить байткод и вообще организацию компиляции и рантайма. Да, VM там JIT, но делает она native code все-таки из байткода…

                Вот вам и байткод, и декомпиляция байткода средствами самого же Cincom VisualWorks (извините за стиль, слишком давно на нем не писал):

                t := [ :arg | arg*2 ] // в момент присвоения в переменную t, этот блок скомпилировался
                
                t value: 100 // проверяем, что работает
                >> 200
                
                t method bytes // получаем байт-код
                >> #[16 75 168 101]
                
                result := String new writeStream.
                t method printSymbolicOn: result.  // печатаем "дизассемблированный" байткод
                result contents
                >> 'normal CompiledBlock numArgs=1 numTemps=0 frameSize=12
                >>
                >>literals: ()
                >>
                >>1 <10> push local 0
                >>2 <4B> push 2
                >>3 <A8> send *
                >>4 <65> return
                >>'
                
                t method decompiledSource // просим декомпилировать байткод
                >> '[:t1 | t1 * 2]'
                
                // печатаем декомпилированный метод asOrderedCollection класса Collection
                Collection enumerateMethods: [ :class :selector :method | selector asString = 'asOrderedCollection' ifTrue: [ Transcript nextPutAll: method decompiledSource ]]
                ....и т.д.
                


          1. AllexIn
            10.05.2015 07:57
            +9

            «security through obscurity» что-ли?


            1. vk2
              10.05.2015 11:22
              +3

              Да нет, просто никому не нужно (очень хороший язык, но вытеснен в совсем уж узкую нишу)


      1. Idot
        10.05.2015 10:17

        >Ну естественно «настоящие хакеры» испугались упоминания языка программу на котором нельзя сломать…

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

        PS Интересно, насколько сложно ломать LISP и прочую функциональщину, человеку с функциональными языками незнакомому.


        1. valplo
          10.05.2015 14:25
          +1

          Да элементарно. LISP, в общем-то, штука очевидная. Алсо, товарищ totuin, взломать можно все, кроме шифра Вернама, было бы желание. Единственная сложность с VM — под них приходится писать все инструменты самому.


      1. MacIn
        10.05.2015 22:04

        А что, для JAVA машин нет декомпилятора?


    1. Amomum
      10.05.2015 02:23
      +1

      Не могли бы вы объяснить, почему реверс-инженеринг не поможет?

      (не обновил комментарии, когда писал свой; с удовольствием почитаю пост на эту тему)


      1. totuin
        10.05.2015 02:24

        Чуть выше написал. Пока писал — появился Ваш коментарий


    1. ntkt
      10.05.2015 23:54
      +3

      Боюсь, Вы просто не знакомы с темой защиты кода от реверсинга.
      Язык высокого уровня тут вообще ни при чем, «вообще» — от слова «совсем».
      Хакеры работают с машинным кодом.
      Хоть Вы там вложенный интерпретатор Smalltalk'а на Smalltalk'е сто раз подряд реализуйте — это только несколько затруднит процесс разбора (придется написать кучу скриптов и их отладить на кошках).

      1) Не первый десяток лет для защиты бинарников их код транслируют из машинного кода целевой архитекутры в машинные коды специальных обфусцированных VM. Самый известный пример: VMProtect (с 2000 года по наши дни).

      2) Референсная реализация VM любого интерпретируемого языка заведомо проще, чем такие специализированные VM более-менее современных «пакеров»/«протекторов». Машина SmallTalk — детский лепет по сравнению с тем же VMProtect (у которого в последних версиях набор инструкций уникален для каждого бинарника, например).

      3) Но и их, при всей их сложности, успешно исследуют и далее ломают с самого начала; ломали, ломают и ломать будут. Некоторый код в любом случае выполняется целевым железом, значит, его можно на уровне железа сдампить и вручную выполнить, а значит, и понять. Увидели там виртуальную машину? ОК, пошагово разобрали ее, ее архитектуру, набор инструкций и т.д. То, что долго делать руками, давно и успешно автоматизируется.

      4) Единственный относительно надежный способ защиты кода от исследования — особая целевая архитектура с шифрованием «на кристалле».
      Это реальная железная машина, напрямую выполняющая зашифрованный машинный код, ключи расшифрования для которого не покидают ее защищенную память. В идеале, ключи уникальны для каждого процессора и для каждого бинарника.
      О защите кода начали задумываться еще в семидесятые-восьмидесятые, основные идеи можно найти в статьях того времени, да и этот вывод там тоже есть:

      Best R. M. Preventing software piracy with crypto-microprocessors //Proceedings of IEEE Spring COMPCON. – 1980. – Т. 80. – С. 466-469.

      На практике нечто отдаленно похожее сейчас массово (~миллиард штук) реализовано в банковских чиповых картах стандарта EMV. На карту от банка-эмитента может прийти зашифрованный issuer script, который содержит, на самом деле, не машинный код, а простенькие аппликационные команды вида «разблокировать оффлайн PIN» или «установить тег X в значение Y», но ключ шифрования, которым закрыты эти команды, знает только карта и банк.


  1. estet
    10.05.2015 00:41
    +7

    Пост автора вызывает уважение. А вы автора Говорилки вы просили открыть исходный код программы?
    На странице программы даже указаны его фамилия, имя и почтовый адрес (Anton Ryazanov, vecs@mail.ru). Ну то есть если автор поддерживает программу, то он должен был сам исправить баг, а если не поддерживает, то почему не открыть исходный код под одной из свободных лицензий?


  1. ThirteenAG
    10.05.2015 00:46
    +1

    Всё жду когда кто-нибудь исправит баг проводника, когда при копировании и вставке файлов диалог замены появляется не поверх всех окон, а где-то там позади. Даже в последнем на данный момент билде windows 10 он есть. Ну а что, звукозапись же фиксили.


  1. alexf2000
    10.05.2015 02:50
    +5

    Опять же повторюсь — удивительный мир хакеров. Заставить комп под виндой говорить человечьим голосом с помощью спич апи — задача на десяток строк кода на любом языке, какой есть. Во всяких скриптовых языках — на две строки. Что может сподвигнуть вместо этого пользоваться чужой неподдерживаемой прогой с багами? Загадка.


    1. kemsky
      10.05.2015 05:06
      +10

      Без этой программы невозможно представить некоторые видео :)


  1. Dywar
    10.05.2015 08:55

    Интересно, познавательно и легко написано.
    Всегда хотел также легко писать ASM, и знать адреса, смещения, IAT и фокусы отладки (хотя прошел Рикардо до 40 главы, забывается когда не используешь повседневно). Но выбрал C#, а там свои чудеса.

    Жду пост о «SmallTalk», интересно.


    1. MacIn
      11.05.2015 04:57

      (хотя прошел Рикардо до 40 главы


      Что имеется в виду?


      1. kpdev
        11.05.2015 07:32

        1. MacIn
          11.05.2015 22:47

          А, ясно. Спасибо большое.


  1. zenden2k
    10.05.2015 14:56
    +3

    Не вижу причин делать бесплатную программу closed-source, кроме как из-за стыда показать свой код.


    1. valplo
      10.05.2015 15:04

      Судя по сайту, эту программу написали лет семь-десять назад, когда о Open Source еще не все знали.


    1. Mrrl
      12.05.2015 14:17

      Основная причина — что для этого надо как-то изучить экосистему Open Source — что, куда выкладывать, как, в каком формате, какие там обычаи и т.п. Изучить это один раз, чтобы выложить одну программу, а через 10 лет изучать снова — смысла не видно. А чтобы жить в этой среде, нужны дополнительные ресурсы. Которые можно было бы пустить на что-нибудь другое.
      Порог вхождения не может быть нулевым.


  1. Idot
    10.05.2015 17:21

    Хотелось бы статью о том как расшифровывают форматы файлов без исходных кодов.


    1. EvilFox
      12.05.2015 13:47
      +1

      Часто вот так.


  1. stalkerg
    10.05.2015 22:20
    +1

    После этой статьи я ещё больше полюбил OpenSource и Free Software…


  1. Security_Lab
    11.05.2015 20:13

    image
    Как-то маловато «всей правды о багах».


    1. Security_Lab
      11.05.2015 20:19
      +2

      image