|
Генератор ключей для Effects Processor Pro 2.2
Effects Processor Pro 2.2 -
довольно качественный процессор звуковых эффектов,
работающий в режиме реального времени. Отличный
инструмент для реализации Вашего творческого потенциала.
Одно из преимуществ этой программы заключается в том,
что настройка любого эффекта осуществляется с помощью
шести ручек управления, что не даст вам запутаться. А их
программа реализует не так уж мало: флэнджер, хорус,
тремоло, фэйзер, задержка. Все они могут функционировать
одновременно. Effects Processor Pro работает с любым
входным сигналом, будь то сигнал аudio CD или сигнал синтезатора.
Предусмотрены также операции с .wav-файлами - обработка их
различными эффектами. Скачать
программу можно здесь
(400 КБ).
Программа эта не
бесплатная, и чтобы воспользоваться
всеми ее возможностями, придется
приобрести лицензию. Защита
представляет собой обычную связку
имя-код. При каждом запуске
незарегистрированной копии
появляется небольшое окно с тремя
кнопками, одна из которых называется
"Registration"; при нажатии на эту
кнопку открывается форма для ввода
имени пользователя и серийного
номера. Попробуем ввести что-нирбудь
в эти поля и отследить процедуру
проверки рег. данных в отладчике (я
использовал OllyDbg).
Загрузим программу в
отладчик и запустим ее оттуда (F9).
Отправимся регистрироваться. Чтобы
прервать выполнение программы при
считывании серийного номера из поля
ввода я установил точку останова на
вызов функции LoadStringA. У Вас может
возникнуть вопрос, почему именно на
эту функцию. Просто я открыл окно "Names"
со списком импортируемых функций (Ctrl+N) и
выбрал ее как наиболее вероятную. (Для
справки: установка брейкпоинта в
OllyDbg на функцию из списка,
отображаемого в окне производится
щелчком правой кнопки на имени
функции и выбором в контекстном меню
пункта "Set Breakpoint on every reference"). Итак,
мы прервались здесь:
00406FBA CALL DWORD PTR DS:[<&USER32.LoadStringA>>; \LoadStringA
00406FC0 MOV EBX,DWORD PTR SS:[ESP+124];помещаем в EBX имя пользователя
00406FC7 MOV ESI,DWORD PTR DS:[<&KERNEL32.lstrcpy>; kernel32.lstrcpyA
00406FCD LEA EDX,DWORD PTR SS:[ESP+1C]
00406FD1 PUSH EBX ;имя кладем в стек
00406FD2 PUSH EDX
00406FD3 CALL ESI
00406FD5 LEA EAX,DWORD PTR SS:[ESP+1C]
00406FD9 LEA ECX,DWORD PTR SS:[ESP+10] ;помещаем в ECX строку J8FG3
00406FDD PUSH EAX
00406FDE PUSH ECX
00406FDF CALL epp22.0040100A ;на основе имя и J8FG3 генерируем промежуточный код (в EDX)
00406FE4 PUSH 29 ;в стек число 29h (ASCII=")")
00406FE6 PUSH 41 ;в стек число 41h (ASCII="A")
00406FE8 LEA EDX,DWORD PTR SS:[ESP+2C]
00406FEC PUSH 28 ;в стек число 28h (ASCII="(")
00406FEE PUSH EDX
00406FEF CALL epp22.004010AF ;вычисляем окончательный рег. номер (будет в ЕАХ)
00406FF4 MOV EBP,DWORD PTR SS:[ESP+140];в EBP помещается наш рег. код
00406FFB MOV EDI,EAX ;помещаем правильный номер в EDI
00406FFD PUSH EBP
00406FFE CALL epp22.004113A6
00407003 CDQ
00407004 XOR EAX,EDX
00407006 ADD ESP,1C
00407009 SUB EAX,EDX
0040700B CMP EDI,EAX ;сравниваем наш номер и правильный
0040700D JE SHORT epp22.00407026 ;если равны - все ОК, иначе получаем
0040700F ADD EDI,1B0 ;другой рег. номер прибавлением числа 1B0
00407015 CMP EDI,EAX ;и снова сравниваем с нашим номером
00407017 JE SHORT epp22.00407026 ;если совпали - все ОК
00407019 POP EDI
0040701A POP ESI
0040701B POP EBP
0040701C XOR EAX,EAX
0040701E POP EBX
0040701F ADD ESP,110
00407025 RETN
Из приведенного листинга должен
быть понятен основной смысл процедуры
проверки регистрационных данных: на основе
UserName и постоянной строки J8FG3
генерируется промежуточный код (это делает
процедура, вызываемая по адресу 00406FDF), который затем обрабатывается по какому-то
алгоритму процедурой, вызываемой по адресу 00406FEF
. Полученный рег. номер сравнивается с тем,
что мы ввели в форме для регистрации, и, если
коды не совпадают, генерируется еще один
правильный рег. код путем прибавления к
первому числа 1B0 (в
десятичной системе 432).
Давайте изучим в отладчике
процедуру генерации промежуточного кода (при
трассировке зайдем в нее - клавиша F7):
00407080 PUSH EBX
00407081 PUSH EBP
00407082 MOV EBP,DWORD PTR DS:[<&KERNEL32.lstrlen>; kernel32.lstrlenA
00407088 PUSH ESI
00407089 PUSH EDI
0040708A MOV EDI,DWORD PTR SS:[ESP+18] ;в EDI помещает UserName
0040708E PUSH EDI ;сохраняем UserName в стек
0040708F XOR ESI,ESI ;обнуляем ESI (ESI будет счетчиком символов из строки J8FG3)
00407091 CALL EBP ;в ЕАХ помещаем число символов в UserName
00407093 MOV EBX,EAX ;в EBX переносим значение ЕАХ
00407095 MOV EAX,DWORD PTR SS:[ESP+14] ;а в ЕАХ помещаем строку J8FG3
00407099 PUSH EAX ;и сохраняем ее в стек
0040709A CALL EBP ;подсчитываем число символов в строке "J8FG3" (результат в EAX)
0040709C XOR ECX,ECX ;ЕСХ будет определять номер символа из UserName
0040709E TEST EBX,EBX ;в UserName должно быть число символов, больше нуля
004070A0 JLE SHORT epp22.004070B9 ;иначе выходим
004070A2 MOV EDX,DWORD PTR SS:[ESP+14] ;в EDX помещаем строку J8FG3
004070A6 INC ESI ;увеличиваем ESI на 1
004070A7 CMP ESI,EAX ;если ESI=5, то по адресу 004070AF производится обнуление
004070A9 MOV DL,BYTE PTR DS:[ESI+EDX-1];берем код символа из строки J8FG3 (номер символа берем из ESI)
004070AD JNZ SHORT epp22.004070B1 ;если ESI <>5, следующую инструкцию перепрыгиваем
004070AF XOR ESI,ESI
004070B1 XOR BYTE PTR DS:[ECX+EDI],DL ;логическое исключение из кода символа UserName кода символа строки
004070B4 INC ECX ;увеличиваем ЕСХ
004070B5 CMP ECX,EBX ;если в ЕСХ число, равное числу букв в имени юзера
004070B7 JL SHORT epp22.004070A2 ;то уходим, иначе повторяем цикл
004070B9 POP EDI
004070BA POP ESI
004070BB POP EBP
004070BC POP EBX
004070BD RETN
Как видно из листинга,
промежуточный код получается логическим
исключением кодов символов из UserName и из
заданной автором строки (инструкция XOR
BYTE PTR DS:[ECX+EDI],DL по адресу 004070B1). Поясню на
примере.
Допустим, вы ввели в поле для регистрации
имя CrackeRF. Тогда генерация промежуточного
кода будет производиться так:
(C) 43 xor 4A (J) = 9 (r)
72 xor 38 (8) = 4A (a) 61 xor 46 (F) = 27 (c) 63 xor 47 (G) =
24 (k) 6B xor 33 (3) = 58 (e) 65 xor 4A (J) = 2F (R) 52 xor 38 (8) = 6A (F)
46 xor 46 (F) = 0
Т.е.
в итоге мы получим промежуточный код из
символов, hex-коды которых по таблице ascii
представлены в крайнем правом столбце (читать
по вертикали ;).
Теперь выясним,
как на основе промежуточного кода
формируется окончательный правильный
регистрационный номер. Для этого изучим в
отладчике процедуру, вызываемую по адресу 00406FEF:
004070D0 PUSH ESI
004070D1 PUSH EDI
004070D2 MOV EDI,DWORD PTR SS:[ESP+C] ; в EDI помещаем промежуточный код
004070D6 XOR ESI,ESI ; обнуляем ESI
004070D8 PUSH EDI
004070D9 CALL DWORD PTR DS:[<&KERNEL32.lstrlenA>] ;определяем число символов промеж. кода
;функция lstrlenA считает символы в строке, пока ей не
;встретится NUL (ascii=0h). В приведенном мной примере промежуточный
;код состоит из 8 символов, но функция вернет значение 7, т.к.
;последний символ имеет hex-код 0. По сути, здесь задается
;число символов, которые будут обрабатываться. Если первым символом
;в UserName окажется символ J, то промежуточный код будет начинаться
;с символа с кодом 0 (т.к. 4A xor 4A =0) и промежуточный код
;вообще обрабатываться не будет (lstrlenA вернет 0).
004070DF XOR ECX,ECX
004070E1 TEST EAX,EAX
004070E3 JLE SHORT epp22.0040710C
004070E5 PUSH EBX
004070E6 OV EBX,DWORD PTR SS:[ESP+1C] ;в ЕВХ помещаем число 29h
004070EA PUSH EBP
004070EB MOVSX EDX,BYTE PTR DS:[ECX+EDI];берем код символа из промежуточного номера
004070EF MOV EBP,DWORD PTR SS:[ESP+1C] ;в ЕВР помещаем число 41h
004070F3 ADD EBP,EDX ;складываем 41h+код символа из пром. кода
004070F5 IMUL EBP,DWORD PTR SS:[ESP+18] ;умножаем сумму на 28h
004070FA ADD EBP,EDX ;и прибавляем к произведению код символа из пром. кода
004070FC ADD EBP,EBX ;к сумме прибавляем 29h
004070FE ADD ESI,EBP ;и помещаем результат в ESI
00407100 INC ECX ;увеличиваем значение ЕСХ на 1
00407101 CMP ECX,EAX ;сравниваем с ЕАХ (в ЕАХ хранится число повторов цикла)
00407103 JL SHORT epp22.004070EB ;повторяем цикл
00407105 POP EBP
00407106 POP EBX
00407107 MOV EAX,ESI ;правильный рег. номер помещаем в EAX
00407109 POP EDI
0040710A POP ESI
0040710B RETN
Думаю, здесь пояснения не
нужны. Все видно из листинга. Как отмечалось выше, чтобы
получить второй правильный рег. номер,
нужно к сгенерированному рег. номеру
прибавить число 432 (в HEX - 1B0). Стоит заметить, что в случае, когда
имя пользователя начинается с буквы J, то
последующие символы на рег. номер не влияют
и он будет постоянный (432), т.е. мы получим
только один серийник.
Генератор ключей напишем на Delphi с
использованием KOL. На форме необходимо
разместить EditBox1 - для ввода имени
пользователя, EditBox2 - для вывода серийных
номеров (оба номера будем выводить в одном
EditBox'e) и кнопку, при нажатии которой будет
выполняться следующий код:
procedure TForm1.Button1Click(Sender: PObj);
var
i, n, s, sn, sn2, k: integer;
t : string;
begin
if length(editbox1.Text)>29 then
editbox2.Text:='число символов имени должно быть меньше 29'
else
begin
{устанавливаем начальные значения переменых}
sn:=0; s:=1; n:=0; i:=0;
t:='J8FG3';
while (n<length(editbox1.Text)) and (s<>0) do
{генерируем промежуточный код, пока не получится
NUL или пока не кончатся все символы в User Name}
begin
n:=n+1; {n-номер буквы из User Name}
i:=i+1; {i-номер символа из строки J8FG3}
s:=Ord(editbox1.text[n]) xor Ord(t[i]);
{функция Ord возвращает код символа по табл. ASCII}
if i>=5 then i:=0;
if s<>0 then {сгенерированный символ пром. кода}
begin {сразу обрабатываем}
k:=s+65; {65=41h}
k:=k*40; {40=28h}
k:=k+s+41; {41=29h}
sn:=sn+k;
end;
end;
sn2:=sn+432; {генерируем второй серийник}
if sn<>0 then {если первый символ не J то выводим 2 кода}
editbox2.text:=int2str(sn)+' or '+int2str(sn2)
else {иначе в EditBox2 отображаем только один код}
editbox2.text:=int2str(sn2);
end;
end;
Чтобы узнать, какой
максимальной длинны может быть имя
пользователя, нужно просто посмотреть
место,
откуда программа выходит на процедуру
проверки регистрационного номера (это
удобнее сделать в Win32dasm).
Информация
приведена в образовательных целях. Повторение
описанных в статье действий
запрещается.
© BioCyborG, 2005
|