Недавно закончился конкурс обратной разработки ZeroNight2015, проводимый «Лабораторией Касперского». Сама организация конкурса, с моей точки зрения, хромала, но статья не об этом. На конкурсе была представлена интересная задача под названием «Смартфон», разбору которой и будет посвящена данная серия статей. Эта статья будет посвящена описанию условия задачи и поиску защитного механизма. Вторая статья затронет оптимизацию скорости работы взламываемой программы посредством внедрения X-кода. В третьей статье будет описан процесс поиска ошибок во внедренном коде с использованием юнит-тестирования.
Начнем с описания задачи. На сайте конкурса дано следующее описание задания и возможность скачать .exe файл программы.
После запуска программы видим окно с предложением ввести email и серийный номер.
Задача заключается в том, чтобы узнать серийный номер для собственного email адреса. После решения задачи серийный номер отправляется на проверку с помощью формы на сайте, в которой предварительно указывается собственный email и ник, который будет отображаться в рейтинге.
После ввода случайного серийного номера в crackme программа предупреждает о том, что мой компьютер слишком медленный и я успею состариться прежде чем дождусь результата проверки. После закрытия предупреждающего сообщения программа безнадежно зависает, загружая по полной одно ядро процессора.
Попытка дождаться результата проверки серийного номера обречена на провал и остается только принудительно завершить программу. В этом отчасти уникальность данной задачи. В других задачах этого конкурса результат проверки правильности отображается сразу. Например, в задаче «Кредитная карта» он отображается так:
Самое время забраться под капот взламываемой программы и разобраться что же в ней собственно происходит, почему она зависает и какой серийный номер она ожидает от нас получить. Для этих целей я буду использовать интерактивный дизассемблер IDA Pro, демонстрационную версию которого можно скачать на сайте hex-rays.
Начинать поиск защитного механизма будем через перекрестные ссылки на вызов функции, вызывающей окно с сообщением «Your computer is extremely slow for this operation! You'll be a greybeard when you get the result… ;-)», которое появляется сразу после нажатия на кнопку «Check». Для этого откроем вкладку Imports и найдем функцию MessageBoxW из библиотеки USER32.
Двойным щелчком переходим по ней к определению функции в таблице импорта. Затем открываем список перекрестных ссылок (горячая клавиша <x>).
Достаточно проверить первые три перекрестные ссылки из списка, т. к. последние три элемента списка дублируют первые. Первые два вызова ведут к участкам кода, которые вызывают messageBox с заголовком «Internal Error:». Очевидно, это вывод сообщений о каких-то внутренних ошибках и нам лучше туда не соваться.
.text:00401090 push ebp
.text:00401091 mov ebp, esp
.text:00401093 mov eax, [ebp+8]
.text:00401096 test eax, eax
.text:00401098 jz short loc_4010AA
.text:0040109A push 10h
.text:0040109C push offset aInternalError ; "Internal Error:"
.text:004010A1 push eax
.text:004010A2 push 0
.text:004010A4 call ds:MessageBoxW
.text:004010B0 push ebp
.text:004010B1 mov ebp, esp
.text:004010B3 mov eax, [ebp+lpText]
.text:004010B6 test eax, eax
.text:004010B8 jz short loc_4010CA
.text:004010BA push 10h ; uType
.text:004010BC push offset aInternalError ; "Internal Error:"
.text:004010C1 push eax ; lpText
.text:004010C2 push 0 ; hWnd
.text:004010C4 call ds:MessageBoxW
Третья перекрестная ссылка приводит к искомому вызову функции с параметрами заголовка «Warning» и сообщением «Your computer is extremely slow….».
.text:00404E98 push ebx
.text:00404E99 push offset Caption ; "Warning!"
.text:00404E9E push offset Text ; "Your computer is extremely slow for thi"...
.text:00404EA3 push ebx ; hWnd
.text:00404EA4 call ds:MessageBoxW
Это и есть то место, из которого вызывается окно с предупреждающим сообщением. Вызов происходит из функции sub_404E50.
.text:00404E50
.text:00404E50 sub_404E50 proc near ; CODE XREF: sub_401340+1C5
.text:00404E50
.text:00404E50 var_104 = dword ptr -104h
.text:00404E50 var_100 = byte ptr -100h
.text:00404E50 var_A8 = dword ptr -0A8h
.text:00404E50 var_A4 = byte ptr -0A4h
.text:00404E50 var_58 = byte ptr -58h
.text:00404E50 var_57 = byte ptr -57h
.text:00404E50 var_24 = byte ptr -24h
.text:00404E50 var_23 = dword ptr -23h
.text:00404E50 var_1F = dword ptr -1Fh
.text:00404E50 var_1B = dword ptr -1Bh
.text:00404E50 var_17 = word ptr -17h
.text:00404E50 var_15 = byte ptr -15h
.text:00404E50 var_14 = byte ptr -14h
.text:00404E50 var_13 = dword ptr -13h
.text:00404E50 var_F = dword ptr -0Fh
.text:00404E50 var_B = dword ptr -0Bh
.text:00404E50 var_7 = word ptr -7
.text:00404E50 var_5 = byte ptr -5
.text:00404E50 var_4 = dword ptr -4
.text:00404E50 arg_0 = dword ptr 8
.text:00404E50 arg_4 = dword ptr 0Ch
.text:00404E50 arg_8 = dword ptr 10h
.text:00404E50 arg_C = dword ptr 14h
.text:00404E50
.text:00404E50 push ebp
.text:00404E51 mov ebp, esp
.text:00404E53 sub esp, 104h
.text:00404E59 mov eax, ___security_cookie
.text:00404E5E xor eax, ebp
.text:00404E60 mov [ebp+var_4], eax
.text:00404E63 mov eax, [ebp+arg_8]
.text:00404E66 push ebx
.text:00404E67 push esi
.text:00404E68 mov esi, [ebp+arg_0]
.text:00404E6B xor ebx, ebx
.text:00404E6D push edi
.text:00404E6E mov [ebp+var_104], eax
.text:00404E74 cmp esi, ebx
.text:00404E76 jz loc_404FBE
.text:00404E7C mov edi, [ebp+arg_4]
.text:00404E7F cmp edi, ebx
.text:00404E81 jz loc_404FBE
.text:00404E87 cmp eax, ebx
.text:00404E89 jz loc_404FBE
.text:00404E8F cmp [ebp+arg_C], ebx
.text:00404E92 jz loc_404FBE
.text:00404E98 push ebx ; uType
.text:00404E99 push offset Caption ; "Warning!"
.text:00404E9E push offset Text ; "Your computer is extremely slow for thi"...
.text:00404EA3 push ebx ; hWnd
.text:00404EA4 call ds:MessageBoxW
.text:00404EAA push 4Ch ; size_t
.text:00404EAC lea eax, [ebp+var_A4]
.text:00404EB2 push ebx ; int
.text:00404EB3 push eax ; void *
.text:00404EB4 mov [ebp+var_A8], ebx
.text:00404EBA call _memset
.text:00404EBF push 31h ; size_t
.text:00404EC1 lea ecx, [ebp+var_57]
.text:00404EC4 push ebx ; int
.text:00404EC5 push ecx ; void *
.text:00404EC6 mov [ebp+var_58], bl
.text:00404EC9 call _memset
.text:00404ECE lea edx, [ebp+var_A8]
.text:00404ED4 push edx
.text:00404ED5 call sub_4047C0
.text:00404EDA xor eax, eax
.text:00404EDC mov [ebp+var_13], eax
.text:00404EDF mov [ebp+var_F], eax
.text:00404EE2 mov [ebp+var_B], eax
.text:00404EE5 mov [ebp+var_7], ax
.text:00404EE9 mov [ebp+var_5], al
.text:00404EEC mov [ebp+var_23], eax
.text:00404EEF mov [ebp+var_1F], eax
.text:00404EF2 mov [ebp+var_1B], eax
.text:00404EF5 mov [ebp+var_17], ax
.text:00404EF9 mov [ebp+var_15], al
.text:00404EFC lea eax, [ebp+var_100]
.text:00404F02 push eax
.text:00404F03 mov [ebp+var_14], bl
.text:00404F06 mov [ebp+var_24], bl
.text:00404F09 call sub_401C90
.text:00404F0E push 40h
.text:00404F10 lea ecx, [ebp+var_A8]
.text:00404F16 push ecx
.text:00404F17 lea edx, [ebp+var_100]
.text:00404F1D push edx
.text:00404F1E call sub_402410
.text:00404F23 lea eax, [ebp+var_14]
.text:00404F26 push eax
.text:00404F27 lea ecx, [ebp+var_100]
.text:00404F2D push ecx
.text:00404F2E call sub_402540
.text:00404F33 lea edx, [ebp+var_100]
.text:00404F39 push edx
.text:00404F3A call sub_401C90
.text:00404F3F push edi
.text:00404F40 lea eax, [ebp+var_100]
.text:00404F46 push esi
.text:00404F47 push eax
.text:00404F48 call sub_402410
.text:00404F4D add esp, 44h
.text:00404F50 lea ecx, [ebp+var_24]
.text:00404F53 push ecx
.text:00404F54 lea edx, [ebp+var_100]
.text:00404F5A push edx
.text:00404F5B call sub_402540
.text:00404F60 add esp, 8
.text:00404F63 xor esi, esi
.text:00404F65 lea edi, [ebp+var_58]
.text:00404F68 jmp short loc_404F70
.text:00404F68 ; ---------------------------------------------------------------------------
.text:00404F6A align 10h
.text:00404F70
.text:00404F70 loc_404F70: ; CODE XREF: sub_404E50+118
.text:00404F70 ; sub_404E50+143
.text:00404F70 mov al, [ebp+esi+var_24]
.text:00404F74 xor [ebp+esi+var_14], al
.text:00404F78 movzx ecx, [ebp+esi+var_14]
.text:00404F7D push ecx
.text:00404F7E push offset a02x ; "%02X"
.text:00404F83 push edi ; char *
.text:00404F84 call _sprintf
.text:00404F89 inc esi
.text:00404F8A add esp, 0Ch
.text:00404F8D add edi, 2
.text:00404F90 cmp esi, 10h
.text:00404F93 jl short loc_404F70
.text:00404F95 mov eax, [ebp+var_104]
.text:00404F9B lea edx, [ebp+var_58]
.text:00404F9E push edx ; char *
.text:00404F9F push eax ; char *
.text:00404FA0 call __stricmp
.text:00404FA5 add esp, 8
.text:00404FA8 pop edi
.text:00404FA9 test eax, eax
.text:00404FAB pop esi
.text:00404FAC setz al
.text:00404FAF pop ebx
.text:00404FB0 mov ecx, [ebp+var_4]
.text:00404FB3 xor ecx, ebp
.text:00404FB5 call @__security_check_cookie@4 ; __security_check_cookie(x)
.text:00404FBA mov esp, ebp
.text:00404FBC pop ebp
.text:00404FBD retn
.text:00404FBE ; ---------------------------------------------------------------------------
.text:00404FBE
.text:00404FBE loc_404FBE: ; CODE XREF: sub_404E50+26
.text:00404FBE ; sub_404E50+31 ...
.text:00404FBE mov ecx, [ebp+var_4]
.text:00404FC1 pop edi
.text:00404FC2 pop esi
.text:00404FC3 xor ecx, ebp
.text:00404FC5 xor al, al
.text:00404FC7 pop ebx
.text:00404FC8 call @__security_check_cookie@4 ; __security_check_cookie(x)
.text:00404FCD mov esp, ebp
.text:00404FCF pop ebp
.text:00404FD0 retn
.text:00404FD0 sub_404E50 endp
.text:00404FD0
Назначение функции сразу сложно понять. Пока только очевидно, что функция принимает 4 аргумента. Вначале аргументы проверяются на неравенство нулю. Если же хоть один из них равен нулю, то управление передается на ветку loc_404FBE, которая завершает выполнение функции с возвратом значения 0 в регистре al.
Попробуем взглянуть на код, вызывающий функцию sub_404E50. Для этого перейдем по перекрестной ссылке sub_401340+1C5.
.text:00401340
.text:00401340 sub_401340 proc near ; CODE XREF: DialogFunc+11E
.text:00401340
.text:00401340 var_10 = dword ptr -10h
.text:00401340 var_C = dword ptr -0Ch
.text:00401340 var_4 = dword ptr -4
.text:00401340
.text:00401340 push ebp
.text:00401341 mov ebp, esp
.text:00401343 push 0FFFFFFFFh
.text:00401345 push offset sub_410040
.text:0040134A mov eax, large fs:0
.text:00401350 push eax
.text:00401351 push ecx
.text:00401352 push ebx
.text:00401353 push esi
.text:00401354 push edi
.text:00401355 mov eax, ___security_cookie
.text:0040135A xor eax, ebp
.text:0040135C push eax
.text:0040135D lea eax, [ebp+var_C]
.text:00401360 mov large fs:0, eax
.text:00401366 mov [ebp+var_10], esp
.text:00401369 mov esi, ecx
.text:0040136B mov eax, [esi+54h]
.text:0040136E xor edi, edi
.text:00401370 push eax
.text:00401371 mov [ebp+var_4], edi
.text:00401374 call sub_4077E5
.text:00401379 mov eax, [esi+4Ch]
.text:0040137C push eax
.text:0040137D mov [esi+54h], edi
.text:00401380 call sub_4077E5
.text:00401385 mov eax, [esi+50h]
.text:00401388 push eax
.text:00401389 mov [esi+4Ch], edi
.text:0040138C call sub_4077E5
.text:00401391 mov eax, [esi+48h]
.text:00401394 push eax
.text:00401395 mov [esi+50h], edi
.text:00401398 call sub_4077E5
.text:0040139D mov eax, [esi+18h]
.text:004013A0 add esp, 10h
.text:004013A3 push eax ; hWnd
.text:004013A4 mov [esi+48h], edi
.text:004013A7 call ds:GetWindowTextLengthW
.text:004013AD mov edi, eax
.text:004013AF xor ecx, ecx
.text:004013B1 lea ebx, [edi+1]
.text:004013B4 mov eax, ebx
.text:004013B6 mov edx, 2
.text:004013BB mul edx
.text:004013BD seto cl
.text:004013C0 neg ecx
.text:004013C2 or ecx, eax
.text:004013C4 push ecx
.text:004013C5 call unknown_libname_2 ; Microsoft VisualC 2-11/net runtime
.text:004013CA mov [esi+48h], eax
.text:004013CD xor ecx, ecx
.text:004013CF mov [eax+edi*2], cx
.text:004013D3 mov edx, [esi+48h]
.text:004013D6 add esp, 4
.text:004013D9 xor eax, eax
.text:004013DB mov [edx], ax
.text:004013DE mov ecx, [esi+48h]
.text:004013E1 mov edx, [esi+18h]
.text:004013E4 push ebx ; nMaxCount
.text:004013E5 push ecx ; lpString
.text:004013E6 push edx ; hWnd
.text:004013E7 call ds:GetWindowTextW
.text:004013ED mov eax, [esi+1Ch]
.text:004013F0 push eax ; hWnd
.text:004013F1 call ds:GetWindowTextLengthW
.text:004013F7 mov ebx, eax
.text:004013F9 xor ecx, ecx
.text:004013FB lea eax, [ebx+1]
.text:004013FE mov edx, 2
.text:00401403 mul edx
.text:00401405 seto cl
.text:00401408 neg ecx
.text:0040140A or ecx, eax
.text:0040140C push ecx
.text:0040140D call unknown_libname_2 ; Microsoft VisualC 2-11/net runtime
.text:00401412 mov [esi+50h], eax
.text:00401415 xor ecx, ecx
.text:00401417 mov [eax+ebx*2], cx
.text:0040141B mov edx, [esi+50h]
.text:0040141E xor eax, eax
.text:00401420 mov [edx], ax
.text:00401423 mov ecx, [esi+50h]
.text:00401426 mov edx, [esi+1Ch]
.text:00401429 add esp, 4
.text:0040142C lea eax, [ebx+1]
.text:0040142F push eax ; nMaxCount
.text:00401430 push ecx ; lpString
.text:00401431 push edx ; hWnd
.text:00401432 call ds:GetWindowTextW
.text:00401438 mov eax, [esi+50h]
.text:0040143B mov ecx, [esi+48h]
.text:0040143E push 0
.text:00401440 push 0
.text:00401442 push ebx
.text:00401443 push eax
.text:00401444 push edi
.text:00401445 push ecx
.text:00401446 push 7Fh
.text:00401448 push esi
.text:00401449 call sub_4012F0
.text:0040144E add esp, 20h
.text:00401451 test eax, eax
.text:00401453 jnz short loc_4014A7
.text:00401455 mov edx, [esi+38h]
.text:00401458 push edx ; lParam
.text:00401459 push eax ; wParam
.text:0040145A mov eax, [esi+28h]
.text:0040145D push 172h ; Msg
.text:00401462 push eax ; hWnd
.text:00401463 call ds:SendMessageW
.text:00401469 mov ecx, [esi+2Ch]
.text:0040146C push offset String ; "Serial is invalid"
.text:00401471 push ecx ; hWnd
.text:00401472 call ds:SetWindowTextW
.text:00401478 mov edx, [esi+28h]
.text:0040147B mov edi, ds:ShowWindow
.text:00401481 push 5 ; nCmdShow
.text:00401483 push edx ; hWnd
.text:00401484 call edi ; ShowWindow
.text:00401486 mov eax, [esi+2Ch]
.text:00401489 push 5 ; nCmdShow
.text:0040148B push eax ; hWnd
.text:0040148C call edi ; ShowWindow
.text:0040148E mov dword ptr [esi+58h], 0
.text:00401495 mov ecx, [ebp+var_C]
.text:00401498 mov large fs:0, ecx
.text:0040149F pop ecx
.text:004014A0 pop edi
.text:004014A1 pop esi
.text:004014A2 pop ebx
.text:004014A3 mov esp, ebp
.text:004014A5 pop ebp
.text:004014A6 retn
.text:004014A7 ; ---------------------------------------------------------------------------
.text:004014A7
.text:004014A7 loc_4014A7: ; CODE XREF: sub_401340+113
.text:004014A7 lea eax, [edi+1]
.text:004014AA push eax
.text:004014AB call unknown_libname_2 ; Microsoft VisualC 2-11/net runtime
.text:004014B0 mov [esi+4Ch], eax
.text:004014B3 mov byte ptr [eax+edi], 0
.text:004014B7 mov ecx, [esi+4Ch]
.text:004014BA add esp, 4
.text:004014BD mov byte ptr [ecx], 0
.text:004014C0 mov edx, [esi+48h]
.text:004014C3 lea eax, [edi+1]
.text:004014C6 push eax ; size_t
.text:004014C7 mov eax, [esi+4Ch]
.text:004014CA push edx ; wchar_t *
.text:004014CB push eax ; char *
.text:004014CC call _wcstombs
.text:004014D1 lea eax, [ebx+1]
.text:004014D4 push eax
.text:004014D5 call unknown_libname_2 ; Microsoft VisualC 2-11/net runtime
.text:004014DA mov [esi+54h], eax
.text:004014DD mov byte ptr [eax+ebx], 0
.text:004014E1 mov ecx, [esi+54h]
.text:004014E4 add esp, 10h
.text:004014E7 mov byte ptr [ecx], 0
.text:004014EA mov edx, [esi+50h]
.text:004014ED lea eax, [ebx+1]
.text:004014F0 push eax ; size_t
.text:004014F1 mov eax, [esi+54h]
.text:004014F4 push edx ; wchar_t *
.text:004014F5 push eax ; char *
.text:004014F6 call _wcstombs
.text:004014FB mov ecx, [esi+54h]
.text:004014FE mov edx, [esi+4Ch]
.text:00401501 push ebx
.text:00401502 push ecx
.text:00401503 push edi
.text:00401504 push edx
.text:00401505 call sub_404E50
.text:0040150A mov bl, al
.text:0040150C add esp, 1Ch
.text:0040150F test bl, bl
.text:00401511 jz short loc_40151D
.text:00401513 mov eax, [esi+34h]
.text:00401516 mov edi, offset aSerialIsValid ; "Serial is valid"
.text:0040151B jmp short loc_401525
.text:0040151D ; ---------------------------------------------------------------------------
.text:0040151D
.text:0040151D loc_40151D: ; CODE XREF: sub_401340+1D1
.text:0040151D mov eax, [esi+38h]
.text:00401520 mov edi, offset String ; "Serial is invalid"
.text:00401525
.text:00401525 loc_401525: ; CODE XREF: sub_401340+1DB
.text:00401525 push eax ; lParam
.text:00401526 mov eax, [esi+28h]
.text:00401529 push 0 ; wParam
.text:0040152B push 172h ; Msg
.text:00401530 push eax ; hWnd
.text:00401531 call ds:SendMessageW
.text:00401537 mov ecx, [esi+2Ch]
.text:0040153A push edi ; lpString
.text:0040153B push ecx ; hWnd
.text:0040153C call ds:SetWindowTextW
.text:00401542 mov edx, [esi+28h]
.text:00401545 mov edi, ds:ShowWindow
.text:0040154B push 5 ; nCmdShow
.text:0040154D push edx ; hWnd
.text:0040154E call edi ; ShowWindow
.text:00401550 mov eax, [esi+2Ch]
.text:00401553 push 5 ; nCmdShow
.text:00401555 push eax ; hWnd
.text:00401556 call edi ; ShowWindow
.text:00401558 movzx ecx, bl
.text:0040155B mov [esi+58h], ecx
.text:0040155E mov ecx, [ebp+var_C]
.text:00401561 mov large fs:0, ecx
.text:00401568 pop ecx
.text:00401569 pop edi
.text:0040156A pop esi
.text:0040156B pop ebx
.text:0040156C mov esp, ebp
.text:0040156E pop ebp
.text:0040156F retn
.text:0040156F sub_401340 endp
.text:0040156F
Для наглядности перейдем в режим отображения graph view, нажав пробел.
Теперь ясно видно, что от возвращаемого функцией sub_404E50 значения зависит выводимое пользователю сообщение о проверке серийного номера. В случае, если функция возвращает значение 0, то выводится сообщение «Serial is invalid», иначе выводится сообщение «Serial is valid». Однако в нашем случае программа не выводит ни одного из сообщений, т.к. зависает где-то раньше.
Ставим брейкпоинт (<F2>) в начале функции по адресу .text:00401340, запускаем отладку (<F9>) и, используя трассировку (<F8>), находим функцию, которая завешивает выполнение программы. Этой функцией довольно предсказуемо оказывается sub_404E50. Чтобы точно удостовериться в этом, повторно запускаем отладку, поставив брейкпоинт на вызывающей функцию строке .text:00401505, но вместо захода в функцию переходим на следующую команду (ставим курсор на следующую команду и нажимаем <ctrl + N>). После чего продолжаем выполнение программы и видим появившееся сообщение о том, что серийный номер является верным.
Так происходит, потому что в регистре ах перед вызовом функции sub_404E50 находилось ненулевое значение, иначе выводилось бы сообщение о неверном серийном номере.
Если бы нам этого было достаточно, то можно было бы в шестнадцатеричном редакторе изменить инструкцию «call sub_404E50» на несколько инструкций «nop» и программа бы принимала любой серийный номер за действительный, но наша задача сгенерировать серийный номер для нашего email. Поэтому продолжим анализ.
Для начала разберемся с аргументами, которые передаются в функцию sub_404E50. В первом блоке инструкций .text:00401340-00401453 дважды вызывается функция GetWindowTextW с разными параметрами hWnd. С помощью отладчика узнаем, что первый вызов получает юникодную строку поля email и сохраняет её по адресу [esi+48h], являющимся предположительно полем объекта, переданного по указателю ecx.
.text:004013DE mov ecx, [esi+48h]
.text:004013E1 mov edx, [esi+18h]
.text:004013E4 push ebx ; nMaxCount
.text:004013E5 push ecx ; lpString
.text:004013E6 push edx ; hWnd
.text:004013E7 call ds:GetWindowTextW
Аналогично второй вызов сохраняет строку серийного номера по адресу [esi+50h].
.text:00401423 mov ecx, [esi+50h]
.text:00401426 mov edx, [esi+1Ch]
.text:00401429 add esp, 4
.text:0040142C lea eax, [ebx+1]
.text:0040142F push eax ; nMaxCount
.text:00401430 push ecx ; lpString
.text:00401431 push edx ; hWnd
.text:00401432 call ds:GetWindowTextW
Экспериментальным путем обнаруживаем, что управление на ветку .text:00401455 передается в том случае, если серийный номер или email содержит расширенные юникодные символы, например кириллицу.
Если расширенных юникодных символов не обнаружено, то строки преобразуются из wchar_t* в char* с помощью функции wcstombs. Преобразованные строки email'а и серийного номера размещаются по адресам [esi+4Ch] и [esi+54h] соответственно. При этом в регистре edi хранится длина строки email, а в регистре ebx длина серийного номера.
.text:004014C0 mov edx, [esi+48h]
.text:004014C3 lea eax, [edi+1]
.text:004014C6 push eax ; size_t
.text:004014C7 mov eax, [esi+4Ch]
.text:004014CA push edx ; wchar_t *
.text:004014CB push eax ; char *
.text:004014CC call _wcstombs
.text:004014EA mov edx, [esi+50h]
.text:004014ED lea eax, [ebx+1]
.text:004014F0 push eax ; size_t
.text:004014F1 mov eax, [esi+54h]
.text:004014F4 push edx ; wchar_t *
.text:004014F5 push eax ; char *
.text:004014F6 call _wcstombs
.text:004014FB mov ecx, [esi+54h]
.text:004014FE mov edx, [esi+4Ch]
.text:00401501 push ebx
.text:00401502 push ecx
.text:00401503 push edi
.text:00401504 push edx
.text:00401505 call sub_404E50
Таким образом, становится понятно, что функция sub_404E50 предназначена для проверки серийного номера, и её сигнатура выглядит примерно так:
bool sub_404E50(char * email_str, size_t email_size, char *serial_str, size_t serial_size);
Теперь время разобраться как же эта функция устроена. Для начала определим в каком месте она зависает, для этого поставим брейкпоинт внутри и потрассируем. Трассировка показала, что зависание происходит по адресу .text:00404ED5 на вызове функции sub_4047C0. Функция sub_4047C0 принимает один аргумент: указатель на локальную переменную var_A8. Содержимое функции sub_4047C0 пугающее и его анализ будет рассмотрен в следующей статье, но для любознательных привожу её код и графическое представление.
.text:004047C0
.text:004047C0 sub_4047C0 proc near ; CODE XREF: sub_404E50+85
.text:004047C0
.text:004047C0 var_EC = dword ptr -0ECh
.text:004047C0 var_E8 = dword ptr -0E8h
.text:004047C0 var_E4 = dword ptr -0E4h
.text:004047C0 var_E0 = dword ptr -0E0h
.text:004047C0 var_D8 = dword ptr -0D8h
.text:004047C0 var_D4 = dword ptr -0D4h
.text:004047C0 var_D0 = dword ptr -0D0h
.text:004047C0 var_CC = dword ptr -0CCh
.text:004047C0 var_C8 = dword ptr -0C8h
.text:004047C0 var_C4 = dword ptr -0C4h
.text:004047C0 var_BC = dword ptr -0BCh
.text:004047C0 var_B8 = dword ptr -0B8h
.text:004047C0 var_B4 = dword ptr -0B4h
.text:004047C0 var_B0 = dword ptr -0B0h
.text:004047C0 var_AC = dword ptr -0ACh
.text:004047C0 var_A8 = dword ptr -0A8h
.text:004047C0 var_A4 = dword ptr -0A4h
.text:004047C0 var_A0 = dword ptr -0A0h
.text:004047C0 var_98 = dword ptr -98h
.text:004047C0 var_94 = dword ptr -94h
.text:004047C0 var_90 = dword ptr -90h
.text:004047C0 var_80 = dword ptr -80h
.text:004047C0 var_7C = dword ptr -7Ch
.text:004047C0 var_75 = byte ptr -75h
.text:004047C0 var_74 = byte ptr -74h
.text:004047C0 var_73 = byte ptr -73h
.text:004047C0 var_10 = dword ptr -10h
.text:004047C0 var_C = dword ptr -0Ch
.text:004047C0 var_4 = dword ptr -4
.text:004047C0 arg_0 = dword ptr 8
.text:004047C0
.text:004047C0 push ebp
.text:004047C1 mov ebp, esp
.text:004047C3 push 0FFFFFFFFh
.text:004047C5 push offset sub_41065C
.text:004047CA mov eax, large fs:0
.text:004047D0 push eax
.text:004047D1 sub esp, 0E0h
.text:004047D7 mov eax, ___security_cookie
.text:004047DC xor eax, ebp
.text:004047DE mov [ebp+var_10], eax
.text:004047E1 push ebx
.text:004047E2 push esi
.text:004047E3 push edi
.text:004047E4 push eax
.text:004047E5 lea eax, [ebp+var_C]
.text:004047E8 mov large fs:0, eax
.text:004047EE mov eax, [ebp+arg_0]
.text:004047F1 push 1Ch ; size_t
.text:004047F3 mov [ebp+var_D8], eax
.text:004047F9 call ??2@YAPAXI@Z ; operator new(uint)
.text:004047FE mov esi, eax
.text:00404800 add esp, 4
.text:00404803 mov [ebp+var_B4], esi
.text:00404809 xor edi, edi
.text:0040480B mov [ebp+var_4], edi
.text:0040480E cmp esi, edi
.text:00404810 jz short loc_40488D
.text:00404812 mov dword ptr [esi], offset off_4117D4
.text:00404818 push 30h ; size_t
.text:0040481A mov [esi+0Ch], edi
.text:0040481D call ??2@YAPAXI@Z ; operator new(uint)
.text:00404822 add esp, 4
.text:00404825 cmp eax, edi
.text:00404827 jz short loc_40485A
.text:00404829 mov [esi+8], eax
.text:0040482C mov [eax], eax
.text:0040482E mov eax, [esi+8]
.text:00404831 mov [eax+4], eax
.text:00404834 mov eax, [esi+8]
.text:00404837 mov [eax+8], eax
.text:0040483A mov ecx, [esi+8]
.text:0040483D mov byte ptr [ecx+2Ch], 1
.text:00404841 mov edx, [esi+8]
.text:00404844 mov byte ptr [edx+2Dh], 1
.text:00404848 mov dword ptr [esi+14h], 200h
.text:0040484F mov [esi+18h], edi
.text:00404852 mov [ebp+var_98], esi
.text:00404858 jmp short loc_404893
.text:0040485A ; ---------------------------------------------------------------------------
.text:0040485A
.text:0040485A loc_40485A: ; CODE XREF: sub_4047C0+67
.text:0040485A lea eax, [ebp+var_94]
.text:00404860 push eax
.text:00404861 lea ecx, [ebp+var_A4]
.text:00404867 mov [ebp+var_94], edi
.text:0040486D call ??0exception@std@@QAE@ABQBD@Z ; std::exception::exception(char const * const &)
.text:00404872 push offset unk_413D14
.text:00404877 lea ecx, [ebp+var_A4]
.text:0040487D push ecx
.text:0040487E mov [ebp+var_A4], offset off_4116C0
.text:00404888 call __CxxThrowException@8 ; _CxxThrowException(x,x)
.text:0040488D ; ---------------------------------------------------------------------------
.text:0040488D
.text:0040488D loc_40488D: ; CODE XREF: sub_4047C0+50
.text:0040488D mov [ebp+var_98], edi
.text:00404893
.text:00404893 loc_404893: ; CODE XREF: sub_4047C0+98
.text:00404893 mov [ebp+var_A8], edi
.text:00404899 mov [ebp+var_A4], edi
.text:0040489F mov [ebp+var_A0], edi
.text:004048A5 mov [ebp+var_4], 1
.text:004048AC mov [ebp+var_CC], edi
.text:004048B2 mov [ebp+var_C8], edi
.text:004048B8 mov [ebp+var_C4], edi
.text:004048BE push 18h ; size_t
.text:004048C0 mov byte ptr [ebp+var_4], 2
.text:004048C4 call ??2@YAPAXI@Z ; operator new(uint)
.text:004048C9 add esp, 4
.text:004048CC mov [ebp+var_94], eax
.text:004048D2 mov byte ptr [ebp+var_4], 3
.text:004048D6 cmp eax, edi
.text:004048D8 jz short loc_4048EB
.text:004048DA push 60h
.text:004048DC mov ecx, eax
.text:004048DE call sub_4033D0
.text:004048E3 mov [ebp+var_B8], eax
.text:004048E9 jmp short loc_4048F1
.text:004048EB ; ---------------------------------------------------------------------------
.text:004048EB
.text:004048EB loc_4048EB: ; CODE XREF: sub_4047C0+118
.text:004048EB mov [ebp+var_B8], edi
.text:004048F1
.text:004048F1 loc_4048F1: ; CODE XREF: sub_4047C0+129
.text:004048F1 push 18h ; size_t
.text:004048F3 mov byte ptr [ebp+var_4], 2
.text:004048F7 call ??2@YAPAXI@Z ; operator new(uint)
.text:004048FC add esp, 4
.text:004048FF mov [ebp+var_94], eax
.text:00404905 mov byte ptr [ebp+var_4], 4
.text:00404909 cmp eax, edi
.text:0040490B jz short loc_404921
.text:0040490D push 200h
.text:00404912 mov ecx, eax
.text:00404914 call sub_4033D0
.text:00404919 mov [ebp+var_AC], eax
.text:0040491F jmp short loc_404927
.text:00404921 ; ---------------------------------------------------------------------------
.text:00404921
.text:00404921 loc_404921: ; CODE XREF: sub_4047C0+14B
.text:00404921 mov [ebp+var_AC], edi
.text:00404927
.text:00404927 loc_404927: ; CODE XREF: sub_4047C0+15F
.text:00404927 mov ebx, [ebp+var_C8]
.text:0040492D mov [ebp+var_BC], edi
.text:00404933 mov edi, [ebp+var_98]
.text:00404939 mov byte ptr [ebp+var_4], 2
.text:0040493D
.text:0040493D loc_40493D: ; CODE XREF: sub_4047C0+4B9
.text:0040493D mov eax, [ebp+var_BC]
.text:00404943 inc eax
.text:00404944 mov [ebp+var_94], eax
.text:0040494A test eax, eax
.text:0040494C jle loc_404B8A
.text:00404952 mov ecx, [ebp+var_A4]
.text:00404958 sub ecx, [ebp+var_A8]
.text:0040495E mov ebx, [ebp+var_AC]
.text:00404964 mov eax, 92492493h
.text:00404969 imul ecx
.text:0040496B add edx, ecx
.text:0040496D sar edx, 4
.text:00404970 mov eax, edx
.text:00404972 shr eax, 1Fh
.text:00404975 add eax, edx
.text:00404977 mov edx, [ebp+var_94]
.text:0040497D mov [ebp+var_D4], eax
.text:00404983 mov [ebp+var_B4], edx
.text:00404989 lea esp, [esp+0]
.text:00404990
.text:00404990 loc_404990: ; CODE XREF: sub_4047C0+3BE
.text:00404990 push 63h ; size_t
.text:00404992 lea eax, [ebp+var_73]
.text:00404995 push 0 ; int
.text:00404997 push eax ; void *
.text:00404998 mov [ebp+var_74], 0
.text:0040499C call _memset
.text:004049A1 add esp, 0Ch
.text:004049A4 xor esi, esi
.text:004049A6 call _rand
.text:004049AB cdq
.text:004049AC mov ecx, 28h
.text:004049B1 idiv ecx
.text:004049B3 add edx, 14h
.text:004049B6 test edx, edx
.text:004049B8 jle short loc_4049E9
.text:004049BA lea ebx, [ebx+0]
.text:004049C0
.text:004049C0 loc_4049C0: ; CODE XREF: sub_4047C0+227
.text:004049C0 call _rand
.text:004049C5 cdq
.text:004049C6 mov ecx, 60h
.text:004049CB idiv ecx
.text:004049CD inc esi
.text:004049CE add dl, 20h
.text:004049D1 mov [ebp+esi+var_75], dl
.text:004049D5 call _rand
.text:004049DA cdq
.text:004049DB mov ecx, 28h
.text:004049E0 idiv ecx
.text:004049E2 add edx, 14h
.text:004049E5 cmp esi, edx
.text:004049E7 jl short loc_4049C0
.text:004049E9
.text:004049E9 loc_4049E9: ; CODE XREF: sub_4047C0+1F8
.text:004049E9 lea eax, [ebp+var_74]
.text:004049EC mov [ebp+var_7C], 0Fh
.text:004049F3 mov [ebp+var_80], 0
.text:004049FA mov byte ptr [ebp+var_90], 0
.text:00404A01 lea edx, [eax+1]
.text:00404A04
.text:00404A04 loc_404A04: ; CODE XREF: sub_4047C0+249
.text:00404A04 mov cl, [eax]
.text:00404A06 inc eax
.text:00404A07 test cl, cl
.text:00404A09 jnz short loc_404A04
.text:00404A0B sub eax, edx
.text:00404A0D push eax ; size_t
.text:00404A0E lea edx, [ebp+var_74]
.text:00404A11 push edx ; void *
.text:00404A12 lea ecx, [ebp+var_90]
.text:00404A18 call sub_405BB0
.text:00404A1D mov eax, [edi]
.text:00404A1F mov edx, [eax+4]
.text:00404A22 lea ecx, [ebp+var_90]
.text:00404A28 push ecx
.text:00404A29 mov ecx, edi
.text:00404A2B mov byte ptr [ebp+var_4], 5
.text:00404A2F call edx
.text:00404A31 cmp [ebp+var_7C], 10h
.text:00404A35 mov byte ptr [ebp+var_4], 2
.text:00404A39 jb short loc_404A4A
.text:00404A3B mov eax, [ebp+var_90]
.text:00404A41 push eax ; void *
.text:00404A42 call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404A47 add esp, 4
.text:00404A4A
.text:00404A4A loc_404A4A: ; CODE XREF: sub_4047C0+279
.text:00404A4A cmp [ebp+var_D4], 0
.text:00404A51 jbe loc_404B10
.text:00404A57 mov ecx, [ebp+var_D4]
.text:00404A5D mov esi, [ebp+var_A8]
.text:00404A63 mov [ebp+var_D0], ecx
.text:00404A69 lea esp, [esp+0]
.text:00404A70
.text:00404A70 loc_404A70: ; CODE XREF: sub_4047C0+34A
.text:00404A70 cmp [ebp+var_BC], 3
.text:00404A77 jl short loc_404A8A
.text:00404A79 mov ecx, [ebp+var_B8]
.text:00404A7F mov edx, [ecx]
.text:00404A81 mov eax, [edx+8]
.text:00404A84 call eax
.text:00404A86 test al, al
.text:00404A88 jz short loc_404B01
.text:00404A8A
.text:00404A8A loc_404A8A: ; CODE XREF: sub_4047C0+2B7
.text:00404A8A lea eax, [ebp+var_74]
.text:00404A8D mov [ebp+var_7C], 0Fh
.text:00404A94 mov [ebp+var_80], 0
.text:00404A9B mov byte ptr [ebp+var_90], 0
.text:00404AA2 lea edx, [eax+1]
.text:00404AA5
.text:00404AA5 loc_404AA5: ; CODE XREF: sub_4047C0+2EA
.text:00404AA5 mov cl, [eax]
.text:00404AA7 inc eax
.text:00404AA8 test cl, cl
.text:00404AAA jnz short loc_404AA5
.text:00404AAC sub eax, edx
.text:00404AAE push eax ; size_t
.text:00404AAF lea ecx, [ebp+var_74]
.text:00404AB2 push ecx ; void *
.text:00404AB3 lea ecx, [ebp+var_90]
.text:00404AB9 call sub_405BB0
.text:00404ABE mov edx, [ebx]
.text:00404AC0 mov edx, [edx+4]
.text:00404AC3 sub esp, 14h
.text:00404AC6 mov eax, esp
.text:00404AC8 mov [ebp+var_B0], esp
.text:00404ACE push eax
.text:00404ACF mov ecx, ebx
.text:00404AD1 mov byte ptr [ebp+var_4], 6
.text:00404AD5 call edx
.text:00404AD7 mov eax, [edi]
.text:00404AD9 mov edx, [eax+8]
.text:00404ADC lea ecx, [ebp+var_90]
.text:00404AE2 push ecx
.text:00404AE3 push esi
.text:00404AE4 mov ecx, edi
.text:00404AE6 call edx
.text:00404AE8 cmp [ebp+var_7C], 10h
.text:00404AEC mov byte ptr [ebp+var_4], 2
.text:00404AF0 jb short loc_404B01
.text:00404AF2 mov eax, [ebp+var_90]
.text:00404AF8 push eax ; void *
.text:00404AF9 call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404AFE add esp, 4
.text:00404B01
.text:00404B01 loc_404B01: ; CODE XREF: sub_4047C0+2C8
.text:00404B01 ; sub_4047C0+330
.text:00404B01 add esi, 1Ch
.text:00404B04 dec [ebp+var_D0]
.text:00404B0A jnz loc_404A70
.text:00404B10
.text:00404B10 loc_404B10: ; CODE XREF: sub_4047C0+291
.text:00404B10 lea eax, [ebp+var_74]
.text:00404B13 mov [ebp+var_7C], 0Fh
.text:00404B1A mov [ebp+var_80], 0
.text:00404B21 mov byte ptr [ebp+var_90], 0
.text:00404B28 lea edx, [eax+1]
.text:00404B2B jmp short loc_404B30
.text:00404B2B ; ---------------------------------------------------------------------------
.text:00404B2D align 10h
.text:00404B30
.text:00404B30 loc_404B30: ; CODE XREF: sub_4047C0+36B
.text:00404B30 ; sub_4047C0+375
.text:00404B30 mov cl, [eax]
.text:00404B32 inc eax
.text:00404B33 test cl, cl
.text:00404B35 jnz short loc_404B30
.text:00404B37 sub eax, edx
.text:00404B39 push eax ; size_t
.text:00404B3A lea ecx, [ebp+var_74]
.text:00404B3D push ecx ; void *
.text:00404B3E lea ecx, [ebp+var_90]
.text:00404B44 call sub_405BB0
.text:00404B49 lea edx, [ebp+var_90]
.text:00404B4F push edx
.text:00404B50 lea ecx, [ebp+var_CC]
.text:00404B56 mov byte ptr [ebp+var_4], 7
.text:00404B5A call sub_4072B0
.text:00404B5F cmp [ebp+var_7C], 10h
.text:00404B63 mov byte ptr [ebp+var_4], 2
.text:00404B67 jb short loc_404B78
.text:00404B69 mov eax, [ebp+var_90]
.text:00404B6F push eax ; void *
.text:00404B70 call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404B75 add esp, 4
.text:00404B78
.text:00404B78 loc_404B78: ; CODE XREF: sub_4047C0+3A7
.text:00404B78 dec [ebp+var_B4]
.text:00404B7E jnz loc_404990
.text:00404B84 mov ebx, [ebp+var_C8]
.text:00404B8A
.text:00404B8A loc_404B8A: ; CODE XREF: sub_4047C0+18C
.text:00404B8A mov ecx, [ebp+var_A4]
.text:00404B90 cmp [ebp+var_A8], ecx
.text:00404B96 jz short loc_404BF9
.text:00404B98 mov edx, [ebp+var_B0]
.text:00404B9E mov eax, [ebp+var_A8]
.text:00404BA4 push edx
.text:00404BA5 push eax ; void *
.text:00404BA6 mov eax, ecx
.text:00404BA8 push eax ; int
.text:00404BA9 push eax ; int
.text:00404BAA call sub_406140
.text:00404BAF mov edi, eax
.text:00404BB1 add esp, 10h
.text:00404BB4 mov esi, edi
.text:00404BB6 cmp edi, [ebp+var_A4]
.text:00404BBC jz short loc_404BED
.text:00404BBE mov edi, edi
.text:00404BC0
.text:00404BC0 loc_404BC0: ; CODE XREF: sub_4047C0+42B
.text:00404BC0 cmp dword ptr [esi+14h], 10h
.text:00404BC4 jb short loc_404BD1
.text:00404BC6 mov eax, [esi]
.text:00404BC8 push eax ; void *
.text:00404BC9 call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404BCE add esp, 4
.text:00404BD1
.text:00404BD1 loc_404BD1: ; CODE XREF: sub_4047C0+404
.text:00404BD1 mov dword ptr [esi+14h], 0Fh
.text:00404BD8 mov dword ptr [esi+10h], 0
.text:00404BDF mov byte ptr [esi], 0
.text:00404BE2 add esi, 1Ch
.text:00404BE5 cmp esi, [ebp+var_A4]
.text:00404BEB jnz short loc_404BC0
.text:00404BED
.text:00404BED loc_404BED: ; CODE XREF: sub_4047C0+3FC
.text:00404BED mov [ebp+var_A4], edi
.text:00404BF3 mov edi, [ebp+var_98]
.text:00404BF9
.text:00404BF9 loc_404BF9: ; CODE XREF: sub_4047C0+3D6
.text:00404BF9 lea ecx, [ebp+var_CC]
.text:00404BFF push ecx
.text:00404C00 lea ecx, [ebp+var_A8]
.text:00404C06 call sub_406F10
.text:00404C0B cmp [ebp+var_CC], ebx
.text:00404C11 jz short loc_404C6A
.text:00404C13 mov edx, [ebp+var_B0]
.text:00404C19 mov eax, [ebp+var_CC]
.text:00404C1F push edx
.text:00404C20 push eax ; void *
.text:00404C21 push ebx ; int
.text:00404C22 push ebx ; int
.text:00404C23 call sub_406140
.text:00404C28 mov edi, eax
.text:00404C2A add esp, 10h
.text:00404C2D mov esi, edi
.text:00404C2F cmp edi, ebx
.text:00404C31 jz short loc_404C5C
.text:00404C33
.text:00404C33 loc_404C33: ; CODE XREF: sub_4047C0+49A
.text:00404C33 cmp dword ptr [esi+14h], 10h
.text:00404C37 jb short loc_404C44
.text:00404C39 mov eax, [esi]
.text:00404C3B push eax ; void *
.text:00404C3C call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404C41 add esp, 4
.text:00404C44
.text:00404C44 loc_404C44: ; CODE XREF: sub_4047C0+477
.text:00404C44 mov dword ptr [esi+14h], 0Fh
.text:00404C4B mov dword ptr [esi+10h], 0
.text:00404C52 mov byte ptr [esi], 0
.text:00404C55 add esi, 1Ch
.text:00404C58 cmp esi, ebx
.text:00404C5A jnz short loc_404C33
.text:00404C5C
.text:00404C5C loc_404C5C: ; CODE XREF: sub_4047C0+471
.text:00404C5C mov ebx, edi
.text:00404C5E mov edi, [ebp+var_98]
.text:00404C64 mov [ebp+var_C8], ebx
.text:00404C6A
.text:00404C6A loc_404C6A: ; CODE XREF: sub_4047C0+451
.text:00404C6A mov eax, [ebp+var_94]
.text:00404C70 mov [ebp+var_BC], eax
.text:00404C76 cmp eax, 32h
.text:00404C79 jl loc_40493D
.text:00404C7F mov edi, [ebp+var_A4]
.text:00404C85 cmp [ebp+var_A8], edi
.text:00404C8B jz short loc_404CE7
.text:00404C8D mov ecx, [ebp+var_B0]
.text:00404C93 mov edx, [ebp+var_A8]
.text:00404C99 push ecx
.text:00404C9A push edx ; void *
.text:00404C9B push edi ; int
.text:00404C9C push edi ; int
.text:00404C9D call sub_406140
.text:00404CA2 mov ebx, eax
.text:00404CA4 add esp, 10h
.text:00404CA7 mov esi, ebx
.text:00404CA9 cmp ebx, edi
.text:00404CAB jz short loc_404CD9
.text:00404CAD lea ecx, [ecx+0]
.text:00404CB0
.text:00404CB0 loc_404CB0: ; CODE XREF: sub_4047C0+517
.text:00404CB0 cmp dword ptr [esi+14h], 10h
.text:00404CB4 jb short loc_404CC1
.text:00404CB6 mov eax, [esi]
.text:00404CB8 push eax ; void *
.text:00404CB9 call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404CBE add esp, 4
.text:00404CC1
.text:00404CC1 loc_404CC1: ; CODE XREF: sub_4047C0+4F4
.text:00404CC1 mov dword ptr [esi+14h], 0Fh
.text:00404CC8 mov dword ptr [esi+10h], 0
.text:00404CCF mov byte ptr [esi], 0
.text:00404CD2 add esi, 1Ch
.text:00404CD5 cmp esi, edi
.text:00404CD7 jnz short loc_404CB0
.text:00404CD9
.text:00404CD9 loc_404CD9: ; CODE XREF: sub_4047C0+4EB
.text:00404CD9 mov edi, ebx
.text:00404CDB mov ebx, [ebp+var_C8]
.text:00404CE1 mov [ebp+var_A4], edi
.text:00404CE7
.text:00404CE7 loc_404CE7: ; CODE XREF: sub_4047C0+4CB
.text:00404CE7 mov esi, [ebp+var_98]
.text:00404CED mov eax, [esi]
.text:00404CEF mov edx, [eax+10h]
.text:00404CF2 lea ecx, [ebp+var_EC]
.text:00404CF8 push ecx
.text:00404CF9 mov ecx, esi
.text:00404CFB call edx
.text:00404CFD mov eax, [ebp+var_D8]
.text:00404D03 push eax
.text:00404D04 lea ecx, [ebp+var_EC]
.text:00404D0A mov byte ptr [ebp+var_4], 8
.text:00404D0E call sub_402920
.text:00404D13 mov ecx, [ebp+var_B8]
.text:00404D19 test ecx, ecx
.text:00404D1B jz short loc_404D25
.text:00404D1D mov edx, [ecx]
.text:00404D1F mov eax, [edx]
.text:00404D21 push 1
.text:00404D23 call eax
.text:00404D25
.text:00404D25 loc_404D25: ; CODE XREF: sub_4047C0+55B
.text:00404D25 mov ecx, [ebp+var_AC]
.text:00404D2B test ecx, ecx
.text:00404D2D jz short loc_404D37
.text:00404D2F mov edx, [ecx]
.text:00404D31 mov eax, [edx]
.text:00404D33 push 1
.text:00404D35 call eax
.text:00404D37
.text:00404D37 loc_404D37: ; CODE XREF: sub_4047C0+56D
.text:00404D37 mov edx, [esi]
.text:00404D39 mov eax, [edx]
.text:00404D3B push 1
.text:00404D3D mov ecx, esi
.text:00404D3F call eax
.text:00404D41 mov eax, [ebp+var_E8]
.text:00404D47 mov ecx, [ebp+var_E4]
.text:00404D4D mov [ebp+var_EC], offset off_41171C
.text:00404D57 cmp eax, ecx
.text:00404D59 jz short loc_404D75
.text:00404D5B push 0 ; size_t
.text:00404D5D push ecx ; void *
.text:00404D5E push eax ; void *
.text:00404D5F mov esi, eax
.text:00404D61 call _memcpy_0
.text:00404D66 mov eax, [ebp+var_E8]
.text:00404D6C add esp, 0Ch
.text:00404D6F mov [ebp+var_E4], esi
.text:00404D75
.text:00404D75 loc_404D75: ; CODE XREF: sub_4047C0+599
.text:00404D75 xor esi, esi
.text:00404D77 cmp eax, esi
.text:00404D79 jz short loc_404D84
.text:00404D7B push eax ; void *
.text:00404D7C call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404D81 add esp, 4
.text:00404D84
.text:00404D84 loc_404D84: ; CODE XREF: sub_4047C0+5B9
.text:00404D84 mov [ebp+var_E8], esi
.text:00404D8A mov [ebp+var_E4], esi
.text:00404D90 mov [ebp+var_E0], esi
.text:00404D96 cmp [ebp+var_CC], esi
.text:00404D9C jz short loc_404DE2
.text:00404D9E mov esi, [ebp+var_CC]
.text:00404DA4 cmp esi, ebx
.text:00404DA6 jz short loc_404DD1
.text:00404DA8
.text:00404DA8 loc_404DA8: ; CODE XREF: sub_4047C0+60F
.text:00404DA8 cmp dword ptr [esi+14h], 10h
.text:00404DAC jb short loc_404DB9
.text:00404DAE mov ecx, [esi]
.text:00404DB0 push ecx ; void *
.text:00404DB1 call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404DB6 add esp, 4
.text:00404DB9
.text:00404DB9 loc_404DB9: ; CODE XREF: sub_4047C0+5EC
.text:00404DB9 mov dword ptr [esi+14h], 0Fh
.text:00404DC0 mov dword ptr [esi+10h], 0
.text:00404DC7 mov byte ptr [esi], 0
.text:00404DCA add esi, 1Ch
.text:00404DCD cmp esi, ebx
.text:00404DCF jnz short loc_404DA8
.text:00404DD1
.text:00404DD1 loc_404DD1: ; CODE XREF: sub_4047C0+5E6
.text:00404DD1 mov edx, [ebp+var_CC]
.text:00404DD7 push edx ; void *
.text:00404DD8 call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404DDD add esp, 4
.text:00404DE0 xor esi, esi
.text:00404DE2
.text:00404DE2 loc_404DE2: ; CODE XREF: sub_4047C0+5DC
.text:00404DE2 cmp [ebp+var_A8], esi
.text:00404DE8 jz short loc_404E34
.text:00404DEA mov esi, [ebp+var_A8]
.text:00404DF0 cmp esi, edi
.text:00404DF2 jz short loc_404E25
.text:00404DF4 mov ebx, 0Fh
.text:00404DF9 lea esp, [esp+0]
.text:00404E00
.text:00404E00 loc_404E00: ; CODE XREF: sub_4047C0+663
.text:00404E00 cmp dword ptr [esi+14h], 10h
.text:00404E04 jb short loc_404E11
.text:00404E06 mov eax, [esi]
.text:00404E08 push eax ; void *
.text:00404E09 call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404E0E add esp, 4
.text:00404E11
.text:00404E11 loc_404E11: ; CODE XREF: sub_4047C0+644
.text:00404E11 mov [esi+14h], ebx
.text:00404E14 mov dword ptr [esi+10h], 0
.text:00404E1B mov byte ptr [esi], 0
.text:00404E1E add esi, 1Ch
.text:00404E21 cmp esi, edi
.text:00404E23 jnz short loc_404E00
.text:00404E25
.text:00404E25 loc_404E25: ; CODE XREF: sub_4047C0+632
.text:00404E25 mov ecx, [ebp+var_A8]
.text:00404E2B push ecx ; void *
.text:00404E2C call ??3@YAXPAX@Z ; operator delete(void *)
.text:00404E31 add esp, 4
.text:00404E34
.text:00404E34 loc_404E34: ; CODE XREF: sub_4047C0+628
.text:00404E34 mov ecx, [ebp+var_C]
.text:00404E37 mov large fs:0, ecx
.text:00404E3E pop ecx
.text:00404E3F pop edi
.text:00404E40 pop esi
.text:00404E41 pop ebx
.text:00404E42 mov ecx, [ebp+var_10]
.text:00404E45 xor ecx, ebp
.text:00404E47 call @__security_check_cookie@4 ; __security_check_cookie(x)
.text:00404E4C mov esp, ebp
.text:00404E4E pop ebp
.text:00404E4F retn
.text:00404E4F sub_4047C0 endp
.text:00404E4F
Пока же разберемся с остальным содержимым функции sub_404E50. Вызов функции sub_401C90 инициализирует первые 18 байт переменной var_100 некоторым константным значением.
.text:00404EFC lea eax, [ebp+var_100]
.text:00404F02 push eax
...
.text:00404F09 call sub_401C90
.text:00401C90 sub_401C90 proc near ; CODE XREF: sub_404E50+B9
.text:00401C90 ; sub_404E50+EA
.text:00401C90
.text:00401C90 arg_0 = dword ptr 8
.text:00401C90
.text:00401C90 push ebp
.text:00401C91 mov ebp, esp
.text:00401C93 mov eax, [ebp+arg_0]
.text:00401C96 mov dword ptr [eax+4], 0
.text:00401C9D mov dword ptr [eax], 0
.text:00401CA3 mov dword ptr [eax+8], 67452301h
.text:00401CAA mov dword ptr [eax+0Ch], 0EFCDAB89h
.text:00401CB1 mov dword ptr [eax+10h], 98BADCFEh
.text:00401CB8 mov dword ptr [eax+14h], 10325476h
.text:00401CBF pop ebp
.text:00401CC0 retn
.text:00401CC0 sub_401C90 endp
В результате вызовов функций sub_402410 и sub_402540 из строки var_A8 длиной 64 байта генерируется 128-битный хэш, который записывается в переменную var_14.
.text:00404F0E push 40h
.text:00404F10 lea ecx, [ebp+var_A8]
.text:00404F16 push ecx
.text:00404F17 lea edx, [ebp+var_100]
.text:00404F1D push edx
.text:00404F1E call sub_402410
.text:00404F23 lea eax, [ebp+var_14]
.text:00404F26 push eax
.text:00404F27 lea ecx, [ebp+var_100]
.text:00404F2D push ecx
.text:00404F2E call sub_402540
.text:00402410 sub_402410 proc near ; CODE XREF: sub_402540+42
.text:00402410 ; sub_404E50+CE ...
.text:00402410
.text:00402410 var_44 = dword ptr -44h
.text:00402410 var_40 = dword ptr -40h
.text:00402410 var_3C = dword ptr -3Ch
.text:00402410 var_38 = dword ptr -38h
.text:00402410 var_4 = dword ptr -4
.text:00402410 arg_0 = dword ptr 8
.text:00402410 arg_4 = dword ptr 0Ch
.text:00402410 arg_8 = dword ptr 10h
.text:00402410
.text:00402410 push ebp
.text:00402411 mov ebp, esp
.text:00402413 sub esp, 44h
.text:00402416 mov eax, ___security_cookie
.text:0040241B xor eax, ebp
.text:0040241D mov [ebp+var_4], eax
.text:00402420 push esi
.text:00402421 mov esi, [ebp+arg_0]
.text:00402424 mov ecx, [esi]
.text:00402426 push edi
.text:00402427 mov edi, [ebp+arg_8]
.text:0040242A mov eax, ecx
.text:0040242C shr eax, 3
.text:0040242F lea edx, [ecx+edi*8]
.text:00402432 and eax, 3Fh
.text:00402435 cmp edx, ecx
.text:00402437 jnb short loc_40243C
.text:00402439 inc dword ptr [esi+4]
.text:0040243C
.text:0040243C loc_40243C: ; CODE XREF: sub_402410+27
.text:0040243C mov ecx, edi
.text:0040243E shr ecx, 1Dh
.text:00402441 add [esi+4], ecx
.text:00402444 mov [esi], edx
.text:00402446 test edi, edi
.text:00402448 jz loc_402524
.text:0040244E push ebx
.text:0040244F nop
.text:00402450
.text:00402450 loc_402450: ; CODE XREF: sub_402410+10D
.text:00402450 mov ecx, [ebp+arg_4]
.text:00402453 mov dl, [ecx]
.text:00402455 mov [esi+eax+18h], dl
.text:00402459 inc eax
.text:0040245A inc ecx
.text:0040245B dec edi
.text:0040245C mov [ebp+arg_4], ecx
.text:0040245F cmp eax, 40h
.text:00402462 jnz loc_40251B
.text:00402468 xor ecx, ecx
.text:0040246A lea eax, [esi+1Ah]
.text:0040246D lea ecx, [ecx+0]
.text:00402470
.text:00402470 loc_402470: ; CODE XREF: sub_402410+F4
.text:00402470 movzx edx, byte ptr [eax+1]
.text:00402474 movzx ebx, byte ptr [eax]
.text:00402477 shl edx, 8
.text:0040247A or edx, ebx
.text:0040247C movzx ebx, byte ptr [eax-1]
.text:00402480 shl edx, 8
.text:00402483 or edx, ebx
.text:00402485 movzx ebx, byte ptr [eax-2]
.text:00402489 shl edx, 8
.text:0040248C or edx, ebx
.text:0040248E movzx ebx, byte ptr [eax+4]
.text:00402492 mov [ebp+ecx*4+var_44], edx
.text:00402496 movzx edx, byte ptr [eax+5]
.text:0040249A shl edx, 8
.text:0040249D or edx, ebx
.text:0040249F movzx ebx, byte ptr [eax+3]
.text:004024A3 shl edx, 8
.text:004024A6 or edx, ebx
.text:004024A8 movzx ebx, byte ptr [eax+2]
.text:004024AC shl edx, 8
.text:004024AF or edx, ebx
.text:004024B1 movzx ebx, byte ptr [eax+8]
.text:004024B5 mov [ebp+ecx*4+var_40], edx
.text:004024B9 movzx edx, byte ptr [eax+9]
.text:004024BD shl edx, 8
.text:004024C0 or edx, ebx
.text:004024C2 movzx ebx, byte ptr [eax+7]
.text:004024C6 shl edx, 8
.text:004024C9 or edx, ebx
.text:004024CB movzx ebx, byte ptr [eax+6]
.text:004024CF shl edx, 8
.text:004024D2 or edx, ebx
.text:004024D4 movzx ebx, byte ptr [eax+0Ch]
.text:004024D8 mov [ebp+ecx*4+var_3C], edx
.text:004024DC movzx edx, byte ptr [eax+0Dh]
.text:004024E0 shl edx, 8
.text:004024E3 or edx, ebx
.text:004024E5 movzx ebx, byte ptr [eax+0Bh]
.text:004024E9 shl edx, 8
.text:004024EC or edx, ebx
.text:004024EE movzx ebx, byte ptr [eax+0Ah]
.text:004024F2 shl edx, 8
.text:004024F5 or edx, ebx
.text:004024F7 mov [ebp+ecx*4+var_38], edx
.text:004024FB add ecx, 4
.text:004024FE add eax, 10h
.text:00402501 cmp ecx, 10h
.text:00402504 jb loc_402470
.text:0040250A lea eax, [esi+8]
.text:0040250D push eax
.text:0040250E lea eax, [ebp+var_44]
.text:00402511 call sub_401CD0
.text:00402516 add esp, 4
.text:00402519 xor eax, eax
.text:0040251B
.text:0040251B loc_40251B: ; CODE XREF: sub_402410+52
.text:0040251B test edi, edi
.text:0040251D jnz loc_402450
.text:00402523 pop ebx
.text:00402524
.text:00402524 loc_402524: ; CODE XREF: sub_402410+38
.text:00402524 mov ecx, [ebp+var_4]
.text:00402527 pop edi
.text:00402528 xor ecx, ebp
.text:0040252A pop esi
.text:0040252B call @__security_check_cookie@4 ; __security_check_cookie(x)
.text:00402530 mov esp, ebp
.text:00402532 pop ebp
.text:00402533 retn
.text:00402533 sub_402410 endp
.text:00402540 sub_402540 proc near ; CODE XREF: sub_404E50+DE
.text:00402540 ; sub_404E50+10B
.text:00402540
.text:00402540 var_44 = dword ptr -44h
.text:00402540 var_40 = dword ptr -40h
.text:00402540 var_C = dword ptr -0Ch
.text:00402540 var_8 = dword ptr -8
.text:00402540 var_4 = dword ptr -4
.text:00402540 arg_0 = dword ptr 8
.text:00402540 arg_4 = dword ptr 0Ch
.text:00402540
.text:00402540 push ebp
.text:00402541 mov ebp, esp
.text:00402543 sub esp, 44h
.text:00402546 mov eax, ___security_cookie
.text:0040254B xor eax, ebp
.text:0040254D mov [ebp+var_4], eax
.text:00402550 push ebx
.text:00402551 push esi
.text:00402552 mov esi, [ebp+arg_0]
.text:00402555 mov eax, [esi]
.text:00402557 mov ecx, [esi+4]
.text:0040255A mov [ebp+var_C], eax
.text:0040255D shr eax, 3
.text:00402560 and eax, 3Fh
.text:00402563 push edi
.text:00402564 mov edi, [ebp+arg_4]
.text:00402567 mov [ebp+var_8], ecx
.text:0040256A mov ecx, 38h
.text:0040256F cmp eax, 38h
.text:00402572 jl short loc_402579
.text:00402574 mov ecx, 78h
.text:00402579
.text:00402579 loc_402579: ; CODE XREF: sub_402540+32
.text:00402579 sub ecx, eax
.text:0040257B push ecx
.text:0040257C push offset unk_411588
.text:00402581 push esi
.text:00402582 call sub_402410
.text:00402587 add esp, 0Ch
.text:0040258A xor ecx, ecx
.text:0040258C lea eax, [esi+1Ah]
.text:0040258F nop
.text:00402590
.text:00402590 loc_402590: ; CODE XREF: sub_402540+9E
.text:00402590 movzx edx, byte ptr [eax+1]
.text:00402594 movzx ebx, byte ptr [eax]
.text:00402597 shl edx, 8
.text:0040259A or edx, ebx
.text:0040259C movzx ebx, byte ptr [eax-1]
.text:004025A0 shl edx, 8
.text:004025A3 or edx, ebx
.text:004025A5 movzx ebx, byte ptr [eax-2]
.text:004025A9 shl edx, 8
.text:004025AC or edx, ebx
.text:004025AE movzx ebx, byte ptr [eax+4]
.text:004025B2 mov [ebp+ecx*4+var_44], edx
.text:004025B6 movzx edx, byte ptr [eax+5]
.text:004025BA shl edx, 8
.text:004025BD or edx, ebx
.text:004025BF movzx ebx, byte ptr [eax+3]
.text:004025C3 shl edx, 8
.text:004025C6 or edx, ebx
.text:004025C8 movzx ebx, byte ptr [eax+2]
.text:004025CC shl edx, 8
.text:004025CF or edx, ebx
.text:004025D1 mov [ebp+ecx*4+var_40], edx
.text:004025D5 add ecx, 2
.text:004025D8 add eax, 8
.text:004025DB cmp ecx, 0Eh
.text:004025DE jb short loc_402590
.text:004025E0 lea ebx, [esi+8]
.text:004025E3 push ebx
.text:004025E4 lea eax, [ebp+var_44]
.text:004025E7 call sub_401CD0
.text:004025EC movzx eax, byte ptr [ebx]
.text:004025EF mov [edi], al
.text:004025F1 movzx ecx, byte ptr [esi+9]
.text:004025F5 mov [edi+1], cl
.text:004025F8 movzx edx, byte ptr [esi+0Ah]
.text:004025FC mov [edi+2], dl
.text:004025FF movzx eax, byte ptr [esi+0Bh]
.text:00402603 mov [edi+3], al
.text:00402606 movzx ecx, byte ptr [esi+0Ch]
.text:0040260A mov [edi+4], cl
.text:0040260D movzx edx, byte ptr [esi+0Dh]
.text:00402611 mov [edi+5], dl
.text:00402614 movzx eax, byte ptr [esi+0Eh]
.text:00402618 mov [edi+6], al
.text:0040261B movzx ecx, byte ptr [esi+0Fh]
.text:0040261F mov [edi+7], cl
.text:00402622 movzx edx, byte ptr [esi+10h]
.text:00402626 mov [edi+8], dl
.text:00402629 movzx eax, byte ptr [esi+11h]
.text:0040262D mov [edi+9], al
.text:00402630 movzx ecx, byte ptr [esi+12h]
.text:00402634 mov [edi+0Ah], cl
.text:00402637 movzx edx, byte ptr [esi+13h]
.text:0040263B mov [edi+0Bh], dl
.text:0040263E movzx eax, byte ptr [esi+14h]
.text:00402642 mov [edi+0Ch], al
.text:00402645 movzx ecx, byte ptr [esi+15h]
.text:00402649 mov [edi+0Dh], cl
.text:0040264C movzx edx, byte ptr [esi+16h]
.text:00402650 mov ecx, [ebp+var_4]
.text:00402653 mov [edi+0Eh], dl
.text:00402656 movzx eax, byte ptr [esi+17h]
.text:0040265A add esp, 4
.text:0040265D mov [edi+0Fh], al
.text:00402660 pop edi
.text:00402661 pop esi
.text:00402662 xor ecx, ebp
.text:00402664 pop ebx
.text:00402665 call @__security_check_cookie@4 ; __security_check_cookie(x)
.text:0040266A mov esp, ebp
.text:0040266C pop ebp
.text:0040266D retn
.text:0040266D sub_402540 endp
Аналогичным образом генерируется хэш от строки, содержащей email, и записывается в переменную var_24.
.text:01324F3F push edi
.text:01324F40 lea eax, [ebp+var_100]
.text:01324F46 push esi
.text:01324F47 push eax
.text:01324F48 call sub_1322410
.text:01324F4D add esp, 44h
.text:01324F50 lea ecx, [ebp+var_24]
.text:01324F53 push ecx
.text:01324F54 lea edx, [ebp+var_100]
.text:01324F5A push edx
.text:01324F5B call sub_1322540
После этого строки var_24 и var_14 побитово складываются и приводятся в текстовый вид. Результирующая строка записывается в переменную var_58, которая на заключительном этапе сравнивается со строкой введенного пользователем программы серийного номера, ссылка на которую хранится в переменной var_104. Если строки var_58 и var_104 совпадают (без учета регистра), то функция sub_404E50 возвращает 1, иначе 0.
Таким образом, становится понятно, что для того, чтобы найти действительный серийный номер, который на завершающем этапе записывается в переменную var_58, требуется сначала узнать строку var_A8, которая генерируется зависающей функцией sub_4047C0. После того, как строка var_A8 станет известна, достаточно будет выполнить блок операций .text:00404EDA-00404F95 и считать строку серийного номера из переменной var_58.
Для того, чтобы убедиться, что весь остальной код отрабатывает корректно, в режиме отладки пропускаем вызов функции sub_4047C0 и доходим до места .text:00404FA0, в котором выполняется сравнение введенного и действительного серийного номера. Весь код отрабатывает исправно и результирующий серийный номер выходит равным «D1985BE6F7AEDF39E4BB93A02C854B99».
И хотя при пропуске функции sub_4047C0 программа принимает этот серийный номер, попытка отправить этот результат вполне предсказуемо заканчивается провалом.
Подведем итоги. Поиск защитного механизма у данного crackme не занимает много времени. Функция проверки серийного номера находится простым переходом по перекрестной ссылке вызова окна сообщения. Никаких антиотладочных приемов или помех дизассемблированию программы обнаружено не было. Основным препятствием к решению задачи является тот факт, что функция sub_4047C0, инициализирующая промежуточную строку, используемую для генерации серийного номера, зависает, не выполнив инициализацию. Следующим этапом будет исследование функции sub_4047C0 и оптимизация её производительности. Для этого будет использоваться вставка X-кода, ссылкой на который будет заменен вызов неэффективной функции.
Автор: Geork