Доброе время суток, у меня следующая проблема: я хочу сделать создание потока с ядра в другом процессе и делаю это следующим кодом: Код (Text): RegionState = PTOCESS_THREAD_STACK_SIZE + sizeof(CONTEXT) + sizeof(USER_STACK) + sizeof(HANDLE) + sizeof(OBJECT_ATTRIBUTES) + sizeof(CLIENT_ID) + InjectCodeSize; status = ZwAllocateVirtualMemory( Process, &Base, 0, &RegionState, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); if (NT_SUCCESS( status )) { Context = (PCONTEXT)( (ULONG)Base + PTOCESS_THREAD_STACK_SIZE ); UserStack = (PUSER_STACK)( (ULONG)Context + sizeof(CONTEXT) ); ThreadHandle = (PHANDLE)( (ULONG)UserStack + sizeof(USER_STACK) ); attributes = (POBJECT_ATTRIBUTES)( (ULONG)ThreadHandle + sizeof(HANDLE) ); ClientId = (PCLIENT_ID)( (ULONG)attributes + sizeof(OBJECT_ATTRIBUTES) ); CodeBase = (PVOID)( (ULONG)ClientId + sizeof(CLIENT_ID) ); status = ObReferenceObjectByHandle( Process, PROCESS_ALL_ACCESS, *PsProcessType, KernelMode, &EProcess, NULL ); if (NT_SUCCESS( status )) { KeStackAttachProcess( EProcess, &ApcState ); UserStack->ExpandableStackBottom = UserStack->ExpandableStackLimit = Base; UserStack->ExpandableStackBase = (PVOID)( (ULONG)Base + PTOCESS_THREAD_STACK_SIZE ); Context->ContextFlags = CONTEXT_FULL; Context->SegGs = 0; Context->SegFs = 0x3B; Context->SegEs = 0x23; Context->SegDs = 0x23; Context->SegSs = 0x23; Context->SegCs = 0x1B; Context->EFlags = 0x3000; Context->Esp = (ULONG)UserStack->ExpandableStackBase - 4; Context->Eip = (ULONG)CodeBase; RtlCopyMemory( CodeBase, InjectThreadProc, InjectCodeSize ); InitializeObjectAttributes( attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); status = NtCreateThread( ThreadHandle, THREAD_ALL_ACCESS, attributes, NtCurrentProcess(), ClientId, Context, UserStack, TRUE ); KeUnstackDetachProcess( &ApcState ); вроде все хорошо, но система падает с ошибкой: INVALID_PROCESS_DETACH_ATTEMPT (0x6) как я понимаю что что-то с KeUnstackDetachProcess, но не могу понять что (мало опыта). Что я делаю не правильно? Заранее всем спасибо!
Либо один из списков APC не пустой (юзермодный и/или ядерный), либо ядерная APC в стадии обработки, либо APC index равен нулю.
Для начала нужно понять какая тут проблема из 4х перечисленных мной, посмотри равна ли Thread->ApcStateIndex нулю, и равна ли Thread->ApcState.KernelApcInProgress true. Ну и есть ли APC в обоих списках Thread->ApcState.
ApcState.KernelApcInProgress = 0 (false) ApcState. ApcListHead: [0] -Flink = 0xffffffff -Blink = 0x80581fe9 [1] -Flink = 0xb21cada5 -Blink = 0x0006d6cc извините что подал инфу в таком виде, я новичок в кернеле и точно не знаю или это вообще та инфа
IsListEmpty( &ApcState.ApcListHead[0] ) - возвращает 0 IsListEmpty( &ApcState.ApcListHead[1] ) - возвращает 0 а как посмотреть ApcStateIndex ?
Cмотреть надо не у своего процесса до аттача, а у того к кому приаттачился. KeGetCurrentThread() после аттача, а потом смотри уже.
Спасибо, ошибся. сделал как ты говорил, результат: Код (Text): Thread = KeGetCurrentThread(); Apc = (PKAPC_STATE)( (ULONG)Thread + 0x34 ); IsListEmpty( &Apc->ApcListHead[0] ) = 1 IsListEmpty( &Apc->ApcListHead[1] ) = 1 это для ХП СП2, а как посмотреть ApcStateIndex ?
Если я не ошибаюсь, то ApcStateIndex находиться по смещению 0xE4 от начала KTHREAD (для ХР SP 2) и у меня ето значение равно 0
Значит текущий поток не приаттачен к процессу, отсюда и бсод. После вызова KeStackAttachProcess( EProcess, &ApcState ) у тебя ApcState->Process равен нулю ?
Если я правильно понял, то, что тебе нужно, лежит вот по этой ссылке. Сильно матом не орать, код писался довольно давно ещё, но рабочий, проверял недавно на всех системах от XP до 7. Смысл приведённого кода в создании полноценного Win32-потока в два захода через CSR. Это всё только для x86, но на 64-бита портировать сможешь, ничего там хитрого особо нет. Дальше сам, думаю, разберёшься.
Скажу по секрету: её ни у кого нет, кроме меня. Я начал разработку этой библиотеки очень давно, несколько лет назад, и теперь использую во всех kernel-mode разработках, при этом постоянно совершенствуя и обкатывая её в реальных проектах, что есть здорово. Это, конечно, оффтоп, но я рекомендую всем системщикам начинать именно с этого, с выделения рутинных задач в некое подобие .lib-файла. Или прикупить готовую, например, я планирую свою выпустить отдельным продуктом в течении ближайшего года. А по поводу Kmlib* функций можно спросить у меня, чем смогу - помогу.
Долгими мучениями сделал запуск потока, но проблема в том что создание потока идет в NtCreateProcess (то есть сделал перехват) Суть в том что если мой код трейсить - то он работает, а если нет - то не работает. Мне кажется что не инициализируеться системный структуры, ошибку делает код KiUserApcDispatcher, как можно это исправить? думаю нужно дождаться окончание инициализации процесса, только как? Заранее спасибо!
Код (Text): Peb = PBI.PebBaseAddress; NtHeaders = RtlImageNtHeader( Peb->ImageBaseAddress ); if (!MaximumStackSize) MaximumStackSize = NtHeaders->OptionalHeader.SizeOfStackReserve; if (!StackSize) StackSize = NtHeaders->OptionalHeader.SizeOfStackCommit; RtlZeroMemory( InitialTeb, sizeof(INITIAL_TEB) ); status = NtAllocateVirtualMemory( NtCurrentProcess(), (PVOID *)(&StackBase), 0, &MaximumStackSize, MEM_RESERVE, PAGE_READWRITE ); if (NT_SUCCESS( status )) { InitialTeb->StackCommit = (PVOID)( (ULONG)StackBase + MaximumStackSize ); InitialTeb->StackCommitMax = StackBase; InitialTeb->StackReserved = StackBase; StackBase += MaximumStackSize - StackSize; if (MaximumStackSize > StackSize) { StackBase -= PageSize; StackSize += PageSize; GuardPage = TRUE; } else { GuardPage = FALSE; } status = NtAllocateVirtualMemory( NtCurrentProcess(), (PVOID *)(&StackBase), 0, &StackSize, MEM_COMMIT, PAGE_READWRITE ); if (!NT_SUCCESS( status )) { RegionSize = 0; NtFreeVirtualMemory( NtCurrentProcess(), (PVOID *)(&StackBase), &RegionSize, MEM_RELEASE ); return status; } InitialTeb->StackLimit = StackBase; if (GuardPage) { RegionSize = PageSize; status = NtProtectVirtualMemory( NtCurrentProcess(), (PVOID *)(&StackBase), &RegionSize, PAGE_GUARD | PAGE_READWRITE, &OldProtect ); if(!NT_SUCCESS( status )) return status; InitialTeb->StackLimit = (PVOID)( (ULONG)InitialTeb->StackLimit + RegionSize ); } что я сделал не правильно?
Запустил код, но только как темп сделал методом "подождать 1 секунду", но такой вариант не есть гуд, как можно подождать пока процесс не захочет создать свой первый поток?