Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   Реверсинг (https://forum.antichat.xyz/forumdisplay.php?f=94)
-   -   [Reversme 09 solution] (https://forum.antichat.xyz/showthread.php?t=109731)

0x0c0de 07.03.2009 16:33

[Reversme 09 solution]
 
[Reverseme09 by 0x0c0de]

Итак, моя девятая работа. Активности в разделе мало, да и как-то вяло реверсится. Ну да ладно.. Расскажу как это должно было быть.
В первый раз так, что ни одного дельного поста за несколько суток. Обычно 1 дня хватает для первого решения ну или хотя бы признаков того, что кто-то решает и двигается в ВЕРНОМ направлении. Я тут не стану описывать алгоритм генерации ключа - там и разбирать-то нечего. Объясню самое интересное.

[Приступим]

Загрузим кодес в иду. Именно в иду, не нужно это отлаживать. Точнее, совсем не обязательно.

В начале WinMain видим

Код:

.text:004017AB                push    ebp            ; hTemplateFile
.text:004017AC                push    80h            ; dwFlagsAndAttributes
.text:004017B1                push    3              ; dwCreationDisposition
.text:004017B3                push    ebp            ; lpSecurityAttributes
.text:004017B4                push    3              ; dwShareMode
.text:004017B6                push    0C0000000h      ; dwDesiredAccess
.text:004017BB                push    offset a_Reverseme0 ; "\\\\.\\reverseme0"

Ага, значит будем иметь дело с драйвером. Но это не значит, что надо хватать ядерный отладчик и ставить бряки на загрузку драйвера.
Здесь мы пойдем другим путем. Посмотрим чуть дальше

Код:

.text:004017C6                cmp    eax, 0FFFFFFFFh
.text:004017C9                mov    hDevice, eax
.text:004017CE                jnz    short loc_4017E1
.text:004017D0                call    sub_401289

Здесь, в процедуре по адресу sub_401289 извлекается из ресурсов драйвер и его файл создается на диске. Драйвер можно вытащить прямо из ресурсов, так как они не криптованы ничем . Что сейчас и сделаем. Думаю, как пользоваться Restorator знают все, поэтому на этом не останавливаюсь.

Итак, загружаем драйвер в дизассемблер

Код:

INIT:00012000                sub    esp, 10h
INIT:00012003                push    esi
INIT:00012004                mov    esi, [esp+14h+DeviceObject]
INIT:00012008                push    edi
INIT:00012009                mov    edi, ds:RtlInitUnicodeString
INIT:0001200F                push    offset SourceString ; "\\Device\\reverseme0"
INIT:00012014                lea    eax, [esp+1Ch+DestinationString]
INIT:00012018                push    eax            ; DestinationString
INIT:00012019                mov    dword ptr [esi+34h], offset loc_11160
INIT:00012020                call    edi ; RtlInitUnicodeString
INIT:00012022                lea    ecx, [esp+18h+DeviceObject]
INIT:00012026                push    ecx            ; DeviceObject
INIT:00012027                push    0              ; Exclusive
INIT:00012029                push    0              ; DeviceCharacteristics
INIT:0001202B                push    22h            ; DeviceType
INIT:0001202D                lea    edx, [esp+28h+DestinationString]

Все бы ничего и все стандартно, на первый взгляд. DriverEntry как DriverEntry. Но тут-то надо быть внимательней. Прокрутите чуть ниже листинг и вы увидите, что

Код:

INIT:00012099 loc_12099:                           
INIT:00012099                call    sub_110C0
INIT:0001209E                test    eax, eax
INIT:000120A0                jz      short loc_120A7
INIT:000120A2                mov    esi, 40010003h // хм, возвращаемое значение?
INIT:000120A7
INIT:000120A7 loc_120A7:                           
INIT:000120A7                mov    eax, esi
INIT:000120A9
INIT:000120A9 loc_120A9:                           
INIT:000120A9                pop    edi
INIT:000120AA                pop    esi
INIT:000120AB                add    esp, 10h
INIT:000120AE                retn    8


То, что DriverEntry может вернуть 40010003h в зависимости от того, как выполниться процедура по адресу sub_110C0 - уже должно насторожить. Посмотрим, что это за процедура.


Код:

.text:000110C0                push    ebp
.text:000110C1                mov    ebp, esp
.text:000110C3                sub    esp, 40h
.text:000110C6                push    esi
.text:000110C7                push    edi
.text:000110C8                xor    eax, eax
.text:000110CA                push    31h            ; size_t
.text:000110CC                push    eax            ; int
.text:000110CD                mov    [ebp+var_4], eax
.text:000110D0                mov    [ebp+var_40], al
.text:000110D3                lea    eax, [ebp+var_3F]
.text:000110D6                push    eax            ; void *
.text:000110D7                call    memset
.text:000110DC                add    esp, 0Ch
.text:000110DF                sidt    fword ptr [ebp+var_C]

Опа, sidt. Инструкция, получающая содержимое регистра idtr. Посмотрим что происходит дальше. Я облегчила задачу в разы и не замусоривала код вообще. Поэтому можно заюзать Hex-Rays. жмем F5 и смотрим псевдокод.

Немного забегая вперед я обозначила имена функций. Читайте комментарии ниже и все станет ясно.

Код:

int __cdecl CheckIdtHook()
{

….

  __asm { sidt    fword ptr [ebp+var_C] }
  v0 = *(unsigned __int16 *)&v5[2] | (*(unsigned __int16 *)&v5[4] << 16);
  GetIdtModuleName(*(_WORD *)((*(unsigned __int16 *)&v5[2] | (*(unsigned __int16 *)&v5[4] << 16)) + 0x168) | (*(_WORD *)((*(unsigned __int16 *)&v5[2] | (*(unsigned __int16 *)&v5[4] << 16)) + 0x16E) << 16),
    &v3);
  if ( *(_DWORD *)&v3 == 'esyS' ) // первая часть имени
  {
    if ( v6 == 'ys.r' ) // вторая часть
      ++v2;
  }
  GetIdtModuleName(*(_WORD *)(v0 + 104) | (*(_WORD *)(v0 + 110) << 16), &v3);
  if ( *(_DWORD *)&v3 == 'stdr' ) // первая часть имени
  {
    if ( v6 == 'ys.c' ) // вторая часть
      ++v2;
  }
  return v2;
}


И? ) 'ys.r'+'esyS' - "Syser.sy". хм. Проверка на драйвер Syser? Да, именно она. Syser.sys перехватывает довольно много прерываний (вы можете это глянуть в каком-нибудь RKU на вкладке Code Hooks): int 1,2,3,6,B,C,D,E,2D... Я проверяю конкретно int 0x2d. KiDebugService )). Смотрим дальше. 'ys.c'+'stdr' - "rdtsc.sy" - проверка на ольгу. Проверяю вход 0xD в идт. Намек на то, что значение, возвращаемое DriverEntry используется где-то. И логично предположить, что это где-то будет в юзермодной части реверсми. Функция получает имя модуля по заданному адресу. И надо сказать вызываться она будет не только в DriverEntry..

На время вернемся в юзермодную часть. Посмотрим внимательней на процесс загрузки драйвера

Код:

.text:004011FB LoadDriver:                            ; CODE XREF: sub_4010F4+9E j
.text:004011FB                push    offset unk_40CC68
.text:00401200                call    ds:NtLoadDriver
.text:00401206                pop    edi
.text:00401207                pop    esi
.text:00401208                mov    NtstatusSave, eax // это будет играть роль при генерации ключа
.text:0040120D                pop    ebx
.text:0040120E                leave
.text:0040120F                retn
.text:0040120F sub_4010F4      endp

Я сразу переименовала в иде переменную, куда сохраняется значение NTSTATUS, возращенное ZwLoadDriver. Хорошо, теперь снова вернемся в WinMain из процедуры создания файла драйвера


Код:

.text:004017E1 loc_4017E1:                            ; CODE XREF: wWinMain(x,x,x,x)+C7 j
.text:004017E1                                        ; wWinMain(x,x,x,x)+D0 j
.text:004017E1                push    ebp            ; lpOverlapped
.text:004017E2                lea    eax, [esp+18h+BytesReturned]
.text:004017E6                push    eax            ; lpBytesReturned
.text:004017E7                push    8              ; nOutBufferSize
.text:004017E9                push    offset byte_40CCA0 ; lpOutBuffer
.text:004017EE                push    ebp            ; nInBufferSize
.text:004017EF                push    ebp            ; lpInBuffer
.text:004017F0                push    222014h        ; dwIoControlCode
.text:004017F5                push    hDevice        ; hDevice
.text:004017FB                call    ds:DeviceIoControl

Итак, первое обращение к дрову. Хм... IOCTL запрос 222014h. Теперь, нужно найти функцию обработки IOCTL запросов в драйвере. И ее расковырять. Определять местоположение процедур обработки можно и нужно из DriverEntry

Типичный код в DriverEntry.

Код:


DriverObject->MajorFunction[IRP_MJ_CREATE]= OpenDeviceHandler;
       
DriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseHandler;
       
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]= DeviceControlRoutine;
   
DriverObject->MajorFunction[IRP_MJ_READ]  = ReadHandler;
       
DriverObject->MajorFunction[IRP_MJ_WRITE] = WriteHandler;

Аналог дизассемблированном листинге DriverEntry

Код:

INIT:00012055                mov    dword ptr [esi+38h], offset loc_111E0
INIT:0001205C                mov    dword ptr [esi+40h], offset loc_111E0
INIT:00012063                mov    dword ptr [esi+70h], offset sub_115B0
INIT:0001206A                mov    dword ptr [esi+44h], offset loc_117E0
INIT:00012071                mov    dword ptr [esi+48h], offset loc_11800

Все, считайте, адреса основных обработчиков у нас в кармане.
На данный момент нужный нам - 000115B0 - это и есть обработчик IOCTL запросов. Я кое-что из стандартных фрагментов переименовала сразу. Что выдал HexRays по F5 [в общем виде]

Код:

int __stdcall DeviceControlRoutine(int a1, PIRP Irp)
{
  code = *((_DWORD *)v14 + 3) - 0x222004; // то, что мы отсылаем из юзермода - 0x222004
  status = 0;
  v17 = 0;
  switch ( code )
  {
    case 20:


    case 16:

    case 4:
….
  }
}

Пока вот так. Нам нужен первый ioctl запрос. 222014h. Отлично, вычитаем 0x222004. Получаем 10h или 16. Нам HexRays как раз-таки и выдал 16-й кейз. Разберемся с ним. На первый взгляд выполняется куча каких-то непонятных операций

Код:

cmp    ecx, 8          ; jumptable 000115E7 case 16
.text:0001161D                jb      short loc_115F3
.text:0001161F                mov    eax, dword_14004
.text:00011624                cmp    eax, ebx
.text:00011626                jz      short loc_1162F
.text:00011628                mov    [esi], eax
.text:0001162A                jmp    loc_116BA
.text:0001162F ; ---------------------------------------------------------------------------
.text:0001162F
.text:0001162F loc_1162F:                              ; CODE XREF: DeviceControlRoutine+76 j
.text:0001162F                mov    cl, [esp+20h+var_A]
.text:00011633                mov    al, [esp+20h+var_B]
.text:00011637                or      cl, 40h
.text:0001163A                and    cl, 0EFh
.text:0001163D                or      cl, 0Fh
.text:00011640                and    al, 9Fh
.text:00011642                or      cl, 80h
.text:00011645                or      al, 10h
.text:00011647                and    cl, 0DFh
.text:0001164A                and    al, 0FBh
.text:0001164C                mov    [esp+20h+var_A], cl
.text:00011650                lea    ecx, [esp+20h+var_10]
.text:00011654                or      al, 8Bh
.text:00011656                push    ecx
.text:00011657                mov    word ptr [esp+24h+var_10+2], bx
.text:0001165C                mov    [esp+24h+var_C], bl
.text:00011660                mov    [esp+24h+var_9], bl
.text:00011664                mov    word ptr [esp+24h+var_10], 0FFFFh
.text:0001166B                mov    [esp+24h+var_B], al
.text:0001166F                call    sub_11250

Однако, заглянем, что у нас по адресу sub_11250 и тогда все станет ясно.

Код:

.text:00011250 sub_11250      proc near              ; CODE XREF: DeviceControlRoutine+BF p
.text:00011250                                        ; DeviceControlRoutine+1A6 p
.text:00011250
.text:00011250 var_10          = dword ptr -10h
.text:00011250 var_C          = dword ptr -0Ch
.text:00011250 var_8          = byte ptr -8
.text:00011250 arg_0          = dword ptr  4
.text:00011250
.text:00011250                sub    esp, 10h
.text:00011253                mov    ecx, ds:KeNumberProcessors
.text:00011259                xor    eax, eax
.text:0001125B                cmp    byte ptr [ecx], 1
.text:0001125E                mov    [esp+10h+var_C], eax
.text:00011262                mov    [esp+10h+var_10], 1
.text:00011269                jl      loc_1131A
.text:0001126F                push    ebx
.text:00011270                mov    ebx, [esp+14h+arg_0]
.text:00011274                push    ebp
.text:00011275                push    esi
.text:00011276                push    edi
.text:00011277                jmp    short loc_11280
.text:00011277 ; ---------------------------------------------------------------------------
.text:00011279                align 10h
.text:00011280
.text:00011280 loc_11280:                              ; CODE XREF: sub_11250+27 j
.text:00011280                                        ; sub_11250+BC j
.text:00011280                mov    edx, [esp+20h+var_10]
.text:00011284                push    edx
.text:00011285                call    KeGetCurrentThread
.text:0001128A                push    eax
.text:0001128B                call    KeSetAffinityThread
.text:00011290                sgdt    fword ptr [esp+20h+var_8]

А тут вы должны были насторожиться второй раз. KeNumberProcessors, вызов KeGetCurrentThread и KeSetAffinityThread, получение gdtr инструкцией sgdt. А если присмотреться к коду далее - уже явно идет поиск свободного дескриптора в gdt

Код:

t:000112B0                mov    eax, dword ptr [esp+20h+var_8+2]
.text:000112B4                lea    esi, [eax+edi*8]
.text:000112B7                push    esi            ; VirtualAddress
.text:000112B8                call    ds:MmIsAddressValid
.text:000112BE                test    al, al
.text:000112C0                jz      short loc_112CD
.text:000112C2                cmp    dword ptr [esi], 0 // чекаем первый дворд
.text:000112C5                jnz    short loc_112CD
.text:000112C7                cmp    dword ptr [esi+4], 0 // чекаем второй дворд
.text:000112CB                jz      short loc_112D6
.text:000112CD
.text:000112CD loc_112CD:                              ; CODE XREF: sub_11250+70 j
.text:000112CD                                        ; sub_11250+75 j
.text:000112CD                add    edi, 1
.text:000112D0                cmp    edi, ebp
.text:000112D2                jb      short loc_112B0
.text:000112D4                jmp    short loc_112F9

Проверка 2-х частей дескриптора. Как известно дескриптор равен 8-ми байтам, вот и проверяется по двордам. Как только мы нашли свободный дескриптор

Код:

.text:000112D6 add_descriptor:                        ; CODE XREF: AddDescriptorIntoGdt+7B j
.text:000112D6                cli
.text:000112D7                mov    ecx, [ebx]
.text:000112D9                mov    [esi], ecx
.text:000112DB                mov    edx, [ebx+4]
.text:000112DE                mov    [esi+4], edx
.text:000112E1                sti

добавляем новый. И этот дескриптор заюзается на следующем этапе, но об этом позже. То есть все те действия, которые выполнялись перед вызовом исследуемой процедуры - это было формирование структуры дескриптора. Исходники, как я говорила, я не утаиваю и кому надо могут их увидеть. Саму процедуру, после того, как поняли, что она делает обзовем AddDescriptorIntoGdt. Она принимает 1 параметр – указатель на структуру дескриптора и возвращает селектор на созданный дескриптор.
Итак, функция AddDescriptorIntoGdt добавит в GDT свой дескриптор и вернет на него селектор (селектор – 16 бит, первые 2 бита – RPL, второй бит TI, определяющий таблицу (ldt/gdt) и 3:15 биты – индекс в таблице дескрипторов). Забегая вперед, скажу, что добавление своего дескриптора в gdt конкретно в этой части кодеса в принципе бессмысленно [с точки зрения кодера, конечно, бессмысленно, неподготовленного реверсера сбивают все эти манипуляции]. Это - атавизм первых вариантов. У меня первоначально была пара хороших идей, но, к сожалению, тут мне помешали некоторые обстоятельства осуществить свой план.

Окей, выходим из этой подпроцедуры и двигаемся дальше

Код:

.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 sub_113E0
.text:00011682                lea    ecx, [esp+20h+var_8]
.text:00011686                mov    edx, offset sub_113E0
.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    sub_114E0

sub_114E0 - разберем ее.

Код:


.text:000114E0 sub_114E0      proc near              ; CODE XREF: DeviceControlRoutine+EE p
.text:000114E0
.text:000114E0 var_8          = byte ptr -8
.text:000114E0 arg_0          = dword ptr  4
.text:000114E0
.text:000114E0                mov    eax, ds:KeNumberProcessors
.text:000114E5                sub    esp, 8
.text:000114E8                push    ebx
.text:000114E9                push    esi
.text:000114EA                mov    ebx, 1
.text:000114EF                xor    esi, esi
.text:000114F1                cmp    [eax], bl
.text:000114F3                jl      loc_115A2
.text:000114F9                push    edi
.text:000114FA                mov    edi, [esp+14h+arg_0]
.text:000114FE                mov    edi, edi
.text:00011500
.text:00011500 loc_11500:                              ; CODE XREF: sub_114E0+BB j
.text:00011500                push    ebx
.text:00011501                call    KeGetCurrentThread
.text:00011506                push    eax
.text:00011507                call    KeSetAffinityThread
.text:0001150C                sidt    fword ptr [esp+14h+var_8]
.text:00011511                movzx  eax, word ptr [esp+14h+var_8+4]
.text:00011516                movzx  ecx, word ptr [esp+14h+var_8+2]
.text:0001151B                shl    eax, 10h
.text:0001151E                or      eax, ecx
.text:00011520                mov    ecx, 20h
.text:00011525                lea    edx, [eax+105h]
.text:0001152B                jmp    short loc_11530


0x0c0de 07.03.2009 16:36

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

В случае, если по прерыванию прошлись по F7 в ольге то в eax положим -4, если все ок, то 4. А значит, в юзермоде эта проверка

Код:

.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

приобрела много больше смысла. 4-4 = 0 и нас не трассирут. -4-4!=0 => нас трассируют. Окей. Двигаемся дальше

Код:

.text:004013E8 loc_4013E8:                            ; CODE XREF: sub_4013AB+24 j
.text:004013E8                and    eax, 0
.text:004013EB                mov    ax, fs
.text:004013EE                mov    [ebp+var_4], eax
.text:004013F1                call    int_call2
.text:004013F1 sub_4013AB      endp
.text:004013F1
.text:004013F6 ; ---------------------------------------------------------------------------
.text:004013F6                push    edi
.text:004013F7                lea    eax, [ebp-10h]
.text:004013FA                push    eax
.text:004013FB                push    0Ch
.text:004013FD                push    offset dword_40CCB4
.text:00401402                push    4
.text:00401404                lea    eax, [ebp-4]
.text:00401407                push    eax
.text:00401408                push    222004h
.text:0040140D                push    hDevice
.text:00401413                call    ds:DeviceIoControl
.text:00401419                test    eax, eax
.text:0040141B                jz      loc_4014FE
.text:00401421                call    int_call2
.text:00401426 ; ---------------------------------------------------------------------------
.text:00401426                call    int_call2 // проверка на трассировку
.text:0040142B ; ---------------------------------------------------------------------------
.text:0040142B                push    offset loc_40135D
.text:00401430                mov    eax, dword_40CCB4
.text:00401435                push    dword ptr [eax]
.text:00401437                mov    [eax], esp
.text:00401439                ud2


Всматриваемся в код внимательно и видим, что в драйвер передается содержание сегментного регистра fs. Окей. Ну тогда снова в драйвер. В процедуру обработки ioctl запросов. На этот раз запрос 222004h. Вычитаем как обычно 222004h. Получаем нулевой кейз. Ай-да его ковырять. Всякие проверки, имеющие отношение только к стабильности я опускаю. Перейдем сразу к делу.

Код:

.text:00011728                sgdt    fword ptr gdtr__ // опять? )))))))
.text:0001172F                mov    eax, [esi]
.text:00011731                lea    edx, [esp+20h+var_8]
.text:00011735                push    edx
.text:00011736                push    eax
.text:00011737                push    offset gdtr__
.text:0001173C                call    sub_11200

Зайдем в sub_11200. Судя по всему этой процедуре зачем-то нужна gdt.

Код:

.text:00011200 GetFsBase      proc near              ; CODE XREF: DeviceControlRoutine+18C p
.text:00011200
.text:00011200 arg_0          = dword ptr  4
.text:00011200 selector        = dword ptr  8
.text:00011200 arg_8          = dword ptr  0Ch
.text:00011200
.text:00011200                mov    ecx, [esp+arg_0]
.text:00011204                mov    eax, [esp+selector]
.text:00011208                mov    edx, [ecx+2]
.text:0001120B                push    esi
.text:0001120C                shr    eax, 3
.text:0001120F                lea    esi, [edx+eax*8]
.text:00011212                push    esi            ; VirtualAddress
.text:00011213                call    ds:MmIsAddressValid
.text:00011219                test    al, al
.text:0001121B                jnz    short valid
.text:0001121D                xor    eax, eax
.text:0001121F                pop    esi
.text:00011220                retn    0Ch
.text:00011223 ; ---------------------------------------------------------------------------
.text:00011223
.text:00011223 valid:                                  ; CODE XREF: GetFsBase+1B j
.text:00011223                mov    eax, [esp+4+arg_8]
.text:00011227                mov    ecx, [esi]
.text:00011229                mov    [eax], ecx
.text:0001122B                mov    edx, [esi+4]
.text:0001122E                xor    ecx, ecx
.text:00011230                mov    [eax+4], edx
.text:00011233                mov    ch, [eax+7]
.text:00011236                pop    esi
.text:00011237                mov    cl, dl
.text:00011239                movzx  edx, word ptr [eax+2]
.text:0001123D                shl    ecx, 10h
.text:00011240                or      ecx, edx
.text:00011242                mov    eax, ecx
.text:00011244                retn    0Ch
.text:00011244 GetFsBase      endp


Объясняю суть того, что здесь происходит. Как мы помним, передан был селектор на дескриптор. Я уже написала как по селектору высчитать индекс в дескрипторной таблице.
Ну так вот. Сначала получаем указатель на сам дескриптор, а потом копируем его содержимое.

Код:

.text:0001173C                call    GetFsBase
.text:00011741                add    [esp+20h+var_6], 0F000h
.text:00011748                add    [esp+20h+var_8], 3E8h
.text:0001174F                lea    ecx, [esp+20h+var_8]
.text:00011753                push    ecx
.text:00011754                mov    edi, eax
.text:00011756                call    AddDescriptorIntoGdt
.text:0001175B                cmp    eax, ebx
.text:0001175D                jnz    short all_good_
.text:0001175F                mov    ebp, [esp+20h+var_10]
.text:00011763                mov    ebx, STATUS_UNSUCCESSFUL
.text:00011768                jmp    short loc_11791
.text:0001176A ; ---------------------------------------------------------------------------
.text:0001176A
.text:0001176A all_good_:                              ; CODE XREF: DeviceControlRoutine+1AD j
.text:0001176A                mov    uFsDescr, eax
.text:0001176F                mov    [esi+4], eax
.text:00011772                mov    [esi], edi
.text:00011774                mov    ebp, 8
.text:00011779                call    CheckIdtHook // снова проверка на хуки в итд, это все будет иметь смысл при генерации ключа
.text:0001177E                neg    eax
.text:00011780                sbb    eax, eax
.text:00011782                and    eax, DBG_TERMINATE_THREAD
.text:00011787                mov    [esi+8], eax
.text:0001178A                jmp    short loc_11791
.text:0001178C ; --------------------------------------------------

Значит скопировали дескриптор, на который указывает селектор в fs. Потом мы его редактируем, а именно новая база нового сегмента будет на 0x1000 меньше. Окей, потом пересчитываем лимит (причем я пересчитываю его не точно, но реально это не имеет значения, так как нужный диапазон это с лихвой покрывает). Скажу тут сразу, что селектор на новый дескриптор будет использован мной для установки seh обработчиков через gs. Так же как и база старого fs. Так что подробно уже на этом не останавливаюсь. Покажу как это в юзермоде

Код:

0040142B  68 5D134000      PUSH reversem.0040135D
00401430  A1 B4CC4000      MOV EAX,DWORD PTR DS:[40CCB4]
00401435  FF30            PUSH DWORD PTR DS:[EAX]
00401437  8920            MOV DWORD PTR DS:[EAX],ESP
00401439  0F0B            UD2
0040143B  66:8EE8          MOV GS,AX                                ; Modification of segment register
0040143E  59              POP ECX
0040143F  59              POP ECX
00401440  68 DD124000      PUSH reversem.004012DD
00401445  65:FF35 00100000 PUSH DWORD PTR GS:[1000]
0040144C  65:8925 00100000 MOV DWORD PTR GS:[1000],ESP
00401453  0F0B            UD2

Видите? Сначала устанавливается обработчик по имеющейся базе. Вот его код

Код:

.text:0040135D loc_40135D:                            ; DATA XREF: .text:0040142B o
.text:0040135D                mov    ecx, [esp+0Ch]
.text:00401361                lea    eax, [ecx+0B8h]
.text:00401367                add    dword ptr [eax], 2 // модификация адреса возврата из seh
.text:0040136A                mov    edx, [eax]
.text:0040136C                push    esi
.text:0040136D                mov    esi, dwCount // а вот тут мы при возврате из seh добавляем еще наш счетчик между int 2a в начале
.text:00401373                add    edx, esi
.text:00401375                mov    [eax], edx
.text:00401377                mov    eax, dword_40CCB8
.text:0040137C                mov    [ecx+0B0h], eax
.text:00401382                xor    eax, eax
.text:00401384                pop    esi
.text:00401385                retn    10h

Этот обработчик не делает ничего интересного, кроме как неявно проверяет счетчки между вызовами KiGetTickCount и кладет в ax селектор на новый созданный дескриптор. Окей! Разобрались. Двигаемся дальше. Второй обработчик

Код:

.text:004012DD ; int __cdecl SEH2Handler(DWORD NumberOfBytesWritten, int, int)
.text:004012DD SEH2Handler    proc near
.text:004012DD
.text:004012DD NumberOfBytesWritten= dword ptr  8
.text:004012DD arg_8          = dword ptr  10h
.text:004012DD
.text:004012DD                push    ebp
.text:004012DE                mov    ebp, esp
.text:004012E0                mov    eax, [ebp+NumberOfBytesWritten]
.text:004012E3                mov    eax, [eax]
.text:004012E5                cmp    eax, EXCEPTION_BREAKPOINT
.text:004012EA                jz      short loc_401329
.text:004012EC                cmp    eax, EXCEPTION_ILLEGAL_INSTRUCTION
.text:004012F1                jnz    short loc_401342
.text:004012F3                push    0              ; lpOverlapped
.text:004012F5                lea    eax, [ebp+NumberOfBytesWritten]
.text:004012F8                push    eax            ; lpNumberOfBytesWritten
.text:004012F9                push    nNumberOfBytesToWrite ; nNumberOfBytesToWrite
.text:004012FF                push    offset byte_40CC70 ; lpBuffer
.text:00401304                push    hDevice        ; hFile
.text:0040130A                call    ds:WriteFile
.text:00401310                push    0              ; lpOverlapped
.text:00401312                push    offset NumberOfBytesRead ; lpNumberOfBytesRead
.text:00401317                push    0              ; nNumberOfBytesToRead
.text:00401319                push    0              ; lpBuffer
.text:0040131B                push    hDevice        ; hFile
.text:00401321                call    ds:ReadFile
.text:00401327                jmp    short loc_401342
.text:00401329 ; ---------------------------------------------------------------------------




.text:0040135C SEH2Handler    endp

Итак, инструкция ud2 спровоцирует EXCEPTION_ILLEGAL_INSTRUCTION => Начинается процесс обращения к драйверу через ReadFile/WriteFile. Скажу сразу, что тут только калькуляция серийного номера. WriteFile считает серийник, ReadFile заканчивает калькуляцию вот так

Код:

.text:000117E0 ReadHandler:                            ; DATA XREF: DllEntryPoint+6A o
.text:000117E0                mov    eax, [esp+8]
.text:000117E4                xor    serialnumb, 33223322h
.text:000117EE                push    0
.text:000117F0                push    0
.text:000117F2                push    eax
.text:000117F3                call    CompleteIrp
.text:000117F8                retn    8

Переменная serialnumb сохранена в драйвере и будет использоваться при заключительной проверке. WriteHandler я оставляю интересующимся.

Отлично, мы отработали в seh – хендлере. Теперь

Код:

.text:00401342 return:                                ; CODE XREF: SEH2Handler+14 j
.text:00401342                                        ; SEH2Handler+4A j
.text:00401342                mov    eax, [ebp+arg_8]
.text:00401345                add    eax, 0B8h
.text:0040134A                add    dword ptr [eax], 2 // eip+2
.text:0040134D                mov    ecx, [eax]
.text:0040134F                mov    edx, dwCount // снова учет времени между int 0x2a
.text:00401355                add    ecx, edx
.text:00401357                mov    [eax], ecx
.text:00401359                xor    eax, eax
.text:0040135B                pop    ebp
.text:0040135C                retn
.text:0040135C SEH2Handler    endp

Возврат из хендлера.

Код:

.text:0040145A                push    edi
.text:0040145B                lea    eax, [ebp-0Ch]
.text:0040145E                push    eax
.text:0040145F                push    3EAh
.text:00401464                push    dword_40CCCC
.text:0040146A                call    ds:GetDlgItemInt // серийник- число онли!
.text:00401470                cmp    [ebp-0Ch], edi
.text:00401473                mov    [ebp-14h], eax
.text:00401476                jz      short loc_4014B1
.text:00401478                mov    eax, NtstatusSave // а вот и наш NtStatus, о котором я говорила в самом начале
.text:0040147D                mov    ecx, dword_40CCBC
.text:00401483                add    ecx, eax
.text:00401485                add    [ebp-14h], ecx
.text:00401488                pusha
.text:00401489                mov    eax, [ebp-14h] // eax - серийник
.text:0040148C                mov    edi, 'last' // окей, снова в прерывание
.text:00401491                call    int_call2
.text:00401496 ; ---------------------------------------------------------------------------
.text:00401496                sub    esi, 0 // серийник верный, в esi адрес перехода?
.text:00401499                jz      short loc_4014A5
.text:0040149B                push    esi
.text:0040149C                pop    edi
.text:0040149D                add    edi, dword_40CCEC
.text:004014A3                call    edi
.text:004014A5
.text:004014A5 loc_4014A5:                            ; CODE XREF: .text:00401499 j

Обратите внимание, что серийник, введенный юзером, считается с учетом наличия отладчика. И если вы решили пойти по пути отладки и были невнимательны, даже в случае нахождения верного ключа - аплодесментов не получите ). Ага, снова отправляемся в наше прерывание и смотрим что будет, если edi == ‘last’.

Код:

.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 msrset
.text:000113E8                cmp    edi, 'sele'
.text:000113EE                jz      short secondcheck
.text:000113F0                cmp    edi, 'last'
.text:000113F6                jnz    short check_tf
.text:000113F8                mov    edi, serialnumb // вот серийник, сохраненный в дрове
.text:000113FE                xor    eax, edi // ксорим что в eax [значение введенное юзером в поле серийника + учет отладки]
.text:00011400                mov    ebx, eax
.text:00011402                mov    edi, 'sele' // прерывание готовится вернутся снова на нструкцию int xx и вызвать прерывание снова
.text:00011407                mov    eax, [esp+0]
.text:0001140A                sub    eax, 2 // eip_ret - 2
.text:0001140D                mov    [esp+0], eax
.text:00011410                jmp    short intreturn
.text:00011412 ; ---------------------------------------------------------------------------
.text:00011412
.text:00011412 check_tf:                              ; CODE XREF: InterruptHandler+16 j
.text:00011412                mov    eax, [esp+arg_4]
.text:00011416                bt      eax, 8
.text:0001141A                jnb    short not_tf
.text:0001141C                mov    eax, 0FFFFFFFCh
.text:00011421                jmp    short intreturn
.text:00011423 ; ---------------------------------------------------------------------------
.text:00011423
.text:00011423 secondcheck:                            ; CODE XREF: InterruptHandler+E j
.text:00011423                cmp    ebx, 0 // результат ксора
.text:00011426                jnz    short not_valid_serial
.text:00011428                mov    esi, 4010F1h // если валид сериал.
.text:0001142D                mov    eax, [esp+0]
.text:00011430                sub    eax, 2
.text:00011433                mov    [esp+0], eax
.text:00011436                sub    edi, edi
.text:00011438                jmp    short intreturn
.text:0001143A ; ---------------------------------------------------------------------------
.text:0001143A
.text:0001143A not_valid_serial:                      ; CODE XREF: InterruptHandler+46 j
.text:0001143A                mov    esi, 0
.text:0001143F                mov    eax, [esp+0]
.text:00011442                sub    eax, 2
.text:00011445                mov    [esp+0], eax
.text:00011448                sub    edi, edi
.text:0001144A                jmp    short intreturn
.text:0001144C ; ---------------------------------------------------------------------------
.text:0001144C
.text:0001144C not_tf:                                ; CODE XREF: InterruptHandler+3A j
.text:0001144C                mov    eax, 4
.text:00011451                jmp    short intreturn
.text:00011453 ; ---------------------------------------------------------------------------
.text:00011453
.text:00011453 msrset:                                ; CODE XREF: InterruptHandler+6 j
.text:00011453                mov    ecx, 1D9h
.text:00011458                rdmsr
.text:0001145A                or      eax, 3
.text:0001145D                wrmsr
.text:0001145F
.text:0001145F intreturn:                              ; CODE XREF: InterruptHandler+30 j
.text:0001145F                                        ; InterruptHandler+41 j ...
.text:0001145F                iret
.text:0001145F InterruptHandler endp

А вот тут уже надо быть еще внимательней. Хендлер прерывания, получая 'last' в edi, ксорит серийник из юзермода с вычисленным значением в дрове, затем изменяет eip (то место, куда по идее надо бы вернуться после iret) и кладет в edi 'sele' . И возврат снова на инструкцию прерывания. Но в edi будет уже 'sele' и если разница между верным серийником и тем, что введено пользователем 0, то в esi кладется адрес 4010F1h.

Usermode part

Код:

.text:00401496                sub    esi, 0
.text:00401499                jz      short loc_4014A5
.text:0040149B                push    esi
.text:0040149C                pop    edi
.text:0040149D                add    edi, dword_40CCEC
.text:004014A3                call    edi

Если серийник верный, то мы перейдем по адресу 4010F1h. Что там?

Код:

.text:004010F1 loc_4010F1:                            ; DATA XREF: sub_401630+8 o
.text:004010F1                int    3              ; Trap to Debugger
.text:004010F2                nop
.text:004010F3                retn

И все =) Однако, вспомним, что у нас до сих пор установлен обработчик исключений SEH2Handler. И там была проверка на эксепшн EXCEPTION_BREAKPOINT.

Код:

]
text:004012E5                cmp    eax, EXCEPTION_BREAKPOINT
.text:004012EA                jz      short loc_401329




.text:00401329 loc_401329:                            ; CODE XREF: SEH2Handler+D j
.text:00401329                push    40004h          ; fdwSound
.text:0040132E                push    0              ; lpModuleName
.text:00401330                call    ds:GetModuleHandleW
.text:00401336                push    eax            ; hmod
.text:00401337                push    83h            ; pszSound
.text:0040133C                call    ds:PlaySoundW
.text:00401342
.text:00401342 return:                                ; CODE XREF: SEH2Handler+14 j

И))))) Если серийник верный, хендлер прерывания возвращает в esi адрес перехода, мы переходим по нему в юзермоде, по этому адресу int 3 == EXCEPTION_BREAKPOINT и мы слышим аплодисменты. Вот таки дела.

Я не объяснила ВСЕ. Но тем, кто пробовал, пускай даже не отписался, этого будет достаточно, чтобы понять что к чему. Надеюсь, эта моя работа будет для кого-то познавательной. Тогда я не зря потратила время.



На этом пока прощаюсь, удачи!

ex3me 08.03.2009 00:31

Пусть модеры удалят этот пост, но тут слов нету. Апплодисменты!!!
Я не супер-реверсер, и даже по рангу - ниже новичка, но изложенное выше меня поразило оО!

Кстати, ветка Реверсинга на ачате дохлая =\ Может не мое дело, но имхо - надо как-то оживлять... Заполнять чтоли или хз =\

RedAlert 08.03.2009 00:46

Огромная работа , респект от сердца . Все понятно и не к чему придраться =)

De-visible 08.03.2009 00:59

протеус походу сначало не видел твою темку, так бы наверняка поковырял...
taha в армии, Грейт редко бывает, neprovad хз, ну а остальные наврядли бы стали браться:D

Tigger 08.03.2009 01:24

Хех) Молодец!

winterfrost 08.03.2009 02:25

всё это конечно здорово, но, имхо, солюшен рано выложен. Очень рано.

Unregistered 08.03.2009 03:08

0x0c0de, с Вами можно связаться как-то еще кроме жабы и ЖЖ?

-m0rgan- 08.03.2009 06:23

респект!
Отличная работа, большой труд!


Время: 18:56