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