Исследование защиты программы Pixillion Image Converter
Скриншот программы Pixillion Image Converter
Pixillion Image Converter - универсальный конвертер графических файлов в различные форматы. Поддерживается несколько десятков форматов, кроме того, изображения можно ресайзить, поворачивать, накладывать водяной знак, и все это в пакетом режиме. Безусловно, есть много бесплатных программ для подобных операций, но вдруг и эта программа найдет своих поклонников. Естественно, после курса интенсивной антишароварной терапии.
Начинаем с загрузки дистрибутива. Устанавливаем, смотрим. Исполняемый файл ничем не защищен и не упакован, отправляем его на переработку в дизассемблер. Запускаем программу и смотрим, как и что тут можно зарегистрировать.
Окно регистрации программы
Хех, в самом окне регистрации нам дается подсказка, каким должен быть серийный номер. Отлично, хоть с такой мелочью возиться не придется. Очевидно, что серийник-подсказка ни к чему хорошему не приведет, поэтому попробуем слепить по шаблону какой-нибудь свой, например, "111111-abcdefgh". Пробуем зарегистрировать.
Сообщение о неправильной регистрации
Теперь попробуем найти строку сообщения и условия, при которых она появляется.
Code (Assembler) : Убрать нумерацию
- .text:0046BAB1 lea eax, [esi-1]
- ; Сравнить какую-то переменную с фиксированным значением 267D40h
- .text:0046BAB4 cmp eax, 267D40h
- ; Если больше, то перепрыгнуть дальше
- .text:0046BAB9 ja loc_46BBBA
- .text:0046BABF cmp esi, 2818F0h
- .text:0046BAC5 jge loc_46BBBA
- .text:0046BACB push offset a4_06_0 ; "4.06"
- .text:0046BAD0 call j__atol
- .text:0046BAD5 dec eax
- .text:0046BAD6 pop ecx
- .text:0046BAD7 jns short loc_46BADB
- .text:0046BAD9 xor eax, eax
- .text:0046BADB loc_46BADB:
- .text:0046BADB push eax
- .text:0046BADC mov esi, edi
- .text:0046BADE push offset aTheCodeYouAreA
- ; "The code you are attempting to use is n"...
- .text:0046BAE3 lea edi, [esp+0CD0h+File]
- .text:0046BAEA call sub_46A2E9
- .text:0046BAEF mov eax, [esp+0CD0h+var_CB0]
Сообщение о неправильной регистрации
На этот раз поведение программы изменилось, выводится сообщение о неправильном серийном номере в виде подсказки у поля ввода. Значит первая половина серийника принята и проверка обламывается на второй половине. Смотрим в листинге дизассемблера, куда бы был выполнен переход в случае первой успешной проверки.
Code (Assembler) : Убрать нумерацию
- ; Сюда мы попадаем после успешной первой поверки
- .text:0046BBBA lea eax, [esp+0CC8h+var_CB8]
- .text:0046BBBE push eax
- .text:0046BBBF push esi
- .text:0046BBC0 lea edi, [esp+0CD0h+Data]
- .text:0046BBC7 mov [esp+0CD0h+var_CB8], ebx
- ; вызвать функцию следующей проверки
- .text:0046BBCB call sub_46CFD3
- .text:0046BBD0 cmp [esp+0CC8h+var_CB8], ebx
- .text:0046BBD4 mov edi, [esp+0CC8h+var_CB0]
- ; Сохранить ее результат из регистра AL в ячейку памяти
- .text:0046BBD8 mov [esp+0CC8h+var_CB1], al
- .text:0046BBDC jnz short loc_46BBED
- .text:0046BBDE push esi
- .text:0046BBDF push edi
- .text:0046BBDE push esi
- .text:0046BBDF push edi
- ; Онлайн-проверка, но если программу не выпускать в интернет, то все нормально
- .text:0046BBE0 call sub_46BF70
- .text:0046BBE5 test al, al
- .text:0046BBE7 jz loc_46BCA5
- .text:0046BBED loc_46BBED:
- ; Сравнить сохраненное значение регистра с нулем
- .text:0046BBED cmp [esp+0CC8h+var_CB1], bl
- ; Если ноль, то серийниый номер неправильный
- .text:0046BBF1 jz loc_46BC7E
- ; Сохранить введенный серийник и поблагодарить за регистрацию
- .text:0046BBF7 push esi ; Args
- .text:0046BBF8 push offset aId ; "ID"
- .text:0046BBFD mov esi, offset aRegistration
- ; "Registration"
- .text:0046BC02 push esi ; int
- .text:0046BC03 mov dword_538CAC, ebx
- .text:0046BC09 call sub_401E41
- .text:0046BC0E lea eax, [esp+0CC8h+Data]
- .text:0046BC15 push eax ; lpData
- .text:0046BC16 push offset aKey ; "Key"
Code (Assembler) : Убрать нумерацию
- .text:0046CFD3 push ebp
- .text:0046CFD4 mov ebp, esp
- .text:0046CFD6 mov eax, [ebp+arg_0]
- .text:0046CFD9 sub esp, 208h
- .text:0046CFDF push ebx
- .text:0046CFE0 push esi
- .text:0046CFE1 push 64h
- .text:0046CFE3 pop ecx
- .text:0046CFE4 xor edx, edx
- .text:0046CFE6 div ecx
- .text:0046CFE8 mov ebx, [ebp+arg_4]
- .text:0046CFEB lea esi, [ebp+var_208]
- .text:0046CFF1 push eax
- ; Из первой половины серийника вычислить контрольную строку
- .text:0046CFF2 call sub_46CE57
- ; Первый символ строки и первый символ второй половины серийника
- .text:0046CFF7 mov ax, [ebp+var_208]
- .text:0046CFFE cmp ax, [edi]
- .text:0046D001 jnz short loc_46D063
- ; Второй символ строки и второй символ второй половины серийника
- .text:0046D003 mov ax, [ebp+var_206]
- .text:0046D00A cmp ax, [edi+2]
- .text:0046D00E jnz short loc_46D063
- ; Третий символ строки и третий символ второй половины серийника
- .text:0046D010 mov ax, [ebp+var_204]
- .text:0046D017 cmp ax, [edi+4]
- .text:0046D01B jnz short loc_46D063
- ; Четвертый символ строки и четвертый символ второй половины серийника
- .text:0046D01D mov ax, [ebp+var_202]
- .text:0046D024 cmp ax, [edi+6]
- .text:0046D028 jnz short loc_46D063
- ; Пятый символ второй половины серийника должен быть "c"
- .text:0046D02A cmp word ptr [edi+8], 63h
- .text:0046D02F jnz short loc_46D063
- ; Шестой символ второй половины серийника должен быть "l"
- .text:0046D031 cmp word ptr [edi+0Ah], 6Ch
- .text:0046D036 jnz short loc_46D063
- .text:0046D038 mov eax, edi
- .text:0046D03A mov dword ptr [ebx], 1
- .text:0046D040 lea edx, [eax+2]
- ; Проверить количество символов во второй половине серийника
- .text:0046D043 loc_46D043:
- .text:0046D043 mov cx, [eax]
- .text:0046D046 inc eax
- .text:0046D047 inc eax
- .text:0046D048 test cx, cx
- .text:0046D04B jnz short loc_46D043
- .text:0046D04D sub eax, edx
- .text:0046D04F sar eax, 1
- ; Количество символов должно быть равно 8
- .text:0046D051 cmp eax, 8
- .text:0046D054 jnz short loc_46D0C1
- ; Сравнить первую половину серийника со значением 100000000
- .text:0046D056 cmp [ebp+arg_0], 5F5E100h
- .text:0046D05D jbe short loc_46D063
- .text:0046D05F loc_46D05F:
- ; Если больше 100000000 и проверки второй половины пройдены, то серийник
- ; считается правильным, установить AL=1 и выйти из функции проверки
- .text:0046D05F mov al, 1
- .text:0046D061 jmp short loc_46D0C9
Программа успешно зарегистрирована
Программа успешно зарегистрирована
В принципе, на этом можно было и остановиться, валидный серийный номер есть, программа работает без ограничений. Но в качестве приятного бонуса разберем алгоритм генерации контрольной строки. Начнем с того, что выясним, какое именно значение передается для генерации.
Code (Assembler) : Убрать нумерацию
- ; Первая часть серийника
- .text:0046CFD6 mov eax, [ebp+arg_0]
- .text:0046CFD9 sub esp, 208h
- .text:0046CFDF push ebx
- .text:0046CFE0 push esi
- ; Делитель = 100
- .text:0046CFE1 push 64h
- .text:0046CFE3 pop ecx
- .text:0046CFE4 xor edx, edx
- .text:0046CFE8 mov ebx, [ebp+arg_4]
- .text:0046CFEB lea esi, [ebp+var_208]
- .text:0046CFF1 push eax
- .text:0046CFF2 call sub_46CE57
- ; Разделить первую часть серийника
- .text:0046CFE6 div ecx
- .text:0046CFE8 mov ebx, [ebp+arg_4]
- .text:0046CFEB lea esi, [ebp+var_208]
- ; Передать результат деления в генератор
- .text:0046CFF1 push eax
- .text:0046CFF2 call sub_46CE57
Code (Assembler) : Убрать нумерацию
- ; Инициализация строки начальным значением "abcdef"
- .text:0046CE60 mov eax, offset aAbcdef ; "abcdef"
- .text:0046CE65 call sub_401039
- ...
- ...
- ; Заполнить первый массив указателями на шестисимвольные строки
- .text:0046CE74 mov [ebp+var_44], offset aMnbvaq ; "mnbvaq"
- .text:0046CE7B mov [ebp+var_40], offset aCxzlbr ; "cxzlbr"
- .text:0046CE82 mov [ebp+var_3C], offset aKjhgct ; "kjhgct"
- .text:0046CE89 mov [ebp+var_38], offset aFdsady ; "fdsady"
- .text:0046CE90 mov [ebp+var_34], offset aPoiueu ; "poiueu"
- .text:0046CE97 mov [ebp+var_30], offset aYtrefo ; "ytrefo"
- .text:0046CE9E mov [ebp+var_2C], offset aWqalgx ; "wqalgx"
- .text:0046CEA5 mov [ebp+var_28], offset aKsjdhv ; "ksjdhv"
- .text:0046CEAC mov [ebp+var_24], offset aHfgbif ; "hfgbif"
- ; Заполнить второй массив указателями на шестисимвольные строки
- .text:0046CEB3 mov ebx, offset aQazwja ; "qazwja"
- .text:0046CEB8 mov edi, offset aTgbymh ; "tgbymh"
- .text:0046CEBD mov ecx, esi
- .text:0046CEBF mov [ebp+var_20], ebx
- .text:0046CEC2 mov [ebp+var_1C], offset aSxedkf ; "sxedkf"
- .text:0046CEC9 mov [ebp+var_18], offset aCrfvlg ; "crfvlg"
- .text:0046CED0 mov [ebp+var_14], edi
- .text:0046CED3 mov [ebp+var_10], offset aHnujni ; "hnujni"
- .text:0046CEDA mov [ebp+var_C], offset aMiklop ; "miklop"
- .text:0046CEE1 mov [ebp+var_8], offset aPlokpc ; "plokpc"
Code (Assembler) : Убрать нумерацию
- ; Поделить контрольное число на 9
- .text:0046CE6A mov eax, [ebp+arg_0]
- .text:0046CE6D push 9
- .text:0046CE6F pop ecx
- .text:0046CE70 xor edx, edx
- .text:0046CE72 div ecx
- ...
- ...
- ; Сохранить результат деления. В регистре EDX остаток от деления
- .text:0046CEE8 mov [ebp+var_4], eax
- ; Указатель на элемент первого массива строк
- .text:0046CEEB mov eax, [ebp+edx*4+var_44]
- ; Функция преобразования
- .text:0046CEEF call sub_46CDB1
; cstr - контрольная строка
; mstr - строка из массива, выбранная по номеру (указателю)
cstr[0] = (cstr[0] + mstr[0] - 194) % 26 + 97
cstr[1] = (cstr[1] + mstr[1] - 194) % 26 + 97
cstr[2] = (cstr[2] + mstr[2] - 194) % 26 + 97
cstr[3] = (cstr[3] + mstr[3] - 194) % 26 + 97
cstr[4] = (cstr[4] + mstr[4] - 194) % 26 + 97
cstr[5] = (cstr[5] + mstr[5] - 194) % 26 + 97
Едем дальше. На втором шаге контрольная строка преобразуется с элементом из второго массива строк.
Code (Assembler) : Убрать нумерацию
- ; Результат предыдущего деления контрольного числа
- .text:0046CEF4 mov eax, [ebp+var_4]
- ; Делитель
- .text:0046CEF7 push 7
- .text:0046CEF9 pop ecx
- .text:0046CEFA xor edx, edx
- .text:0046CEFC div ecx
- .text:0046CEFE mov ecx, esi
- ; Указатель на строку второго массива
- .text:0046CF00 mov eax, [ebp+edx*4+var_20]
- .text:0046CF04 call sub_46CDB1
Code (Assembler) : Убрать нумерацию
- ; Контрольное число делится на 63
- .text:0046CF09 mov eax, [ebp+arg_0]
- .text:0046CF0C push 3Fh
- .text:0046CF0E xor edx, edx
- .text:0046CF10 pop ecx
- .text:0046CF11 div ecx
- ; Результат деления делится еще на 9
- .text:0046CF13 push 9
- .text:0046CF15 pop ecx
- .text:0046CF16 xor edx, edx
- ; Результат этого деления - новое контрольное число
- .text:0046CF18 mov [ebp+arg_0], eax
- ; Делим новое контрольное число на 9
- .text:0046CF1B div ecx
- .text:0046CF1D mov ecx, esi
- ; Сохранить результат деления
- .text:0046CF1F mov [ebp+var_4], eax
- ; Указатель на строку из первого массива
- .text:0046CF22 mov eax, [ebp+edx*4+var_44]
- ; Функция преобразования
- .text:0046CF26 call sub_46CDB1
Code (Assembler) : Убрать нумерацию
- ; Сохраненный результат деления
- .text:0046CF2B mov eax, [ebp+var_4]
- .text:0046CF2E push 7
- .text:0046CF30 pop ecx
- .text:0046CF31 xor edx, edx
- ; Поделить на 7
- .text:0046CF33 div ecx
- .text:0046CF35 mov ecx, esi
- ; Остаток - номер элемента второго массива
- .text:0046CF37 mov eax, [ebp+edx*4+var_20]
- ; Функция преобразования
- .text:0046CF3B call sub_46CDB1
Code (Assembler) : Убрать нумерацию
- ; Контрольное число
- .text:0046CF40 mov eax, [ebp+arg_0]
- .text:0046CF43 push 3Fh
- .text:0046CF45 xor edx, edx
- .text:0046CF47 pop ecx
- .text:0046CF48 div ecx
- .text:0046CF4A push 9
- .text:0046CF4C pop ecx
- .text:0046CF4D xor edx, edx
- .text:0046CF4F mov [ebp+arg_0], eax
- .text:0046CF52 div ecx
- .text:0046CF54 mov ecx, esi
- .text:0046CF56 mov [ebp+var_4], eax
- .text:0046CF59 mov eax, [ebp+edx*4+var_44]
- .text:0046CF5D call sub_46CDB1
Code (Assembler) : Убрать нумерацию
- .text:0046CF62 mov eax, [ebp+var_4]
- .text:0046CF65 push 7
- .text:0046CF67 xor edx, edx
- .text:0046CF69 pop ecx
- .text:0046CF6A div ecx
- .text:0046CF6C mov eax, [ebp+edx*4+var_20]
- .text:0046CF70 mov ecx, esi
- .text:0046CF72 call sub_46CDB1
Code (Assembler) : Убрать нумерацию
- .text:0046CF77 mov eax, [ebp+arg_0]
- .text:0046CF7A push 3Fh
- .text:0046CF7C xor edx, edx
- .text:0046CF7E pop ecx
- .text:0046CF7F div ecx
- .text:0046CF81 push 9
- .text:0046CF83 pop ecx
- .text:0046CF84 xor edx, edx
- .text:0046CF86 div ecx
- .text:0046CF88 mov ecx, esi
- .text:0046CF8A mov [ebp+arg_0], eax
- .text:0046CF8D mov eax, [ebp+edx*4+var_44]
- .text:0046CF91 call sub_46CDB1
- .text:0046CF96 mov eax, [ebp+arg_0]
- .text:0046CF99 push 7
- .text:0046CF9B pop ecx
- .text:0046CF9C xor edx, edx
- .text:0046CF9E div ecx
- .text:0046CFA0 mov ecx, esi
- .text:0046CFA2 mov eax, [ebp+edx*4+var_20]
- .text:0046CFA6 call sub_46CDB1
Code (Assembler) : Убрать нумерацию
- ; Если забыли, то регистры указывают на эти строки
- .text:0046CEB3 mov ebx, offset aQazwja ; "qazwja"
- .text:0046CEB8 mov edi, offset aTgbymh ; "tgbymh"
- ...
- ...
- ...
- .text:0046CFAB mov eax, offset aKjhgct ; "kjhgct"
- .text:0046CFB0 call sub_46CDB1
- ; Смотри выше
- .text:0046CFB5 mov eax, edi
- .text:0046CFB7 call sub_46CDB1
- .text:0046CFBC mov eax, offset aMnbvaq ; "mnbvaq"
- .text:0046CFC1 call sub_46CDB1
- ; Смотри выше
- .text:0046CFC6 mov eax, ebx
- .text:0046CFC8 call sub_46CDB1
Вот и все, теперь можно писать генератор ключей аж на корпоративную лицензию. Остальные продукты разработчика кейгенятся аналогичным образом, защита там похожая.
Просмотров: 3056 | Комментариев: 2
Метки: исследование защиты, мультимедиа
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(19.09.2017 в 06:34):
Конечно можно, и не одним способом.
xussr
(19.09.2017 в 06:22):
Можно и пропачить
CPU Disasm
Address Hex dump Command Comments
00CCC458 |. 5B POP EBX
00CCC459 |. C9 LEAVE
00CCC45A |. C3 RETN
00CCC45B |> 8D4D FC LEA ECX,[LOCAL.1]
00CCC45E |. 51 PUSH ECX ; /Arg2 => OFFSET LOCAL.1
00CCC45F |. 50 PUSH EAX ; |Arg1
00CCC460 |. 8DBD F0FDFFFF LEA EDI,[LOCAL.132] ; |
00CCC466 |. 8975 FC MOV DWORD PTR SS:[LOCAL.1],ESI ; |
00CCC469 |. E8 650B0000 CALL 00CCCFD3 ; \pixillion.00CCCFD3
00CCC46E |. 84C0 TEST AL,AL
00CCC470 |.^ 74 D2 JZ SHORT 00CCC444
00CCC472 |. 2135 AC8CD900 AND DWORD PTR DS:[0D98CAC],ESI
00CCC478 |. B0 01 MOV AL,1
00CCC47A \.^ EB DA JMP SHORT 00CCC456
00CCC47C /$ 53 PUSH EBX
00CCC47D |. 56 PUSH ESI
CPU Disasm
Address Hex dump Command Comments
00CCC458 |. 5B POP EBX
00CCC459 |. C9 LEAVE
00CCC45A |. C3 RETN
00CCC45B |> 8D4D FC LEA ECX,[LOCAL.1]
00CCC45E |. 51 PUSH ECX ; /Arg2 => OFFSET LOCAL.1
00CCC45F |. 50 PUSH EAX ; |Arg1
00CCC460 |. 8DBD F0FDFFFF LEA EDI,[LOCAL.132] ; |
00CCC466 |. 8975 FC MOV DWORD PTR SS:[LOCAL.1],ESI ; |
00CCC469 |. E8 650B0000 CALL 00CCCFD3 ; \pixillion.00CCCFD3
00CCC46E |. 84C0 TEST AL,AL
00CCC470 |.^ 74 D2 JZ SHORT 00CCC444
00CCC472 |. 2135 AC8CD900 AND DWORD PTR DS:[0D98CAC],ESI
00CCC478 |. B0 01 MOV AL,1
00CCC47A \.^ EB DA JMP SHORT 00CCC456
00CCC47C /$ 53 PUSH EBX
00CCC47D |. 56 PUSH ESI
Добавить комментарий
Заполните форму для добавления комментария