ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > Программирование > Реверсинг
   
 
 
Опции темы Поиск в этой теме Опции просмотра

[Reversme 09 solution]
  #1  
Старый 07.03.2009, 16:33
Аватар для 0x0c0de
0x0c0de
Постоянный
Регистрация: 25.05.2007
Сообщений: 448
Провел на форуме:
4226446

Репутация: 1564
Отправить сообщение для 0x0c0de с помощью ICQ
По умолчанию [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 в 17:58..
 
Ответить с цитированием
 





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ