Исследование защиты программы iResizer


Скриншот программы iResizer

Программа iResizer - удобный инструмент для изменения размеров графических файлов, с уникальной функцией сохранения исходных пропорций выбранных объектов. Также с ее помощью можно удалять с фотографий ненужные объекты. Конечно, это все прекрасно реализуется и в разных фотошопах, но iResizer позволяет выполнить такие операции буквально за несколько кликов мышкой. Как это все делается, вы можете посмотреть на офсайте, а здесь вы можете посмотреть, как сэкономить на этом процессе пару десятков баксов.

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


Окно ввода серийного номера

Поле ввода серийного номера не совсем обычное, оно сразу же показывает формат серийника, а также фильтрует при вводе недопустимые символы. Автор нам значительно облегчил задачу. Еще даже не открывая ни отладчика, мы знаем, что серийный номер может состоять только из латинских букв и имеет вид типа "ABCD-EFGH-IJKL-MNOP-QRST-UVWX-YZAA-AAAA".

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


Нехорошая строка найдена

Очевидно, что это и есть сообщение, которое выдается при попытке сохранить файл в триальной версии на англоязычной локали. Снова возвращаемся к дизассемблеру. Здесь выводится найденное сообщение:
...
.text:0047E687 loc_47E687:
.text:0047E687                 mov     [ebp+var_28], offset unk_BE7EA0
.text:0047E68E                 mov     ecx, offset unk_BE7EA0
.text:0047E693                 mov     edx, 1
.text:0047E698                 lock xadd [ecx], edx
.text:0047E69C                 push    0FFFFFFFFh
.text:0047E69E                 push    offset aInpaint ; "Inpaint"
.text:0047E6A3                 mov     [ebp+var_4], 0
.text:0047E6AA                 call    sub_87C5B0
.text:0047E6AF                 mov     [ebp+var_24], eax
.text:0047E6B2                 push    0
.text:0047E6B4                 lea     eax, [ebp+var_34]
.text:0047E6B7                 push    offset aNo_0    ; "No"
.text:0047E6BC                 push    eax
.text:0047E6BD                 mov     byte ptr [ebp+var_4], 1
.text:0047E6C1                 call    sub_479CE0
.text:0047E6C6                 mov     esi, eax
.text:0047E6C8                 push    0
.text:0047E6CA                 lea     ecx, [ebp+var_30]
.text:0047E6CD                 push    offset aYes_1   ; "Yes"
.text:0047E6D2                 push    ecx
.text:0047E6D3                 mov     byte ptr [ebp+var_4], 2
.text:0047E6D7                 call    sub_479CE0
.text:0047E6DC                 mov     ebx, eax
.text:0047E6DE                 push    0
.text:0047E6E0                 lea     edx, [ebp+var_2C]
.text:0047E6E3                 push    offset aThisFeatureIsA
; "This feature is available in registered"...
.text:0047E6E8                 push    edx
.text:0047E6E9                 mov     byte ptr [ebp+var_4], 3
.text:0047E6ED                 call    sub_479CE0
...

А вот отсюда к нему идут два условных перевода:
...
.text:0047E36E                 mov     edi, ecx
.text:0047E370                 mov     eax, [edi+14h]
.text:0047E373                 mov     eax, [eax+8]
.text:0047E376                 lea     esi, [edi+14h]
.text:0047E379                 test    eax, eax
; Первый условный переход
.text:0047E37B                 jz      loc_47E687
.text:0047E381                 push    esi
; Вызвать функцию проверки правильности серийного номера
.text:0047E382                 call    sub_47C4F0
.text:0047E387                 add     esp, 4
.text:0047E38A                 test    al, al
.text:0047E38C                 jnz     short loc_47E39F
.text:0047E38E                 push    esi
.text:0047E38F                 call    sub_47C840
.text:0047E394                 add     esp, 4
.text:0047E397                 test    al, al
; Второй условный переход
.text:0047E399                 jz      loc_47E687
.text:0047E39F loc_47E39F:
.text:0047E39F                 mov     ecx, [edi+0B4h]
.text:0047E3A5                 push    0
.text:0047E3A7                 call    sub_4CA4C0
...

Достаточно пропатчить эти условные переходы, заменив NOP'ами, и ограничение на сохранение обработанного файла волшебным образом исчезает. Более того, программа приобретает новое свойство - портативность, то есть может работать с любого носителя без всяких ограничений. Для полной портабелизации надо убрать из программы обращения к ветке реестра, куда она пишет свои регистрационные данные. Любым монитором работы с реестром, или же просто поиском по реестру строки "iResizer", находим следующую ветку:

HKEY_CURRENT_USER\Software\Teorex\iResizer

В исполняемом файле эти строки выглядит так:


Названия веток реестра в файле

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

С удобными решениями закончили, переходим к решениям красивым. То есть попробуем отреверсить алгоритм генерации серийного номера. Вернемся к условным переходам при сохранении файла. Кроме всего прочего, там вызывается одна интересная функция, которую я отметил в листинге как "Функция проверки правильности серийного номера". Если посмотреть по перекрестным ссылкам, то она же вызывается еще из двух мест. Ситуация становится еще более понятной:
...
.text:0047D682                 lea     ecx, [ebp+arg_0]
.text:0047D685                 push    ecx
; Вызвать функцию проверки правильности серийного номера
.text:0047D686                 call    sub_47C4F0
.text:0047D68B                 add     esp, 4
.text:0047D68E                 test    al, al
.text:0047D690                 jnz     short loc_47D6A6
.text:0047D692                 lea     edx, [ebp+arg_0]
.text:0047D695                 push    edx
.text:0047D696                 call    sub_47C840
.text:0047D69B                 add     esp, 4
.text:0047D69E                 test    al, al
.text:0047D6A0                 jz      loc_47D783
.text:0047D6A6 loc_47D6A6:
; Вывести сообщение об успешной регистрации
.text:0047D6A6                 mov     ecx, [esi+0B4h]
.text:0047D6AC                 push    0
.text:0047D6AE                 call    sub_4CA4C0
.text:0047D6B3                 mov     ecx, [esi+0B8h]
.text:0047D6B9                 push    0
.text:0047D6BB                 call    sub_4CA4C0
.text:0047D6C0                 lea     edx, [ebp+arg_0]
.text:0047D6C3                 push    edx
.text:0047D6C4                 lea     ecx, [esi+14h]
.text:0047D6C7                 call    sub_87A450
.text:0047D6CC                 mov     ecx, esi
.text:0047D6CE                 call    sub_47C340
.text:0047D6D3                 push    0FFFFFFFFh
.text:0047D6D5                 push    offset aIresizer ; "iResizer"
.text:0047D6DA                 call    sub_87C5B0
.text:0047D6DF                 mov     [ebp+var_10], eax
.text:0047D6E2                 push    0
.text:0047D6E4                 lea     eax, [ebp+var_14]
.text:0047D6E7                 push    offset aThankYouForReg
; "Thank you for registration!"
.text:0047D6EC                 push    eax
...

Третье место вызова не столь очевидно, но там после проверки добавляются или не добавляются пункты в главное меню программы, связанные с вводом серийника или с ее покупкой. Это нас не особо интересует, хотя тоже можно поковыряться для большей эстетичности портативного варианта программы. А вот функция проверки правильности серийного номера нас интересует. Ее лучше пройти под отладчиком, чтобы можно было установить взаимосвязь между всеми символами и выяснить какие операции над ними проводятся. Обратите внимание, что серийный номер передается для проверки в виде строки без разделителей "-". Чтобы было понятнее, с какими символами серийного номера производится проверка, при трассировке, если срабатывает какой-либо условный переход на возврат с ошибкой, то просто меняйте флаг ZF на нужное значение.
...
.text:0047C50D                 mov     word ptr [ebp+arg_0+2], cx
.text:0047C511                 push    edi
.text:0047C512                 lea     ecx, [ebp+arg_0+2]
.text:0047C515                 call    sub_87B190
; Взять нулевой символ серийника
.text:0047C51A                 movsx   eax, al
; Умножить его на 3
.text:0047C51D                 lea     eax, [eax+eax*2]
.text:0047C520                 cdq
; Разделить на 19h
.text:0047C521                 mov     ecx, 19h
.text:0047C526                 idiv    ecx
.text:0047C528                 lea     ecx, [ebp+var_2]
; Добавить результат к символу "A"
.text:0047C52B                 lea     edi, [edx+41h]
; Взять первый символ серийника
.text:0047C52E                 call    sub_87B190
.text:0047C533                 movsx   edx, al
; Результаты равны?
.text:0047C536                 cmp     edx, edi
.text:0047C538                 jz      short loc_47C542
.text:0047C53A loc_47C53A:
; Серийный номер неправильный, на выходе AL=0
.text:0047C53A                 pop     edi
.text:0047C53B                 xor     al, al
.text:0047C53D                 pop     esi
.text:0047C53E                 mov     esp, ebp
.text:0047C540                 pop     ebp
.text:0047C541                 retn
.text:0047C542 ; ------------------------------------
.text:0047C542 loc_47C542:
; Следующие проверки. В листинге неудобочитаемые, но под отладчиком в
; пошаговом режиме все предельно понятно
.text:0047C542                 mov     eax, [esi]
.text:0047C544                 mov     ecx, [eax+0Ch]
.text:0047C547                 movzx   edx, word ptr [ecx+4]
.text:0047C54B                 mov     [ebp+var_4], dx
.text:0047C54F                 mov     ecx, [eax+0Ch]
.text:0047C552                 movzx   edx, word ptr [ecx]
.text:0047C555                 mov     [ebp+var_2], dx
.text:0047C559                 mov     eax, [eax+0Ch]
.text:0047C55C                 mov     cx, [eax+2]
.text:0047C560                 mov     word ptr [ebp+arg_0+2], cx
.text:0047C564                 lea     ecx, [ebp+arg_0+2]
.text:0047C567                 call    sub_87B190
.text:0047C56C                 lea     ecx, [ebp+var_2]
.text:0047C56F                 movsx   edi, al
.text:0047C572                 call    sub_87B190
.text:0047C577                 movsx   eax, al
.text:0047C57A                 imul    eax, edi
.text:0047C57D                 cdq
.text:0047C57E                 mov     ecx, 19h
.text:0047C583                 idiv    ecx
.text:0047C585                 lea     ecx, [ebp+var_4]
.text:0047C588                 lea     edi, [edx+41h]
.text:0047C58B                 call    sub_87B190
.text:0047C590                 movsx   edx, al
.text:0047C593                 cmp     edx, edi
; Символы не совпадают, серийный номер неправильный
.text:0047C595                 jnz     short loc_47C53A
.text:0047C597                 mov     eax, [esi]
.text:0047C599                 mov     ecx, [eax+0Ch]
.text:0047C59C                 mov     dx, [ecx+6]
.text:0047C5A0                 mov     [ebp+var_4], dx
.text:0047C5A4                 mov     eax, [eax+0Ch]
.text:0047C5A7                 mov     cx, [eax+4]
.text:0047C5AB                 mov     word ptr [ebp+arg_0+2], cx
.text:0047C5AF                 lea     ecx, [ebp+arg_0+2]
.text:0047C5B2                 call    sub_87B190
.text:0047C5B7                 movsx   eax, al
.text:0047C5BA                 lea     eax, [eax+eax*4]
.text:0047C5BD                 cdq
.text:0047C5BE                 mov     ecx, 19h
.text:0047C5C3                 idiv    ecx
.text:0047C5C5                 lea     ecx, [ebp+var_4]
.text:0047C5C8                 lea     edi, [edx+41h]
.text:0047C5CB                 call    sub_87B190
.text:0047C5D0                 movsx   edx, al
.text:0047C5D3                 cmp     edx, edi
; Символы не совпадают, серийный номер неправильный
.text:0047C5D5                 jnz     loc_47C53A
.text:0047C5DB                 mov     eax, [esi]
.text:0047C5DD                 mov     ecx, [eax+0Ch]
.text:0047C5E0                 movzx   edx, word ptr [ecx+0Ah]
.text:0047C5E4                 mov     [ebp+var_2], dx
.text:0047C5E8                 mov     ecx, [eax+0Ch]
.text:0047C5EB                 movzx   edx, word ptr [ecx+4]
.text:0047C5EF                 mov     [ebp+var_4], dx
.text:0047C5F3                 mov     eax, [eax+0Ch]
.text:0047C5F6                 mov     cx, [eax+6]
.text:0047C5FA                 mov     word ptr [ebp+arg_0+2], cx
.text:0047C5FE                 lea     ecx, [ebp+arg_0+2]
.text:0047C601                 call    sub_87B190
.text:0047C606                 lea     ecx, [ebp+var_4]
.text:0047C609                 movsx   edi, al
.text:0047C60C                 call    sub_87B190
.text:0047C611                 movsx   eax, al
.text:0047C614                 imul    eax, edi
.text:0047C617                 lea     eax, [eax+eax*2]
.text:0047C61A                 cdq
.text:0047C61B                 mov     ecx, 19h
.text:0047C620                 idiv    ecx
.text:0047C622                 lea     ecx, [ebp+var_2]
.text:0047C625                 lea     edi, [edx+41h]
.text:0047C628                 call    sub_87B190
.text:0047C62D                 movsx   edx, al
.text:0047C630                 cmp     edx, edi
; Символы не совпадают, серийный номер неправильный
.text:0047C632                 jnz     loc_47C53A
.text:0047C638                 mov     eax, [esi]
.text:0047C63A                 mov     ecx, [eax+0Ch]
.text:0047C63D                 movzx   edx, word ptr [ecx+0Ch]
.text:0047C641                 mov     [ebp+var_2], dx
.text:0047C645                 mov     ecx, [eax+0Ch]
.text:0047C648                 movzx   edx, word ptr [ecx+8]
.text:0047C64C                 mov     [ebp+var_4], dx
.text:0047C650                 mov     eax, [eax+0Ch]
.text:0047C653                 mov     cx, [eax+0Ah]
.text:0047C657                 mov     word ptr [ebp+arg_0+2], cx
.text:0047C65B                 lea     ecx, [ebp+arg_0+2]
.text:0047C65E                 call    sub_87B190
.text:0047C663                 lea     ecx, [ebp+var_4]
.text:0047C666                 movsx   edi, al
.text:0047C669                 call    sub_87B190
.text:0047C66E                 movsx   eax, al
.text:0047C671                 imul    eax, edi
.text:0047C674                 add     eax, 0Eh
.text:0047C677                 cdq
.text:0047C678                 mov     ecx, 19h
.text:0047C67D                 idiv    ecx
.text:0047C67F                 lea     ecx, [ebp+var_2]
.text:0047C682                 lea     edi, [edx+41h]
.text:0047C685                 call    sub_87B190
.text:0047C68A                 movsx   edx, al
.text:0047C68D                 cmp     edx, edi
; Символы не совпадают, серийный номер неправильный
.text:0047C68F                 jnz     loc_47C53A
.text:0047C695                 mov     eax, [esi]
.text:0047C697                 mov     ecx, [eax+0Ch]
.text:0047C69A                 movzx   edx, word ptr [ecx+0Eh]
.text:0047C69E                 mov     [ebp+var_6], dx
.text:0047C6A2                 mov     ecx, [eax+0Ch]
.text:0047C6A5                 movzx   edx, word ptr [ecx+0Ah]
.text:0047C6A9                 mov     [ebp+var_2], dx
.text:0047C6AD                 mov     ecx, [eax+0Ch]
.text:0047C6B0                 movzx   edx, word ptr [ecx+0Ch]
.text:0047C6B4                 mov     [ebp+var_4], dx
.text:0047C6B8                 mov     eax, [eax+0Ch]
.text:0047C6BB                 mov     cx, [eax+0Ch]
.text:0047C6BF                 mov     word ptr [ebp+arg_0+2], cx
.text:0047C6C3                 lea     ecx, [ebp+arg_0+2]
.text:0047C6C6                 call    sub_87B190
.text:0047C6CB                 lea     ecx, [ebp+var_4]
.text:0047C6CE                 movsx   edi, al
.text:0047C6D1                 call    sub_87B190
.text:0047C6D6                 movsx   edx, al
.text:0047C6D9                 lea     ecx, [ebp+var_2]
.text:0047C6DC                 add     edi, edx
.text:0047C6DE                 call    sub_87B190
.text:0047C6E3                 movsx   eax, al
.text:0047C6E6                 add     eax, edi
.text:0047C6E8                 cdq
.text:0047C6E9                 mov     ecx, 19h
.text:0047C6EE                 idiv    ecx
.text:0047C6F0                 lea     ecx, [ebp+var_6]
.text:0047C6F3                 lea     edi, [edx+41h]
.text:0047C6F6                 call    sub_87B190
.text:0047C6FB                 movsx   edx, al
.text:0047C6FE                 cmp     edx, edi
; Символы не совпадают, серийный номер неправильный
.text:0047C700                 jnz     loc_47C53A
.text:0047C706                 mov     eax, [esi]
.text:0047C708                 mov     ecx, [eax+0Ch]
.text:0047C70B                 mov     dx, [ecx+12h]
.text:0047C70F                 mov     [ebp+var_6], dx
.text:0047C713                 mov     eax, [eax+0Ch]
.text:0047C716                 mov     cx, [eax+10h]
.text:0047C71A                 mov     word ptr [ebp+arg_0+2], cx
.text:0047C71E                 lea     ecx, [ebp+arg_0+2]
.text:0047C721                 call    sub_87B190
.text:0047C726                 movsx   eax, al
.text:0047C729                 lea     eax, [eax+eax*4]
.text:0047C72C                 add     eax, eax
.text:0047C72E                 cdq
.text:0047C72F                 mov     ecx, 19h
.text:0047C734                 idiv    ecx
.text:0047C736                 lea     ecx, [ebp+var_6]
.text:0047C739                 lea     edi, [edx+41h]
.text:0047C73C                 call    sub_87B190
.text:0047C741                 movsx   edx, al
.text:0047C744                 cmp     edx, edi
; Символы не совпадают, серийный номер неправильный
.text:0047C746                 jnz     loc_47C53A
.text:0047C74C                 mov     eax, [esi]
.text:0047C74E                 mov     ecx, [eax+0Ch]
.text:0047C751                 movzx   edx, word ptr [ecx+14h]
.text:0047C755                 mov     [ebp+var_2], dx
.text:0047C759                 mov     ecx, [eax+0Ch]
.text:0047C75C                 movzx   edx, word ptr [ecx+0Ch]
.text:0047C760                 mov     [ebp+var_6], dx
.text:0047C764                 mov     ecx, [eax+0Ch]
.text:0047C767                 movzx   edx, word ptr [ecx+0Eh]
.text:0047C76B                 mov     word ptr [ebp+arg_0+2], dx
.text:0047C76F                 mov     eax, [eax+0Ch]
.text:0047C772                 mov     cx, [eax+0Ah]
.text:0047C776                 mov     [ebp+var_4], cx
.text:0047C77A                 push    ebx
.text:0047C77B                 lea     ecx, [ebp+arg_0+2]
.text:0047C77E                 call    sub_87B190
.text:0047C783                 lea     ecx, [ebp+var_6]
.text:0047C786                 movsx   ebx, al
.text:0047C789                 call    sub_87B190
.text:0047C78E                 movsx   edi, al
.text:0047C791                 lea     ecx, [ebp+var_4]
.text:0047C794                 imul    edi, ebx
.text:0047C797                 call    sub_87B190
.text:0047C79C                 movsx   edx, al
.text:0047C79F                 lea     eax, [edx+edi+29h]
.text:0047C7A3                 cdq
.text:0047C7A4                 mov     ecx, 19h
.text:0047C7A9                 idiv    ecx
.text:0047C7AB                 lea     ecx, [ebp+var_2]
.text:0047C7AE                 lea     edi, [edx+41h]
.text:0047C7B1                 call    sub_87B190
.text:0047C7B6                 movsx   edx, al
.text:0047C7B9                 pop     ebx
.text:0047C7BA                 cmp     edx, edi
; Символы не совпадают, серийный номер неправильный
.text:0047C7BC                 jnz     loc_47C53A
.text:0047C7C2                 mov     esi, [esi]
.text:0047C7C4                 mov     eax, [esi+0Ch]
.text:0047C7C7                 movzx   ecx, word ptr [eax+16h]
.text:0047C7CB                 mov     [ebp+var_2], cx
.text:0047C7CF                 mov     edx, [esi+0Ch]
.text:0047C7D2                 mov     ax, [edx+10h]
.text:0047C7D6                 mov     [ebp+var_4], ax
.text:0047C7DA                 mov     ecx, [esi+0Ch]
.text:0047C7DD                 mov     dx, [ecx+12h]
.text:0047C7E1                 mov     [ebp+var_6], dx
.text:0047C7E5                 mov     eax, [esi+0Ch]
.text:0047C7E8                 movzx   ecx, word ptr [eax+14h]
.text:0047C7EC                 mov     word ptr [ebp+arg_0+2], cx
.text:0047C7F0                 lea     ecx, [ebp+arg_0+2]
.text:0047C7F3                 call    sub_87B190
.text:0047C7F8                 lea     ecx, [ebp+var_6]
.text:0047C7FB                 movsx   edi, al
.text:0047C7FE                 call    sub_87B190
.text:0047C803                 movsx   esi, al
.text:0047C806                 lea     ecx, [ebp+var_4]
.text:0047C809                 imul    esi, edi
.text:0047C80C                 call    sub_87B190
.text:0047C811                 movsx   eax, al
.text:0047C814                 imul    eax, esi
.text:0047C817                 inc     eax
.text:0047C818                 cdq
.text:0047C819                 mov     ecx, 19h
.text:0047C81E                 idiv    ecx
.text:0047C820                 lea     ecx, [ebp+var_2]
.text:0047C823                 lea     esi, [edx+41h]
.text:0047C826                 call    sub_87B190
.text:0047C82B                 movsx   edx, al
.text:0047C82E                 cmp     edx, esi
; Символы совпадают? Результат в AL
.text:0047C830                 pop     edi
.text:0047C831                 setz    al
...

Переведем машинный код на человеческий язык. Если условно обозначить символы серийного номера их позицией, то получится такой псевдокод. Операция "%" означает результат от деления (регистр EDX после выполнения команды IDIV).

[0] = любой разрешенный символ
[1] = ([0] * 3) % 19h + 'A'
[2] = ([1] * [0]) % 19h + 'A'
[3] = ([2] * 5) % 19h + 'A'

[4] = любой разрешенный символ
[5] = ([3] * [2] * 3) % 19h + 'A'
[6] = ([5] * [4] + 0Eh) % 19h + 'A'
[7] = ([6] + [6] + [5]) % 19h + 'A'

[8] = любой разрешенный символ
[9] = ([8] * 0Ah) % 19h + 'A'
[10] = ([6] * [7] + [5] + 29h) % 19h + 'A'
[11] = ([10] * [9] * [8] + 1) % 19h + 'A'


Как видите, значимые только первые три группы символов серийного номера, остальные символы не используются и могут быть любыми из числа допустимых. Перевести псевдокод на любой язык программирования не составит никакого труда. Зная алгоритм, генерируем правильный серийный номер и регистрируем программу. Все работает, цель достигнута.


Программа успешно зарегистрирована

iResizer, как и другие продукты автора, - на самом деле очень полезные программы, к тому же сделаны качественно. И, хоть это не в моих правилах, я все-таки рекомендую по возможности поддержать разработчика. А автору бы я порекомендовал задуматься о портабелизации своих программ штатными средствами, без необходимости их потрошения.
Теги:
защита, взлом
Добавлено: 17 Сентября 2013 03:36:23 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...