воскресенье, 7 ноября 2010 г.

Изменения SSDT на x64

В 64 битных windows внутренности System Service Table изменились, например, вместо адресов в KiServiceTable находятся смещения, а KiArgumentTable не используется вовсе.

Причем глядя в IDA на KiServiceTable все это как-то неочевидно:

.text:000000014005B000 KiServiceTable  dq offset NtMapUserPhysicalPagesScatter
.text:000000014005B008                 dq offset NtWaitForSingleObject
.text:000000014005B010                 dq offset NtCallbackReturn
.text:000000014005B018                 dq offset NtReadFile
.text:000000014005B020                 dq offset NtDeviceIoControlFile
.text:000000014005B028                 dq offset NtWriteFile
.text:000000014005B030                 dq offset NtRemoveIoCompletion

Однако стоит в отладчике посмотреть якобы "адреса" в KiServiceTable:

kd> dqs  nt!KiServiceTable
fffff800`01c6e000  025ff700`03935200
fffff800`01c6e008  022b7d05`fff95e00
fffff800`01c6e010  0268e605`026b1506
fffff800`01c6e018  021d6440`02389701

... чтобы увидеть, что на адреса это мало похоже(адреса то не полноценно 64х битные, а всего лишь 48ми битные). А если смотреть двойные слова:

kd> dds  nt!KiServiceTable
fffff800`01c6e000  03935200
fffff800`01c6e004  025ff700
fffff800`01c6e008  fff95e00
fffff800`01c6e00c  022b7d05 <== 5 это число стековых аргументов ф-ции
fffff800`01c6e010  026b1506

... то видно, что это офсеты.

А KiArgumentTable не используется, потому что аргументы закодированы в 4х младших битах офсета.

Напомню, что 4 аргумента всегда передаются через регистры ( rcx, rdx, r8, r9 ), остальные через стек, таким образом для ф-ций с <= 4 агрументами количество этих самых аргументов нигде не храниться.

Взглянув на обработчик syscall'ов, ф-цию KiSystemCall64 ( получить можно через MSR(LSTAR) ) видно следующее:

KiSystemCall64:

movsxd  r11, dword ptr [r10+rax*4] <== берем из KiServiceTable LONG ( именно LONG, ибо оффсет знаковый, может быть отрицательным )
mov     rax, r11
sar       r11, 4   <== 4 бита убираем, чтобы получить чистый офсет
add     r10, r11 <== KiServiceTable + полученный офсет = адрес сервисной ф-ции
...
далее если необходимо копируются стековые аргументы из юзермодного стека в ядерный, и вызывается сервисная ф-ция.

Преобразование таблички из той, что видно в IDA, в ту, которая на самом деле лежит в памяти делает ф-ция KeCompactServiceTable на этапе инициализации ядра.

Если взглянуть на nt!KiArgumentTable, то видно, что она тоже заполнена, однако не используется. Почему сделано так, а не иначе мне неведомо, если кто знает, опишитесь в комментах.

1 комментарий:

  1. Ага, сталкивался с этой темой, логику подобных изменений по сравнению с x32 так и не вкурил.
    Кстати, Vista и старше эти смешения ещё сдвинуты на 4-е байта.
    Вот здесь есть ф-ции поиска и разбора таблицы, которые я для драйверного фаззера писал: http://code.google.com/p/ioctlfuzzer/source/browse/trunk/src/driver/src/driver.cpp

    ОтветитьУдалить