просматривал проект kexec(запуск процесса из драйвера). драйвер прекрасно работает. Процесс запускает explorer.exe, попробовал изменить на winlogon.exe: процесс запускается с username == System, но ничего не делает, не отображается. Запускаемый процесс - обычная окошка. В чем может быть причина?
kexec твой проект и Cr4sh. explorer.exe заменил на winlogon.exe winlogon.exe запускает окошку, в смысле windows application.
1. У меня не работает ( XP SP2), kexec() ERROR. Трассировкой показала где, см код Code (Text): if (KeInsertQueueApc(pApc, (PVOID)((ULONG)pMappedAddress + SizeOfCode), NULL, 0)) { *((unsigned char *)pThread + ET_pending) = 1; timeout.QuadPart = -(10 * 10000000); if (KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, &timeout)!= STATUS_TIMEOUT) { PsLookupProcessByProcessId((HANDLE)sc_data->dwProcId, &pRetProcess); DbgMsg("Process %d created; EPROCESS: 0x%.8x\n", sc_data->dwProcId, pRetProcess); } else { DbgMsg("KeWaitForSingleObject() timeout\n"); <- Сюда попадаем } } Подскажите в чем может быть проблема 2. я правильно понял, что ET_pending это KernelApcPending из struct _ETHREAD (kd> dt -v -r nt!_ETHREAD) потому что, alertable один, а pending-ов несколько, спрашиваюб т.к. хочу перенести под VISTA
Проблма может быть в оффсетах - ты уверен, что у тебя такие же? UserApcPending. юзермодная апц доставляется ведь
спасибо Great +0x034 ApcState : struct _KAPC_STATE, 5 elements, 0x18 bytes +0x000 ApcListHead : [2] struct _LIST_ENTRY, 2 elements, 0x8 bytes +0x010 Process : Ptr32 to struct _KPROCESS, 29 elements, 0x6c bytes +0x014 KernelApcInProgress : UChar +0x015 KernelApcPending : UChar +0x016 UserApcPending : UChar +34h = 4ah +0x164 Alertable : UChar
Дабы нормальным образом запустить процесс необходимо вызвать в юзермоде kernel32!CreateProcessInternalA(). Чтоб её вызвать нужен процесс и пользовательский поток в нём. Так как создавать потоки палево, поэтому следует использовать уже имеющиеся. Тоесть нужно выполнить наш код в контексте какогото потока. Так как некоторые потоки могут простаивать, например находясь в ожидании какихто событий, то следует использовать несколько потоков. Нам нужно какимто образом перечислить потоки и изменить их контекст. Для этого нам нужно добраться до трап-фрейма. Тоесть поток должен поменять кпл на ноль, сохранить хардварный контекст, после чего мы должны перехватить поток. Тут три пути есть. o Исполнить код в контексте целевого потока, тоесть он является текущим. - Использовать прерывания. - Исключения. - Сискалы. Тут вариантов стопяцот, следует взять что удобно. Мне нравяться сепшены. Выполняем манипуляции с памятью процесса и вызывается наш обработчик. Из него имеем контекст. Или например запускаем профилирование и регаем ISR. Рано или поздно хэндлер вызовется в контексте нужного треда. Тут главное IRQL. Нужны низкие, ибо придётся обращаться к пользовательской памяти, в частности к стеку. o Выполнить манипуляции с его контекстом удалённо(из другого потока). Это требует синхронизацию. Нужно какимто образом обождать формирование трап-фрейма для потока, либо инициировать это. Когда происходит смена кпл на нулевое, то формируется трап-фрейм, а исполнение этого треда отлагается планировщиком, либо наш второй тред исполняется на другом процессоре. Вот тут мы поимеем контекст из другого потока. Вручную взяв из описателя обьекта. Либо используя ядерную апк, которая доставляется при возврате из прерываний. Это может быть наша апк, которую мы сами поставим в очередь(что приведёт к исполнению нашего кода в контексте целевого потока), либо используя системные апк. Это гетконтекст- и суспенд- апк. Первая используется функой PsGetContextThread(), вторая PsSuspendThread(). Лучше взять вторую, тогда будет синхронно. Походу найдётся есчо и PsGetNextProcessThread() для перечисления потоков. o Исполнить код прямо в юзермоде, не выполняя телодвижений в ядре(сюда относится и пользовательские апк). Зарегав для этой цели какойто системный калбэк, ктото юзал шадова калбэки, ктото иные, это не важно. Просто регаем его записью в память и ждём пока вызовется.
Еще четвертый вариант в догонку: создать процесс как обычно. NtCreateProcess + NtCreateThread, а зарегистрировать через вызов csrsrv!CsrCreateRemoteThread внутри Native-потока, который необходимо создать внутри csrss.exe ну или любым другим способом исполнив этот код в контексте csrss.exe в юзермоде Code (Text): VOID CsrShellcode (DRIVER_TO_SHELLCODE_PARAMETERS *Params) { CSRSS_NOTIFY_PARAMETERS *p = (CSRSS_NOTIFY_PARAMETERS*) Params->Data; // csrsrv.dll functions char szCsrsrvDll[] = {'c', 's', 'r', 's', 'r', 'v', '.', 'd', 'l', 'l', 0}; char szCsrCreateRemoteThread[] = {'C', 's', 'r', 'C', 'r', 'e', 'a', 't', 'e', 'R', 'e', 'm', 'o', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 0}; // ntdll.dll functions char szNtTerminateThread[] = {'N', 't', 'T', 'e', 'r', 'm', 'i', 'n', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 0}; char szNtOpenThread[] = {'N', 't', 'O', 'p', 'e', 'n', 'T', 'h', 'r', 'e', 'a', 'd', 0}; char szNtClose[] = {'N', 't', 'C', 'l', 'o', 's', 'e', 0}; // pointers PVOID csrsrv; NTSTATUS Status; NTSTATUS (NTAPI *pCsrCreateRemoteThread)(HANDLE hThread, PCLIENT_ID ClientId); NTSTATUS (NTAPI *pNtOpenThread)(PHANDLE,ULONG,POBJECT_ATTRIBUTES,PCLIENT_ID); NTSTATUS (NTAPI *pNtClose)(HANDLE); NTSTATUS (NTAPI *pNtTerminateThread)(HANDLE, NTSTATUS); csrsrv = Params->LoadLibraryA(szCsrsrvDll); if (csrsrv) { *(PVOID*)&pCsrCreateRemoteThread = Params->GetProcAddress(csrsrv, szCsrCreateRemoteThread); *(PVOID*)&pNtOpenThread = Params->GetProcAddress(Params->Ntdll, szNtOpenThread); *(PVOID*)&pNtClose = Params->GetProcAddress(Params->Ntdll, szNtClose); if (!(pCsrCreateRemoteThread && pNtOpenThread && pNtClose)) { Status = 0xF0000003; } else { OBJECT_ATTRIBUTES Oa = STATIC_OBJECT_ATTRIBUTES(NULL, 0, 0, 0); HANDLE hThread; PVOID Process = 0; CLIENT_ID ClientId = p->ClientId; Status = pNtOpenThread (&hThread, THREAD_ALL_ACCESS, &Oa, &ClientId); if (NT_SUCCESS(Status)) { Status = pCsrCreateRemoteThread (hThread, &ClientId); pNtClose (hThread); } } } else Status = 0xF0000001; *(PVOID*)&pNtTerminateThread = Params->GetProcAddress(Params->Ntdll, szNtTerminateThread); pNtTerminateThread(0, Status); } Работоспособность гарантируется) PS. Закрепил тему, чтобы больше не спрашивали
Great Ну тогда до кучи Sb-сервис(откопал у себя старинный кодес): Code (Text): ; Запуск нативного приложения посредством сервиса порта \SbApiPort ; (OPTIONAL_HEADER.Subsystem = IMAGE_SUBSYSTEM_NATIVE). SB_CREATE_PROCESS equ 3 PORT_MESSAGE struct DataSize USHORT ? ;+0 MessageSize USHORT ? ;+2 MessageType USHORT ? ;+4 VirtualRangesOffset USHORT ? ;+6 ClientId CLIENT_ID <> ;+8 MessageId ULONG ? ;+10 SectionSize ULONG ? ;+14 PORT_MESSAGE ends SB_PROCESS_PATHS struct ImageFileName UNICODE_STRING <> CurrentDirectory UNICODE_STRING <> CommandLine UNICODE_STRING <> DefaultLibPath UNICODE_STRING <> SB_PROCESS_PATHS ends PSB_PROCESS_PATHS typedef ptr SB_PROCESS_PATHS SB_PORT_MESSAGE struct Header PORT_MESSAGE <> Service ULONG ? ; 3 Status NTSTATUS ? ImageFileName PUNICODE_STRING ? CurrentDirectory PUNICODE_STRING ? CommandLine PUNICODE_STRING ? DefaultLibPath PUNICODE_STRING ? DebugFlags ULONG ? ProcessParameters PRTL_USER_PROCESS_PARAMETERS ? SB_PORT_MESSAGE ends PSB_PORT_MESSAGE typedef ptr SB_PORT_MESSAGE PORT_CONNECT equ 1 ;"\Windows\SbApiPort" align 4 SbPortNameW WCHAR "\","W","i","n","d","o","w","s","\","S","b","A","p","i","P","o","r","t",0 SbPortNameU UNICODE_STRING <sizeof SbPortNameW - 2, sizeof SbPortNameW, offset SbPortNameW> $ProcessName WCHAR "\","?","?","\","c",":","\","n","t","s","b",".","e","x","e",0 $CurrentDirectory WCHAR "\","?","?","\","d",":","\","w","i","n","d","o","w","s",0 $CommandLine WCHAR ".",0 InitializeProcessParametersInternal proc uses ebx esi edi ProcessParameters:PVOID mov edi,ProcessParameters cld mov ebx,edi assume ebx:PSB_PROCESS_PATHS lea edi,[edi + sizeof(SB_PROCESS_PATHS)] lea esi,$ProcessName mov ecx,(sizeof $ProcessName)/2 mov [ebx].ImageFileName.Buffer,edi mov [ebx].ImageFileName._Length,sizeof($ProcessName - 2) mov [ebx].ImageFileName.MaximumLength,sizeof($ProcessName) rep movsw add edi,3 and edi,Not(3) lea esi,$CurrentDirectory mov ecx,(sizeof $CurrentDirectory - 2)/2 mov [ebx].CurrentDirectory.Buffer,edi mov [ebx].CurrentDirectory._Length,sizeof($CurrentDirectory - 2) mov [ebx].CurrentDirectory.MaximumLength,sizeof($CurrentDirectory) rep movsw add edi,3 and edi,Not(3) lea esi,$CommandLine mov ecx,(sizeof $CommandLine - 2)/2 mov [ebx].CommandLine.Buffer,edi mov [ebx].CommandLine._Length,sizeof($CommandLine - 2) mov [ebx].CommandLine.MaximumLength,sizeof($CommandLine) rep movsw ret InitializeProcessParametersInternal endp _imp__PsGetProcessInheritedFromUniqueProcessId proto :dword SbCreateProcess proc uses ebx esi edi Local PortObject:PVOID ;PLPCP_PORT_OBJECT Local ProcessObject:PVOID ;PEPROCESS Local OldProcessId:HANDLE Local RegionAddress:PVOID, RegionSize:ULONG Local RequestMessage:SB_PORT_MESSAGE invoke ObReferenceObjectByName, addr SbPortNameU, 0, NULL, PORT_CONNECT, LpcPortObjectType, KernelMode, NULL, addr PortObject test eax,eax jnz err_obj_ lea ecx,ProcessObject mov ebx,PortObject push ecx push dword ptr [ebx + 4*6] ;LPCP_PORT_OBJECT.Creator.UniqueProcess, csrss. Call PsLookupProcessByProcessId test eax,eax jnz err_ps_ mov RegionSize,PAGE_SIZE mov RegionAddress,NULL invoke ZwAllocateVirtualMemory, NtCurrentProcess, addr RegionAddress, 0, addr RegionSize, MEM_COMMIT, PAGE_READWRITE test eax,eax jnz err_alloc_ invoke InitializeProcessParametersInternal, RegionAddress invoke PsGetCurrentProcessId ; Сервер открывает процесс родитель csrss и читает оттуда параметры. ; Определяется через NtQueryInformationProcess(ProcessBasicInformation). ; Перед вызовом заменяем PID родителя. ; Для Win7 смещение PsGetProcessInheritedFromUniqueProcessId также 0xA. ; Для висты код иной. mov ebx,ProcessObject mov ecx,dword ptr [_imp__PsGetProcessInheritedFromUniqueProcessId] add ebx,dword ptr [ecx + 0Ah] ;EPROCESS.InheritedFromUniqueProcessId lock xchg dword ptr [ebx],eax mov OldProcessId,eax xor ecx,ecx mov esi,RegionAddress mov dword ptr [RequestMessage + 4],ecx mov dword ptr [RequestMessage + 8],ecx mov dword ptr [RequestMessage + 0Ch],ecx mov dword ptr [RequestMessage + 10h],ecx mov dword ptr [RequestMessage + 14h],ecx mov RequestMessage.Service,SB_CREATE_PROCESS mov edx,RegionAddress mov RequestMessage.Header.DataSize,sizeof(SB_PORT_MESSAGE) - sizeof(PORT_MESSAGE) mov RequestMessage.Header.MessageSize,sizeof(SB_PORT_MESSAGE) mov RequestMessage.ImageFileName,edx add edx,UNICODE_STRING mov RequestMessage.CurrentDirectory,edx add edx,UNICODE_STRING mov RequestMessage.CommandLine,edx mov RequestMessage.DefaultLibPath,NULL mov RequestMessage.ProcessParameters,NULL mov RequestMessage.DebugFlags,0 ;Синхронно, ожидает завершения процесса. invoke LpcRequestWaitReplyPort, PortObject, addr RequestMessage, addr RequestMessage ;RequestMessage.Status:NTSTATUS from csrss. ;RequestMessage.Status:STATUS_INVALID_HANDLE ;DBG: 'CSRSS: CsrSrvCreateProcess: NtDuplicateObject failed for process - Status = STATUS_INVALID_HANDLE' ;..PID ;Восстанавливаем PID smss. mov ecx,OldProcessId lock xchg dword ptr [ebx],ecx push eax invoke ZwFreeVirtualMemory, NtCurrentProcess, addr RegionAddress, addr RegionSize, MEM_RELEASE pop eax err_alloc_: push eax invoke ObDereferenceObject, ProcessObject pop eax err_ps_: push eax invoke ObDereferenceObject, PortObject pop eax err_obj_: ret SbCreateProcess endp
помогите разобраться, что не так в этом коде Win7 либо выводит сообщение , что explorer накрылся и предлагает отладить/перезагрузить или никак не реагирует, мол ничего не произошло pTargetThread и pTargetProcess правильные, проверенно Code (Text): NTSTATUS InstallUserModeApc(LPSTR lpProcess, PKTHREAD pTargetThread, PEPROCESS pTargetProcess) { PRKAPC pApc = NULL; //Our APC PVOID pMappedAddress = NULL; //This is where the UserMode routine's code will be placed at ULONG dwSize = 0; //Size of code to be executed in Explorer's address space KAPC_STATE ApcState; // Needed for KeStackAttachProcess ULONG *data_addr=0; //just a helper to change the address of the 'push' instruction in the ApcCreateProcess routine ULONG dwMappedAddress = 0; //same as above NTSTATUS Status = STATUS_UNSUCCESSFUL; //__asm int 3; if (!pTargetThread || !pTargetProcess) return STATUS_UNSUCCESSFUL; //Allocate memory for our APC pApc = ExAllocatePool (NonPagedPool,sizeof (KAPC)); if (!pApc) { DbgPrint(" * * * * * KernelExec -> Failed to allocate memory for the APC structure\n"); return STATUS_INSUFFICIENT_RESOURCES; } //Get the size of our UserMode code dwSize = (unsigned char*)ApcCreateProcessEnd-(unsigned char*)ApcCreateProcess; //Allocate an MDL describing our ApcCreateProcess' memory pMdl = IoAllocateMdl (ApcCreateProcess, dwSize, FALSE,FALSE,NULL); if (!pMdl) { DbgPrint(" * * * * * KernelExec -> Failed to allocate MDL\n"); ExFreePool (pApc); return STATUS_INSUFFICIENT_RESOURCES; } __try { //Probe the pages for Write access and make them memory resident MmProbeAndLockPages (pMdl,KernelMode,IoWriteAccess); } __except (EXCEPTION_EXECUTE_HANDLER) { DbgPrint(" * * * * * KernelExec -> Exception during MmProbeAndLockPages\n"); IoFreeMdl (pMdl); ExFreePool (pApc); return STATUS_UNSUCCESSFUL; } //Attach to the Explorer's address space KeStackAttachProcess( pTargetProcess,&ApcState); //Now map the physical pages (our code) described by 'pMdl' pMappedAddress = MmMapLockedPagesSpecifyCache (pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority); if (!pMappedAddress) { DbgPrint(" * * * * * KernelExec -> Cannot map address\n"); KeUnstackDetachProcess (&ApcState); IoFreeMdl (pMdl); ExFreePool (pApc); return STATUS_UNSUCCESSFUL; } else DbgPrint(" * * * * * KernelExec -> UserMode memory at address: 0x%p\n",pMappedAddress); dwMappedAddress = (ULONG)pMappedAddress; memset ((unsigned char*)pMappedAddress + 0x14, 0, 300);//zero everything out ecxept our assembler code memcpy ((unsigned char*)pMappedAddress + 0x14, lpProcess,strlen (lpProcess)); //copy the path to the executable data_addr = (ULONG*)((char*)pMappedAddress+0x9); //address pushed on the stack (originaly 0xabcd)... *data_addr = dwMappedAddress+0x14; //..gets changed to point to our exe's path //all done, detach now KeUnstackDetachProcess (&ApcState); //Initialize the APC... KeInitializeApc(pApc,pTargetThread, OriginalApcEnvironment, &ApcKernelRoutine,NULL, pMappedAddress, UserMode, (PVOID) NULL); //...and queue it if (!KeInsertQueueApc(pApc,0,NULL,0)) { DbgPrint(" * * * * * KernelExec -> Failed to insert APC\n"); MmUnlockPages(pMdl); IoFreeMdl (pMdl); ExFreePool (pApc); return STATUS_UNSUCCESSFUL; } else { DbgPrint(" * * * * * KernelExec -> APC delivered\n"); } if(!pTargetThread->ApcState.UserApcPending) //is this a non-alertable //if yes then alert it pTargetThread->ApcState.UserApcPending = TRUE; return 0; } //------------- __declspec(naked) void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) { __asm { mov eax, 0x75e9e695 //win7 , 0x7C86114D xp sp2 // WinExec push 1 nop push 0xabcdef01// <- pMappedAddress + 9 call eax jmp end много nop-ов / <- pMappedAddress + 0x14
для полноты приведу сообщения дебагера * * * * * RP -> TargetProcess : 0x840CB030 -> explorer.exe * * * * * RP -> Thread: 0x843ED030 Alertable:No * * * * * RP -> Thread: 0x84314358 Alertable:Yes ............ Tcb.Alertable == 0x03c & 0x20 *((unsigned char *)pTargetThread + /*ET_pending*/ 0x56) = 1; ......... * * * * * InstallUserModeApc * * * * * KernelExec -> Targeted thread: 0x84314358 * * * * * KernelExec -> UserMode memory at address: 0x01ED0670 * * * * * KernelExec -> APC delivered это выводит дебагер на виртуалке Unhandled exception at 0x036e0660 in explorer.exe: 0xC0000005: Access violation. 0x01ED0670 : -> mov eax, 0x75e9e695 // WinExec т.е. 1-ая команда вроде все правильно, что это может быть ?
Вопрос про этот же код, под Win2003 SP2 нет никакой реакции на АРС, все успешно, ни БСОДов, не ошибок, ничего, все тихо
смотри http://www.rsdn.ru/article/baseserv/InjectDll.xml , а именно "заключение". расширь с висты на 2003 sp2; win7 не тестировал, но думаю что аналогично.
0xFox Я же выше написал рабочий способ без всяких кривых апц. Регистрация через экспортируемые сервисы csrsrv. Вы бы еще код 10летней давности взяли
На сколько я понял уважаемый dfrsa предполажил что система х64, или я что то не совсем понял.... Или имелось в виду раздел "Форсированная доставка АРС"? Система х86, поэтому вроде как должно все работать, но почему то не работает... Подскажите пожалуйста
Нет. Читай внимательно. >>>В качестве ограничений предложенного способа можно выделить следующие: * Внедрение DLL невозможно в защищенные процессы в Windows Vista(из моих личных исследований, 2003 sp2 - точно ). Однако, поскольку для реализации предложенного способа используется драйвер режима ядра, то в дальнейшем данное ограничение может быть устранено путем модификации структур режима ядря процесса. В случае не защищенных процессов, инжект должен отрабатывать на ура. Метод для обхода защиты системных процессов существует, там достаточно просто все.