
Скриншот программы Advanced JPEG Compressor
Программа
Advanced JPEG Compressor предназначена для оптимизации изображений, изменения размеров, повышения резкости, а также для выполнения многих других операций над картинками, в том числе и в режиме пакетной обработки. Важно, что все действия выполняются без значительной потери качества. Очень неплохая альтернатива тяжеленным графическим редакторам, особенно когда надо быстро подправить большое количество фотографий. Но стоимость лицензии колеблется от 35 до 1500 баксов, хотя единственно допустимая цена любой программы - это 0 (прописью: НОЛЬ) в любой валюте.
Скачиваем
дистрибутив, распаковываем, устанавливаем, запускаем программу. Пока вроде все нормально, кроме принудительно открываемого каждый раз при старте файла помощи и окна с предложением принять участие в растрате собственного бабла. Это интереса не представляет. Теперь попробуем отредактировать какую-нибудь фотографию. При попытке сохранить любые изменения получаем сообщение:

Окно незарегистрированной программы
Это уже интереснее, мы узнали, что триальная версия программы не дает сохранять изменения. Главный исполняемый файл программы ajc.exe запакован ASPack, его можно снять или руками, или воспользовавшись каким-нибудь автоматическим распаковщиком. После распаковки файла загоняем его в дизассемблер, а сами в редакторе ресурсов поищем что-нибудь интересное. Вот что нашлось:

Строка о регистрации в ресурсах
Это ни что иное, как строка о регистрации, которая где-то появляется при наличии правильных регистрационных данных. Правильность регистрационных данных определяется какой-то проверкой, значит можно будет найти в коде условие, при котором программа считает себя зарегистрированной. Нам уже известен индекс строки в ресурсах - это число 65247 или 0FEDFh в шестнадцатеричной системе счисления, поищем его в листинге дизассемблера.
; DATA XREF: DATA:off_5600F0
CODE:0043CE18 off_43CE18 dd offset hModule
CODE:0043CE1C dd 0FEDFh ; Индекс строки "LICENSED TO:"
На него ссылается следующий указатель:
Code (Assembler) : Убрать нумерацию
; Dbtables::TBlobStream::TBlobStream(Db::TBlobField *,Db::TBlobStreamMode)+1BE
; sub_53BA2C+102
DATA:005600F0 off_5600F0 dd offset off_43CE18
А на него, в свою очередь, вот такой фрагмент кода:
...
CODE:0053BAE9 mov eax, [ebp+var_4]
; Если байт по адресу [eax+0E89h] равен нулю, то данные о лицензии
; не загружать и не выводить
CODE:0053BAEC cmp byte ptr [eax+0E89h], 0
CODE:0053BAF3 jz loc_53BB7F
; Загрузить строку из ресурсов и прописать данные в заголовок главного
; окна программы
CODE:0053BAF9 lea edx, [ebp+var_14]
CODE:0053BAFC mov eax, ds:off_560034
CODE:0053BB01 call @System@LoadResString$qqrp20System@TResStringRec
; System::LoadResString(System::TResStringRec *)
CODE:0053BB06 mov edx, [ebp+var_14]
CODE:0053BB09 mov eax, [ebp+var_4]
CODE:0053BB0C mov eax, [eax+6E4h]
CODE:0053BB12 call @Menus@TMenuItem@SetCaption$qqrx17System@AnsiString
; Menus::TMenuItem::SetCaption(System::AnsiString)
CODE:0053BB17 lea eax, [ebp+var_18]
CODE:0053BB1A push eax
CODE:0053BB1B mov eax, [ebp+var_4]
CODE:0053BB1E mov eax, [eax+9CB4h]
CODE:0053BB24 mov [ebp+var_30], eax
CODE:0053BB27 mov [ebp+var_2C], 0Bh
CODE:0053BB2B lea edx, [ebp+var_34]
; Указатель на указатель на строку "LICENSED TO:"
CODE:0053BB2E mov eax, ds:off_5600F0
CODE:0053BB33 call @System@LoadResString$qqrp20System@TResStringRec
; System::LoadResString(System::TResStringRec *)
CODE:0053BB38 mov eax, [ebp+var_34]
CODE:0053BB3B mov [ebp+var_28], eax
CODE:0053BB3E mov [ebp+var_24], 0Bh
...
При корректной регистрации байт по адресу [eax+0E89h] содержит ненулевое значение. Поищем место, где он инициализируется. Далеко ходить не пришлось, это место чуть выше по коду, прямо перед проверкой:
...
CODE:0053BA9C call @Idimap4$qqrx17System@AnsiStringp20Idmessage@TIdMessage
; Idimap4::TIdIMAP4::UIDRetrieve(System::AnsiString,Idmessage::TIdMessage *)
CODE:0053BAA1 mov ebx, eax
CODE:0053BAA3 mov eax, [ebp+var_4]
CODE:0053BAA6 mov [eax+0E89h], bl
...
По адресу 0053BAA1 в коде находится двухбайтовая команда mov ebx, eax, заменим ее такой же двухбайтовой командой mov bl,1 и посмотрим что получилось.

Программа успешно "зарегистрирована"
В заголовке окна надпись, что программа на кого-то зарегистрирована, надоедливый файл помощи при старте не открывается. Попробуем отредактировать какую-нибудь фотографию и сохранить изменения. Все работает! Файл сохраняется, никаких предупреждений не выдается. Последний штрих: в меню "Help" пункт "Purchase a license..." сменился на "Purchase more licenses..." То есть программа считает, что какое-то количество лицензий у нас есть, но можно прикупить еще. Накормим ее регистрациями до отвала. Если предположить, что в байте по адресу [eax+0E89h] содержится количество лицензий, а мы туда записываем единичку, то максимум, что туда может быть записано - это 255 или 0FFh в шестнадцатеричной системе счисления. Заменим команду по адресу 0053BAA1 на mov bl,0FF и снова посмотрим что получилось. Пункт в меню с предложением купить дополнительные лицензии пропал. Все поставленные цели достигнуты. В пропатченном состоянии Advanced JPEG Compressor становится портативным и прекрасно работает со съемных носителей. Лично я его таскаю на флешке вместе с другим полезным инструментарием.