Доброго времени суток Вычитал в Рихтере способ внедрения dll в адресное пространство с помощью функции CreateRemoteThread. В Windows 7 CreateRemoteThread передает управление NativeApi функции NtCreateThreadEx, которая перехватывается аналогом антивируса, в то время как NtCreateThread вызывается свободно... Вопрос: можно ли напрямую вызвать NtCreateThread? Я пытался подсоединить ntdll к проекту, и вызывать NtCreateThread напрямую, добился появления нового потока у целевого процесса в "счетчике потоков" диспетчера задач. Подскажите, как можно заставить созданный поток выполнять код (конкретно — LoadLibrary)? Возможно, есть какой-то способ заставить CreateRemoteThread вызывать старую функцию NtCreateThread?? Заранее спасибо
В Рихтере указан лишь способ заставить поток выполнять код с использованием WinAPI функции CreateRemoteThread. Каких-либо примеров, посвященных созданию потоков с помощью NativeAPI, кроме Неббета мне найти не удалось. Однако, оба примера Неббета не затрагивают создания потоков с пользовательской функцией. Моя просьба касалась именно NativeAPI - как передать NtCreateThread адрес выполняемой функции?
Очаровательно Я так понимаю что для вызова LoadLibrary достаточно в контексте созданного потока выставить eip на адрес LoadLibrary? Подскажите, как ему в таком случае передавать строку с параметром. По логике, ее надо поместить в стек, однако к какому стеку будет обращаться загружаемая LoadLibrary свежесозданного потока?
HANDLE hInjectThread; wchar_t szLibPath[MAX_PATH]; DWORD dwLoadRes; LPVOID lpLibPath = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath),MEM_COMMIT, PAGE_READWRITE ); addressLoadLibraryW = GetProcAddress("kernel32.dll", "LoadLibraryW"); //Validate lpLibPath //Validate addressLoadLibraryW status = NtCreateThreadEx(&hInjectThread, , , hProcess, addressLoadLibraryW, lpLibPath, FALSE, 0, 0, NULL); //Validate status while ( WaitForSingleObjectEx(hInjectThread, INFNITE, TRUE) != WAIT_OBJECT_0 ); if ( ::GetExitCodeThread( hThread, &dwLoadRes ) ) { // check error in dwLoadRes } else { // ERROR LOADING } CloseHandle(hInjectThread); ::VirtualFreeEx( hProcess, lpLibPath, sizeof(szLibPath), MEM_RELEASE );
Спасибо, но проблема состоит как раз в том, что бы вызвать NtCreateThread, не принимающий ни LPTHREAD_START_ROUTINE lpStartAddress, ни LPVOID lpParameter, из под семерки, а не NtCreateThreadEx.
PotapovPV вы еще тут? - бегом в гугль) ток сначала объясните - вот вы создаёте ветвь, что это такое в вашем понимании - Thread?
PotapovPV Хотите через ntdll? Используйте RtlCreateUserThread, это удобнее.(параметры найдёте в гугле).
qwe8013 К сожалению, RtlCreateUserThread в итоге вызывает ZwCreateThreadEx, использования которого я стараюсь избежать. ASMatic Поверьте, я знаю что такое Thread. Также поверьте что я прочитал соответствующий раздел Рихтера и посвятил достаточное время гуглу. ntkernelspawn Спасибо, как-то эта тема прошла мимо меня... Будет разбирать паскаль
PotapovPV видимо я вас не понял...чем вам мешает lpStartAddressи и lpParameter в варианте с NtCreateThreadEx% он же также присутствует в NtCreateThread ток в другом виде.
ASMatic И правда, не поняли Мне мешают не параметры, мне мешает функция NtCreateThreadEx, вызовы которой перехватываются. При этом - начиная с Висты вызов CreateRemoteThread приводит именно к вызову NtCreateThreadEx. NtCreateThread же в моем случае не перехватывается, поэтому вызывать надо именно ее. И названные Вами параметры передаются через стек с контекст... Вопрос как раз и состоит в том, как корректно сформировать эти самые контекст и стек. Бьюсь над проблемой уже несколько дней, но, видимо, чего-то недопонимаю - выделить стек не получается
В результате вкуривания исходников win2k, Неббета и всех найденых примеров получил приведенный ниже код... Пытаюсь создать поток, например, в одном из процессов Google Chrome, однако при вызове NtResumeThread процесс просто падает. Большая просьба посмотреть и по возможности сообщить - что я забыл, или сделал неправильно Код (Text): #include <windows.h> #include "ntdll.h" #include "MyCreateThread.h" HANDLE APIENTRY MyCreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) { POBJECT_ATTRIBUTES pObja; OBJECT_ATTRIBUTES Obja; HANDLE Handle; CONTEXT ThreadContext; CLIENT_ID ClientId; ULONG i; PUSER_STACK pStack = new USER_STACK; NTSTATUS NtStatus; BaseCreateStack(hProcess, 4096, 1048576, pStack); //значения получены экспериментально //прогоном CreateRemoteThread под WinXP //с отладчиком BaseInitializeContext( &ThreadContext, lpParameter, (PVOID)lpStartAddress, pStack->ExpandableStackBase, BaseContextTypeThread ); pObja = BaseFormatObjectAttr(&Obja, lpThreadAttributes, NULL); NtStatus = NtCreateThread( &Handle, THREAD_ALL_ACCESS, pObja, hProcess, &ClientId, &ThreadContext, pStack, TRUE ); InformCsrss(hProcess, Handle, ULONG (ClientId.UniqueProcess), ULONG (ClientId.UniqueThread), ClientId); if (!NT_SUCCESS(NtStatus)) { NtStatus = (NTSTATUS)STATUS_NO_MEMORY; } else { if ( ARGUMENT_PRESENT(lpThreadId) ) { *lpThreadId = HandleToUlong(ClientId.UniqueThread); } if (!( dwCreationFlags & CREATE_SUSPENDED) ) { NtResumeThread(Handle,&i); } } return Handle; } NTSTATUS BaseCreateStack( HANDLE hProcess, SIZE_T StackSize, SIZE_T MaximumStackSize, PUSER_STACK stack ) { PCH Stack; Stack = NULL; PULONG llong = new ULONG; NTSTATUS NtStatus; StackSize = ROUND_UP( StackSize, PAGE_SIZE); NtStatus = NtAllocateVirtualMemory( hProcess, (PVOID *)&Stack, 0, &MaximumStackSize, MEM_RESERVE, PAGE_READWRITE ); stack->ExpandableStackBottom = Stack; stack->ExpandableStackBase = Stack + MaximumStackSize; Stack += MaximumStackSize - StackSize; Stack -= PAGE_SIZE; StackSize += PAGE_SIZE; NtStatus = NtAllocateVirtualMemory( hProcess, (PVOID *)&Stack, 0, &StackSize, MEM_COMMIT, PAGE_READWRITE ); stack->ExpandableStackLimit = Stack; SIZE_T RegionSize = PAGE_SIZE; ULONG OldProtect; NtStatus = NtProtectVirtualMemory( hProcess, (PVOID *)&Stack, &RegionSize, PAGE_GUARD | PAGE_READWRITE, &OldProtect ); stack->ExpandableStackLimit = (PVOID)((PUCHAR)stack->ExpandableStackLimit + RegionSize); stack->FixedStackBase = NULL; stack->FixedStackLimit = NULL; return NtStatus; } VOID BaseInitializeContext ( OUT PCONTEXT Context, IN PVOID Parameter OPTIONAL, IN PVOID InitialPc OPTIONAL, IN PVOID InitialSp OPTIONAL, IN BASE_CONTEXT_TYPE ContextType ) { Context->Eax = (ULONG)InitialPc; Context->Ebx = (ULONG)Parameter; Context->SegGs = 0; Context->SegFs = 0x38; Context->SegEs = 0x20; Context->SegDs = 0x20; Context->SegSs = 0x20; Context->SegCs = 0x18; Context->EFlags = 0x3000; Context->Esp = (ULONG) InitialSp - 4; HMODULE hKernel32 = LoadLibrary(L"kernel32"); DWORD procBaseThread = (DWORD)GetProcAddress(hKernel32, "BaseThreadInitThunk"); Context->Eip = (ULONG) procBaseThread; Context->ContextFlags = CONTEXT_FULL; Context->Esp -= sizeof(Parameter); // Reserve room for ret address } VOID InformCsrss(HANDLE hProcess, HANDLE hThread, ULONG pid, ULONG tid, CLIENT_ID ClientId) { struct THREAD_INFO { HANDLE hThread; CLIENT_ID id; }; struct CSRSS_MESSAGE { ULONG Unknown1; ULONG Opcode; ULONG Status; ULONG Unknown2; }; struct PORT_MESSAGE { ULONG u1; ULONG u2; union { CLIENT_ID ClientId; float DoNotUseThisField; }; ULONG MessageId; union { ULONG ClientViewSize; ULONG CallbackId; }; }; struct { PORT_MESSAGE PortMessage; CSRSS_MESSAGE CsrssMessage; THREAD_INFO ThreadInfo; } csrmsg = { {0}, {0}, {hThread, ClientId}}; HMODULE hKernel32 = LoadLibrary(L"ntdll.dll"); DWORD procLocalAlloc = (DWORD)GetProcAddress(hKernel32, "CsrClientCallServer"); __asm { push 0x0C push 0x10001 push NULL lea eax, csrmsg push eax mov eax, procLocalAlloc call eax } } POBJECT_ATTRIBUTES BaseFormatObjectAttr( OUT POBJECT_ATTRIBUTES ObjectAttributes, IN PSECURITY_ATTRIBUTES SecurityAttributes, IN PUNICODE_STRING ObjectName) { HANDLE RootDirectory; ULONG Attributes; PVOID SecurityDescriptor; if ( ARGUMENT_PRESENT(SecurityAttributes) || ARGUMENT_PRESENT(ObjectName) ) { RootDirectory = NULL; if ( SecurityAttributes ) { Attributes = (SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0); SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor; } else { Attributes = 0; SecurityDescriptor = NULL; } if ( ARGUMENT_PRESENT(ObjectName) ) { Attributes |= OBJ_OPENIF; } InitializeObjectAttributes( ObjectAttributes, ObjectName, Attributes, RootDirectory, SecurityDescriptor ); return ObjectAttributes; } else { return NULL; } }
PotapovPV код не рассматривал, но NtStatus видать для того чтобы его проверять.) пробежался бегло - не вижу как вы туда сам код треда напрвляете, поставте инт3 на входе в тред (lpStartAddress) и тогда резюмайте. если падает - посмотрите что по адресу lpStartAddress находиться, мож куда-то "поплыли" указатели.
ASMatic NtStatus везде в порядке. Ошибку, кажется, нашел: не знаю, откуда я выкопал имя "BaseThreadInitThunk", однако свежесозданному треду, судя по исходникам винды, передается не оно, а "BaseThreadStartThunk". Именно он и передает треду код и параметры, адреса которых "прячутся" в регистрах eax и ebx