Создание кейгена для EmFTP 2.01 Исследуемая программа - FTP-клиент EmFTP 2.01, имеет 30 day trial и позволяет вводить к окне регистрации полученый от разработчиков регкод. PEID выдал после проверки файла EmFTP.exe такой результат: Microsoft Visual C++ 7.0 [Debug]. Это не может не радовать и дает пищу для дальнейших непродолжительных экспериментов. Сразу переходим к исследованию. Жмем Help->About EmFTP...(попутно замечаем надпись Unregistered)->How To Purchase->Enter Registration Key и видим 4 поля по 4 символа для ввода регистрационной информации. Сюда можно запихнуть лишь цифры (запомним...). Вводим набум 1111-2222-3333-4444 и получаем в ответ месаджбокс "Wrong registration key". Для отлова вызова этого сообщения грузим выполняемый файл в ольку и ставим "bp MessageBoxA" в плагине Command Bar. После повторного ввода "1111-2222-3333-4444" и нажатия на ОК прерываемся. Чтобы выяснить место, откуда функция вызывается, просмотрим стек вызовов (Alt+K). Он имеет такой вид: Code: Address Stack Procedure Called from Frame 0012F3EC 00416F11 USER32.MessageBoxA EmFTP.00416F0B 0012F60C 0012F400 00416F47 EmFTP.00416ED8 EmFTP.00416F42 0012F60C 0012F610 00418BCC EmFTP.00416F14 EmFTP.00418BC7 0012F60C 0012F668 00401220 EmFTP.00418A61 EmFTP.0040121B 0012F664 0012F670 004094A8 EmFTP.004011F7 EmFTP.004094A3 0012F6C8 0012F6CC 0040A02D EmFTP.00409281 EmFTP.0040A028 0012F6C8 0012FD64 77D38734 Maybe EmFTP.00409F64 USER32.77D38731 0012FD60 0012FD90 77D38816 ? USER32.77D3870C USER32.77D38811 0012FD8C 0012FDF8 77D389CD ? USER32.77D3875F USER32.77D389C8 0012FDF4 0012FE58 77D396C7 ? USER32.77D388F1 USER32.77D396C2 0012FE54 Последовательно проверяем функции столбца "Called from" пока не дойдем до 00418BC7. Именно тут произошел вызов MessageBox с сообщением о неправильно введенном регистрационном коде Code: .text:00418B84 call __RegOpenKey .text:00418B89 mov esi, eax .text:00418B8B cmp esi, ebx .text:00418B8D jz short end .text:00418B8F push esi ; hKey .text:00418B90 call ReadRegKey_FromRegistry_And_Check .text:00418B95 cmp eax, ebx .text:00418B97 jle short loc_418BB0 ; no JMP for registration! .text:00418B99 xor ecx, ecx .text:00418B9B cmp eax, 2 .text:00418B9E setz cl .text:00418BA1 mov dword_466984, eax .text:00418BA6 push 40h .text:00418BA8 add ecx, 455h ; registered! .text:00418BAE jmp short loc_418BC6 .text:00418BB0 ; --------------------------------------------------------------------------- .text:00418BB0 .text:00418BB0 loc_418BB0: ; CODE XREF: sub_418A61+136j .text:00418BB0 jz short loc_418BCC .text:00418BB2 xor ecx, ecx .text:00418BB4 cmp eax, 0FFFFFFFEh .text:00418BB7 setnz cl .text:00418BBA push 30h ; uType .text:00418BBC dec ecx .text:00418BBD and ecx, 3 .text:00418BC0 add ecx, 454h ; not registered! .text:00418BC6 .text:00418BC6 loc_418BC6: ; CODE XREF: sub_418A61+14Dj .text:00418BC6 push ecx ; uID .text:00418BC7 call _LoadString ;!!!! here loads "Wrong regcode" and calls MessageBox .text:00418BCC .text:00418BCC loc_418BCC: ; CODE XREF: sub_418A61:loc_418BB0j .text:00418BCC push esi ; hKey .text:00418BCD call ds:RegCloseKey .text:00418BD3 .text:00418BD3 end: ; CODE XREF: sub_418A61+FCj .text:00418BD3 ; sub_418A61+101j ... .text:00418BD3 xor eax, eax .text:00418BD5 inc eax .text:00418BD6 .text:00418BD6 loc_418BD6: ; CODE XREF: sub_418A61+196j .text:00418BD6 pop esi .text:00418BD7 pop ebx .text:00418BD8 leave .text:00418BD9 retn 4 Как видно с листинга, по адресу 00418BC7 просиходит загрузка из файла ресурса с ID 454h (или 1108, "Wrong registration key", как показывает любой редактор ресурсов). Пробежавшись немного вверх по коду, замечаем, что по адресу 00418BA8 точно такая же загрузка ресурса с ID 455h (или 1109, "Thank for registering!"). Стало быть, этот код исполняется в случае удачно введенного регкода (и мы на верном пути, движемся выше...). Code: .text:00418B90 call ReadRegKey_FromRegistry_And_Check .text:00418B95 cmp eax, ebx .text:00418B97 jle short loc_418BB0 ; no JMP for registration! Поскольку после вызова функции 00418B90 (ReadRegKey_FromRegistry_And_Check) выполняется проверка регистров (программа будет выводить сообщение о зарегистрированности если eax > ebx), то можно сделать вывод, что именно в этой функции и сосредоточен модуль проверки введенного регкода на валидность. Code: .text:004189FE ; int __stdcall ReadRegKey_FromRegistry_And_Check(HKEY hKey) .text:004189FE ReadRegKey_FromRegistry_And_Check proc near ; CODE XREF: sub_418A61+2Cp .text:004189FE ; sub_418A61+12Fp .text:004189FE .text:004189FE Data = byte ptr -10h .text:004189FE Type = dword ptr -8 .text:004189FE cbData = dword ptr -4 .text:004189FE hKey = dword ptr 8 .text:004189FE .text:004189FE push ebp .text:004189FF mov ebp, esp .text:00418A01 sub esp, 10h .text:00418A04 and [ebp+cbData], 0 .text:00418A08 push esi .text:00418A09 mov esi, ds:RegQueryValueExA .text:00418A0F push edi .text:00418A10 lea eax, [ebp+cbData] .text:00418A13 push eax ; lpcbData .text:00418A14 push 0 ; lpData .text:00418A16 lea eax, [ebp+Type] .text:00418A19 push eax ; lpType .text:00418A1A push 0 ; lpReserved .text:00418A1C mov edi, offset ValueName ; "EmFTP-Pro" .text:00418A21 push edi ; lpValueName .text:00418A22 push [ebp+hKey] ; hKey .text:00418A25 call esi ; RegQueryValueExA .text:00418A27 test eax, eax .text:00418A29 jnz short loc_418A59 .text:00418A2B cmp [ebp+Type], 3 .text:00418A2F jnz short loc_418A59 .text:00418A31 cmp [ebp+cbData], 8 .text:00418A35 jnz short loc_418A59 .text:00418A37 lea eax, [ebp+cbData] .text:00418A3A push eax ; lpcbData .text:00418A3B lea eax, [ebp+Data] .text:00418A3E push eax ; lpData .text:00418A3F lea eax, [ebp+Type] .text:00418A42 push eax ; lpType .text:00418A43 push 0 ; lpReserved .text:00418A45 push edi ; lpValueName .text:00418A46 push [ebp+hKey] ; hKey .text:00418A49 call esi ; RegQueryValueExA .text:00418A4B test eax, eax .text:00418A4D jnz short loc_418A59 .text:00418A4F lea eax, [ebp+Data] .text:00418A52 call main_reg_routine .text:00418A57 jmp short loc_418A5B .text:00418A59 ; --------------------------------------------------------------------------- .text:00418A59 .text:00418A59 loc_418A59: ; CODE XREF: ReadRegKey_FromRegistry_And_Check+2Bj .text:00418A59 ; ReadRegKey_FromRegistry_And_Check+31j ... .text:00418A59 xor eax, eax .text:00418A5B .text:00418A5B loc_418A5B: ; CODE XREF: ReadRegKey_FromRegistry_And_Check+59j .text:00418A5B pop edi .text:00418A5C pop esi .text:00418A5D leave .text:00418A5E retn 4 .text:00418A5E ReadRegKey_FromRegistry_And_Check endp В это модуле считывается записаный только что ключ в реесте "HKEY_LOCAL_MACHINE\SOFTWARE\Emurasoft\Regist" "EmFTP-Pro", который в нашем случае имеет тип REG_BINARY и равен "57 04 AE 08 05 0D 5C 11". Code: lea eax, [ebp+Data] call main_reg_routine Указатель на введенный код будет доступен в функции в регистре EAX. Давайте теперь расберемся в алгоритме генерации сохраняемого в реестре значения параметра EmFTP-Pro: если вводимый ключ состоит из 4 полей (вспоминаем, что доступны только цифры 0..9), а запись состоит из 8 байт, то логично предположить, что это 4 переменные размером в WORD, каждая отвечающая за соответственное поле ввода. Проверим: переведем "04 57" (не забываем про обратный порядок следования байт) из 16ричной системы в 10чную и получим "1111", "08 AE" - "2222", "0D 05" - "3333", "11 5C" - "4444" - точно те же данные, что мы и вводили при регистрации. Перейдем к изучению основной функции проверки введенных данных main_reg_routine. Code: .text:00425328 main_reg_routine proc near ; CODE XREF: ReadRegKey_FromRegistry_And_Check+54p .text:00425328 push esi ; бэкапим старое значение регистра .text:00425329 mov esi, eax ; заносим в esi указатель на считаные с реестра данные .text:0042532B movzx eax, word ptr [esi] ; первый ворд из 4 .text:0042532E push 0Ah ; заносим в верхушку стека 0A .text:00425330 cdq .text:00425331 pop ecx ; ecx = 0A .text:00425332 idiv ecx ; eax : = eax div 0Ah .text:00425334 cmp eax, 0BFh ; если eax = 0BFh тогда можно продолжать .text:00425339 jz short loc_425340 ; прыгаем если не равно .text:0042533B or eax, 0FFFFFFFFh ; записываем в EAX значение провала регистрации и выходим .text:0042533E pop esi ; восстанавливаем старое значение регистра .text:0042533F retn .text:00425340 ; --------------------------------------------------------------------------- .text:00425340 .text:00425340 loc_425340: ; CODE XREF: main_reg_routine+11j .text:00425340 push edi .text:00425341 mov di, [esi+6] ; 4 ворд .text:00425345 call zamut .text:0042534A cmp eax, 1 .text:0042534D jnz short loc_42535C .text:0042534F xor eax, eax .text:00425351 cmp di, [esi+6] ; сравниваем 4 ворд с результатом функции .text:00425355 setz al .text:00425358 lea eax, [eax+eax-1] .text:0042535C .text:0042535C loc_42535C: ; CODE XREF: main_reg_routine+25j .text:0042535C pop edi .text:0042535D pop esi .text:0042535E retn .text:0042535E main_reg_routine endp С первой части функции видно, что в первом поле должно быть такое число, что chislo div $0A = $BF. Если это условие правдиво, то мы движемся дальше и по адресу 00425345 происходит вызов основной функции просчета валидного серийника и окончательной его проверки с нами введенным. Code: .text:0042522E zamut proc near ; CODE XREF: main_reg_routine+1Dp .text:0042522E .text:0042522E var = dword ptr -8 .text:0042522E first_word = dword ptr -4 .text:0042522E .text:0042522E push ecx .text:0042522F push ecx .text:00425230 mov dx, [esi+2] ; 2 ворд .text:00425234 and word ptr [esi+6], 0 ; 4 ворд .text:00425239 cmp dx, 270Fh .text:0042523E ja ending .text:00425244 mov ax, [esi+4] .text:00425248 cmp ax, 270Fh .text:0042524C ja ending .text:00425252 xor ecx, ecx .text:00425254 mov cx, [esi] ; 1 ворд .text:00425257 cmp cx, 715h .text:0042525C mov [esp+8+first_word], ecx .text:00425260 jnz short loc_425276 .text:00425262 cmp dx, 1C1Eh .text:00425267 jnz short loc_425276 .text:00425269 cmp ax, 159Dh .text:0042526D jnz short loc_425276 .text:0042526F .text:0042526F fail: ; CODE XREF: zamut+5Aj .text:0042526F ; zamut+6Ej .text:0042526F push 0FFFFFFFEh .text:00425271 jmp ending2 .text:00425276 ; --------------------------------------------------------------------------- .text:00425276 .text:00425276 loc_425276: ; CODE XREF: zamut+32j .text:00425276 ; zamut+39j ... .text:00425276 cmp cx, 71Ah .text:0042527B jnz short loc_42528A .text:0042527D cmp dx, 1009h .text:00425282 jnz short loc_42528A .text:00425284 cmp ax, 15h .text:00425288 jz short fail .text:0042528A .text:0042528A loc_42528A: ; CODE XREF: zamut+4Dj .text:0042528A ; zamut+54j .text:0042528A cmp cx, 714h .text:0042528F jnz short loc_42529E .text:00425291 cmp dx, 1321h .text:00425296 jnz short loc_42529E .text:00425298 cmp ax, 0B6Ch .text:0042529C jz short fail .text:0042529E .text:0042529E loc_42529E: ; CODE XREF: zamut+61j .text:0042529E ; zamut+68j .text:0042529E push ebx .text:0042529F push ebp .text:004252A0 push edi .text:004252A1 movzx edi, ax .text:004252A4 movzx eax, dx .text:004252A7 mov [esp+14h+var], eax .text:004252AB push 64h .text:004252AD pop ebx .text:004252AE mov eax, edi .text:004252B0 cdq .text:004252B1 idiv ebx ; 3 word div 64h .text:004252B3 push 0Ah .text:004252B5 pop ebp .text:004252B6 movzx ecx, cx .text:004252B9 push 64h .text:004252BB mov ebx, eax .text:004252BD mov eax, ecx .text:004252BF cdq .text:004252C0 idiv ebp ; 1 word div Ah .text:004252C2 add ebx, [esp+18h+var] ; добавляем 3 word к остатку от "3 word div 64h" .text:004252C6 add eax, ebx ; + eax .text:004252C8 add eax, edi ; + 3 word .text:004252CA cdq .text:004252CB pop edi .text:004252CC idiv edi ; eax div 64h .text:004252CE mov eax, [esp+14h+var] ; eax = 2 word .text:004252D2 push 64h .text:004252D4 pop ebx .text:004252D5 push 64h .text:004252D7 pop ebp .text:004252D8 push ebp .text:004252D9 mov di, word ptr byte_463E20[edx*4] .text:004252E1 cdq .text:004252E2 imul di, 64h .text:004252E6 idiv ebx ; div 64h .text:004252E8 mov ebx, eax .text:004252EA mov eax, ecx .text:004252EC cdq .text:004252ED idiv ebp ; div 64h .text:004252EF add ebx, ecx .text:004252F1 pop ecx .text:004252F2 add eax, ebx .text:004252F4 cdq .text:004252F5 idiv ecx ; div 64h .text:004252F7 add di, word ptr byte_463E20[edx*4] .text:004252FF cmp word ptr [esp+14h+first_word], 77Bh .text:00425306 mov [esi+6], di ; result? .text:0042530A pop edi .text:0042530B pop ebp .text:0042530C pop ebx .text:0042530D jz short fail2 ; no JMP! .text:0042530F cmp word ptr [esp+8+first_word], 77Ah .text:00425316 jz short fail2 ; no JMP! .text:00425318 xor eax, eax .text:0042531A inc eax .text:0042531B jmp short end .text:0042531D ; --------------------------------------------------------------------------- .text:0042531D .text:0042531D fail2: ; CODE XREF: zamut+DFj .text:0042531D ; zamut+E8j .text:0042531D push 2 .text:0042531F .text:0042531F ending2: ; CODE XREF: zamut+43j .text:0042531F pop eax .text:00425320 jmp short end .text:00425322 ; --------------------------------------------------------------------------- .text:00425322 .text:00425322 ending: ; CODE XREF: zamut+10j .text:00425322 ; zamut+1Ej .text:00425322 or eax, 0FFFFFFFFh .text:00425325 .text:00425325 end: ; CODE XREF: zamut+EDj .text:00425325 ; zamut+F2j .text:00425325 pop ecx .text:00425326 pop ecx .text:00425327 retn .text:00425327 zamut endp
Вся "красота" функции заключается в математических операциях над первыми тремя введенными числами и записи просчитанного валидного для них четвертого (.text:00425306 mov [esi+6], di). Как мы помним, по адресу 00425351 (cmp di, [esi+6] ; сравниваем 4 ворд с результатом функции) происходит окончательная их проверка. Так что для создания кейгена достаточно "понять" алгоритм проверок и преобразовать его на любой любимый язык. Но можно сделать проще, просто рипнув эту функцию и использовав ее для своих нужд (я употребил плагин для ольки AsmToClipboard -> Copy Fixed Asm To Clipboard). При этих манипуляциях не стоит забывать, что для правильной работы рипнутого кода в качестве ассемблерной вставки, например, в делфи, нужно корректно заменить используемые в функции указатели на данные на передаваемые ей в своей функции соответствующие переменные, поменять адреса меток на их символьные аналоги и самое важное - что в даной функции используется внешняя таблица констант: Code: 004252D9 |. 66:8B3C95 203E>MOV DI,WORD PTR DS:[EDX*4+463E20] ; ТУТ 004252E1 |. 99 CDQ 004252E2 |. 66:6BFF 64 IMUL DI,DI,64 004252E6 |. F7FB IDIV EBX 004252E8 |. 8BD8 MOV EBX,EAX 004252EA |. 8BC1 MOV EAX,ECX 004252EC |. 99 CDQ 004252ED |. F7FD IDIV EBP 004252EF |. 03D9 ADD EBX,ECX 004252F1 |. 59 POP ECX 004252F2 |. 03C3 ADD EAX,EBX 004252F4 |. 99 CDQ 004252F5 |. F7F9 IDIV ECX 004252F7 |. 66:033C95 203E>ADD DI,WORD PTR DS:[EDX*4+463E20] ; И ТУТ чтобы сделать полностью рабочий кейген нужно рипнуть и эту таблицу. Для этого щелкаем в ольке на строке "004252D9 |. 66:8B3C95 203E>MOV DI,WORD PTR DS:[EDX*4+463E20] ; ТУТ" и жмем Follow in dump -> Address Constant и получаем в окне дампов начало искомой таблицы (00463E20). Code: 00463E20 26 00 00 00 5B 00 00 00 62 00 00 00 36 00 00 00 &...[...b...6... 00463E30 34 00 00 00 60 00 00 00 13 00 00 00 35 00 00 00 4...`......5... 00463E40 19 00 00 00 54 00 00 00 3F 00 00 00 44 00 00 00 ...T...?...D... 00463E50 4C 00 00 00 38 00 00 00 5D 00 00 00 33 00 00 00 L...8...]...3... 00463E60 56 00 00 00 61 00 00 00 42 00 00 00 21 00 00 00 V...a...B...!... 00463E70 3E 00 00 00 2D 00 00 00 23 00 00 00 0E 00 00 00 >...-...#...... 00463E80 1E 00 00 00 5F 00 00 00 57 00 00 00 12 00 00 00 ..._...W...... 00463E90 1B 00 00 00 17 00 00 00 22 00 00 00 58 00 00 00 ......"...X... 00463EA0 2C 00 00 00 63 00 00 00 5C 00 00 00 18 00 00 00 ,...c...\...... 00463EB0 37 00 00 00 41 00 00 00 59 00 00 00 4D 00 00 00 7...A...Y...M... 00463EC0 15 00 00 00 5A 00 00 00 53 00 00 00 0B 00 00 00 ...Z...S...... 00463ED0 05 00 00 00 1C 00 00 00 10 00 00 00 2E 00 00 00 ............. 00463EE0 49 00 00 00 40 00 00 00 0D 00 00 00 07 00 00 00 I...@.......... 00463EF0 50 00 00 00 3D 00 00 00 32 00 00 00 46 00 00 00 P...=...2...F... 00463F00 0A 00 00 00 43 00 00 00 2B 00 00 00 00 00 00 00 ....C...+....... 00463F10 3B 00 00 00 48 00 00 00 5E 00 00 00 4E 00 00 00 ;...H...^...N... 00463F20 51 00 00 00 1F 00 00 00 20 00 00 00 3A 00 00 00 Q...... ...:... 00463F30 01 00 00 00 2A 00 00 00 45 00 00 00 55 00 00 00 ...*...E...U... 00463F40 4A 00 00 00 02 00 00 00 52 00 00 00 27 00 00 00 J......R...'... 00463F50 03 00 00 00 4B 00 00 00 08 00 00 00 3C 00 00 00 ...K......<... 00463F60 0F 00 00 00 14 00 00 00 24 00 00 00 25 00 00 00 ......$...%... 00463F70 28 00 00 00 29 00 00 00 16 00 00 00 1D 00 00 00 (...)......... 00463F80 1A 00 00 00 11 00 00 00 2F 00 00 00 39 00 00 00 ....../...9... 00463F90 09 00 00 00 47 00 00 00 06 00 00 00 4F 00 00 00 ....G......O... 00463FA0 04 00 00 00 31 00 00 00 0C 00 00 00 30 00 00 00 ...1.......0... копируем дамп по адрес 463FB0 (ровно 400 байт, которые имеют визуально схожую структуру). Забив в своем кейгене дамп в отдельную таблицу, получаем примерно такое: Code: unit main; //на форме баттон и 4 спинедита interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin; type TForm1 = class(TForm) Button1: TButton; SpinEdit1: TSpinEdit; SpinEdit2: TSpinEdit; SpinEdit3: TSpinEdit; SpinEdit4: TSpinEdit; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; const Data: array [1..400] of byte =( $26, 00, 00, 00, $5B, 00, 00, 00, $62, 00, 00, 00, $36, 00, 00, 00, //&...[...b...6... $34, 00, 00, 00, $60, 00, 00, 00, $13, 00, 00, 00, $35, 00, 00, 00, //4...`......5... $19, 00, 00, 00, $54, 00, 00, 00, $3F, 00, 00, 00, $44, 00, 00, 00, //...T...?...D... $4C, 00, 00, 00, $38, 00, 00, 00, $5D, 00, 00, 00, $33, 00, 00, 00, //L...8...]...3... $56, 00, 00, 00, $61, 00, 00, 00, $42, 00, 00, 00, $21, 00, 00, 00, //V...a...B...!... $3E, 00, 00, 00, $2D, 00, 00, 00, $23, 00, 00, 00, $0E, 00, 00, 00, //>...-...#...... $1E, 00, 00, 00, $5F, 00, 00, 00, $57, 00, 00, 00, $12, 00, 00, 00, //..._...W...... $1B, 00, 00, 00, $17, 00, 00, 00, $22, 00, 00, 00, $58, 00, 00, 00, //......"...X... $2C, 00, 00, 00, $63, 00, 00, 00, $5C, 00, 00, 00, $18, 00, 00, 00, //,...c...\...... $37, 00, 00, 00, $41, 00, 00, 00, $59, 00, 00, 00, $4D, 00, 00, 00, //7...A...Y...M... $15, 00, 00, 00, $5A, 00, 00, 00, $53, 00, 00, 00, $0B, 00, 00, 00, //...Z...S...... $05, 00, 00, 00, $1C, 00, 00, 00, $10, 00, 00, 00, $2E, 00, 00, 00, //............. $49, 00, 00, 00, $40, 00, 00, 00, $0D, 00, 00, 00, $07, 00, 00, 00, //I...@.......... $50, 00, 00, 00, $3D, 00, 00, 00, $32, 00, 00, 00, $46, 00, 00, 00, //P...=...2...F... $0A, 00, 00, 00, $43, 00, 00, 00, $2B, 00, 00, 00, $00, 00, 00, 00, //....C...+....... $3B, 00, 00, 00, $48, 00, 00, 00, $5E, 00, 00, 00, $4E, 00, 00, 00, //;...H...^...N... $51, 00, 00, 00, $1F, 00, 00, 00, $20, 00, 00, 00, $3A, 00, 00, 00, //Q...... ...:... $01, 00, 00, 00, $2A, 00, 00, 00, $45, 00, 00, 00, $55, 00, 00, 00, //...*...E...U... $4A, 00, 00, 00, $02, 00, 00, 00, $52, 00, 00, 00, $27, 00, 00, 00, //J......R...'... $03, 00, 00, 00, $4B, 00, 00, 00, $08, 00, 00, 00, $3C, 00, 00, 00, //...K......<... $0F, 00, 00, 00, $14, 00, 00, 00, $24, 00, 00, 00, $25, 00, 00, 00, //......$...%... $28, 00, 00, 00, $29, 00, 00, 00, $16, 00, 00, 00, $1D, 00, 00, 00, //(...)......... $1A, 00, 00, 00, $11, 00, 00, 00, $2F, 00, 00, 00, $39, 00, 00, 00, //....../...9... $09, 00, 00, 00, $47, 00, 00, 00, $06, 00, 00, 00, $4F, 00, 00, 00, //....G......O... $04, 00, 00, 00, $31, 00, 00, 00, $0C, 00, 00, 00, $30, 00, 00, 00); //...1.......0... var Form1: TForm1; implementation {$R *.dfm} function Generate(first, second, third, fourth :word): word; begin asm PUSH ESI PUSH ECX PUSH ECX MOV DX, second AND fourth, 0 CMP DX, 270Fh JA @ending MOV AX, third CMP AX, 270Fh JA @ending XOR ECX, ECX MOV CX, first CMP CX, 715h MOV esi, ECX //!!! JNZ @next CMP DX, 1C1Eh JNZ @next CMP AX, 159Dh JNZ @next @fail: PUSH -2 JMP @ending2 @next: CMP CX, 71Ah JNZ @next2 CMP DX, 1009h JNZ @next2 CMP AX, 15h JE @fail @next2: CMP CX, 714h JNZ @main CMP DX, 1321h JNZ @main CMP AX, 0B6Ch JE @fail @main: PUSH EBX PUSH EBP PUSH EDI MOVZX EDI,AX MOVZX EAX,DX MOV esi, EAX //!!! PUSH 64h POP EBX MOV EAX,EDI CDQ IDIV EBX PUSH 0Ah POP EBP MOVZX ECX, CX PUSH 64h MOV EBX, EAX MOV EAX, ECX CDQ IDIV EBP ADD EBX, esi ADD EAX, EBX ADD EAX, EDI CDQ POP EDI IDIV EDI MOV EAX, esi PUSH 64h POP EBX PUSH 64h POP EBP PUSH EBP MOV DI, WORD PTR DS:[EDX*4 + Data] CDQ IMUL DI,DI,64h IDIV EBX MOV EBX, EAX MOV EAX, ECX CDQ IDIV EBP ADD EBX, ECX POP ECX ADD EAX, EBX CDQ IDIV ECX ADD DI, WORD PTR DS:[EDX*4 + Data] MOV DX, DI POP EDI POP EBP POP EBX CMP first, 77Bh MOV fourth, DX //result JE @fail2 CMP first, 77Ah JE @fail2 XOR EAX, EAX INC EAX JMP @end @fail2: PUSH 2 @ending2: POP EAX JMP @end @ending: OR EAX, -1h @end: MOV CX, fourth MOV RESULT, CX POP ECX POP ECX POP ESI end; end; procedure TForm1.Button1Click(Sender: TObject); label next_iteration; var first, second, third, fourth: word; begin randomize; next_iteration: first := random(9999); //генерируем 4 случайных числа second := random(9999); third := random(9999); fourth := random(9999); if first div $A <> $BF then goto next_iteration; //значение первого числа не подходит if first = $77B then goto next_iteration; //эти значения не следует брать, т.к. они используются только в if first = $77A then goto next_iteration; //education и academic version, а нам нужна FULL SpinEdit1.Value := first; SpinEdit2.Value := second; SpinEdit3.Value := third; SpinEdit4.Value := Generate(first, second, third, fourth); end; end. gl hf!
Отлично! Но есть вопрос - что за олька? Я пользовался только SoftICE и WinDASM для реверсинга.... "олька" лучше? ------ UPD: насчет ольки (ollyDBG) вопрос снят.
олька - отлад4ик OllyDbg, о4ень удобен для на4инающих, да и вообще незаменим при отладке приложений пользовательского уровня. имеет ку4у дополнительных плагинов, скриптов для автораспаковки многих пакеров\протекторов - вообщем наземенимая тулза для исследований и отладки багов в своем же софте! ка4аем последний релиз: http://wasm.ru/baixado.php?mode=tool&id=89 http://cracklab.ru/download.php?action=get&n=MzYw