Перейдем к следующему виду проверки,
кнопке "Hw.Check" с полем ввода. Попробуем написать,
туда что-нибудь, скорее всего получим сообщение "THE KEY MUST CONSIST THE LETTERS FROM A TO
J". Сие означает, что ключ должен содержать латинские буквы от A до J. Пробуем вписать туда
"ABCDEFGHIJ" и  получим "Incorrect". Снова вернемся в win32dasm, смотрим в Dialog
Information, ищем кнопку "Hw.Check".

Number of Dialogs = 1 (decimal)

Name: DialogID_0064, # of Controls=010, Caption:"", ClassName:""
001 - ControlID:0066, Control Class:"EDIT" Control Text:"" 
002 - ControlID:0067, Control Class:"EDIT" Control Text:"" 
003 - ControlID:03E9, Control Class:"BUTTON" Control Text:"Reg.Check"
004 - ControlID:0065, Control Class:"EDIT" Control Text:"" 
005 - ControlID:03EA, Control Class:"BUTTON" Control Text:"Hw.Check" ; искомая кнопка 
006 - ControlID:03EB, Control Class:"BUTTON" Control Text:"Check" 
007 - ControlID:0000, Control Class:"BUTTON" Control Text:"" 
008 - ControlID:0000, Control Class:"BUTTON" Control Text:"" 
009 - ControlID:0000, Control Class:"BUTTON" Control Text:"" 
010 - ControlID:FFFF, Control Class:"" Control Text:"Z"

Нашли. Смотрим ее ControlID - 03EA, и тем же методом, что и
в прошлый раз, ищем
нужную нам конструкцию вида cmp ..., 03ea, она будет находится рядом с предыдущей.

:00419637 817D10EA030000 cmp dword ptr [ebp+10], 000003EA ;
проверка нажата ли кнопка
"Reg.Check"

:0041963E 7505 jne 00419645 ;
если не нажата прыгает, нажата - идет дальше
:00419640 E8FFFBFFFF call 00419244 ; с
нова нужный нам call

Идем по этому адресу (жмем shift+f12) вводим 00419244, затем OK.
Приступим к исследованию.

:00419244 55 push ebp
:00419245 8BEC mov ebp, esp
:00419247 83C4D8 add esp, FFFFFFD8
:0041924A 53 push ebx
:0041924B 56 push esi
:0041924C 33C0 xor eax, eax
:0041924E 8945D8 mov dword ptr [ebp-28], eax
:00419251 8945DC mov dword ptr [ebp-24], eax
:00419254 8945E0 mov dword ptr [ebp-20], eax
:00419257 8945FC mov dword ptr [ebp-04], eax
:0041925A 8945F8 mov dword ptr [ebp-08], eax
:0041925D 33C0 xor eax, eax
:0041925F 55 push ebp
:00419260 685A944100 push 0041945A
:00419265 64FF30 push dword ptr fs:[eax]
:00419268 648920 mov dword ptr fs:[eax], esp
:0041926B 6804010000 push 00000104 ; Max Path
:00419270 6A00 push 00000000 ; File System Name
:00419272 8D45E8 lea eax, dword ptr [ebp-18]
:00419275 50 push eax ; File System Flags
:00419276 8D45EC lea eax, dword ptr [ebp-14]
:00419279 50 push eax ; Max. Component Length
:0041927A 8D45F0 lea eax, dword ptr [ebp-10]
:0041927D 50 push eax ; Volume Serial Number
:0041927E 6804010000 push 00000104 ; max path
:00419283 6A00 push 00000000 ; VolumeName

* Possible StringData Ref from Code Obj ->"C:\"
|
:00419285 6868944100 push 00419468 ; по диску "C:\"

* Reference To: kernel32.GetVolumeInformationA, Ord:0000h
|
:0041928A E8EDD1FEFF Call 0040647C ;
вызов API GetVolumeInformationA, для получения метки диска, серийный номера тома и т.д. (параметры описаны выше)
:0041928F 8D55F8 lea edx, dword ptr [ebp-08]
:00419292 8B45F0 mov eax, dword ptr [ebp-10] ;
в eax серийный номер тома
C:

:00419295 E89AFDFFFF call 00419034 ;
функция переводит число
(серийный номер тома) в строку

:0041929A 8B45F8 mov eax, dword ptr [ebp-08] ;
в eax смещение серийного номера тома
C:

:0041929D E8FAB0FEFF call 0040439C ;
функция получает длину серийного номера тома
:004192A2 48 dec eax
:004192A3 84C0 test al, al
:004192A5 0F8680000000 jbe 0041932B
:004192AB 8845E6 mov byte ptr [ebp-1A], al ; помещает длину в [ebp-1A]
:004192AE B301 mov bl, 01

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00419329(C)
|
:004192B0 8D4301 lea eax, dword ptr [ebx+01]
:004192B3 50 push eax
:004192B4 8B45F8 mov eax, dword ptr [ebp-08]
:004192B7 E8E0B0FEFF call 0040439C
:004192BC 5A pop edx
:004192BD 2AC2 sub al, dl
:004192BF 7264 jb 00419325
:004192C1 40 inc eax
:004192C2 8845E5 mov byte ptr [ebp-1B], al
:004192C5 8855E7 mov byte ptr [ebp-19], dl

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00419323(C)
|
:004192C8 33D2 xor edx, edx
:004192CA 8A55E7 mov dl, byte ptr [ebp-19]
:004192CD 8B4DF8 mov ecx, dword ptr [ebp-08]
:004192D0 8A5411FF mov dl, byte ptr [ecx+edx-01]
:004192D4 8BF3 mov esi, ebx
:004192D6 81E6FF000000 and esi, 000000FF
:004192DC 8B45F8 mov eax, dword ptr [ebp-08]
:004192DF 8A4430FF mov al, byte ptr [eax+esi-01]
:004192E3 3AD0 cmp dl, al
:004192E5 7336 jnb 0041931D
:004192E7 33D2 xor edx, edx
:004192E9 8AD3 mov dl, bl
:004192EB 8B4DF8 mov ecx, dword ptr [ebp-08]
:004192EE 8845F7 mov byte ptr [ebp-09], al
:004192F1 8D45F8 lea eax, dword ptr [ebp-08]
:004192F4 E8F3B2FEFF call 004045EC
:004192F9 33D2 xor edx, edx
:004192FB 8A55E7 mov dl, byte ptr [ebp-19]
:004192FE 8B4DF8 mov ecx, dword ptr [ebp-08]
:00419301 8A5411FF mov dl, byte ptr [ecx+edx-01]
:00419305 885430FF mov byte ptr [eax+esi-01], dl
:00419309 8D45F8 lea eax, dword ptr [ebp-08]
:0041930C E8DBB2FEFF call 004045EC
:00419311 33D2 xor edx, edx
:00419313 8A55E7 mov dl, byte ptr [ebp-19]
:00419316 8A4DF7 mov cl, byte ptr [ebp-09]
:00419319 884C10FF mov byte ptr [eax+edx-01], cl

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004192E5(C)
|
:0041931D FE45E7 inc [ebp-19]
:00419320 FE4DE5 dec [ebp-1B]
:00419323 75A3 jne 004192C8

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004192BF(C)
|
:00419325 43 inc ebx
:00419326 FE4DE6 dec [ebp-1A]
:00419329 7585 jne 004192B0

Код выше, делает следующее:

создает 2 цикла

For i := 1 to length(SerialN)-1 do
For j := i+1 to length(SerialN) do

проверяет больше ли предыдущий элемент следующего

If SerialN[i] > SerialN[j] then

если да, то меняет их местами

begin
s:=SerialN[i];
SerialN[i]:=SerialN[j];
SerialN[j]:=s;
end;

после этого число выстраивается по возрастанию(пример: число 88011, примет вид 01188).

:0041933D B800040000 mov eax, 00000400
:00419342 E88193FEFF call 004026C8
:00419347 8BF0 mov esi, eax
:00419349 6800040000 push 00000400
:0041934E 56 push esi

* Possible Reference to Dialog: DialogID_0064, CONTROL_ID:0066, ""
|
:0041934F 6A66 push 00000066
:00419351 A11CBA4100 mov eax, dword ptr [0041BA1C]
:00419356 50 push eax

* Reference To: user32.GetDlgItemTextA, Ord:0000h
|
:00419357 E8C0D1FEFF Call 0040651C ;
GetDlgItemTextA получает пароль из поля ввода (смещение пароля помещает в
esi)

:0041935C 8D45E0 lea eax, dword ptr [ebp-20]
:0041935F 8BD6 mov edx, esi ;
смещение пароля помещается в edx
:00419361 E86EAFFEFF call 004042D4
:00419366 8B45E0 mov eax, dword ptr [ebp-20]
:00419369 E82EB0FEFF call 0040439C ;
функция получает длину пароля в eax (т.е. eax будет содержать длину пароля)
:0041936F 84C0 test al, al ;
если
al (к-во символов пароля)>0 продолжат, иначе

:00419371 7419 jz 004193B0 ;
прыгает
и регистрации не видать

:00419374 8845E6 mov byte ptr [ebp-1A], al ;
помещает в [ebp-1A] длину пароля (это будет счетчик для цикла) 
:00419377 B300 mov bl, 00

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004193AE(C)
|
:00419379 33C0 xor eax, eax ;
очищаем eax
:0041937B 8AC3 mov al, bl ;
помещаем в al, bl
:0041937D 8A0406 mov al, byte ptr [esi+eax];
в al n-ный символ пароля (с каждым циклом след. символ)
:00419380 3C4A cmp al, 4A ;
сравниваем n-ный символ пароля с 4A hex = 74 dec = символ J
:00419382 7708 ja 0041938C ;
если больше, т.е. больше J, допустим K то программа прыгает на 0041938C и выводит
;
сообщение о
несоответствии пароля

:00419384 33D2 xor edx, edx
:00419386 8AD3 mov dl, bl
:00419388 3C41 cmp al, 41 ;
сравниваем n-ный символ пароля с 41 hex = 65 dec = символ A
:0041938A 731E jnb 004193AA ;
если не меньше прыгает на 004193AA(что нам и надо), иначе
;
иначе остается и следующие инструкции выводят
;
сообщение о
несоответствии пароля

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00419382(C)
|

* Possible StringData Ref from Code Obj ->"The key must consist the letters "
->"from A to J"
|
:0041938C 687C944100 push 0041947C

* Possible Reference to Dialog: DialogID_0064, CONTROL_ID:0066, ""
|
:00419391 6A66 push 00000066
:00419393 A11CBA4100 mov eax, dword ptr [0041BA1C]
:00419398 50 push eax

* Reference To: user32.SetDlgItemTextA, Ord:0000h
|
:00419399 E8AED1FEFF Call 0040654C ;
вывод сообщения "The key must consist the letters from A to
J"

:0041939E 8BC6 mov eax, esi
:004193A0 E84393FEFF call 004026E8
:004193A5 E988000000 jmp 00419432

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041938A(C)
|
:004193AA 43 inc ebx ; увеличивает ebx
:004193AB FE4DE6 dec [ebp-1A] ;
уменьшает [ebp-1A](счетчик) если=0 выходит из цикла, иначе
:004193AE 75C9 jne 00419379 ;
прыгает обратно в цикл (00419379)

:004193B0 8D45DC lea eax, dword ptr [ebp-24] ; если мы здесь, значит введенный нами пароль удовлетворяет требованиям (The key must consist the letters from A to J)
:004193B3 8BD6 mov edx, esi ;
помещает в edx смещение пароля
:004193B5 E81AAFFEFF call 004042D4
:004193BA 8B45DC mov eax, dword ptr [ebp-24]
:004193BD E8DAAFFEFF call 0040439C ;
функция снова получает длину пароля
:004193C2 48 dec eax
:004193C3 84C0 test al, al
:004193C5 722A jb 004193F1
:004193C7 40 inc eax
:004193C8 8845E6 mov byte ptr [ebp-1A], al ;
снова помещает в [ebp-1A] длину пароля (это будет счетчик для цикла) 
:004193CB B300 mov bl, 00 ;
помещает в bl, 0 (bl будет служить индексом, увеличиваясь на 1 с каждым циклом)

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004193EF(C)
|
:004193CD 8D45D8 lea eax, dword ptr [ebp-28]
:004193D0 33D2 xor edx, edx ;
очищает регистр edx
:004193D2 8AD3 mov dl, bl ;
помещает в dl, bl(индекс)
:004193D4 0FB61416 movzx edx, byte ptr [esi+edx] ;
в edx помещает n-ный символ пароля
:004193D8 83EA11 sub edx, 00000011 ;
от n-ного символа пароля, отнимает 11 hex = 17 dec, допустим символ A(65 dec)-17=48 dec, а 48 dec это код "0"
!
;
B(66 dec)-17=49 dec, а 49 dec это код "1", ... и J(74 dec)-17=57 dec, а 57 dec это код "9", т.о. все символы от A до J
;
переводятся в цифры от 0 до 9. 
:004193DB E8E4AEFEFF call 004042C4
:004193E0 8B55D8 mov edx, dword ptr [ebp-28]
:004193E3 8D45FC lea eax, dword ptr [ebp-04]
:004193E6 E8B9AFFEFF call 004043A4 ;
эти цифры помещает по адресу в [ebp-4], т.о. *[ebp-4] будет содержать число полученное из нашего пароля
:004193EB 43 inc ebx ;
увеличивает ebx(индекс)
:004193EC FE4DE6 dec [ebp-1A] ;
уменьшает [ebp-1A](счетчик) если=0 выходит из цикла, иначе
:004193EF 75DC jne 004193CD ;
прыгает обратно в цикл (004193CD)

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004193C5(C)
|
:004193F1 8B45F8 mov eax, dword ptr [ebp-08] ;
в [ebp-08]
выстроенный по возрастанию серийный номер тома

:004193F4 8B55FC mov edx, dword ptr [ebp-04] ;
в [ebp-04] число полученное из нашего пароля
:004193F7 E8E4B0FEFF call 004044E0 ;
сравнивает две вышеупомянутые строки, если равны выводит сообщение "MACHINE KEY CHECK ... OK!", иначе
:004193FC 751B jne 00419419 ;
прыгает и пишет
"Incorrect"

* Possible StringData Ref from Code Obj ->"MACHINE KEY CHECK ... OK!"
|
:004193FE 68AC944100 push 004194AC

* Possible Reference to Dialog: DialogID_0064, CONTROL_ID:0066, ""
|
:00419403 6A66 push 00000066
:00419405 A11CBA4100 mov eax, dword ptr [0041BA1C]
:0041940A 50 push eax

* Reference To: user32.SetDlgItemTextA, Ord:0000h
|
:0041940B E83CD1FEFF Call 0040654C ;
выводит "MACHINE KEY CHECK ... OK!" 
:00419410 8BC6 mov eax, esi
:00419412 E8D192FEFF call 004026E8
:00419417 EB19 jmp 00419432

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004193FC(C)
|

* Possible StringData Ref from Code Obj ->"INCORRECT!"
|
:00419419 68C8944100 push 004194C8 ;
выводит
"Incorrect"

Подведем итоги второй проверки (Hw.Check). Итак, программа с помощью API функции
getvolumeinformationa получает серийный номер тома C:, затем выстраивает его
по возрастанию и сохраняет в *(ebp+8). Мы вводим пароль состоящий из латинских букв верхнего регистра от A до J
(ABCDEFGHIJ). Из askii кода каждой буквы вычитается 17 и получаются цифры.
A->0 B->1 C->2 D->3 E->4 F->5 G->6 H->7 I->8 J->9, полученное число сохраняется в
*(ebp+4). Затем *(ebp+8) сравнивается с *(ebp+4) - если равны проверка прошла успешно.

Теперь напишем keygen на delphi. Поместим на форму кнопку и поле ввода(edit1).
Добавим кнопке событие onclick:

procedure TForm1.Button1Click(Sender: TObject);
var
VolumeSerialNumber:string;
s:char;
VolumeSerialNo, MaxComponentLength, FileSystemFlags : DWORD;
i,j:byte;
begin
GetVolumeInformation('C:\',nil,MAX_PATH,@VolumeSerialNo,MaxComponentLength,FileSystemFlags,nil,MAX_PATH);
VolumeSerialNumber:=IntToStr(VolumeSerialNo);
For i := 1 to length(VolumeSerialNumber)-1 do
For j := i+1 to length(VolumeSerialNumber) do
If VolumeSerialNumber[i] > VolumeSerialNumber[j] then
begin
s:=VolumeSerialNumber[i];
VolumeSerialNumber[i]:=VolumeSerialNumber[j];
VolumeSerialNumber[j]:=s;
end;
For i := 1 to length(VolumeSerialNumber) do
VolumeSerialNumber[i]:=char(ord(VolumeSerialNumber[i])+17);
edit1.text:=VolumeSerialNumber
end;

Запустим программу, нажмем на кнопку и получим код, в моем случае я получил
AABCCDEEE, у вас будет другой, введем его в программу и нажмем кнопку
"Hw.Check", - "MACHINE KEY CHECK ... OK!". Проверка прошла успешно!

Приступим к третьей, последней проверке "Check". Эта проверка из программы
предыдущей
статьи
. Та самая,  которая была в качестве домашнего задания. Мне пришло порядка 5-7 сообщений
с просьбой детально растолковать как можно найти пароль.
Итак, приступим. Тем же методом, что и в предыдущих проверках ищем кнопку
"Сheck" в Dialog Information, смотрим ее ControlID - 03EB и ищем ее в коде, конструкция вида cmp ..., 03eb.

Находим по адресу 00419645.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041963E(C)
|
:00419645 817D10EB030000 cmp dword ptr [ebp+10], 000003EB ;
проверка, нажата ли кнопка
"Check"

:0041964C 755B jne 004196A9 ;
если не нажата прыгает, нажата - идет дальше
:0041964E E895FEFFFF call 004194E8 ;
нужный нам call

Идем по этому адресу(004194E8).

:004194E8 55 push ebp
:004194E9 8BEC mov ebp, esp
:004194EB 6A00 push 00000000
:004194ED 6A00 push 00000000
:004194EF 53 push ebx
:004194F0 56 push esi
:004194F1 33C0 xor eax, eax
:004194F3 55 push ebp
:004194F4 68C6954100 push 004195C6
:004194F9 64FF30 push dword ptr fs:[eax]
:004194FC 648920 mov dword ptr fs:[eax], esp

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00419498(C)
|
:004194FF B800040000 mov eax, 00000400

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041948E(C)
|
:00419504 E8BF91FEFF call 004026C8
:00419509 8BD8 mov ebx, eax
:0041950B 6800040000 push 00000400
:00419510 53 push ebx

* Possible Reference to Dialog: DialogID_0064, CONTROL_ID:0067, ""
|
:00419511 6A67 push 00000067
:00419513 A11CBA4100 mov eax, dword ptr [0041BA1C]
:00419518 50 push eax

* Reference To: user32.GetDlgItemTextA, Ord:0000h
|
:00419519 E8FECFFEFF Call 0040651C ;
получает пароль из поля ввода (в
ebx)

:0041951E 33F6 xor esi, esi ;
очищает регистр esi
:00419520 8D45FC lea eax, dword ptr [ebp-04]
:00419523 8BD3 mov edx, ebx ;
помещает смещение пароля в eax
:00419525 E8AAADFEFF call 004042D4 ;
помещает смещение пароля в [ebp-04]
:0041952A 8B45FC mov eax, dword ptr [ebp-04]
:0041952D E86AAEFEFF call 0040439C ;
получает длину пароля (в
eax)

:00419532 83F80C cmp eax, 0000000C ;
сравнивает длину пароля с 0C hex=12 dec
:00419535 7405 je 0041953C ;
если длина пароля = 12 символам пыгает на 0041953C и продолжаем, иначе
:00419537 E8B8AAFEFF call 00403FF4 ;
выходит из программы

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00419535(C)
|
:0041953C 8D45F8 lea eax, dword ptr [ebp-08]
:0041953F 8BD3 mov edx, ebx
:00419541 E88EADFEFF call 004042D4
:00419546 8B45F8 mov eax, dword ptr [ebp-08]
:00419549 E84EAEFEFF call 0040439C ;
снова получает длину пароля (в
eax)

:0041954E 85C0 test eax, eax
:00419550 7C0E jl 00419560
:00419552 40 inc eax ;
увеличивает eax на 1
:00419553 33D2 xor edx, edx ;
очищает регистр edx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041955E(C)
|
:00419555 33C9 xor ecx, ecx ;
очищает регистр ecx
:00419557 8A0C13 mov cl, byte ptr [ebx+edx] ;
помещает в cl n-ный символ пароля
:0041955A 03F1 add esi, ecx ;
накапливает сумму в esi
:0041955C 42 inc edx ;
увеличивает edx на 1 (для перебора символов пароля)
:0041955D 48 dec eax ;
уменьшает eax (полученную длину пароля), при eax=0 выход из цикла, иначе
:0041955E 75F5 jne 00419555 ;
прыгает обратно в цикл

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00419550(C)
|
:00419560 8BC6 mov eax, esi ;
помещает в eax, esi(накопленная сумма всех символов)
:00419562 353D880000 xor eax, 0000883D ;
xor'ит eax с 883D hex=34877 dec
:00419567 8BF0 mov esi, eax ;
помещает в esi, перексоренный eax 
:00419569 81F65C010000 xor esi, 0000015C ;
xor'ит esi с 15C hex=348 dec 
:0041956F 81FE768D0000 cmp esi, 00008D76 ;
сравнивает перексоренный esi с константой 8D76 hex=36214 dec, если равно выводит "REGISTRATION KEY ... OK!", иначе
:00419575 751B jne 00419592 ;
прыгает на 00419592 и выводит
"Incorrect"

* Possible StringData Ref from Code Obj ->"REGISTRATION KEY ... OK!"
|
:00419577 68D4954100 push 004195D4

Подведем итоги последней проверки. Программа проверяет длину пароля, если длина не равна 12 выходит.
Далее накапливает сумму всех 12-ти символов пароля, xor'ит ее с 34877 и 348
и с константой 36214, если равно выводит "REGISTRATION KEY ... OK!".

Теперь найдем пароль.
(36214 xor 348) xor 34877 = 1047
1047 - такая должна быть сумма 12-ти символов.
На калькуляторе делим это число на 12
1047/12 ~ 87
Теперь умножим 85 (код символа "U")*11=935
1047-935=112 (код символа "p").

Простыми вычислениями мы нашли один из множества существующих паролей, т.е.
наш пароль будет состоять из 11 символом "U" и одной "p", что в сумме дает
число 1047. Вводим этот пароль "UUUUUUUUUUUp" в программу и получаем "REGISTRATION KEY ...
OK!".

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии