Помогло волшебное слово extern так не падает: Код (Text): #define sysenter __asm _emit 0x0f __asm _emit 0x34 #define NtUserSendInput 11F6h void KiFastSystemCall(void) { __asm{ mov edx, esp sysenter } } int extern __stdcall NtUserSendInputServiceCall (UINT Count,LPINPUT Input,int Size) { __asm { mov eax, NtUserSendInput call KiFastSystemCall } } ... Так что сервис вызывается вроде-бы корректно (насколько можно судить по отфонарному тесту на "упадёт / не упадёт") Но xmm0 всё равно портится и если дело в этом то стабильноти это "понижение уровня" не добавит.
кто что эмулирует? я лишь убедился что сервис отрабатывает на скормленных ему данных и возвращается куда нужно а правильно ли он их обработал можно выяснить только на реальной задаче. PS: порча xmm0 это фича не сервиса а с++ компилятора.
да действительно там компилятор ещё шаманство с push ebp и т.п. добавляет потому и данные в стеке смещены. В общем тут геморой не в вызове сервиса (который в api переходниках вызывается лаконично и без излишеств с которыми нужно было бы бороться) а в особенностях С компиляции. Попробуй лучше вариант: Код (Text): void GenerateKeyService ( WORD vk) { DWORD64 tmpXMM0; __asm movq [tmpXMM0], xmm0; KEYBDINPUT kinpt={0}; INPUT inpt={0}; // generate down inpt.type=INPUT_KEYBOARD; kinpt.wVk=vk; kinpt.time=NULL; kinpt.dwExtraInfo=NULL; kinpt.wScan=NULL; kinpt.dwFlags=NULL; inpt.ki=kinpt; SendInput(1,&inpt,sizeof(inpt)); kinpt.dwFlags=KEYEVENTF_KEYUP; SendInput(1,&inpt,sizeof(inpt)); __asm movq xmm0, [tmpXMM0]; return; } может всё и стабилизируется.
Я не увидел в нём ничего что можно было бы посчитать источником глюков на пути к вызову сервиса, напротив всё лаконично и гладко. Чтобы добиться такой лаконичности от альтернативной версии с использованием С компилятора нужен изрядный танец с бубном. Так что единственное что могу заподозрить как причину нестабильности это изменение xmm0, который использует компилятор для копирования структуры в стек. Имхо проще всего его просто временно сохранить.
Там простая модель вызова. Удобнее использовать сервисный шлюз, чем сискал. Для вызова шерез шлюз(Int 0x2e) регистр Edx должен ссылаться на параметры сервиса, причём стек значения не имеет и не используется(тоесть можно обнулить Esp и вызвать сервис). При вызове сискала(Sysenter) в Edx должна быть ссылка на аргументы, уменьшенная на два слова(-8 байт). Стек восстанавливается при возврате в значение которое было в Edx. Сискал стек восстанавливает, шлюз не восстанавливает. При вызове шлюза возврат происходит на следующую инструкцию. При вызове сискала в Ip загружается ссылка на заглушку(Ret). Тоесть очевидно что сискал должен вызываться через процедурные ветвления.
Clerk можно пример на си пожалуйста вызова NtUserSendInput ну или что бы можно было вставку организовать я пока попробую сам, но возможно не осилю
punxer Разобрался (и попутно прочуствавал за что Clerk не любит С ) так работает и даже возвращает eax = 1 как и сама SendInput. Рекомендованное выше сохранение xmm0 советую оставить, т.к. оно попрежнему портится компиляторм при заполнении структур. Код (Text): int SendInputServiceCall_int2e (UINT Count, LPINPUT Input, int SizeInput) { __asm { mov eax, NtUserSendInput push SizeInput push Input push Count mov edx, esp int 0x2E add esp, 12 ; очистка стека от временных переменных } } int SendInputServiceCall_sysenter (UINT Count, LPINPUT Input, int SizeInput) { __asm { mov eax, NtUserSendInput push SizeInput push Input push Count push eax ; просто заполнитель до -8 push aa mov edx, esp sysenter aa: add esp, 16 ; очистка стека от временных переменных } } Clerk спасибо за подсказки, но к ним нужны некоторые уточнения: только удаляет адрес возврата, а параметры нужно чистить самому. нет на входе edx=esp после занесения адреса возврата, а на выходе адрес возврата в стеке отсутствует. Это да, но можно его и обмануть как я и сделал хотя конечно я наверно нарушил работу предсказателя ret-ов в камушке, но имхо здесь это мелочь.
Y_Mur Не спорьте, стек восстанавливается(это никак не значит что очищается, это выполняется в стабе). Смотрите тут для фасткала http://files.virustech.org/indy/wrk/trap.asm: Код (Text): _KiFastCallEntry proc ; ; Sanitize the segment registers ; mov ecx, KGDT_R3_DATA OR RPL_MASK push KGDT_R0_PCR pop fs mov ds, ecx mov es, ecx ; ; When we trap into the kernel via fast system call we start on the DPC stack. We need ; shift to the threads stack before enabling interrupts. ; mov ecx, PCR[PcTss] ; mov esp, [ecx]+TssEsp0 push KGDT_R3_DATA OR RPL_MASK ; Push user SS push edx ; Push ESP pushfd Kfsc10: push 2 ; Sanitize eflags, clear direction, NT etc add edx, 8 ; (edx) -> arguments И тут для шлюза http://files.virustech.org/indy/wrk/kimacro.inc.
Y_Mur Зачем же вводить ссылки и фиксапы, если можно выполнить процедурное ветвление ? Он не отсутствует, возврат выполняется не на следующую инструкцию, я ведь написал. Менеджер загружает в трап-фрейм ссылку на ntdll!KiFastSystemCallRet(), а она выполняет Ret. Просто вы туда брейк не ставите, а RF устанавливается, тоесть трассировочный останов генерится после исполнения Ret. Не доверяйте на столько отладчику
punxer Это запредельная наглость. Уходите на соответствующие фурумы, где вам обьяснят как манипулировать регистрами средствами скриптов.
Не один из вариантов почему то не отжимает кнопку, как и сама SendInput, может кто нить знает в чем может быть трабла Код (Text): void GenerateKeyService ( WORD vk) { KEYBDINPUT kinpt={0}; INPUT inpt={0}; // generate down inpt.type=INPUT_KEYBOARD; kinpt.wVk=vk; kinpt.time=NULL; kinpt.dwExtraInfo=NULL; kinpt.wScan=NULL; kinpt.dwFlags=NULL; inpt.ki=kinpt; SendInputServiceCall_int2e(1,&inpt,sizeof(inpt)); kinpt.dwFlags=KEYEVENTF_KEYUP; SendInputServiceCall_int2e(1,&inpt,sizeof(inpt)); return; }
Народ реально есть проблема. Ничего не помогает в 3 кольце, даже сервис ведет себя так же как и SendInput, как именно написано в предыдущем посте, отжатия не происходит, эмулируются VK_RETURN и NUMPAD_тралала.
присутсвия клавиатуры физической на стенде и рабочем месте не предполагается вот может попробовать Код (Text): BOOL SetKeyboardState( LPBYTE lpKeyState ); для обнуления клавы, хотя нужноо же отжатие имитировать и это не покатит. И после очистки тоже отжатие вроде как не катит, не может же быть нажатия без отжатия%(
сейчас функция выглядит так Код (Text): void GenerateKeyService ( WORD vk) { KEYBDINPUT kinpt={0}; INPUT inpt={0}; DWORD64 tmpXMM0; __asm movq [tmpXMM0], xmm0; inpt.type=INPUT_KEYBOARD; kinpt.wVk=vk; kinpt.time=NULL; kinpt.dwExtraInfo=NULL; kinpt.wScan= MapVirtualKey(vk, 0); kinpt.dwFlags=NULL; inpt.ki=kinpt; SendInputServiceCall_int2e(1,&inpt,sizeof(inpt)); WinErrDebugOut(); inpt.ki.dwFlags=KEYEVENTF_KEYUP; Sleep(1000); SendInputServiceCall_int2e(1,&inpt,sizeof(inpt)); WinErrDebugOut(); __asm movq xmm0, [tmpXMM0]; return; }