Перейдем к следующему виду проверки,
кнопке "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!".
 
