FindShadowTable.asm Код (Text): invoke GetServiceDescriptorTableShadowAddress .if eax != NULL mov eax,[eax] mov eax,[eax] .endif работает отлично Код (Text): invoke GetServiceDescriptorTableShadowAddress .if eax != NULL add eax,10h mov eax,[eax] ; eax == BF997600 (kproccheck показывает этот же адрес) mov eax,[eax] ;<-PAGE_FAULT (MmIsAddressValid == 0) .endif BSoD
Смутно уже всё помню , но думаю проблема в том, что GetServiceDescriptorTableShadowAddress вызывается из контекста системного процесса, например из DriverEntry. Есть два вида потоков: GUI и не-GUI. Не-GUI потокам не нужны сервисы win32k. Все потоки изначально не-GUI. Как только поток делает свой первый вызов к какой-либо функции GDI или USER, то система чего-то там меняет в его сервисной таблице (то ли добавляет указатель на сервисную таблицу win32k, то ли чего там перегруппирует). К тому же, кажется сервисная таблица win32k лежит на адресном пространстве сеанса (session address space). У системного процесса нет туда доступа, кажись. Вобщем детали я скорее всего путаю, но идея должна быть понятна. Если просто добавить в драйвер обработчик IRP_MJ_DEVICE_CONTROL, дернуть его из юзера и уже в контексте юзерного потока вызывать GetServiceDescriptorTableShadowAddress, то тогда твой код скорее всего заработает без бсодов. Или же придется переключаться на контекст любого GUI потока и оттуда вызывать GetServiceDescriptorTableShadowAddress. Кажись где-то так. Погугли детали.
я читал конференции и статьи, это я уяснил хорошо а вот про "session address space, у системного процесса нет туда доступа" - нигде не встречал. осталось научиться "переключаться на контекст любого GUI потока"... а вообще, большое спасибо за направление. буду изучать дальше. а насчет погуглить детали - это вряд ли. почти все что находится так или иначе относится к твоим наработкам или упоминается твое имя.
если я знаю адрес списка, я могу с ним работать из user-mode'а посредством NtMapViewOfSection? Вызов GetServiceDescriptorTableShadowAddress из DispatchControl задал мне больше вопросов. теперь адрес таблицы вообще не возвращается. KeServiceDescriptorTable и адрес KTHREAD.ServiceTable (этого потока) не равны!!! как следствие - GetServiceDescriptorTableShadowAddress не определяет смещение по которому в KTHREAD находится ServiceTable.
хз. Поищи исходники всяких анхукеров SSDT и посмотри как они работают с таблицей. В буржунете точно есть статьи по теме. Вспоминать некогда. Вот кусок из работающего драйвера. Код (Text): SYSTEM_SERVICE_TABLE STRUCT ; sizeof = 10h pServiceTable PVOID ? ; array of entry points pCounterTable PDWORD ? ; array of usage counters dwServiceLimit DWORD ? ; number of table entries pArgumentTable PBYTE ? ; array of byte counts SYSTEM_SERVICE_TABLE ENDS PSYSTEM_SERVICE_TABLE typedef ptr SYSTEM_SERVICE_TABLE SERVICE_DESCRIPTOR_TABLE STRUCT ; sizeof = 40h ntoskrnl SYSTEM_SERVICE_TABLE <> ; ntoskrnl.exe (native api) win32k SYSTEM_SERVICE_TABLE <> ; win32k.sys (gdi/user) iis SYSTEM_SERVICE_TABLE <> ; Internet Information Services Table4 SYSTEM_SERVICE_TABLE <> ; reserved SERVICE_DESCRIPTOR_TABLE ENDS PSERVICE_DESCRIPTOR_TABLE typedef ptr SERVICE_DESCRIPTOR_TABLE g_dwServiceTableFieldOffset DWORD ? g_pKeServiceDescriptorTableShadow PSERVICE_DESCRIPTOR_TABLE ? DispatchControl proc uses esi edi ebx pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP mov esi, pIrp assume esi:ptr _IRP mov [esi].IoStatus.Status, STATUS_UNSUCCESSFUL and [esi].IoStatus.Information, 0 IoGetCurrentIrpStackLocation esi mov edi, eax assume edi:ptr IO_STACK_LOCATION mov eax, [edi].Parameters.DeviceIoControl.IoControlCode .if eax == IOCTL_FIND_SERVICE_TABLE_FIELD_OFFSET ; Find KTHREAD.ServiceTable field ; For non-GUI threads this field == KeServiceDescriptorTable ; and it points to ServiceDescriptorTable invoke KeGetCurrentThread mov edx, KeServiceDescriptorTable mov edx, [edx] mov ecx, 200h-4 .while ecx .break .if dword ptr [eax][ecx] == edx dec ecx .endw mov g_dwServiceTableFieldOffset, ecx .if ecx != 0 ; ecx = offset to ServiceTable field in KTHREAD structure mov [esi].IoStatus.Status, STATUS_SUCCESS .endif .elseif eax == IOCTL_FIND_SHADOW_TABLE_ADDRESS .if g_dwServiceTableFieldOffset != 0 ; Find not exported KeServiceDescriptorTableShadow. ; The calling thread should be GUI one. ; So its KTHREAD.ServiceTable == KeServiceDescriptorTableShadow. ; And we already know the right offset to this field invoke KeGetCurrentThread mov ecx, g_dwServiceTableFieldOffset mov eax, dword ptr [eax][ecx] mov edx, KeServiceDescriptorTable mov edx, [edx] .if eax != edx ; If KTHREAD.ServiceTable != KeServiceDescriptorTable ; it nothing more then KeServiceDescriptorTableShadow. mov g_pKeServiceDescriptorTableShadow, eax mov [esi].IoStatus.Status, STATUS_SUCCESS IFDEF DBG invoke DbgPrint, $CTA0("KeServiceDescriptorTableShadow found at address: %08X\n"), \ g_pKeServiceDescriptorTableShadow ENDIF .endif .endif .else mov [esi].IoStatus.Status, STATUS_INVALID_DEVICE_REQUEST .endif push [esi].IoStatus.Status assume esi:nothing assume edi:nothing fastcall IofCompleteRequest, esi, IO_NO_INCREMENT pop eax ret DispatchControl endp
В общем как я говорил, KeServiceDescriptorTable и KTHREAD.ServiceTable хранят разные адреса (и смещение не определяется). НО! я прямо дал смещение для KTHREAD == E0h, и доступ к адресу BF997600 из DispatchControl есть! собственно мне большего и не надо. Спасибо большое Four-F, Twister!
безусловно. но мне это нужно на моем компе только. да и я всегда могу получать нужные адреса (тот же ~BF997600) в DriverEntry сначала (вызванная оттуда функция нормально получала адрес shadow таблицы), а уже потом ломиться по ним из DispatchControl. в общем надо установить закономерность когда и что происходит с этими адресами и работать.
Four-F, извини, я опять затупил... DbgPrint оказывается GUI функция и я ее вызывал как раз перед сравнением (люблю эту функцию просто), поэтому получалось что "KeServiceDescriptorTable и KTHREAD.ServiceTable хранят разные адреса", т.к. поток переводился в разряд GUI'шных... убрал DbgPrint - все как часы.
Нет, ни чего подобного DbgPrint() не делает. Скорее всего ее вызов у тебя "портил" значения регистров.
Twister, я проверю эту мысль. Наверное ты прав. Все. Добавил сервис, научился запускать его с User Mode. Кому интересно - могу выложить сурсы. Пока еще только не понял можно ли подменять KTHREAD.ServiceTable. Но это вроде не за горами.