Ага, опять похожий код на предыдущую функцию. только на этот раз sidt. Эта функция добавляет вход в idt.
Причем, поиск свободного входа осуществляется только среди 0x20 - 0x29 прерываниями. Почему? Да потому что они обычно свободны. Смысла первые чекать нет - они стандартны и уже заняты системой. Хорошо, раз это прерывание новое, то надо бы найти адрес обработчика. Да его и искать не надо. смотрим снова
Код:
.text:0001166F call AddDescriptorIntoGdt
.text:00011674 cmp eax, ebx
.text:00011676 jz short zero_selector_erro
.text:00011678 mov [esp+20h+var_6], ax
.text:0001167D mov eax, offset InterruptHandler
.text:00011682 lea ecx, [esp+20h+var_8]
.text:00011686 mov edx, offset InterruptHandler
.text:0001168B shr eax, 10h
.text:0001168E push ecx
.text:0001168F mov [esp+24h+var_8], dx
.text:00011694 mov [esp+24h+var_2], ax
.text:00011699 mov [esp+24h+var_3], 0EEh
.text:0001169E call AddDescriptorIntoIdt
В исходном коде это было так
Код:
intEntry.wSelector = uSel;
intEntry.wLowOffset = LOWORD(&InterruptHandler);
intEntry.wHiOffset = HIWORD(&InterruptHandler);
intEntry.DPL = 3;
intEntry.P = 1;
// 32 битный шлюз прерывания
intEntry.unused_hi = 14;
puInfoBuf[0] = CreateInterruptGateIntoIdt(&intEntry);
В общем вот так . Хендлер прерывания мы нашли. Селектор на добавленный нами дескриптор (как вы уже могли заметить), используется при составлении дескриптора шлюза в idt. Теперь снова в юзермод, разбираться что где юзоется и где вызывается это наше прерывание.
Код:
.text:00401805 lea eax, [esp+14h+flOldProtect]
.text:00401809 push eax ; lpflOldProtect
.text:0040180A push 40h ; flNewProtect
.text:0040180C push 2 ; dwSize
.text:0040180E mov ebx, offset sub_401388
.text:00401813 push ebx ; lpAddress
.text:00401814 call ds:VirtualProtect
.text:0040181A test eax, eax
.text:0040181C jz short loc_401860
.text:0040181E push ebp ; dwInitParam
.text:0040181F push offset DialogFunc ; lpDialogFunc
.text:00401824 push ebp ; hWndParent
.text:00401825 mov eax, ebx
.text:00401827 push 67h ; lpTemplateName
.text:00401829 push hModule ; hInstance
.text:0040182F mov byte ptr [eax], 0CDh // опкод команды int
.text:00401832 mov al, byte_40CCA0 // то, что вернул драйвер [вектор добавленного прерывания]
.text:00401837 mov [ebx+1], al
.text:0040183A call ds:DialogBoxParamW
Окей, кажется, мы нашли место, где будет юзотся прерывание. Обзовем эту процедуру int_call. Теперь, самое интересное. Отправляемся в DialogFunc и начинаем непосредственно изучать что происходит после того, как мы нажали кнопку Try!. Ковырять DialogFunc все умеют, думаю, поэтому я не останавливаюсь на поиске обработки конкретной кнопки.
Код:
.text:0040191D push 0 ; bEnable
.text:0040191F push dword_40CCC8 ; hWnd
.text:00401925 call ds:EnableWindow
.text:0040192B push offset sub_4016A4
.text:00401930 push large dword ptr fs:0
.text:00401937 mov large fs:0, esp
.text:0040193E mov edi, 'bran'
.text:00401943 call int_call
Итак, как видите вызывается та процедура, которая патчится в WinMain. Устанавливается обработчик исключений, потом что-то ложится в edi и вызывается прерывание.
Итак, вызываем в первый раз прерывание. Инструкция sub eax, eax будет изменена на int xx. Далее, устанавливается флаг трассировки и все бы ничего. Но это пока так кажется, что ничего и мы должны отправиться в сех с первого нопа.
Код:
.text:00401388 int_call proc near ; CODE XREF: DialogFunc+B5 p
.text:00401388 ; DATA XREF: wWinMain(x,x,x,x)+107 o
.text:00401388 sub eax, eax
.text:0040138A pushf
.text:0040138B pop edi
.text:0040138C bts edi, 8
.text:00401390 push edi
.text:00401391 popf
.text:00401392 nop // в SEH отсюда? Нет! Читаем комменты ниже
.text:00401393 nop
.text:00401394 nop
.text:00401395 nop
.text:00401396 nop
.text:00401397 nop
.text:00401398 nop
.text:00401399 xor eax, eax
.text:0040139B
.text:0040139B infinite_loop: ; CODE XREF: int_call:infinite_loop j
.text:0040139B jmp short infinite_loop
.text:0040139B int_call endp
.text:0040139B
.text:0040139D ; ---------------------------------------------------------------------------
.text:0040139D retn
А теперь разберем хендлер прерывания. Ага, значит все-таки значение в edi имеет смысл. Что же происходит? Если в edi - 'bran', то начинается манипуляция с msr регистром MSR_DEBUGCTLA (1D9h). Как вы можете помнить 0 –бит там LBR, а 1-й BTF. В результате копипаста со своего пробного кодеса, устанавливаю 2 бита. Реально же, нужен нам BTF.
Код:
.text:000113E0 InterruptHandler proc near ; DATA XREF: DeviceControlRoutine+CD o
.text:000113E0 ; DeviceControlRoutine+D6 o
.text:000113E0
.text:000113E0 arg_4 = dword ptr 8
.text:000113E0
.text:000113E0 cmp edi, 'bran'
.text:000113E6 jz short loc_11453
….
.text:00011453 loc_11453: ; CODE XREF: InterruptHandler+6 j
.text:00011453 mov ecx, 1D9h // MSR_DEBUGCTLA
.text:00011458 rdmsr
.text:0001145A or eax, 3 // LBR BTF
.text:0001145D wrmsr
.text:0001145F
.text:0001145F locret_1145F: ; CODE XREF: InterruptHandler+30 j
.text:0001145F ; InterruptHandler+41 j ...
.text:0001145F iret
.text:0001145F InterruptHandler endp
Как это работает? Когда мы устанавливаем в MSR регистре MSR_DEBUGCTLA бит BTF установленный в EFLAGS бит TF начинает интерпретироваться как BTF – то есть мы будем останавливаться только на переходах, а не на любой инструкции. То есть, в данном случае, после вызова прерывания и установки TF флажка мы остановимся не на первом нопе, а именно на прыжке
Код:
.text:0040139B infinite_loop: ; CODE XREF: int_call:infinite_loop j
.text:0040139B jmp short infinite_loop
Дальше, конечно, возникнет исключение и мы благополучно отправимся в SEH –обработчик, нами установленный. Что же там?
Код:
text:004016A4 SEHFirstHandler proc near ; DATA XREF: DialogFunc+9D o
.text:004016A4
.text:004016A4 arg_0 = dword ptr 8
.text:004016A4 arg_8 = dword ptr 10h
.text:004016A4
.text:004016A4 push ebp
.text:004016A5 mov ebp, esp
.text:004016A7 mov eax, [ebp+arg_0]
.text:004016AA cmp dword ptr [eax+0Ch], 4013C0h // это не играет роли
.text:004016B1 jz short loc_4016DC
.text:004016B3 str ax // если мы на варе в eax 4000h
.text:004016B6 cmp ax, 4000h
.text:004016BA jnz short loc_4016DC
.text:004016BC
.text:004016BC loc_4016BC: ; CODE XREF: SEHFirstHandler+36 j
.text:004016BC push 'cann'
.text:004016C1 push 'ot w'
.text:004016C6 push 'ork '
.text:004016CB push 'with'
.text:004016D0 push 'vmwa'
.text:004016D5 push 're '
.text:004016DA jmp short loc_4016BC
.text:004016DC ; ---------------------------------------------------------------------------
.text:004016DC
.text:004016DC loc_4016DC: ; CODE XREF: SEHFirstHandler+D j
.text:004016DC ; SEHFirstHandler+16 j
.text:004016DC push offset ThreadId ; lpThreadId
.text:004016E1 xor eax, eax
.text:004016E3 push eax ; dwCreationFlags
.text:004016E4 push eax ; lpParameter
.text:004016E5 push offset StartAddress ; lpStartAddress
.text:004016EA push eax ; dwStackSize
.text:004016EB push eax ; lpThreadAttributes
.text:004016EC call ds:CreateThread
.text:004016F2 mov dword_40CC94, eax
.text:004016F7 mov eax, [ebp+arg_8]
.text:004016FA add dword ptr [eax+0B8h], 2
.text:00401701 xor eax, eax
.text:00401703 pop ebp
.text:00401704 retn 10h
На самом деле, тут я поленилась немного. Значение 4013C0h было когда-то адресом джампа, посредством которого, после установки BTF мы окажемся в хендлере. Понятное дело, что после перекомпиляций этот код сместился. Потом я порывалась поправить, а потом подумала, что нахер его исправлять, если следующий код все равно проверяет на варю, а на варе полюбому не пашет трассировка ветвлений. Далее я просто устраиваю переполнение стека и все слетает. Ну метод с str ax в общем-то немудреный и практически всем известен. Далее, если мы не на варе и все круто мы создаем тред, который дальше будет работать. Давайте заглянем что как в этом треде. Помимо стандартного кода чтения имени с эдита, там есть 1 подъ№б с KiGetTickCount (int 0x2a). Расчет сделан та тех, кто опрометчиво начнет останавливаться на всяких GetWindowText и тут-то время выполнения увеличиться и далее реверсми упадет после возврата из первого же исключения. Ну это я опять забежала вперед. Зайдем в первый, не связанный с различными манипуляциями с именем call
Код:
.text:004013AB sub_4013AB proc near ; CODE XREF: StartAddress+EA p
.text:004013AB
.text:004013AB flOldProtect = dword ptr -8
.text:004013AB var_4 = dword ptr -4
.text:004013AB
.text:004013AB push ebp
.text:004013AC mov ebp, esp
.text:004013AE sub esp, 14h
.text:004013B1 push ebx
.text:004013B2 push esi
.text:004013B3 push edi
.text:004013B4 lea eax, [ebp+flOldProtect]
.text:004013B7 push eax ; lpflOldProtect
.text:004013B8 push 40h ; flNewProtect
.text:004013BA push 3 ; dwSize
.text:004013BC mov esi, offset int_call2
.text:004013C1 xor edi, edi
.text:004013C3 push esi ; lpAddress
.text:004013C4 mov [ebp+var_4], edi
.text:004013C7 call ds:VirtualProtect
.text:004013CD test eax, eax
.text:004013CF jz short loc_4013E8
.text:004013D1 mov eax, esi
.text:004013D3 mov byte ptr [eax], 0CDh // опкод int XX
.text:004013D6 mov cl, byte_40CCA0
.text:004013DC mov [eax+1], cl
.text:004013DF mov byte ptr [eax+2], 90h // nop
.text:004013E3 call int_call2
Как видим, снова VirtualProtect и снова запись каких-то инструкций прерыванием. Обзовем модифицируемый код int_call2
Код:
.text:0040139E int_call2 proc near ; CODE XREF: sub_4013AB+38 p
.text:0040139E ; sub_4013AB+46 p ...
.text:0040139E push 4 // это будет перезаписано прерыванием
.text:004013A0 pop eax
.text:004013A1 add eax, 0FFFFFFFCh // + (-4)
.text:004013A4 jz short loc_4013AA
.text:004013A6
.text:004013A6 loc_4013A6: ; CODE XREF: int_call2+A j
.text:004013A6 push 0FFFFFFFFh // переполнение стека
.text:004013A8 jmp short loc_4013A6
.text:004013AA ; ---------------------------------------------------------------------------
.text:004013AA
.text:004013AA loc_4013AA: ; CODE XREF: int_call2+6 j
.text:004013AA retn
В чем тут фишка? Снова смотрим выше на хендлер прерывания. Если в edi не передано никаких значений, то проверяем флаг трассировки.
Код:
.text:00011412 mov eax, [esp+arg_4] // EFLAGS
.text:00011416 bt eax, 8 // 8-й бит
.text:0001141A jnb short loc_1144C
.text:0001141C mov eax, 0FFFFFFFCh
.text:00011421 jmp short locret_1145F
.text:00011423 ; ---------------------------------------------------------------------------
…
.text:0001144C loc_1144C: ; CODE XREF: InterruptHandler+3A j
.text:0001144C mov eax, 4 // нет трассировки
.text:00011451 jmp short locret_1145F
.text:00011453 ; ---------------------------------------------------------------------------
.text:00011453
…
.text:0001145F iret
.text:0001145F InterruptHandler endp