Примеры использования функциональности аппаратной виртуализации процессоров Intel для реализации Anti-Vm Detect для VMware

Примеры использования функциональности аппаратной виртуализации процессоров Intel для реализации Anti-Vm Detect для VMware

В статье продемонстрированы примеры использования функциональности аппаратной виртуализации процессоров Intel для реализации Anti-Vm Detect для VMware и трассировки кода режима ядра.

Автор: Gerhart

Термины и определения

Гипервизор (или, согласно документации Intel, монитор виртуальных машин) – код, обладающий возможностью полного контроля над процессором и иным аппаратным обеспечением. В контексте статьи гипервизором будет называться код, выполняемый процедурой Vm_Handler.

VMCS (virtual-machine control structure) – структура, определяющая логику работы гипервизора (условия, при которых происходит VmExit; адрес процедуры, вызываемой при VmExit и т.д.). Поля структуры описаны в приложении B к Intel SDM, том 3.

VMX root – режим, в котором работает гипервизор.

VMX non-root – режим, в котором работает операционная система и обслуживаемое ею прикладное программное обеспечение.

VM exit – переход из VMX non-root в VMX root. Происходит при выполнении инструкций или условий, заданных в VMCS или заложенных непосредственно в логику работы процессора. В результате этого перехода процессор заполняет некоторые поля VMCS (например, поле GUEST_RIP и поле EXIT_REASON) и продолжает выполнение кода с адреса, указанного в поле HOST_RIP.

Vm entry – переход из VMX root в VMX non-root. Происходит при вызове инструкций VMLAUNCH или VMRESUME.

Среда выполнения

Примеры были разработаны на основе драйвера от deroko (http://deroko.phearless.org/cpuid_break.rar), который позволяет перехватывать управление кодом при выполнении инструкции cpuid. Особенностью этого драйвера является то, что он запускает гипервизор внутри самой операционной системы. Код гипервизора выполняется в адресном пространстве ядра ОС, что даёт возможность во время его работы использовать сервисы ядра (правда, далеко не все, учитывая, что гипервизор работает на HIGH IRQL с отключенной обработкой прерываний (IF = 0)).

Начиная с 8-й версии VMWare Workstation (при условии поддержки процессором EPT) поддерживает расширения аппаратной виртуализации внутри виртуальной машины (подробности здесь: http://www.veeam.com/blog/nesting-hyper-v-with-vmware-workstation-8-and-esxi-5.html), что даёт возможность полноценной отладки гипервизора в виртуальной среде.

Тестирование кода производилась в виртуальной машине под управлением Windows 7 SP1 x86, которую необходимо настроить следующим образом:

  1. Отключить файл подкачки
  2. Отключить PAE (bcdedit /set pae ForceDisable)
  3. Отключить DEP (bcdedit /set nx AlwaysOff)
  4. Оставить один активный процессор (bcdedit /set onecpu on)
  5. Создать DWORD ключ HKLM\Session Manager\Memory Management\LargePageMinimum и установить его значение в FFFFFFFF (отключит использование 4 мб страниц для ядра ОС и некоторых драйверов).

Теоретически, при выполнении таких настроек драйвер может работать и на обычном, не виртуальном, железе.

Для сборки драйвера достаточно запустить Windows 7 x86 Free Build Environment из WDK 7.1, перейти в каталог с исходными кодами драйвера и выполнить команду build.

Перед запуском драйвера необходимо запустить DbgView от Sysinternals для просмотра отладочных сообщений.

Для загрузки драйвера надо запустить loader.exe (грузит любой драйвер с именем test.sys, расположенный в той же директории). Если загрузка прошла успешно, появится сообщение «test.sys loaded. Ok to unload». Однако если нажать на «ОК» ничего не произойдёт, т.к выгрузка драйвера не реализована. Также драйвер можно грузить любым лоадером, например, Osrloader.

Теория

В данном разделе кратко описывается принцип работы некоторых возможностей аппаратной виртуализации, используемых в примерах. Полное описание технологии виртуализации приводится в Intel SDM, том 3, главы 23-32 (редакция 043 на момент написания статьи):

I/O bitmap

25-й бит Use I/O bitmaps поля VMCS primary processor-based VM-execution controls определяет возможность контроля операций с портами ввода\вывода гипервизором.

Также VMCS имеет 2 поля, каждое из которых содержит 64-битный физический адрес региона памяти. Эти регионы называются I/O bitmap A и I/O bitmap B, размер каждого региона – 4 КБайта. Регион I/O bitmap A контролирует диапазон портов ввода\вывода с 0 по 7FFFh, регион I/O bitmap A – с 8000h по FFFFh.

IN, INS/INSB/INSW/INSD, OUT, OUTS/OUTSB/OUTSW/OUTSD – инструкции, выполнение которых можно контролировать.

При появлении необходимости контроля операций, производимых с определённым портом, необходимо, во-первых установить бит Use I/O bitmaps в 1, во-вторых выставить соответствующий бит в I/O bitmaps регионах. Например, если необходимо контролировать порт с номером 100, то в I/O bitmap A сотый по счёту бит устанавливается в 1, а все биты I/O bitmap B - в 0.

Monitor Trap Flag

27-й бит Monitor trap flag (далее - MTF) поля VMCS primary processor-based VM-execution controls является неким аналогом TF из EFLAGS. Если MTF бит равен 1, процессор после выполнении каждой инструкции в VMX non-root режиме выполняет VM exit, называемый MTF VM exit, что приводит к передаче управления гипервизору. В Intel SDM описано поведение MTF VM exit в различных условиях.

Event Injection

Поле VMCS VM-entry interruption-information field. Указывает на структуру, контролирующую поведение процессора при VM Entry. Если обычно после завершения VM Entry выполнение кода продолжается с адреса, указанного в VMCS поле GUEST_RIP, то при использовании Event Injection выполнение кода передаётся обработчику исключений, номер которого указывается в поле Vector, либо, если поле Vector = 0, а поле InterruptionType = 7, включается MTF VM Exit. Подробности в Intel SDM. В примерах будет использоваться только первый вариант.

Необходимость указания ErrorCode зависит от обрабатываемого исключения и указана в Intel SDM, том 3, глава 6 «Interrupt and Exception Handling. Exception and interrupt Reference». Определение структуры:

typedef struct{
unsigned Vector:8;
unsigned InterruptionType:3;
unsigned DeliverErrorCode:1; Если 1, то через поле VM_ENTRY_EXCEPTION_ERROR_CODE
дополнительно указывается код ошибки.

unsigned Reserved:19;
unsigned Valid:1; если 0, то Event Injection не используется
}INTERRUPTION_INFORMATION_FIELD, *PINTERRUPTION_INFORMATION_FIELD;

Например, если из гипервизора управление необходимо передать обработчику DEBUG EXCEPTION операционной системы, то значения элементов структуры будет выглядеть следующим образом:

pinject_event->Vector = DEBUG_EXCEPTION;
pinject_event->InteruptionType = HARDWARE_EXCEPTION;
pinject_event->DeliverErrorCode = 0;
pinject_event->Valid = 1;

Exception Bitmap

Поле VMCS exception bitmap определяет возможность контроля исключений, генерируемых в VMX non-root режиме. Каждый бит поля определяет соответствующий ему номер исключения. Например, если в гипервизоре необходимо обрабатывать исключение DEBUG EXCEPTION, то в поле необходимо записать число 2.

Если необходимо контролировать Page Fault Exception (далее - PF), то дополнительно необходимо указывать значения полей page-fault error-code mask (PFEC_MASK) и pagefault error-code match (PFEC_MATCH).

При каждом PF процессор будет побитно сравнивать значения в левой и правой части выражения:

PFEC & PFEC_MASK = PFEC_MATCH

Где PFEC – это PF Error Code, возможные значения которого приведены в Intel SDM, том 3, рисунок 4-12. Page-Fault Error Code.

При совпадении произойдёт VM exit.

Описание работы драйвера

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

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

Режим работы гипервизора зависит от значения переменной ControlMode в loadvm.c. Возможные значения переменной:

enum CONTROL_MODE {
KERNEL_TRACE_MODE, трассировка драйверов
NTAPI_TRACE_MODE, контроль выполнения NtCreateFile
IO_CONTROL_MODE, anti VM detect
};

1. Контроль выполнения I/O инструкций (anti-VM detect)

Довольно широко известен метод детектирования исполнения кода внутри виртуальных машин производства VMware посредством обращения к определённому порту ввода\вывода. Простейший вариант обнаружения VM может быть представлен в виде следующего кода

mov eax, 0x564D5868
mov ebx,0
mov ecx, 0x0A
mov edx, 0x5658
in eax,dx
cmp ebx, 0x564D5868
je VMWare_detected

Если приложение работает внутри VmWare, то после выполнения инструкции in eax,dx в ebx окажется число 564D5868h. Если приложение выполняется на физическом хосте или же внутри VirtualBox (на виртуальных машинах других производителей тестирование не производилось), то в результате выполнения инструкции in eax,dx Windows сгенерирует исключение PRIVILEGED_INSTRUCTION.

Чтобы получить аналогичный результат внутри VMware потребуется модифицировать драйвер таким образом, чтобы любое обращение к порту 5658h приводило к возникновению VM exit и передаче управления гипервизору:

в I/O bitmap A бит с номером 22104 (5658h) устанавливается в 1, все остальные биты - в 0. Все биты в I/O bitmap B равны 0:

memtmp = MmAllocateNonCachedMemory(4096); выделяем память. Выравнивание по 4 КБ границе
происходит автоматически.
memset(memtmp, 0, 4096); обнуляем регион
*((PUINT8)memtmp+2763) = 0x1; устанавливаем нужный бит
PhysicalIOBitmapA[i] = MmGetPhysicalAddress(memtmp); записываем физический адрес региона
в VMCS поле. i содержит номер логического процессора (в нашем случае всегда 0, т.к.
система однопроцессорная и одноядерная).

memtmp = MmAllocateNonCachedMemory(4096);
memset(memtmp, 0, 4096);
PhysicalIOBitmapB[i] = MmGetPhysicalAddress(memtmp);

Далее в процедуру RunVirtualMachine необходимо добавить код, который активирует обработку I/O bitmap:

if (IO_CONTROL_MODE == TRUE)
{
dummy = VmRead(CPU_BASED_VM_EXEC_CONTROL) | CPU_BASED_ACTIVATE_IO_BITMAP;
VmWrite(CPU_BASED_VM_EXEC_CONTROL,dummy);
VmWrite(IO_BITMAP_A,PhysicalIOBitmapA[current_cpu].LowPart);
VmWrite(IO_BITMAP_B,PhysicalIOBitmapB[current_cpu].LowPart);
}

В процедуру VM_Handler и HandleVMX необходимо добавить следующие блоки кода:

HandleVMX:

VM_Handler:

После VM exit в eax содержится номер BASIC_EXIT_REASON, по которому можно установить причину VM exit (Таблица C-1. Basic Exit Reasons Intel SDM. Том 3). Далее внутри HandleVMX происходит обработка в зависимости от BASIC_EXIT_REASON.

Логика обработки следующая:

При выполнении инструкции in eax,dx происходит VM exit и управление передаётся на процедуру VMHandler и далее в HandleVMX. В этой процедуре происходит анализ BASIC_EXIT_REASON (при выполнении I/O инструкции это будет EXIT_REASON_IO_INSTRUCTION (30)). При обработке необходимо учитывать, на каком уровне привилегий произошёл VM exit – в пользовательском режиме или в режиме ядра. Если VM exit произошёл во время выполнения I/O инструкции в режиме ядра, то достаточно проверить параметры, передаваемые I/O инструкции, чтобы удостовериться в том, что драйвер пытается обнаружить VMware:

if ((x86->regEax == 0x564D5868) && (x86->regEdx == 0x5658) && (x86->regEcx == 0xA))
{
DbgLog("EXIT_REASON_IO_INSTRUCTION.KM.VMWare Magic Number Check", vMCS.GUEST_RIP);
VMMagicNumberDetect = TRUE;
}

x86 – это структура, содержащая значения основных регистров процессора непосредственно перед VM exit. Далее нужно выполнить I/O инструкцию. Если просто вернуться обратно на эту же инструкцию, то VM exit будет выполнен снова, и система впадёт в бесконечный цикл. Для того, чтобы избежать зацикливания, перед возвратом из гипервизора необходимо временно деактивировать контроль над выполнением I/O инструкций:

dummy = VmRead(CPU_BASED_VM_EXEC_CONTROL);
dummy &= ~CPU_BASED_ACTIVATE_IO_BITMAP; выключаем IO control
VmWrite(CPU_BASED_VM_EXEC_CONTROL,dummy); записываем новое значение в VMCS
Cразу же после выполнения I/O инструкции необходимо снова активировать I/O bitmap, иначе будут пропущены последующие возможные попытки обнаружения работы внутри VMware. Для этого будет использоваться MTF:

  • при обработке EXIT_REASON_IO_INSTRUCTION отключается контроль I/O bitmap и включается MTF, происходит VM entry
  • после исполнения инструкции происходит MTF VM exit, в котором снова включается контроль I/O bitmap, выключается MTF, происходит VM entry

В случае если VM exit был произведён при выполнении I/O инструкции в пользовательском режиме, то обработка происходит несколько иначе:

if ((x86->regEax == 0x564D5868) && (x86->regEdx == 0x5658) && (x86->regEcx == 0xA))
{
DbgLog("EXIT_REASON_IO_INSTRUCTION. UM. VMWare Magic Number Check",
vMCS.GUEST_RIP); выводим адрес инструкции
VMMagicNumberDetect = TRUE; для последующего обнуления ebx
VmWrite(GUEST_RIP, (ULONG) vMCS.GUEST_RIP); после VM entry инструкция, вызвавшая
Vm exit, будет исполнена снова
dummy = 0;
pinject_event = (PINTERUPTION_INFORMATION_FIELD)&dummy;формируется Event Injection
pinject_event->Vector = GENERAL_PROTECTION_EXCEPTION; Номер вектора 14
pinject_event->InteruptionType = HARDWARE_EXCEPTION;т.к. GP
pinject_event->DeliverErrorCode = 1;раздел 6.15, GP
pinject_event->Valid = 1;
VmWrite(VM_ENTRY_INTR_INFO_FIELD, dummy);
dummy = 0;
VmWrite(VM_ENTRY_EXCEPTION_ERROR_CODE, dummy);в VMCS записывается Error Code
}

Для эмуляции исключения PRIVILEGED_EXCEPTION необходимо выполнить Event Injection для GENERAL_PROTECTION_EXCEPTION с указанием кода ошибки - 0. В этом случае после VM entry управление будет передано процедуре обработки GENERAL_PROTECTION_EXCEPTION KiTrap0D, которая, в свою очередь, самостоятельно проанализирует инструкцию, адрес которой указан в GUEST_RIP, обнаружит, что она является инструкцией ввода\вывода и затем доставит ошибку PRIVILEGED_INSTRUCTION приложению.

Если ошибиться и указать GUEST_RIP неправильно, то исключение будет другого типа (ACCESS_VIOLATION)

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

К примеру, если использовать следующий код для проверки, то в гипервизоре достаточно непосредственно перед выполнением vmresume обнулить ebx:

Без гипервизора результат будет:

С активным гипервизором:

P.S. Если для отладки драйвера используется VirtualKD, то система будет зависать. Это связано с тем, что библиотека kdbazis.dll, устанавливаемая в гостевой системе и работающая в kernel mode, также использует порт 5658h для работы.

2. Контроль вызовов Native API (на примере NtCreateFile)

Обнуление Present Bit в PTE страницы памяти, на которой размещается первая инструкция NtCreateFile, приводит к возникновению Page Fault Exception, который и будет обрабатываться гипервизором. Включается MTF и после MTF VM exit, происходящем после выполнения каждой инструкции, производится анализ выполнения кода в пределах заданной страницы. Как только начнёт выполняться код, расположенный на другой странице, Present Bit предыдущей страницы сбрасывается в 0, а MTF выключается.

Драйвер компилируется с поддержкой Exception Bitmap для PF:

if ((ControlMode == KERNEL_TRACE_MODE) | (ControlMode == USER_TRACE_MODE) | (ControlMode
== NTAPI_TRACE_MODE)) Режим трассировки
{
VmWrite(EXCEPTION_BITMAP, 0x4000); PageFault VMExit enable
VmWrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
VmWrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
}

Для отправки IOCTL можно использовать приложенную к исходникам утилиту io.exe:

При получении IOCTL NTAPI_ACCESS драйвер вызывает функцию CreateKernelAccessAddressTable, которая ищет адрес NtCreateFile в SDT и передаёт его функции NtapiCreateDriverPageTable, заполняющую таблицу DriverPageTable (состояющую в данном случае из одного элемента, содержащего адрес NtCreateFile). Каждый элемент таблицы - это структура, содержащая указатель на PTE, виртуальный адрес начала страницы памяти NtCreateFile, а также непосредственно виртуальный адрес начала NtCreateFile. Затем функция CreateKernelAccessAddressTable вызывает DisablePresentBitDriverTable, которая для всех элементов таблицы DriverPageTable обнуляет Present Bit PTE, что, соответственно, приводит к PF при любой попытке доступа к этим страницам. Также в этой процедуре определяется минимальный и максимальный виртуальный адрес для множества всех страниц элементов DriverPageTable, что позволяет несколько увеличить скорость обработки PF в случае, если страницы памяти расположены близко друг к другу.

Также не следует забывать о том, что даже при отключенном файле подкачки PF исключения всё равно постоянно генерируются операционной системой и требуют соответствующей обработки. Если причиной PF является попытка доступа к страницам в DriverPageTable, то его необходимо обработать таким образом, чтобы ядро Windows не узнало о возникшем исключении. В ином случае информация о PF должна быть доставлена ОС через Event Injection.

При возникновении PF происходит VM exit и в HandleVMX обработчик PF cчитывает необходимые для обработки PF поля VMCS:
EXIT_QUALIFICATION – содержит адрес памяти, попытка доступа к которому вызвала PF. Если PF происходит при попытке выполнения кода в недоступной странице, то в этом случае EXIT_QUALIFICATION равен GUEST_RIP.
GUEST_RIP – адрес инструкции, выполнение которой вызвало PF.

Далее происходит проверка попадания EXIT_QUALIFICATION в диапазон заблокированных страниц. Если EXIT_QUALIFICATION находится вне пределов диапазона, то обработка прерывается и исключение доставляется до ОС через Event Injection.

if (((ExitQualification[ccpu] > DriverPageTable.maxVirtualAddress+MMU_PAGE_SIZE)) |
(ExitQualification[ccpu] < DriverPageTable.minVirtualAddress))
break;

Если адрес памяти, доступ к которому вызвал PF, входит в указанный диапазон, то происходит проверка попадания адреса в страницы из таблицы DriverPageTable. Если адрес находится в одной из страниц, то происходят дополнительные проверки:

if (vMCS.GUEST_RIP == DriverPageTable.DrvPageInfo[i].NtapiVirtualAddress)

Если адрес совпал с адресом NtCreateFile, то выводится отладочное сообщение о вызове этой функции и в качестве дополнительной информации выводится имя объекта из структуры OBJECT_ATTRIBUTES, являющейся одним из параметров функции. Для отображения POBJECT_ATTRIBUTES, расположенной в пользовательском адресном пространстве, выполняется функция vmm_memcpy_objattr, которая копирует имя объекта из пользовательского адресного пространства в адресное пространство ядра, временно изменяя значение регистра CR3 на значение поля GUEST_CR3 из VMCS.

Если адрес находится в одной из страниц в DriverPageTable, но не совпадает с началом NT-сервиса ядра, то Present Bit этой страницы устанавливается в 1 и включается MTF для того, чтобы отследить, когда закончит выполняться код с этой страницы.

Далее при выполнении каждой инструкции происходит VM exit с EXIT_REASON = EXIT_REASON_MONITOR_TRAP_FLAG (37) до тех пор, пока GUEST_RIP не выйдет за пределы страницы, попытка доступа к которой сгенерировала PF.

В итоге в DbgView можно получить следующую картину:

Метод сильно снижает производительность системы и его применение имеет смысл только в том случае, когда по каким-то причинам нельзя изменять SDT или использовать сплайсинг.

3. Трассировка кода

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

Трассировка кода в ring-0.

При получении IOCTL DRIVER_TRACE драйвер в первую очередь создаёт отдельный поток, который будет записывать результаты трассировки в файл C:\data.trace, формат которого совместим с визуализатором трасс кода, генерируемых Intel PIN framework и гипервизорным трассировщиком на базе XEN Ether, под названием VERA, разработанным Danny Quist’ом.

Далее драйвер, используя функцию WindowsGetDriverCodeSection, получает виртуальный адрес и размер секции кода драйвера.

Затем вызывается функция CreateDriverPageTable, которая заполняет уже знакомую по предыдущему примеру таблицу DriverPageTable исходя из адреса и размера кода, который необходимо трассировать. Далее функция DisablePresentBitDriverTable обнуляет Present Bit PTE страниц из таблицы DriverPageTable.

Можно задать несколько секций одного или нескольких драйверов последовательно вызывая эти функции.

После выполнения вышеописанных действий доступ к таким страницам генерирует PF, при обработке которого включается MTF. После каждого MTF VM exit в массив RawTraceBuffer добавляется значения GUEST_RIP из VMCS.

Если размер буфера достигнет предела, определяемого TRACE_COUNTER_LIMIT, то трассировка прекратится, Present Bit PTE всех страниц из таблицы DriverPageTable установится в 1, содержимое RawTraceBuffer сбросится в файл функцией WriteTraceFile, выполняемой в отдельном потоке и ожидающей, когда переменная EndOfTrace станет TRUE.

if (EndOfTrace == FALSE)
{
RawTraceBuffer[TraceCounter] = (ULONG)vMCS.GUEST_RIP;
TraceCounter++;
if (TraceCounter == TRACE_COUNTER_LIMIT)
{
EnablePresentBitDriverTable();
EndOfTrace = TRUE;
DbgPrint("Trace finished\n");
}
}

Остановить трассировку и сбросить данные в файл можно принудительно, если отправить драйверу IOCTL WRITE_TRACE_FILE.

Для примера посмотрим трассировку драйвера srv2.sys, выполненную при старте службы lanmanserver:

s_info = WindowsGetDriverCodeSection(s_info,"srv2.sys",".text");
CreateDriverPageTable(s_info);
DisablePresentBitDriverTable();
s_info = WindowsGetDriverCodeSection(s_info,"srv2.sys","PAGE");
CreateDriverPageTable(s_info);
DisablePresentBitDriverTable();

Трассировке подвергнется код, размещённый в секциях .text и PAGE. Для проверки предварительно нужно остановить службу lanmanserver: net stop lanmanserver.

После загрузки драйвера гипервизора и отправки ему IOCTL DRIVER_TRACE будет выведена информация об адресе загрузки драйвера:

Driver Load base cpu:[0][8D0DA000]

Она пригодится для загрузки драйвера в IDA PRO.

Далее служба lanmanserver запускается обратно: net start lanmanserver. В DbgView появится следующая информация

После отправки драйверу IOCTL WRITE_TRACE_FILE вся данные из буфера RawTraceBuffer сбросятся в файл C:\data.trace:

Файл data.trace лучше скопировать на физическую машину, т.к. VERA для отображения графа будет активно использовать ресурсы видеоадаптера.

После запуска wxVera.exe необходимо открыть файл data.trace, указать трассируемый драйвер и путь для сохранения gml-файла:

Получится подобный граф:

Для настройки взаимодействия VERA c IDA Pro необходимо:

  • запустить IDA Pro module listener: 
  • скопировать в директорию с плагинами для IDA файл vera_ida.plw 
  • запустить IDA и загрузить в неё файл srv2.sys. При загрузке выбрать опцию «Manual load» и указать в image base базу загрузки драйвера, который был получен ранее 8D0DA000. Далее загрузить все секции и отладочные символы. 
  • перейти в IDA->plugins>-vera_ida и указывать в поле «Server» IP-адрес машины, на которой запущена VERA (если IDA Pro и VERA работают на одной машине, то прописывается адрес 127.0.0.1). IDA Pro должна выдать сообщение в output window:

vera_ida: successfully connected to 127.0.0.1:2005

После этого при щелчке правой кнопкой мыши на адресе в графе, отображаемом VERA, в окне Ida View происходит переход к инструкции, расположенной по этому адресу.

Например, на графе хорошо заметны циклы:

Щёлкнув ПКМ на 8d0f07e6 попадаем в

По перекрёстным ссылкам можно увидеть, что функция SrvLibGetDWord используется при считывании параметров службы из реестра:

Подробности использования VERA изложены в презентации автора (http://www.shmoocon.org/2012/presentations/Danny_Quist-3dmalware-shmoocon2012.pdf):

Трассировка кода в ring-3. В настоящее время разработано огромное количество разнообразных трассировщиков ring-3 приложений, так что выдумывать ещё один является довольно бессмысленным занятием. В драйвере реализована возможность трассировки кода в жёстко заданном диапазоне адресов 403000 – 403FFF. Для проверки драйвер нужно скомпилировать с ControlMode = USER_TRACE_MODE, запустить утилиту cpuid_loader_mod.exe и указать ей приложение для запуска (На Windows 7 ASLR не даст загрузить приложение со стандартной базой 400000, так что с помощью PE Tools у тестового приложения можно отключить релоки).

Заключение

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

Если появятся вопросы или замечания, пишите на gerhart xakep ru.

Скачать архив с файлами к этой статье можно по адресу: http://www.securitylab.ru/upload/files-427855.zip

Источники:

  1. http://deroko.phearless.org/cpuid_break.rar
  2. Phrack. http://www.phrack.org/
  3. Hyperdbg. http://code.google.com/p/hyperdbg/
  4. Virtdbg. http://code.google.com/p/virtdbg/
  5. Intel SDM. http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
  6. http://csr.lanl.gov/vera

Не ждите, пока хакеры вас взломают - подпишитесь на наш канал и станьте неприступной крепостью!

Подписаться