LEA EAX, DS:110H[EAX*4]
Программа умножает значение 0x2 на 4 и складывает полученное значение со значением 0x110 и затем вычитает из найденного значения HEAP_BUCKET и сохраняет результат в переменную VAR_2C.
Этот адрес, который сохраняется в переменную VAR_2C является началом таблицы LFH, так как HEAP_BUCKETS находится по смещению 0x110 и должен быть равен 8, потому что поле находится внутри таблицы BUCKETS, поэтому в переменной VAR_2C программа сохраняет значение 0x24ACF8, которое было началом таблицы LFH.
То, что программа сейчас делает, это то, что говорит нам картинка. Программа пытаясь найти адрес LFH для этой структуры BUCKET, используя переменную SIZEINDEX.
Очевидно, мы находимся в этой части, только в моём случае переменная не равна единице и программа продолжает выполнение здесь.
Программа достигает инструкции LEA, где на данный момент регистр EAX равен нулю, поскольку он получается из умножения 0x3418 на CONST_CERO и суммируется с регистром ESI, который хранит начало таблицы LFH и добавляет значение 0x310.
Мы напомним, что смещение 0x310 из LFH это _HEAP_LOCAL_DATA.
Это значение сохраняется в переменную VAR_44. Я переименую это поле в HEAP_LOCAL_DATA.
Основная идея состоит в том, что мы пытаемся найти эти структуры и увидим, можем ли мы их найти и идентифицировать.
Хорошо. Мы должны создать структуру для HEAP_LOCAL_DATA.
Я создаю структуру из 0x22 байт, хотя она наверняка будет намного больше, но пока пойдет и это.
По смещению 0x18 есть структуры. Их размер равен 0x128 байт.
[128] _HEAP_LOCAL_SEGMENT_INFO
Программа проходит через все эти 128 структур, используя SIZEINDEX как индекс, который умножается на 0x68, а затем добавляет значение, чтобы найти адрес это структуры SEGMENTINFO.
Это означает, что адрес DIRECCION3 равен HEAP_LOCAL_SEGMENT_INFO.
Поэтому мы будем создавать структуру больше чем 0x64 байта.
Хорошо. Внутри отладчика этого выглядит так.
ntdll!_HEAP_LOCAL_SEGMENT_INFO
+0x000 Hint : Ptr32 _HEAP_SUBSEGMENT
Первое поле, которое программа пытается использовать здесь, говорит, что это HINT .
И программа сохранит это значение в переменную VAR_30. Я переименовываю переменную в HINT.
Если значение HINT не равно нулю, программа ищет ACTIVESUBSEGMENT, что является следующим полем.
А если это поле равно нулю, программа переходит сюда
В любом из трех случае, программа сохраняет результат в переменной, которую мы назвали HINT, но она может быть любой из трех.
Хорошо. Мы находимся здесь.
Мы будем переименовывать переменную HINT в RESULTADO, поскольку переменная может принимать три значения.
Картинка показывает нам три варианта. Сейчас же мы находимся в HINT.
Этот результат должен был бы быть _HEAP_SUBSEGMENT.
Здесь программа говорит мне, что _HEAP_LOCAL_SEGMENT_INFO находится в памяти по адресу 0x24B0F0 и что 0x282660 это структура _HEAP_USERDATA_HEADER а по смещению 0x08 это структура INTERLOCK_SEQ.
Мы уже подходим к концу. Фууууууууууууууууууххххххххххххх.
Здесь я добавляю новую структуру.
Здесь я вижу, что программа находит с помощью инструкции LEA адрес поля _INTERLOCK_SEQ
На данный момент, я думаю что она состоит из 4 байтов.
Программа может прочитать поле как WORD или как DWORD, это сложно для имени. В моем случае, программа читает DWORD т.е. имеет значение 0x56000D (ЭТО ЗНАЧЕНИЕ ОЧЕНЬ ВАЖНО)
Я добавляю поле SEQUENCE.
Программа тестирует регистр DI который хранит поле OFFSETANDDEPTH. Это поле в моём случае равно 0xD.
Здесь программа читает поле USERBLOCKS, которое находится по смещению 0x4 структуры HEAP_SUBSEGMENT.
Программа сравнивает регистр EDX который хранит LOCALINFO высчитанный с помощью указателя HEAP_SUBSEGMENT.LOCALINFO и они должны быть одинаковыми.
Поскольку значения одинаковые, программа идет к этому блоку.
Хорошо. Я не собираюсь просчитывать все эти значения, но очевидно, что то, что программа делает, это получает первый свободный блок запрошенного размера из значений структуры _INTERLOCK_SEQ, и когда программа покинет этот блок, она сохранит его здесь.
Регистр ECX здесь равен значению 282918 и если я посмотрю список блоков с размером 0x10 с помощью команды.
!heap -flt s 0x10
В выводе блоки находятся здесь
И это первое значение из этих LFH, потому что предыдущие размеры 0x10, которые говорят что они FREE(СВОБОДНЫЕ), имеют другую LFH младшего адреса, возможно, соответствующей другой куче.
Здесь по адресу чанка 0x282918 без заголовка, вычитается 8, и остается адрес полного блока с заголовком 0x282910.
Структура, которую мы ещё не добавили называется структурой LFH. Сейчас я сделаю это.
Теперь используется поле 0x24, которое должно найти базовый адрес КУЧИ по адресу 0x240000. Полученное значение помещается в регистр ESI.
BLOCKUNITS был равен 0x3 в инструкции SHL EAX, 3
Это похоже на умножение 8 поэтому
И это то значение, что осталось в поле USERSIZE
И это значение программа сравнивает со значением 0x3F . Поскольку оно меньше, программа идёт сюда.
Здесь программа пишет в заголовок чанка LFH. Мы не сделали структуру.
Программа перезаписывает 7 байт, меняя его со значения 0x80 на 0x88.
Сейчас блок обозначен как занятый. Если мы посмотрим следующий свободный блок по адресу 282928
Свободные блоки - это блоки со значение 0x80 , а занятые со значением 0x88.
Вопрос состоит в том, что значение, которое находится в структуре INTERLOCK_SEQ и которое определяет следующий блок для доставки находится в по адресу 0x282A78 (по смещению 0x8 от начала структуры HEAP_SUBSEGMENT)
До этого значение было равно 56000D.
А сейчас значение равно 59000C.
Расстояние между началом чанка, в который я могу написать, который решает, кто следующий….
То, что мы сказали в предыдущем туториале проверено здесь.
Это значение 0x282660 USERBLOCKS, помещается в регистр ESI.
Это означает, что в следующий раз, когда запрашивается размер 0x010, программа поместит в EDI значение 0x59000C если оно не перезаписано.
Программа помещает значение в регистр EAX и затем исполняет инструкцию SHR EAX,0xD
2 в 0xD степени = 8192 десятичных байт, т.е. 0x2000 в шестнадцатеричной системе
Другими словами, это эквивалентно значению 0x59000С делённому на значение 0x2000, что даёт мне результат 0x2C8
К этому значению программа применяет инструкцию AND c параметром 0x7FFF8
Затем программа добавляет регистр ESI, который равен 0x282660
И это даём мне результат 0x282928, что является следующим свободным
Это означает, что если есть переполнение, мы можем перезаписать эти данные переписав значение внутри структуры INTERLOCK_SEQ и программа предоставит мне предыдущий блок, про который мы расскажем в следующей части.
=======================================================
Автор текста: Рикардо Нарваха - Ricardo Narvaja (@ricnar456)
Перевод на русский с испанского: Яша_Добрый_Хакер(Ростовский фанат Нарвахи).
Исправление ошибок и неточностей - репетитор и носитель испанского языка.
Перевод специально для форума системного и низкоуровневого программирования — WASM.IN
24.06.2018
Версия 1.0
Введение в реверсинг с нуля, используя IDA PRO. Часть 48-2.
Дата публикации 20 июн 2018
| Редактировалось 24 июн 2018