Код (Text): .text:77F05070 public ZwMapViewOfSection .text:77F05070 ZwMapViewOfSection proc near ; CODE XREF: sub_77EC826D+100p .text:77F05070 ; RtlCreateQueryDebugBuffer+63p ... .text:77F05070 mov eax, 0A8h ; NtMapViewOfSection .text:77F05075 mov edx, 7FFE0300h .text:77F0507A call dword ptr [edx] .text:77F0507C retn 28h .text:77F0507C ZwMapViewOfSection endp Насколько я понял из этой темы, по адресу 0x7FFE0300 лежит код который вытаскивает из таблицы нужный адрес и дескриптор, пишет их в MSR-ы и выполняет SYSENTER. Меня интересует как поглядеть на этот код? IDA я так понимаю, вычисляет адреса по принципу PE.MountBase + RVA, но никаким 0x7FFE0300 там и не пахнет. Меня больше всего интересует как эта функция вычисляет (или откуда берет) нужный дескриптор+адрес. Я ведь правильно понимаю что сделать такой системный вызов по сути может любой процесс, если бы было по другому тот же DeviceIoControl не смог бы работать.
В дизассембле Kernel32.dll тоже максимальный адрес намного меньше этого. .data:77EA6FEC end DllEntryPoint ; это последняя строка в дизассембле. Может я неправильно пользуюсь идой?
Ivan_32 MSR'ы загружает ядро при инициализации в функе KiLoadFastSyscallMachineSpecificRegisters(), код выше называется системным стабом, ссылка на разделяемую ядром память в конце ап, загружается туда тоже ядром на основе экспорта нтдлл в PspLookupKernelUserEntryPoints(). Эта память отображена на все процессы(0x7FFE0000) и ядро(0xFFDF0000). +0x300: KiFastSystemCall/KiIntSystemCall, +0x304: KiFastSystemCallRet, +0x2F8: 0xC3(Ret опкод).
Clerk, огромное спасибо! Но вот еще такой вопрос. Получается в системе всего один адрес отвечает за SYSENTER( я думал что каждый раз при вызове в MSR-ы грузятся адреса функций в KM) и получается все входные параметры - это номера функций в ядре и какие то еще доп.параметры? А каким образом передаются аргументы для функций? Или они туда едут в регистрах общего назначения? Можно если не сложно алгоритм этого действа в общих чертах? Т.е. в eax пишется номер функции, в edx что то еще и вызывается SYSENTER параметры для которого ядро уже подгрузило. Скажем, если я опробую такой общий метод: mov eax,0x8 mov edx,0x7FFE0300 call [edx] PS: Дизассемблер в CheatEngine(им всегда смотрю память процессов - очень удобно, хоть и дизассемблер хромает...) показал по адресу 0x7FFE0300 вот такую штуку: 7FFE0300 - f0 64 1d 77 f4 64 1d - lock sbb eax,1d64f477
Не надо пользоваться непонятно чем, используй нормальные утилиты. OllyDbg может тебе показать, что по адресу 7FFE0300 лежит указатель на KiFastSystemCall: Код (Text): 7FFE0300 7C90E4F0 ntdll.KiFastSystemCall Именно он и вызывается кодом Код (Text): mov edx, 7FFE0300h call dword ptr [edx] Ну а там всего-ничего до разгадки тайны осталось: Код (Text): 7C90E4F0 > 8BD4 MOV EDX,ESP 7C90E4F2 0F34 SYSENTER 7C90E4F4 > C3 RETN На стеке.
Так ведь дескриптор стека берется из IA32_SYSENTER_CS+8 да и сам ESP из IA32_SYSENTER_ESP или я что то неправильно понял?
У вас температура, вы бредите? Какая таблица? Какие дескрипторы? Обычный системный сервис выполняется командой SYSENTER или int 0x2e. В случае с сисентер нужно передать параметры: EAX = номер системного сервиса в таблице (младшие 12 бит), номер таблицы системных сервисов (2 бита). ну или просто можно сказать, что в EAX номер системного сервиса. а в EDX указатель на параметры, один за другим. располагают их на стеке. Параметры передаются как обычные параметры в ф-ии push'ами, поэтому они там уже лежат. Достаточно записать esp в edx. (на самом деле, там еще лежит адрес возврата из KiFastSystemCall в ZwXXX, и еще один адрес возврата из ZwXXX в пользовательский код, но ядро делает корректировки самостоятельно). На системах, что не поддерживают инструкцию SYSENTER, используется программное прерывание 2E. Системный сервис выполняется командой int 0x2e. в EAX по прежнему номер системного сервиса, в EDX уже должен быть прямой указатель на параметры (минуя два адреса возврата). Именно это и делает код KiIntSystemCall: lea edx, [esp+8] ; edx = указатель на параметры (взять стек и пропустить 8 байт - два адреса возврата) int 0x2e Вот такие вот дела. Еще есть KiFastSystemCallRet - ее видели все, кто хоть раз что-то отлаживал в ольке. Она состоит из одного RET и туда управление попадает после каждого системного сервиса, для этого в EDX ядро предварительно перед SYSEXIT загружает адрес этой самой KiFastSystemCallRet, которое берет из той же структуры KUSER_SHARED_DATA, из которой и юзермодный код берет адрес SystemCallStub. В юзермод эта структура промаплена про адресу 7FFE0000 обычно, в ядро - FFDF0000. В случае с int 0x2e возврат выполняется обычным iretd. int 0x2e сейчас обычно используется в драйверах (например, хотят вызвать неэкспортируемый системный сервис из дарйвера ядра. нужно юзать int 0x2e, SYSENTER из ядра нельзя вызывать). Хотя, выше я немножко приврвал насчет SYSEXIT. Как я помню, возврат из сервиса, в который вошли по SYSENTER, происходит через тот же IRETD. Впрочем, это совершенно не важно в данном контексте.
Great Он и через Iret и через Sysexit выполняется. Зависит от некоторых условий, как например TF. d2k9 Ведь вы можите логически подумать, наверно..
Откуда и с какой целью? Из юзермода с целью перехватить возврат из сервиса? Не получится, загружается из ядра. Из ядра - смысла мало. Хм. Да, точно. На трассировку условие есть
В юзермоде, как вариант извратиться и в юзермоде записать перед вызовом в эту структуру свой адрес возврата, а затем вернуть обратно. З.Ы. Перехваченные функции в ядре через SSDT к примеру при вызове из юзермода через сисколы или прерывания ессно срабатывают, а не оригинальные? Что-то я замотался сегодня...