Показать сообщение отдельно

  #2  
Старый 07.03.2009, 16:36
0x0c0de
Постоянный
Регистрация: 25.05.2007
Сообщений: 448
С нами: 9981026

Репутация: 1564
По умолчанию

Ага, опять похожий код на предыдущую функцию. только на этот раз 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

Последний раз редактировалось 0x0c0de; 07.03.2009 в 23:04..
 
Ответить с цитированием