![]() |
[Reversme 09 solution]
[Reverseme09 by 0x0c0de]
Итак, моя девятая работа. Активности в разделе мало, да и как-то вяло реверсится. Ну да ладно.. Расскажу как это должно было быть. В первый раз так, что ни одного дельного поста за несколько суток. Обычно 1 дня хватает для первого решения ну или хотя бы признаков того, что кто-то решает и двигается в ВЕРНОМ направлении. Я тут не стану описывать алгоритм генерации ключа - там и разбирать-то нечего. Объясню самое интересное. [Приступим] Загрузим кодес в иду. Именно в иду, не нужно это отлаживать. Точнее, совсем не обязательно. В начале WinMain видим Код:
.text:004017AB push ebp ; hTemplateFileЗдесь мы пойдем другим путем. Посмотрим чуть дальше Код:
.text:004017C6 cmp eax, 0FFFFFFFFhИтак, загружаем драйвер в дизассемблер Код:
INIT:00012000 sub esp, 10hКод:
INIT:00012099 loc_12099: То, что DriverEntry может вернуть 40010003h в зависимости от того, как выполниться процедура по адресу sub_110C0 - уже должно насторожить. Посмотрим, что это за процедура. Код:
.text:000110C0 push ebpНемного забегая вперед я обозначила имена функций. Читайте комментарии ниже и все станет ясно. Код:
int __cdecl CheckIdtHook()И? ) '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:004017E1 loc_4017E1: ; CODE XREF: wWinMain(x,x,x,x)+C7 jТипичный код в DriverEntry. Код:
Код:
INIT:00012055 mov dword ptr [esi+38h], offset loc_111E0На данный момент нужный нам - 000115B0 - это и есть обработчик IOCTL запросов. Я кое-что из стандартных фрагментов переименовала сразу. Что выдал HexRays по F5 [в общем виде] Код:
int __stdcall DeviceControlRoutine(int a1, PIRP Irp)Код:
cmp ecx, 8 ; jumptable 000115E7 case 16Код:
.text:00011250 sub_11250 proc near ; CODE XREF: DeviceControlRoutine+BF pКод:
t:000112B0 mov eax, dword ptr [esp+20h+var_8+2]Код:
.text:000112D6 add_descriptor: ; CODE XREF: AddDescriptorIntoGdt+7B jИтак, функция AddDescriptorIntoGdt добавит в GDT свой дескриптор и вернет на него селектор (селектор – 16 бит, первые 2 бита – RPL, второй бит TI, определяющий таблицу (ldt/gdt) и 3:15 биты – индекс в таблице дескрипторов). Забегая вперед, скажу, что добавление своего дескриптора в gdt конкретно в этой части кодеса в принципе бессмысленно [с точки зрения кодера, конечно, бессмысленно, неподготовленного реверсера сбивают все эти манипуляции]. Это - атавизм первых вариантов. У меня первоначально была пара хороших идей, но, к сожалению, тут мне помешали некоторые обстоятельства осуществить свой план. Окей, выходим из этой подпроцедуры и двигаемся дальше Код:
.text:0001166F call AddDescriptorIntoGdtКод:
|
Ага, опять похожий код на предыдущую функцию. только на этот раз sidt. Эта функция добавляет вход в idt.
Причем, поиск свободного входа осуществляется только среди 0x20 - 0x29 прерываниями. Почему? Да потому что они обычно свободны. Смысла первые чекать нет - они стандартны и уже заняты системой. Хорошо, раз это прерывание новое, то надо бы найти адрес обработчика. Да его и искать не надо. смотрим снова Код:
.text:0001166F call AddDescriptorIntoGdtКод:
intEntry.wSelector = uSel; Код:
.text:00401805 lea eax, [esp+14h+flOldProtect]Код:
.text:0040191D push 0 ; bEnableИтак, вызываем в первый раз прерывание. Инструкция sub eax, eax будет изменена на int xx. Далее, устанавливается флаг трассировки и все бы ничего. Но это пока так кажется, что ничего и мы должны отправиться в сех с первого нопа. Код:
.text:00401388 int_call proc near ; CODE XREF: DialogFunc+B5 pКод:
.text:000113E0 InterruptHandler proc near ; DATA XREF: DeviceControlRoutine+CD oКод:
.text:0040139B infinite_loop: ; CODE XREF: int_call:infinite_loop jКод:
text:004016A4 SEHFirstHandler proc near ; DATA XREF: DialogFunc+9D oКод:
.text:004013AB sub_4013AB proc near ; CODE XREF: StartAddress+EA pКак видим, снова VirtualProtect и снова запись каких-то инструкций прерыванием. Обзовем модифицируемый код int_call2 Код:
.text:0040139E int_call2 proc near ; CODE XREF: sub_4013AB+38 pКод:
.text:00011412 mov eax, [esp+arg_4] // EFLAGS |
В случае, если по прерыванию прошлись по F7 в ольге то в eax положим -4, если все ок, то 4. А значит, в юзермоде эта проверка
Код:
.text:004013A1 add eax, 0FFFFFFFCh // + (-4)Код:
.text:004013E8 loc_4013E8: ; CODE XREF: sub_4013AB+24 jВсматриваемся в код внимательно и видим, что в драйвер передается содержание сегментного регистра fs. Окей. Ну тогда снова в драйвер. В процедуру обработки ioctl запросов. На этот раз запрос 222004h. Вычитаем как обычно 222004h. Получаем нулевой кейз. Ай-да его ковырять. Всякие проверки, имеющие отношение только к стабильности я опускаю. Перейдем сразу к делу. Код:
.text:00011728 sgdt fword ptr gdtr__ // опять? )))))))Код:
.text:00011200 GetFsBase proc near ; CODE XREF: DeviceControlRoutine+18C pОбъясняю суть того, что здесь происходит. Как мы помним, передан был селектор на дескриптор. Я уже написала как по селектору высчитать индекс в дескрипторной таблице. Ну так вот. Сначала получаем указатель на сам дескриптор, а потом копируем его содержимое. Код:
.text:0001173C call GetFsBaseКод:
0040142B 68 5D134000 PUSH reversem.0040135DКод:
.text:0040135D loc_40135D: ; DATA XREF: .text:0040142B oКод:
.text:004012DD ; int __cdecl SEH2Handler(DWORD NumberOfBytesWritten, int, int)Код:
.text:000117E0 ReadHandler: ; DATA XREF: DllEntryPoint+6A oОтлично, мы отработали в seh – хендлере. Теперь Код:
.text:00401342 return: ; CODE XREF: SEH2Handler+14 jКод:
.text:0040145A push ediКод:
.text:000113E0 InterruptHandler proc near ; DATA XREF: DeviceControlRoutine+CD oUsermode part Код:
.text:00401496 sub esi, 0Код:
.text:004010F1 loc_4010F1: ; DATA XREF: sub_401630+8 oКод:
]Я не объяснила ВСЕ. Но тем, кто пробовал, пускай даже не отписался, этого будет достаточно, чтобы понять что к чему. Надеюсь, эта моя работа будет для кого-то познавательной. Тогда я не зря потратила время. На этом пока прощаюсь, удачи! |
Пусть модеры удалят этот пост, но тут слов нету. Апплодисменты!!!
Я не супер-реверсер, и даже по рангу - ниже новичка, но изложенное выше меня поразило оО! Кстати, ветка Реверсинга на ачате дохлая =\ Может не мое дело, но имхо - надо как-то оживлять... Заполнять чтоли или хз =\ |
Огромная работа , респект от сердца . Все понятно и не к чему придраться =)
|
протеус походу сначало не видел твою темку, так бы наверняка поковырял...
taha в армии, Грейт редко бывает, neprovad хз, ну а остальные наврядли бы стали браться:D |
Хех) Молодец!
|
всё это конечно здорово, но, имхо, солюшен рано выложен. Очень рано.
|
0x0c0de, с Вами можно связаться как-то еще кроме жабы и ЖЖ?
|
респект!
Отличная работа, большой труд! |
| Время: 18:56 |