> For the complete documentation index, see [llms.txt](https://yutewiyof.gitbook.io/intro-rev-ida-pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yutewiyof.gitbook.io/intro-rev-ida-pro/chast-47.md).

# Часть 47

Давайте попробуем прояснить некоторое вещи, которые мы ещё не упоминали в теме о куче и которые очень необходимы. Мы будем делать это снова смотря на упражнение **PRACTICA 44** о котором мы говорили в **WINDOWS 7**. Мы снова посмотрим на него же в тех же программах.

Хорошо заметить, что способ обработки кучи очень сильно изменился от **XP** к **WINDOWS 7**, и имеет больше изменений даже до **WINDOWS 10**. Поэтому способы эксплуатации, которые работали в одной системе, могут не работать в другой.

Верно также, что мы должны очень много бороться с типами эксплоитов, который эксплуатирует переполнение кучи они не просты в большинстве случаев и не всегда работают на **100%**.

Хорошо. Мы будем рассматривать упражнение из **44** части.

<http://ricardonarvaja.info/WEB/INTRODUCCION%20AL%20REVERSING%20CON%20IDA%20PRO%20DESDE%20CERO/EJERCICIOS/PRACTICA_44.7z>

Мы будем использовать **WINDBG** вне **IDA**.

![](/files/-LjrTADh84p06Vsmxnoz)

Мы уже увидели, что начальный адрес функции **MALLOC** находится по адресу **0x004010D7**. Поэтому я помещаю **BP** в **WINDBG** с помощью команды

```
BA E1 0x004010D7
```

Поскольку мы знаем, что размер был **NUMERO**, которые мы передавали умноженное на **4**.

![](/files/-LjrTADqPeztM7mXUe3h)

То число, которое передается в **HEX** виде равно **HEX(1073741828)** или **0x40000004**

Умножение на **4** даёт мне значение **0x10**

![](/files/-LjrTADzlL_BVwuO_AmY)

Поэтому функция выделяет нам **0x10** байт.

![](/files/-LjrTAEAYkXJ6PMk6amV)

При переходе через функцию **MALLOC** с помощью клавиши **F10** я вижу, что в моём случае, выделение памяти происходит по адресу **0x00301B20**

![](/files/-Ljtu3eV6_D8c02OqBjE)

Выделенная память принадлежит к блоку размером **0x10** байт **USERSIZE**, т.е. будет **0x10** байт пространства, которое резервирует память для использования пользователем, без учета заголовка.

Я использую команду `!HEAP -A 0x2C0000` для того, чтобы увидеть чанки кучи.

![](/files/-Ljtu3ekpnU73iMOOW3S)

У нас есть чанк по адресу **0x301860** длиной **0x400** байт, который будет иметь мой адрес внутри, потому что адрес **0x301B20** включен в этот блок, который начинается по адресу **0x301860** и прибавляя **0x400** байт получим адрес где заканчиваться чанк, т. е. **0x301C60**.

**HEX**(**0x301860** + **0x400**) = **0x301C60**

Посмотрим, что скажет нам **MONA** в этом случае.

Я загружаю её с помощью

```
.LOAD PYKD.PYD
```

И затем ввожу команду

```
!PY MONA.PY HEAP -H 0x2C0000 -T CHUNKS
```

![](/files/-Ljtu3exaOwd8jfIX8N5)

**WINDBG** показывает нам тот же чанк с размером **0x400** байт за исключением того, что в **INTERNAL** говорит нам, что он принадлежит **LFH**.

## LOW FRAGMENTATION HEAP

Можно написать много туториалов о **LFH**. Это сложно. Мы попытаемся, чтобы у Вас не закружилась голова и пойдем частям. Это будет первая. В следующей части мы постараемся увидеть, сможем ли мы понять и следовать распределению.

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

Фрагментация кучи происходит, когда выделяются небольшие несмежные блоки. Когда это происходит, выделения памяти может быть неудачным, хотя может быть достаточно общей памяти в куче для того, чтобы удовлетворить запрос. Тем не менее, поскольку никакой блок свободной памяти не является достаточно большим, запрос на выделение может быть неудачным. Для приложений с использованием небольшого объёма памяти, стандартная куча подходит и проблем не будет, там выделения не будут неудачными из-за фрагментации кучи. Тем не менее, если приложения распределяют память часто с использованием разных размеров, эти выделения памяти могут быть неудачными из-за фрагментация кучи.

Мы увидим несколько таблиц и в следующих частях мы попытаемся понять как система принимает решение выделять в **LFH** или в стандартной **КУЧE** и как это работает.

Принимайте все это спокойно и с терпением, я знаю, что никому не нравится эта вся ерунда. Мы будем все это делать потихоньку с тем же примером, который остановлен в **WINDBG**.

Теперь, имея адрес базы кучи, мы можем увидеть её содержимое с помощью команды **DT \_HEAP** адрес

![](/files/-Ljtu3fE0gsNjYMNSFR8)

Здесь находится главная таблица кучи, которую можно увидеть с помощью команды **DT \_HEAP** и адреса таблицы, который в моем случае равен **0x2C0000**.

В позиции **0xB8** находится **BLOCKSINDEX**, который указывает на другую таблицу. В моем случае эта таблица находится по адресу **0x2C0150**, т.e. **0x150** байт от начал кучи.

`+0x0B8 BLOCKSINDEX : PTR32 VOID`

![](/files/-LjrTAEcx9Y2ZfTlzKer)

Для просмотра содержимого этой таблицы **BLOCKSINDEX** используется следующая команда **DT \_HEAP\_LIST\_LOOKUP** адрес

![](/files/-LjrTAEif-CKTR7J6r6d)

Мы попытаемся показать вам таблицы и объяснить минимальные нужные знания, и вернемся позже к этой таблице.

Следующая важная таблица происходит из главной таблицы значения **FRONTENDHEAP**

![](/files/-Ljtu3g1oIixmN2cE3Nj)

В моём случае значение указывает на адрес **0x2C9FB8**. Помните, что при поиске моего чанка в списке было так

![](/files/-LjrTAEut_o451sVJojD)

Случайно по адресу **0x2C9FB0** начинались эти чанки **INTERNAL LFH**. Это показывает положение **LOW FRAGMENTATION HEAP** что является **FRONTEND HEAP**, в то время как стандартная куча называется **BACKEND HEAP**.

Здесь ясно видно, что **LFH** это куча внутри другой кучи. Он начинается там, поскольку это был чанк больше, чем основная куча, но внутри он имеет другую кучу.

Давайте продолжать.

Для просмотра содержимого **LFH** через указатель **FRONTENDHEAP** используется команда **DT \_LFH\_HEAP** адрес

![](/files/-LjrTAF0827yBFb43SEe)

Осталось немного потерпеть.

В качестве любопытства давайте отметим, что смещение **0x18 SUBSEGMENTZONES** имеет указатель на третий блок **INTERNAL LFH**.

![](/files/-LjrTAF62xbji0Wq4D3z)

Внутри **LFH** есть пара структур более важных. Одна из них это **\_HEAP\_LOCAL\_DATA**, которая находится по смещению **0x310**, чьё содержимое можно увидеть с помощью команды

**DT \_HEAP\_LOCAL\_DATA** адрес

![](/files/-Ljtu3h8XdNEbUExaKrh)

**SEGMENTINFO** это список из **128** байт. Давайте посмотрим, что там есть. В том же **WINDBG** делаем щелчок на **SEGMENTINFO**, и нам покажется список. Если это не сработало, тогда так.

**DT \_HEAP\_LOCAL\_SEGMENT\_INFO**

![](/files/-Ljtu3hM-atk0ocOmLjr)

и перемещая мышь над номерами **\[0]**, **\[1]**, и т.д. нам показывается адрес.

![](/files/-Ljtu3hdnwTGo646DU_f)

Это будет первый **LOCAL SEGMENT INFO**. Мы можем увидеть, что значит его содержимое, нажимая например на ячейку **\[0]**.

![](/files/-LjrTAFQjFPP_IxjxAXb)

Мы видим, что есть список под названием **CACHEDITEMS** по смещению **0x8** поэтому мы можем нажать туда. В моём случае первый **SEGMENTINFO** начинается по адресу **0x2CA2E8**.

![](/files/-Ljtu3iM9jcNsB_VsALT)

Каждый из них является типом **\_HEAP\_SUBSEGMENT**.

Чтобы увидеть содержимое, Вы должны использовать команду

**DT \_HEAP\_SUBSEGMENT** адрес

![](/files/-Ljtu3ig0pceQzpk3L0Q)

И после всего этого мы прибудем туда куда хотим, т.е. внутрь структуры **AGGREGATEEXCH**, которая находится по смещению **0x8**. Это будет \_**INTERLOCK\_SEQ**. Её может показать следующая команда

```
DT _INTERLOCK_SEQ *адрес*
```

![](/files/-Ljtu3ixamWA-DKlkaNt)

Также, сделав щелчок в **WINDBG**

![](/files/-Ljtu3jGTX0qYdYPqdQ7)

Хорошо, наша задача была дойти до поля **FREEENTRYOFFSET**. В этом случае оно равна нулю. Давайте напишем правильно как дойти до этого места, если мы увидим определение этого значения.

**FREEENTRYOFFSET** - это **2**-байтное целое число, которое хранит значение. При добавлении к адресу \_**HEAP\_USERDATA\_HEADER**, результат приводит к указателю на следующее местоположение для освобождения или выделения памяти.

Другими словами это зависит от текущего значения которое будет следующим блоком, который будет выделен или освобожден. К нему добавляет другое поле, которое называется \_**HEAP\_USERDATA\_HEADER**. Давайте посмотрим где находится это.

Это значение приходит из той же предыдущей таблицы, только находится по смещению **0x4** т.е. это **USERBLOCKS**

![](/files/-Ljtu3jiKZqCQaLDVykj)

И структура дампиться с помощью команды

![](/files/-Ljtu3k-ZqoArD71EuOP)

Хорошо. Потихоньку мы получаем значения, чтобы собрать головоломку. Мы видим, что **USERBLOCKS** находится прямо над **\_INTERLOCK\_SEQ** который является тем у которого есть указатель на **FREEENTRYOFFSET** и поскольку переполняя данные чанка он бы смог переписать его и изменить следующий чанк, который вы хотите выделить. Здесь на картинке это видно более ясно.

![](/files/-LjrTAGEHIBIBFOvBXyc)

Здесь на картинки это видно более понятно. Вы видите заголовок **\_HEAP\_USER\_DATA** который мы видели, прямо под которым находится область записанная пользователем, и прямо под ней находится структура **\_INTERLOCK\_SEQ** которая является той, которая имеет значение, и которая решает, что является следующим.

С этим у нас есть видение основных таблиц и их значений. В следующей части мы увидим помогает ли нам изучение того, что программа решает выделить память в стандартной куче или в **LFH**.

Автор оригинального текста — Рикардо Нарваха.

Перевод и адаптация на английский язык — IvinsonCLS.

Перевод и адаптация на русский язык — Яша Яшечкин.

Перевод специально для форума системного и низкоуровневого программирования - WASM.IN

02.06.2018

[**Источник: ricardonarvaja.info**](http://ricardonarvaja.info/WEB/IDA%20DESDE%20CERO/CURSO%20DE%20IDA%20TUTES/47-INTRODUCCION%20AL%20REVERSING%20CON%20IDA%20PRO%20DESDE%20CERO.docx)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://yutewiyof.gitbook.io/intro-rev-ida-pro/chast-47.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
