static VOID GdiPoolDeleteSection(PGDI_POOL pPool, PGDI_POOL_SECTION pSection) { NTSTATUS status; SIZE_T cjSize = 0; /* Should not have any allocations */ if (pSection->cAllocCount != 0) { DPRINT1("There are %lu allocations left, section=%p, pool=%p\n", pSection->cAllocCount, pSection, pPool); DBG_DUMP_EVENT_LIST(&pPool->slhLog); ASSERT(FALSE); } /* Release the virtual memory */ status = ZwFreeVirtualMemory(NtCurrentProcess(), &pSection->pvBaseAddress, &cjSize, MEM_RELEASE); ASSERT(NT_SUCCESS(status)); /* Free the section object */ EngFreeMem(pSection); }
NTSTATUS RtlpFreeStack( IN HANDLE Process, IN PINITIAL_TEB InitialTeb ) { NTSTATUS Status; SIZE_T Zero; Zero = 0; Status = ZwFreeVirtualMemory( Process, &InitialTeb->StackAllocationBase, &Zero, MEM_RELEASE ); if ( !NT_SUCCESS( Status ) ) { #if DBG DbgPrint( "NTRTL: RtlpFreeStack( %lx ) failed. Stack DeCommit Status == %X\n", Process, Status ); #endif // DBG return( Status ); } RtlZeroMemory( InitialTeb, sizeof( *InitialTeb ) ); return( STATUS_SUCCESS ); }
BOOLEAN NTAPI RtlDebugDestroyHeap(HANDLE HeapPtr) { SIZE_T Size = 0; PHEAP Heap = (PHEAP)HeapPtr; if (Heap == RtlGetCurrentPeb()->ProcessHeap) { DPRINT1("HEAP: It's forbidden delete process heap!"); return FALSE; } if (Heap->Signature != HEAP_SIGNATURE) { DPRINT1("HEAP: Invalid heap %p signature 0x%x\n", Heap, Heap->Signature); return FALSE; } if (!RtlpValidateHeap(Heap, FALSE)) return FALSE; /* Make heap invalid by zeroing its signature */ Heap->Signature = 0; /* Free validate headers copy if it was existing */ if (Heap->HeaderValidateCopy) { ZwFreeVirtualMemory(NtCurrentProcess(), &Heap->HeaderValidateCopy, &Size, MEM_RELEASE); } return TRUE; }
/* * @implemented */ NTSTATUS NTAPI LsaFreeReturnBuffer(PVOID Buffer) { SIZE_T Size = 0; return ZwFreeVirtualMemory(NtCurrentProcess(), &Buffer, &Size, MEM_RELEASE); }
/// <summary> /// Allocate/Free process memory /// </summary> /// <param name="pAllocFree">Request params.</param> /// <param name="pResult">Allocated region info.</param> /// <returns>Status code</returns> NTSTATUS BBAllocateFreeMemory( IN PALLOCATE_FREE_MEMORY pAllocFree, OUT PALLOCATE_FREE_MEMORY_RESULT pResult ) { NTSTATUS status = STATUS_SUCCESS; PEPROCESS pProcess = NULL; ASSERT( pResult != NULL ); if (pResult == NULL) return STATUS_INVALID_PARAMETER; status = PsLookupProcessByProcessId( (HANDLE)pAllocFree->pid, &pProcess ); if (NT_SUCCESS( status )) { KAPC_STATE apc; PVOID base = (PVOID)pAllocFree->base; ULONG_PTR size = pAllocFree->size; KeStackAttachProcess( pProcess, &apc ); if (pAllocFree->allocate) { if (pAllocFree->physical != FALSE) { status = BBAllocateFreePhysical( pProcess, pAllocFree, pResult ); } else { status = ZwAllocateVirtualMemory( ZwCurrentProcess(), &base, 0, &size, pAllocFree->type, pAllocFree->protection ); pResult->address = (ULONGLONG)base; pResult->size = size; } } else { MI_VAD_TYPE vadType = VadNone; BBGetVadType( pProcess, pAllocFree->base, &vadType ); if (vadType == VadDevicePhysicalMemory) status = BBAllocateFreePhysical( pProcess, pAllocFree, pResult ); else status = ZwFreeVirtualMemory( ZwCurrentProcess(), &base, &size, pAllocFree->type ); } KeUnstackDetachProcess( &apc ); } else DPRINT( "BlackBone: %s: PsLookupProcessByProcessId failed with status 0x%X\n", __FUNCTION__, status ); if (pProcess) ObDereferenceObject( pProcess ); return status; }
VP_STATUS NTAPI IntInt10AllocateBuffer( IN PVOID Context, OUT PUSHORT Seg, OUT PUSHORT Off, IN OUT PULONG Length) { PVOID MemoryAddress; NTSTATUS Status; PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); KAPC_STATE ApcState; TRACE_(VIDEOPRT, "IntInt10AllocateBuffer\n"); IntAttachToCSRSS(&CallingProcess, &ApcState); MemoryAddress = (PVOID)0x20000; Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &MemoryAddress, 0, Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!NT_SUCCESS(Status)) { WARN_(VIDEOPRT, "- ZwAllocateVirtualMemory failed\n"); IntDetachFromCSRSS(&CallingProcess, &ApcState); return ERROR_NOT_ENOUGH_MEMORY; } if (MemoryAddress > (PVOID)(0x100000 - *Length)) { ZwFreeVirtualMemory(NtCurrentProcess(), &MemoryAddress, Length, MEM_RELEASE); WARN_(VIDEOPRT, "- Unacceptable memory allocated\n"); IntDetachFromCSRSS(&CallingProcess, &ApcState); return ERROR_NOT_ENOUGH_MEMORY; } *Seg = (USHORT)((ULONG)MemoryAddress >> 4); *Off = (USHORT)((ULONG)MemoryAddress & 0xF); INFO_(VIDEOPRT, "- Segment: %x\n", (ULONG)MemoryAddress >> 4); INFO_(VIDEOPRT, "- Offset: %x\n", (ULONG)MemoryAddress & 0xF); INFO_(VIDEOPRT, "- Length: %x\n", *Length); IntDetachFromCSRSS(&CallingProcess, &ApcState); return NO_ERROR; }
NTSTATUS NTAPI RtlpFreeUserStack(IN HANDLE Process, IN PINITIAL_TEB InitialTeb) { SIZE_T Dummy = 0; NTSTATUS Status; /* Free the Stack */ Status = ZwFreeVirtualMemory(Process, &InitialTeb->AllocatedStackBase, &Dummy, MEM_RELEASE); /* Clear the initial TEB */ RtlZeroMemory(InitialTeb, sizeof(INITIAL_TEB)); return Status; }
VP_STATUS NTAPI IntInt10FreeBuffer( IN PVOID Context, IN USHORT Seg, IN USHORT Off) { PVOID MemoryAddress = (PVOID)((Seg << 4) | Off); NTSTATUS Status; PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); KAPC_STATE ApcState; SIZE_T Size = 0; TRACE_(VIDEOPRT, "IntInt10FreeBuffer\n"); INFO_(VIDEOPRT, "- Segment: %x\n", Seg); INFO_(VIDEOPRT, "- Offset: %x\n", Off); IntAttachToCSRSS(&CallingProcess, &ApcState); Status = ZwFreeVirtualMemory(NtCurrentProcess(), &MemoryAddress, &Size, MEM_RELEASE); IntDetachFromCSRSS(&CallingProcess, &ApcState); return Status; }
/* * FUNCTION: Terminates the current thread * See "Windows Internals" - Chapter 13, Page 50-53 */ VOID NTAPI PspExitThread(IN NTSTATUS ExitStatus) { CLIENT_DIED_MSG TerminationMsg; NTSTATUS Status; PTEB Teb; PEPROCESS CurrentProcess; PETHREAD Thread, OtherThread, PreviousThread = NULL; PVOID DeallocationStack; SIZE_T Dummy; BOOLEAN Last = FALSE; PTERMINATION_PORT TerminationPort, NextPort; PLIST_ENTRY FirstEntry, CurrentEntry; PKAPC Apc; PTOKEN PrimaryToken; PAGED_CODE(); PSTRACE(PS_KILL_DEBUG, "ExitStatus: %d\n", ExitStatus); /* Get the Current Thread and Process */ Thread = PsGetCurrentThread(); CurrentProcess = Thread->ThreadsProcess; ASSERT((Thread) == PsGetCurrentThread()); /* Can't terminate a thread if it attached another process */ if (KeIsAttachedProcess()) { /* Bugcheck */ KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG_PTR)CurrentProcess, (ULONG_PTR)Thread->Tcb.ApcState.Process, (ULONG_PTR)Thread->Tcb.ApcStateIndex, (ULONG_PTR)Thread); } /* Lower to Passive Level */ KeLowerIrql(PASSIVE_LEVEL); /* Can't be a worker thread */ if (Thread->ActiveExWorker) { /* Bugcheck */ KeBugCheckEx(ACTIVE_EX_WORKER_THREAD_TERMINATION, (ULONG_PTR)Thread, 0, 0, 0); } /* Can't have pending APCs */ if (Thread->Tcb.CombinedApcDisable != 0) { /* Bugcheck */ KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT, 0, Thread->Tcb.CombinedApcDisable, 0, 1); } /* Lock the thread */ ExWaitForRundownProtectionRelease(&Thread->RundownProtect); /* Cleanup the power state */ PopCleanupPowerState((PPOWER_STATE)&Thread->Tcb.PowerState); /* Call the WMI Callback for Threads */ //WmiTraceThread(Thread, NULL, FALSE); /* Run Thread Notify Routines before we desintegrate the thread */ PspRunCreateThreadNotifyRoutines(Thread, FALSE); /* Lock the Process before we modify its thread entries */ KeEnterCriticalRegion(); ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock); /* Decrease the active thread count, and check if it's 0 */ if (!(--CurrentProcess->ActiveThreads)) { /* Set the delete flag */ InterlockedOr((PLONG)&CurrentProcess->Flags, PSF_PROCESS_DELETE_BIT); /* Remember we are last */ Last = TRUE; /* Check if this termination is due to the thread dying */ if (ExitStatus == STATUS_THREAD_IS_TERMINATING) { /* Check if the last thread was pending */ if (CurrentProcess->ExitStatus == STATUS_PENDING) { /* Use the last exit status */ CurrentProcess->ExitStatus = CurrentProcess-> LastThreadExitStatus; } } else { /* Just a normal exit, write the code */ CurrentProcess->ExitStatus = ExitStatus; } /* Loop all the current threads */ FirstEntry = &CurrentProcess->ThreadListHead; CurrentEntry = FirstEntry->Flink; while (FirstEntry != CurrentEntry) { /* Get the thread on the list */ OtherThread = CONTAINING_RECORD(CurrentEntry, ETHREAD, ThreadListEntry); /* Check if it's a thread that's still alive */ if ((OtherThread != Thread) && !(KeReadStateThread(&OtherThread->Tcb)) && (ObReferenceObjectSafe(OtherThread))) { /* It's a live thread and we referenced it, unlock process */ ExReleasePushLockExclusive(&CurrentProcess->ProcessLock); KeLeaveCriticalRegion(); /* Wait on the thread */ KeWaitForSingleObject(OtherThread, Executive, KernelMode, FALSE, NULL); /* Check if we had a previous thread to dereference */ if (PreviousThread) ObDereferenceObject(PreviousThread); /* Remember the thread and re-lock the process */ PreviousThread = OtherThread; KeEnterCriticalRegion(); ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock); } /* Go to the next thread */ CurrentEntry = CurrentEntry->Flink; } } else if (ExitStatus != STATUS_THREAD_IS_TERMINATING) { /* Write down the exit status of the last thread to get killed */ CurrentProcess->LastThreadExitStatus = ExitStatus; } /* Unlock the Process */ ExReleasePushLockExclusive(&CurrentProcess->ProcessLock); KeLeaveCriticalRegion(); /* Check if we had a previous thread to dereference */ if (PreviousThread) ObDereferenceObject(PreviousThread); /* Check if the process has a debug port and if this is a user thread */ if ((CurrentProcess->DebugPort) && !(Thread->SystemThread)) { /* Notify the Debug API. */ Last ? DbgkExitProcess(CurrentProcess->ExitStatus) : DbgkExitThread(ExitStatus); } /* Check if this is a Critical Thread */ if ((KdDebuggerEnabled) && (Thread->BreakOnTermination)) { /* Break to debugger */ PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n", Thread, CurrentProcess->ImageFileName); } /* Check if it's the last thread and this is a Critical Process */ if ((Last) && (CurrentProcess->BreakOnTermination)) { /* Check if a debugger is here to handle this */ if (KdDebuggerEnabled) { /* Break to debugger */ PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n", CurrentProcess, CurrentProcess->ImageFileName); } else { /* Bugcheck, we can't allow this */ KeBugCheckEx(CRITICAL_PROCESS_DIED, (ULONG_PTR)CurrentProcess, 0, 0, 0); } } /* Sanity check */ ASSERT(Thread->Tcb.CombinedApcDisable == 0); /* Process the Termination Ports */ TerminationPort = Thread->TerminationPort; if (TerminationPort) { /* Setup the message header */ TerminationMsg.h.u2.ZeroInit = 0; TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED; TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg); TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) - sizeof(PORT_MESSAGE); /* Loop each port */ do { /* Save the Create Time */ TerminationMsg.CreateTime = Thread->CreateTime; /* Loop trying to send message */ while (TRUE) { /* Send the LPC Message */ Status = LpcRequestPort(TerminationPort->Port, &TerminationMsg.h); if ((Status == STATUS_NO_MEMORY) || (Status == STATUS_INSUFFICIENT_RESOURCES)) { /* Wait a bit and try again */ KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); continue; } break; } /* Dereference this LPC Port */ ObDereferenceObject(TerminationPort->Port); /* Move to the next one */ NextPort = TerminationPort->Next; /* Free the Termination Port Object */ ExFreePoolWithTag(TerminationPort, '=TsP'); /* Keep looping as long as there is a port */ TerminationPort = NextPort; } while (TerminationPort); } else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) && (Thread->DeadThread)) || !(Thread->DeadThread)) { /* * This case is special and deserves some extra comments. What * basically happens here is that this thread doesn't have a termination * port, which means that it died before being fully created. Since we * still have to notify an LPC Server, we'll use the exception port, * which we know exists. However, we need to know how far the thread * actually got created. We have three possibilities: * * - NtCreateThread returned an error really early: DeadThread is set. * - NtCreateThread managed to create the thread: DeadThread is off. * - NtCreateThread was creating the thread (with DeadThread set, * but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING * is our exit code.) * * For the 2 & 3rd scenarios, the thread has been created far enough to * warrant notification to the LPC Server. */ /* Setup the message header */ TerminationMsg.h.u2.ZeroInit = 0; TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED; TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg); TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) - sizeof(PORT_MESSAGE); /* Make sure the process has an exception port */ if (CurrentProcess->ExceptionPort) { /* Save the Create Time */ TerminationMsg.CreateTime = Thread->CreateTime; /* Loop trying to send message */ while (TRUE) { /* Send the LPC Message */ Status = LpcRequestPort(CurrentProcess->ExceptionPort, &TerminationMsg.h); if ((Status == STATUS_NO_MEMORY) || (Status == STATUS_INSUFFICIENT_RESOURCES)) { /* Wait a bit and try again */ KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); continue; } break; } } } /* Rundown Win32 Thread if there is one */ if (Thread->Tcb.Win32Thread) PspW32ThreadCallout(Thread, PsW32ThreadCalloutExit); /* If we are the last thread and have a W32 Process */ if ((Last) && (CurrentProcess->Win32Process)) { /* Run it down too */ PspW32ProcessCallout(CurrentProcess, FALSE); } /* Make sure Stack Swap is enabled */ if (!Thread->Tcb.EnableStackSwap) { /* Stack swap really shouldn't be disabled during exit! */ KeBugCheckEx(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0); } /* Cancel I/O for the thread. */ IoCancelThreadIo(Thread); /* Rundown Timers */ ExTimerRundown(); /* FIXME: Rundown Registry Notifications (NtChangeNotify) CmNotifyRunDown(Thread); */ /* Rundown Mutexes */ KeRundownThread(); /* Check if we have a TEB */ Teb = Thread->Tcb.Teb; if (Teb) { /* Check if the thread is still alive */ if (!Thread->DeadThread) { /* Check if we need to free its stack */ if (Teb->FreeStackOnTermination) { /* Set the TEB's Deallocation Stack as the Base Address */ Dummy = 0; DeallocationStack = Teb->DeallocationStack; /* Free the Thread's Stack */ ZwFreeVirtualMemory(NtCurrentProcess(), &DeallocationStack, &Dummy, MEM_RELEASE); } /* Free the debug handle */ if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1], UserMode); } /* Decommit the TEB */ MmDeleteTeb(CurrentProcess, Teb); Thread->Tcb.Teb = NULL; } /* Free LPC Data */ LpcExitThread(Thread); /* Save the exit status and exit time */ Thread->ExitStatus = ExitStatus; KeQuerySystemTime(&Thread->ExitTime); /* Sanity check */ ASSERT(Thread->Tcb.CombinedApcDisable == 0); /* Check if this is the final thread or not */ if (Last) { /* Set the process exit time */ CurrentProcess->ExitTime = Thread->ExitTime; /* Exit the process */ PspExitProcess(TRUE, CurrentProcess); /* Get the process token and check if we need to audit */ PrimaryToken = PsReferencePrimaryToken(CurrentProcess); if (SeDetailedAuditingWithToken(PrimaryToken)) { /* Audit the exit */ SeAuditProcessExit(CurrentProcess); } /* Dereference the process token */ ObFastDereferenceObject(&CurrentProcess->Token, PrimaryToken); /* Check if this is a VDM Process and rundown the VDM DPCs if so */ if (CurrentProcess->VdmObjects) { /* VdmRundownDpcs(CurrentProcess); */ } /* Kill the process in the Object Manager */ ObKillProcess(CurrentProcess); /* Check if we have a section object */ if (CurrentProcess->SectionObject) { /* Dereference and clear the Section Object */ ObDereferenceObject(CurrentProcess->SectionObject); CurrentProcess->SectionObject = NULL; } /* Check if the process is part of a job */ if (CurrentProcess->Job) { /* Remove the process from the job */ PspExitProcessFromJob(CurrentProcess->Job, CurrentProcess); } } /* Disable APCs */ KeEnterCriticalRegion(); /* Disable APC queueing, force a resumption */ Thread->Tcb.ApcQueueable = FALSE; KeForceResumeThread(&Thread->Tcb); /* Re-enable APCs */ KeLeaveCriticalRegion(); /* Flush the User APCs */ FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode); if (FirstEntry) { /* Start with the first entry */ CurrentEntry = FirstEntry; do { /* Get the APC */ Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry); /* Move to the next one */ CurrentEntry = CurrentEntry->Flink; /* Rundown the APC or de-allocate it */ if (Apc->RundownRoutine) { /* Call its own routine */ Apc->RundownRoutine(Apc); } else { /* Do it ourselves */ ExFreePool(Apc); } } while (CurrentEntry != FirstEntry); } /* Clean address space if this was the last thread */ if (Last) MmCleanProcessAddressSpace(CurrentProcess); /* Call the Lego routine */ if (Thread->Tcb.LegoData) PspRunLegoRoutine(&Thread->Tcb); /* Flush the APC queue, which should be empty */ FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode); if ((FirstEntry) || (Thread->Tcb.CombinedApcDisable != 0)) { /* Bugcheck time */ KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT, (ULONG_PTR)FirstEntry, Thread->Tcb.CombinedApcDisable, KeGetCurrentIrql(), 0); } /* Signal the process if this was the last thread */ if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE); /* Terminate the Thread from the Scheduler */ KeTerminateThread(0); }
BOOL CProcess::HideProcess() { EnableDebugPriv(SE_DEBUG_NAME); (InitializeFunction()); //进程信息及长度 PSYSTEM_HANDLE_INFORMATION pHandleInfo = NULL; DWORD buflen=0x10000,needlen=0; ULONG uObjCnt = 0; NTSTATUS status; BOOL bRet; HANDLE hProcess; //通过打开进程获取进程句柄 hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,GetCurrentProcessId()); //获得进程对象的地址 PBYTE pBuf = NULL; do { //申请查询句柄信息所需的内存 ZwAllocateVirtualMemory(GetCurrentProcess(),(PVOID*)&pBuf,0,&buflen,MEM_COMMIT,PAGE_READWRITE); if (pBuf == NULL) return FALSE; //查询系统句柄信息 status=NtQuerySystemInformation(SystemHandleInformation,(PVOID)pBuf,buflen,&needlen); if (NT_SUCCESS(status)) break; //不成功,则释放内存 //这里只要一块大内存够放这些内容就行,或者直接申请一块足够大的也可以 //返回的needlen可以做为参考 ZwFreeVirtualMemory(GetCurrentProcess(),(PVOID*)&pBuf,&buflen,MEM_RELEASE); //然后把要申请的内存大小乘2,直至成功为止 buflen *= 2; pBuf = NULL; } while(TRUE); uObjCnt = (ULONG)*(ULONG*)pBuf; DWORD dwEPROCESS; //ULONG dwCurrentPID; pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)(pBuf+sizeof(ULONG)); if(NT_SUCCESS(status)) { for(int i=0;i<(int)uObjCnt;i++) { ( Out(Dbg,"pHandleInfo->Handle:%d pHandleInfo->ProcessID:%d \n",pHandleInfo->Handle,pHandleInfo->ProcessID)); if(pHandleInfo->Handle==(USHORT)hProcess && pHandleInfo->ProcessID==(ULONG)GetCurrentProcessId())/*pHandleInfo->ProcessID==dwPID && pHandleInfo->Handle==(USHORT)GetProcessHand()*/ { dwEPROCESS = (DWORD)pHandleInfo->Object; Out(Dbg,"dwEPROCESS: 0x%x",(ULONG)dwEPROCESS); //dwCurrentPID = pHandleInfo->ProcessID; break; } pHandleInfo++; } //在拿到当前进程的EPROCESS基址后,释放掉内存 ZwFreeVirtualMemory(GetCurrentProcess(),(PVOID*)&pBuf,&buflen,MEM_RELEASE); //关闭句柄 CloseHandle(hProcess); bRet = TRUE; } //FCHK(SystemDebugControl(dwEPROCESS+0x088,&list,sizeof(list),SysDbgCopyMemoryChunks_0)); //FCHK(SystemDebugControl((ULONG)(list.Blink)+0x4,&list.Blink,sizeof(list.Blink),SysDbgCopyMemoryChunks_1)); //FCHK(SystemDebugControl((ULONG)(list.Blink),&list.Flink,sizeof(list.Flink),SysDbgCopyMemoryChunks_1)); MEMORY_CHUNKS datas; datas.Address = dwEPROCESS+0x088; LIST_ENTRY list = {0}; datas.Data =&list; datas.Length = sizeof(list); OperateSystemMemory(datas,SysDbgCopyMemoryChunks_0); datas.Address = (ULONG)(list.Blink)+0x4; datas.Data =&list.Blink; datas.Length = sizeof(list.Blink); OperateSystemMemory(datas,SysDbgCopyMemoryChunks_1); datas.Address = (ULONG)(list.Blink); datas.Data =&list.Flink; datas.Length = sizeof(list.Flink); OperateSystemMemory(datas,SysDbgCopyMemoryChunks_1); return TRUE; }
NTSTATUS SepRmCallLsa( PSEP_WORK_ITEM SepWorkItem ) /*++ Routine Description: This function sends a command to the LSA via the LSA Reference Monitor Server Command LPC Port. If the command has parameters, they will be copied directly into a message structure and sent via LPC, therefore, the supplied parameters may not contain any absolute pointers. A caller must remove pointers by "marshalling" them into the buffer CommandParams. This function will create a queue of requests. This is in order to allow greater throughput for the majority if its callers. If a thread enters this routine and finds the queue empty, it is the responsibility of that thread to service all requests that come in while it is working until the queue is empty again. Other threads that enter will simply hook their work item onto the queue and exit. To implement a new LSA command, do the following: ================================================ (1) If the command takes no parameters, just call this routine directly and provide an LSA worker routine called Lsap<command>Wrkr. See file lsa\server\lsarm.c for examples (2) If the command takes parameters, provide a routine called SepRmSend<command>Command that takes the parameters in unmarshalled form and calls SepRmCallLsa() with the command id, marshalled parameters, length of marshalled parameters and pointer to optional reply message. The marshalled parameters are free format: the only restriction is that there must be no absolute address pointers. These parameters are all placed in the passed LsaWorkItem structure. (3) In file private\inc\ntrmlsa.h, append a command name to the enumerated type LSA_COMMAND_NUMBER defined in file private\inc\ntrmlsa.h. Change the #define for LsapMaximumCommand to reference the new command. (4) Add the Lsap<command>Wrkr to the command dispatch table structure LsapCommandDispatch[] in file lsarm.c. (5) Add function prototypes to lsap.h and sep.h. Arguments: LsaWorkItem - Supplies a pointer to an SE_LSA_WORK_ITEM containing the information to be passed to LSA. This structure will be freed asynchronously by some invocation of this routine, not necessarily in the current context. !THIS PARAMETER MUST BE ALLOCATED OUT OF NONPAGED POOL! Return Value: NTSTATUS - Result Code. This is either a result code returned from trying to send the command/receive the reply, or a status code from the command itself. --*/ { NTSTATUS Status = STATUS_SUCCESS; LSA_COMMAND_MESSAGE CommandMessage; LSA_REPLY_MESSAGE ReplyMessage; PSEP_LSA_WORK_ITEM WorkQueueItem; ULONG LocalListLength = 0; SIZE_T RegionSize; PVOID CopiedCommandParams = NULL; PVOID LsaViewCopiedCommandParams = NULL; PAGED_CODE(); #if 0 DbgPrint("Entering SepRmCallLsa\n"); #endif WorkQueueItem = SepWorkListHead(); KeAttachProcess( &SepRmLsaCallProcess->Pcb ); while ( WorkQueueItem ) { #if 0 DbgPrint("Got a work item from head of queue, processing\n"); #endif // // Construct a message for LPC. First, fill in the message header // fields for LPC, specifying the message type and data sizes for // the outgoing CommandMessage and the incoming ReplyMessage. // CommandMessage.MessageHeader.u2.ZeroInit = 0; CommandMessage.MessageHeader.u1.s1.TotalLength = ((CSHORT) RM_COMMAND_MESSAGE_HEADER_SIZE + (CSHORT) WorkQueueItem->CommandParamsLength); CommandMessage.MessageHeader.u1.s1.DataLength = CommandMessage.MessageHeader.u1.s1.TotalLength - (CSHORT) sizeof(PORT_MESSAGE); ReplyMessage.MessageHeader.u2.ZeroInit = 0; ReplyMessage.MessageHeader.u1.s1.DataLength = (CSHORT) WorkQueueItem->ReplyBufferLength; ReplyMessage.MessageHeader.u1.s1.TotalLength = ReplyMessage.MessageHeader.u1.s1.DataLength + (CSHORT) sizeof(PORT_MESSAGE); // // Next, fill in the header info needed by the LSA. // CommandMessage.CommandNumber = WorkQueueItem->CommandNumber; ReplyMessage.ReturnedStatus = STATUS_SUCCESS; // // Set up the Command Parameters either in the LPC Command Message // itself, in the preallocated Lsa shared memory block, or in a // specially allocated block. The parameters are either // immediate (i.e. in the WorkQueueItem itself, or are in a buffer // pointed to by the address in the WorkQueueItem. // switch (WorkQueueItem->CommandParamsMemoryType) { case SepRmImmediateMemory: // // The Command Parameters are in the CommandParams buffer // in the Work Queue Item. Just copy them to the corresponding // buffer in the CommandMessage buffer. // CommandMessage.CommandParamsMemoryType = SepRmImmediateMemory; RtlCopyMemory( CommandMessage.CommandParams, &WorkQueueItem->CommandParams, WorkQueueItem->CommandParamsLength ); break; case SepRmPagedPoolMemory: case SepRmUnspecifiedMemory: // // The Command Parameters are contained in paged pool memory. // Since this memory is is not accessible by the LSA, we must // copy of them either to the LPC Command Message Block, or // into LSA shared memory. // if (WorkQueueItem->CommandParamsLength <= LSA_MAXIMUM_COMMAND_PARAM_SIZE) { // // Parameters will fit into the LPC Command Message block. // CopiedCommandParams = CommandMessage.CommandParams; RtlCopyMemory( CopiedCommandParams, WorkQueueItem->CommandParams.BaseAddress, WorkQueueItem->CommandParamsLength ); CommandMessage.CommandParamsMemoryType = SepRmImmediateMemory; } else { // // Parameters too large for LPC Command Message block. // If possible, copy them to the preallocated Lsa Shared // Memory block. If they are too large to fit, copy them // to an individually allocated chunk of Shared Virtual // Memory. // if (WorkQueueItem->CommandParamsLength <= SEP_RM_LSA_SHARED_MEMORY_SIZE) { RtlCopyMemory( SepRmState.RmViewPortMemory, WorkQueueItem->CommandParams.BaseAddress, WorkQueueItem->CommandParamsLength ); LsaViewCopiedCommandParams = SepRmState.LsaViewPortMemory; CommandMessage.CommandParamsMemoryType = SepRmLsaCommandPortSharedMemory; } else { Status = SepAdtCopyToLsaSharedMemory( SepLsaHandle, WorkQueueItem->CommandParams.BaseAddress, WorkQueueItem->CommandParamsLength, &LsaViewCopiedCommandParams ); if (!NT_SUCCESS(Status)) { // // An error occurred, most likely in allocating // shared virtual memory. For now, just ignore // the error and discard the Audit Record. Later, // we may consider generating a warning record // indicating some records lost. // break; } CommandMessage.CommandParamsMemoryType = SepRmLsaCustomSharedMemory; } // // Buffer has been successfully copied to a shared Lsa // memory buffer. Place the address of the buffer valid in // the LSA's process context in the Command Message. // *((PVOID *) CommandMessage.CommandParams) = LsaViewCopiedCommandParams; CommandMessage.MessageHeader.u1.s1.TotalLength = ((CSHORT) RM_COMMAND_MESSAGE_HEADER_SIZE + (CSHORT) sizeof( LsaViewCopiedCommandParams )); CommandMessage.MessageHeader.u1.s1.DataLength = CommandMessage.MessageHeader.u1.s1.TotalLength - (CSHORT) sizeof(PORT_MESSAGE); } // // Free input command params buffer if Paged Pool. // if (WorkQueueItem->CommandParamsMemoryType == SepRmPagedPoolMemory) { ExFreePool( WorkQueueItem->CommandParams.BaseAddress ); } break; default: Status = STATUS_INVALID_PARAMETER; break; } if (NT_SUCCESS(Status)) { // // Send Message to the LSA via the LSA Server Command LPC Port. // This must be done in the process in which the handle was created. // Status = ZwRequestWaitReplyPort( SepRmState.LsaCommandPortHandle, (PPORT_MESSAGE) &CommandMessage, (PPORT_MESSAGE) &ReplyMessage ); // // If the command was successful, copy the data back to the output // buffer. // if (NT_SUCCESS(Status)) { // // Move output from command (if any) to buffer. Note that this // is done even if the command returns status, because some status // values are not errors. // if (ARGUMENT_PRESENT(WorkQueueItem->ReplyBuffer)) { RtlCopyMemory( WorkQueueItem->ReplyBuffer, ReplyMessage.ReplyBuffer, WorkQueueItem->ReplyBufferLength ); } // // Return status from command. // Status = ReplyMessage.ReturnedStatus; if (!NT_SUCCESS(Status)) { KdPrint(("Security: Command sent from RM to LSA returned 0x%lx\n", Status)); } } else { KdPrint(("Security: Sending Command RM to LSA failed 0x%lx\n", Status)); } // // On return from the LPC call to the LSA, we expect the called // LSA worker routine to have copied the Command Parameters // buffer (if any). If a custom shared memory boffer was allocated, // free it now. // if (CommandMessage.CommandParamsMemoryType == SepRmLsaCustomSharedMemory) { RegionSize = 0; Status = ZwFreeVirtualMemory( SepLsaHandle, (PVOID *) &CommandMessage.CommandParams, &RegionSize, MEM_RELEASE ); ASSERT(NT_SUCCESS(Status)); } } // // Clean up. We must call the cleanup functions on its parameter // and then free the used WorkQueueItem itself. // if ( ARGUMENT_PRESENT( WorkQueueItem->CleanupFunction)) { (WorkQueueItem->CleanupFunction)(WorkQueueItem->CleanupParameter); } // // Determine if there is more work to do on this list // WorkQueueItem = SepDequeueWorkItem(); #if 0 if ( WorkQueueItem ) { DbgPrint("Got another item from list, going back\n"); } else { DbgPrint("List is empty, leaving\n"); } #endif } KeDetachProcess(); if ( LocalListLength > SepLsaQueueLength ) { SepLsaQueueLength = LocalListLength; } return Status; }
SECURITY_STATUS SEC_ENTRY AcceptSecurityContext( PCredHandle phCredential, // Cred to base context PCtxtHandle phContext, // Existing context (OPT) PSecBufferDesc pInput, // Input buffer unsigned long fContextReq, // Context Requirements unsigned long TargetDataRep, // Target Data Rep PCtxtHandle phNewContext, // (out) New context handle PSecBufferDesc pOutput, // (inout) Output buffers unsigned long SEC_FAR * pfContextAttr, // (out) Context attributes PTimeStamp ptsExpiry // (out) Life span (OPT) ) { SECURITY_STATUS scRet; NTSTATUS SubStatus; PAUTHENTICATE_MESSAGE AuthenticateMessage; ULONG AuthenticateMessageSize; PNTLM_AUTHENTICATE_MESSAGE NtlmAuthenticateMessage; ULONG NtlmAuthenticateMessageSize; PNTLM_ACCEPT_RESPONSE NtlmAcceptResponse = NULL; PMSV1_0_LM20_LOGON LogonBuffer = NULL; ULONG LogonBufferSize; PMSV1_0_LM20_LOGON_PROFILE LogonProfile = NULL; ULONG LogonProfileSize; PSecBuffer AcceptResponseToken = NULL; PClient Client = NULL; ANSI_STRING SourceName; LUID LogonId; LUID UNALIGNED * TempLogonId; LARGE_INTEGER UNALIGNED * TempKickoffTime; HANDLE TokenHandle = NULL; QUOTA_LIMITS Quotas; PUCHAR Where; STRING DomainName; STRING UserName; STRING Workstation; STRING NtChallengeResponse; STRING LmChallengeResponse; ULONG EffectivePackageId; RtlInitString( &SourceName, NULL ); PAGED_CODE(); // // Check for valid sizes, pointers, etc.: // if (!phCredential) { return(SEC_E_INVALID_HANDLE); } // // Check that we can indeed call the LSA and get the client // handle to it. // scRet = IsOkayToExec(&Client); if (!NT_SUCCESS(scRet)) { return(scRet); } // // Locate the buffers with the input data // if (!GetTokenBuffer( pInput, 0, // get the first security token (PVOID *) &AuthenticateMessage, &AuthenticateMessageSize, TRUE // may be readonly ) || (!GetTokenBuffer( pInput, 1, // get the second security token (PVOID *) &NtlmAuthenticateMessage, &NtlmAuthenticateMessageSize, TRUE // may be readonly ))) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Get the output tokens // if (!GetSecurityToken( pOutput, 0, &AcceptResponseToken ) ) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Make sure the sizes are o.k. // if ((AuthenticateMessageSize < sizeof(AUTHENTICATE_MESSAGE)) || (NtlmAuthenticateMessageSize < sizeof(NTLM_AUTHENTICATE_MESSAGE))) { scRet = SEC_E_INVALID_TOKEN; } // // Make sure the caller does not want us to allocate memory: // if (fContextReq & ISC_REQ_ALLOCATE_MEMORY) { scRet = SEC_E_UNSUPPORTED_FUNCTION; goto Cleanup; } if (AcceptResponseToken->cbBuffer < sizeof(NTLM_ACCEPT_RESPONSE)) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Verify the validity of the Authenticate message. // if (strncmp( AuthenticateMessage->Signature, NTLMSSP_SIGNATURE, sizeof(NTLMSSP_SIGNATURE))) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } if (AuthenticateMessage->MessageType != NtLmAuthenticate) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Fixup the buffer pointers // UserName = AuthenticateMessage->UserName; UserName.Buffer = UserName.Buffer + (ULONG) AuthenticateMessage; DomainName = AuthenticateMessage->DomainName; DomainName.Buffer = DomainName.Buffer + (ULONG) AuthenticateMessage; Workstation = AuthenticateMessage->Workstation; Workstation.Buffer = Workstation.Buffer + (ULONG) AuthenticateMessage; NtChallengeResponse = AuthenticateMessage->NtChallengeResponse; NtChallengeResponse.Buffer = NtChallengeResponse.Buffer + (ULONG) AuthenticateMessage; LmChallengeResponse = AuthenticateMessage->LmChallengeResponse; LmChallengeResponse.Buffer = LmChallengeResponse.Buffer + (ULONG) AuthenticateMessage; // // Allocate a buffer to pass into LsaLogonUser // LogonBufferSize = sizeof(MSV1_0_LM20_LOGON) + UserName.Length + DomainName.Length + Workstation.Length + LmChallengeResponse.Length + NtChallengeResponse.Length; scRet = ZwAllocateVirtualMemory( NtCurrentProcess(), &LogonBuffer, 0L, &LogonBufferSize, MEM_COMMIT, PAGE_READWRITE ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } // // Fill in the fixed-length portions // LogonBuffer->MessageType = MsV1_0NetworkLogon; RtlCopyMemory( LogonBuffer->ChallengeToClient, NtlmAuthenticateMessage->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH ); // // Fill in the variable length pieces // Where = (PUCHAR) (LogonBuffer + 1); PutString( (PSTRING) &LogonBuffer->LogonDomainName, &DomainName, 0, &Where ); PutString( (PSTRING) &LogonBuffer->UserName, &UserName, 0, &Where ); PutString( (PSTRING) &LogonBuffer->Workstation, &Workstation, 0, &Where ); PutString( (PSTRING) &LogonBuffer->CaseSensitiveChallengeResponse, &NtChallengeResponse, 0, &Where ); PutString( (PSTRING) &LogonBuffer->CaseInsensitiveChallengeResponse, &LmChallengeResponse, 0, &Where ); LogonBuffer->ParameterControl = MSV1_0_CLEARTEXT_PASSWORD_ALLOWED | NtlmAuthenticateMessage->ParameterControl; scRet = RtlUnicodeStringToAnsiString( &SourceName, (PUNICODE_STRING) &Workstation, TRUE ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } if ( fContextReq & ASC_REQ_LICENSING ) { EffectivePackageId = PackageId | LSA_CALL_LICENSE_SERVER ; } else { EffectivePackageId = PackageId ; } scRet = LsaLogonUser( Client->hPort, &SourceName, Network, EffectivePackageId, LogonBuffer, LogonBufferSize, NULL, // token groups &KsecTokenSource, (PVOID *) &LogonProfile, &LogonProfileSize, &LogonId, &TokenHandle, &Quotas, &SubStatus ); if (scRet == STATUS_ACCOUNT_RESTRICTION) { scRet = SubStatus; } if (!NT_SUCCESS(scRet)) { // // LsaLogonUser returns garbage for the token if it fails, // so zero it now so we don't try to close it later. // TokenHandle = NULL; goto Cleanup; } // // Create the kernel context // scRet = NtlmInitKernelContext( LogonProfile->UserSessionKey, LogonProfile->LanmanSessionKey, TokenHandle, phNewContext ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } TokenHandle = NULL; // // Allocate the return buffer. // NtlmAcceptResponse = (PNTLM_ACCEPT_RESPONSE) AcceptResponseToken->pvBuffer; if (NtlmAcceptResponse == NULL) { scRet = SEC_E_INSUFFICIENT_MEMORY; goto Cleanup; } TempLogonId = (LUID UNALIGNED *) &NtlmAcceptResponse->LogonId; *TempLogonId = LogonId; NtlmAcceptResponse->UserFlags = LogonProfile->UserFlags; RtlCopyMemory( NtlmAcceptResponse->UserSessionKey, LogonProfile->UserSessionKey, MSV1_0_USER_SESSION_KEY_LENGTH ); RtlCopyMemory( NtlmAcceptResponse->LanmanSessionKey, LogonProfile->LanmanSessionKey, MSV1_0_LANMAN_SESSION_KEY_LENGTH ); TempKickoffTime = (LARGE_INTEGER UNALIGNED *) &NtlmAcceptResponse->KickoffTime; *TempKickoffTime = LogonProfile->KickOffTime; AcceptResponseToken->cbBuffer = sizeof(NTLM_ACCEPT_RESPONSE); if ( fContextReq & ASC_REQ_LICENSING ) { *pfContextAttr = ASC_RET_ALLOCATED_MEMORY | ASC_RET_LICENSING ; } else { *pfContextAttr = ASC_RET_ALLOCATED_MEMORY; } *ptsExpiry = LogonProfile->LogoffTime; scRet = SEC_E_OK; Cleanup: if (SourceName.Buffer != NULL) { RtlFreeAnsiString(&SourceName); } if (LogonBuffer != NULL) { ZwFreeVirtualMemory( NtCurrentProcess(), &LogonBuffer, &LogonBufferSize, MEM_RELEASE ); } if (LogonProfile != NULL) { LsaFreeReturnBuffer(LogonProfile); } if (TokenHandle != NULL) { NtClose(TokenHandle); } return(scRet); }
SECURITY_STATUS SEC_ENTRY InitializeSecurityContextW( PCredHandle phCredential, // Cred to base context PCtxtHandle phContext, // Existing context (OPT) PSECURITY_STRING pssTargetName, // Name of target unsigned long fContextReq, // Context Requirements unsigned long Reserved1, // Reserved, MBZ unsigned long TargetDataRep, // Data rep of target PSecBufferDesc pInput, // Input Buffers unsigned long Reserved2, // Reserved, MBZ PCtxtHandle phNewContext, // (out) New Context handle PSecBufferDesc pOutput, // (inout) Output Buffers unsigned long SEC_FAR * pfContextAttr, // (out) Context attrs PTimeStamp ptsExpiry // (out) Life span (OPT) ) { SECURITY_STATUS scRet; PMSV1_0_GETCHALLENRESP_REQUEST ChallengeRequest = NULL; ULONG ChallengeRequestSize; PMSV1_0_GETCHALLENRESP_RESPONSE ChallengeResponse = NULL; ULONG ChallengeResponseSize; PCHALLENGE_MESSAGE ChallengeMessage = NULL; ULONG ChallengeMessageSize; PNTLM_CHALLENGE_MESSAGE NtlmChallengeMessage = NULL; ULONG NtlmChallengeMessageSize; PAUTHENTICATE_MESSAGE AuthenticateMessage = NULL; ULONG AuthenticateMessageSize; PNTLM_INITIALIZE_RESPONSE NtlmInitializeResponse = NULL; PClient Client = NULL; UNICODE_STRING PasswordToUse; UNICODE_STRING UserNameToUse; UNICODE_STRING DomainNameToUse; ULONG ParameterControl = USE_PRIMARY_PASSWORD | RETURN_PRIMARY_USERNAME | RETURN_PRIMARY_LOGON_DOMAINNAME; NTSTATUS FinalStatus = STATUS_SUCCESS; PUCHAR Where; PSecBuffer AuthenticationToken = NULL; PSecBuffer InitializeResponseToken = NULL; BOOLEAN UseSuppliedCreds = FALSE; PAGED_CODE(); RtlInitUnicodeString( &PasswordToUse, NULL ); RtlInitUnicodeString( &UserNameToUse, NULL ); RtlInitUnicodeString( &DomainNameToUse, NULL ); // // Check for valid sizes, pointers, etc.: // if (!phCredential) { return(SEC_E_INVALID_HANDLE); } // // Check that we can indeed call the LSA and get the client // handle to it. // scRet = IsOkayToExec(&Client); if (!NT_SUCCESS(scRet)) { return(scRet); } // // Locate the buffers with the input data // if (!GetTokenBuffer( pInput, 0, // get the first security token (PVOID *) &ChallengeMessage, &ChallengeMessageSize, TRUE // may be readonly )) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // If we are using supplied creds, get them now too. // if (fContextReq & ISC_REQ_USE_SUPPLIED_CREDS) { if (!GetTokenBuffer( pInput, 1, // get the second security token (PVOID *) &NtlmChallengeMessage, &NtlmChallengeMessageSize, TRUE // may be readonly )) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } else { UseSuppliedCreds = TRUE; } } // // Get the output tokens // if (!GetSecurityToken( pOutput, 0, &AuthenticationToken) || !GetSecurityToken( pOutput, 1, &InitializeResponseToken ) ) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Make sure the sizes are o.k. // if ((ChallengeMessageSize < sizeof(CHALLENGE_MESSAGE)) || (UseSuppliedCreds && !(NtlmChallengeMessageSize < sizeof(NTLM_CHALLENGE_MESSAGE)))) { scRet = SEC_E_INVALID_TOKEN; } // // Make sure the caller wants us to allocate memory: // if (!(fContextReq & ISC_REQ_ALLOCATE_MEMORY)) { scRet = SEC_E_UNSUPPORTED_FUNCTION; goto Cleanup; } // // BUGBUG: allow calls requesting PROMPT_FOR_CREDS to go through. // We won't prompt, but we will setup a context properly. // // if ((fContextReq & ISC_REQ_PROMPT_FOR_CREDS) != 0) // { // scRet = SEC_E_UNSUPPORTED_FUNCTION; // goto Cleanup; // } // // Verify the validity of the challenge message. // if (strncmp( ChallengeMessage->Signature, NTLMSSP_SIGNATURE, sizeof(NTLMSSP_SIGNATURE))) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } if (ChallengeMessage->MessageType != NtLmChallenge) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } if (ChallengeMessage->NegotiateFlags & NTLMSSP_REQUIRED_NEGOTIATE_FLAGS != NTLMSSP_REQUIRED_NEGOTIATE_FLAGS) { scRet = SEC_E_UNSUPPORTED_FUNCTION; goto Cleanup; } if ((ChallengeMessage->NegotiateFlags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY) != 0) { ParameterControl |= RETURN_NON_NT_USER_SESSION_KEY; } if ((fContextReq & ISC_REQ_USE_SUPPLIED_CREDS) != 0) { if ( NtlmChallengeMessage->Password.Buffer != NULL) { ParameterControl &= ~USE_PRIMARY_PASSWORD; PasswordToUse = NtlmChallengeMessage->Password; PasswordToUse.Buffer = (LPWSTR) ((PCHAR) PasswordToUse.Buffer + (ULONG) NtlmChallengeMessage); } if (NtlmChallengeMessage->UserName.Length != 0) { UserNameToUse = NtlmChallengeMessage->UserName; UserNameToUse.Buffer = (LPWSTR) ((PCHAR) UserNameToUse.Buffer + (ULONG) NtlmChallengeMessage); ParameterControl &= ~RETURN_PRIMARY_USERNAME; } if (NtlmChallengeMessage->DomainName.Length != 0) { DomainNameToUse = NtlmChallengeMessage->DomainName; DomainNameToUse.Buffer = (LPWSTR) ((PCHAR) DomainNameToUse.Buffer + (ULONG) NtlmChallengeMessage); ParameterControl &= ~RETURN_PRIMARY_LOGON_DOMAINNAME; } } // // Package up the parameter for a call to the LSA. // ChallengeRequestSize = sizeof(MSV1_0_GETCHALLENRESP_REQUEST) + PasswordToUse.Length; scRet = ZwAllocateVirtualMemory( NtCurrentProcess(), &ChallengeRequest, 0L, &ChallengeRequestSize, MEM_COMMIT, PAGE_READWRITE ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } // // Build the challenge request message. // ChallengeRequest->MessageType = MsV1_0Lm20GetChallengeResponse; ChallengeRequest->ParameterControl = ParameterControl; ChallengeRequest->LogonId = * (PLUID) phCredential; RtlCopyMemory( ChallengeRequest->ChallengeToClient, ChallengeMessage->Challenge, MSV1_0_CHALLENGE_LENGTH ); if ((ParameterControl & USE_PRIMARY_PASSWORD) == 0) { ChallengeRequest->Password.Buffer = (LPWSTR) (ChallengeRequest+1); RtlCopyMemory( ChallengeRequest->Password.Buffer, PasswordToUse.Buffer, PasswordToUse.Length ); ChallengeRequest->Password.Length = PasswordToUse.Length; ChallengeRequest->Password.MaximumLength = PasswordToUse.Length; } // // Call the LSA to get the challenge response. // scRet = LsaCallAuthenticationPackage( Client->hPort, PackageId, ChallengeRequest, ChallengeRequestSize, &ChallengeResponse, &ChallengeResponseSize, &FinalStatus ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } if (!NT_SUCCESS(FinalStatus)) { scRet = FinalStatus; goto Cleanup; } ASSERT(ChallengeResponse->MessageType == MsV1_0Lm20GetChallengeResponse); // // Now prepare the output message. // if (UserNameToUse.Buffer == NULL) { UserNameToUse = ChallengeResponse->UserName; } if (DomainNameToUse.Buffer == NULL) { DomainNameToUse = ChallengeResponse->LogonDomainName; } AuthenticateMessageSize = sizeof(AUTHENTICATE_MESSAGE) + UserNameToUse.Length + DomainNameToUse.Length + ChallengeResponse->CaseSensitiveChallengeResponse.Length + ChallengeResponse->CaseInsensitiveChallengeResponse.Length; // // BUGBUG: where do I get the workstation name from? // AuthenticateMessage = (PAUTHENTICATE_MESSAGE) SecAllocate(AuthenticateMessageSize); if (AuthenticateMessage == NULL) { scRet = SEC_E_INSUFFICIENT_MEMORY; goto Cleanup; } Where = (PUCHAR) (AuthenticateMessage + 1); RtlCopyMemory( AuthenticateMessage->Signature, NTLMSSP_SIGNATURE, sizeof(NTLMSSP_SIGNATURE) ); AuthenticateMessage->MessageType = NtLmAuthenticate; PutString( &AuthenticateMessage->LmChallengeResponse, &ChallengeResponse->CaseInsensitiveChallengeResponse, AuthenticateMessage, &Where ); PutString( &AuthenticateMessage->NtChallengeResponse, &ChallengeResponse->CaseSensitiveChallengeResponse, AuthenticateMessage, &Where ); PutString( &AuthenticateMessage->DomainName, (PSTRING) &DomainNameToUse, AuthenticateMessage, &Where ); PutString( &AuthenticateMessage->UserName, (PSTRING) &UserNameToUse, AuthenticateMessage, &Where ); // // BUGBUG: no workstation name to fill in. // AuthenticateMessage->Workstation.Length = 0; AuthenticateMessage->Workstation.MaximumLength = 0; AuthenticateMessage->Workstation.Buffer = NULL; // // Build the initialize response. // NtlmInitializeResponse = (PNTLM_INITIALIZE_RESPONSE) SecAllocate(sizeof(NTLM_INITIALIZE_RESPONSE)); if (NtlmInitializeResponse == NULL) { scRet = SEC_E_INSUFFICIENT_MEMORY; goto Cleanup; } RtlCopyMemory( NtlmInitializeResponse->UserSessionKey, ChallengeResponse->UserSessionKey, MSV1_0_USER_SESSION_KEY_LENGTH ); RtlCopyMemory( NtlmInitializeResponse->LanmanSessionKey, ChallengeResponse->LanmanSessionKey, MSV1_0_LANMAN_SESSION_KEY_LENGTH ); // // Fill in the output buffers now. // AuthenticationToken->pvBuffer = AuthenticateMessage; AuthenticationToken->cbBuffer = AuthenticateMessageSize; InitializeResponseToken->pvBuffer = NtlmInitializeResponse; InitializeResponseToken->cbBuffer = sizeof(NTLM_INITIALIZE_RESPONSE); // // Make a local context for this // scRet = NtlmInitKernelContext( NtlmInitializeResponse->UserSessionKey, NtlmInitializeResponse->LanmanSessionKey, NULL, // no token, phNewContext ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } scRet = SEC_E_OK; Cleanup: if (ChallengeRequest != NULL) { ZwFreeVirtualMemory( NtCurrentProcess(), &ChallengeRequest, &ChallengeRequestSize, MEM_RELEASE ); } if (ChallengeResponse != NULL) { LsaFreeReturnBuffer( ChallengeResponse ); } if (!NT_SUCCESS(scRet)) { if (AuthenticateMessage != NULL) { SecFree(AuthenticateMessage); } if (NtlmInitializeResponse != NULL) { SecFree(NtlmInitializeResponse); } } return(scRet); }
BOOLEAN InjectDll(PINJECT_INFO InjectInfo) { PEPROCESS Process; PETHREAD Thread; PKINJECT mem; ULONG size; PKAPC_STATE ApcState; PKAPC apc; PVOID buffer; PSYSTEM_PROCESS_INFO pSpi; LARGE_INTEGER delay; buffer=ExAllocatePool(NonPagedPool,1024*1024); // Allocate memory for the system information if(!buffer) { DbgPrint("Error: Unable to allocate memory for the process thread list."); return FALSE; } // Get the process thread list if(!NT_SUCCESS(ZwQuerySystemInformation(5,buffer,1024*1024,NULL))) { DbgPrint("Error: Unable to query process thread list."); ExFreePool(buffer); return FALSE; } pSpi=(PSYSTEM_PROCESS_INFO)buffer; // Find a target thread while(pSpi->NextEntryOffset) { if(pSpi->UniqueProcessId==InjectInfo->ProcessId) { DbgPrint("Target thread found. TID: %d",pSpi->Threads[0].ClientId.UniqueThread); break; } pSpi=(PSYSTEM_PROCESS_INFO)((PUCHAR)pSpi+pSpi->NextEntryOffset); } // Reference the target process if(!NT_SUCCESS(PsLookupProcessByProcessId(InjectInfo->ProcessId,&Process))) { DbgPrint("Error: Unable to reference the target process."); ExFreePool(buffer); return FALSE; } DbgPrint("Process name: %s",PsGetProcessImageFileName(Process)); DbgPrint("EPROCESS address: %#x",Process); // Reference the target thread if(!NT_SUCCESS(PsLookupThreadByThreadId(pSpi->Threads[0].ClientId.UniqueThread,&Thread))) { DbgPrint("Error: Unable to reference the target thread."); ObDereferenceObject(Process); // Dereference the target process ExFreePool(buffer); // Free the allocated memory return FALSE; } DbgPrint("ETHREAD address: %#x",Thread); ExFreePool(buffer); // Free the allocated memory KeAttachProcess(Process); // Attach to target process's address space mem=NULL; size=4096; // Allocate memory in the target process if(!NT_SUCCESS(ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,0,&size,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE))) { DbgPrint("Error: Unable to allocate memory in the target process."); KeDetachProcess(); // Detach from target process's address space ObDereferenceObject(Process); // Dereference the target process ObDereferenceObject(Thread); // Dereference the target thread return FALSE; } DbgPrint("Memory allocated at %#x",mem); mem->LdrLoadDll=LdrLoadDll; // Write the address of LdrLoadDll to target process wcscpy(mem->Buffer,InjectInfo->DllName); // Write the DLL name to target process RtlInitUnicodeString(&mem->DllName,mem->Buffer); // Initialize the UNICODE_STRING structure ApcState=(PKAPC_STATE)((PUCHAR)Thread+ApcStateOffset); // Calculate the address of the ApcState structure ApcState->UserApcPending=TRUE; // Force the target thread to execute APC memcpy((PKINJECT)(mem+1),InjectDllApc,(ULONG)KernelRoutine-(ULONG)InjectDllApc); // Copy the APC code to target process DbgPrint("APC code address: %#x",(PKINJECT)(mem+1)); apc=(PKAPC)ExAllocatePool(NonPagedPool,sizeof(KAPC)); // Allocate the APC object if(!apc) { DbgPrint("Error: Unable to allocate the APC object."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); // Free the allocated memory KeDetachProcess(); // Detach from target process's address space ObDereferenceObject(Process); // Dereference the target process ObDereferenceObject(Thread); // Dereference the target thread return FALSE; } KeInitializeApc(apc,Thread,OriginalApcEnvironment,KernelRoutine,NULL,(PKNORMAL_ROUTINE)((PKINJECT)mem+1),UserMode,mem); // Initialize the APC DbgPrint("Inserting APC to target thread"); // Insert the APC to the target thread if(!KeInsertQueueApc(apc,NULL,NULL,IO_NO_INCREMENT)) { DbgPrint("Error: Unable to insert APC to target thread."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); // Free the allocated memory KeDetachProcess(); // Detach from target process's address space ObDereferenceObject(Process); // Dereference the target process ObDereferenceObject(Thread); // Dereference the target thread ExFreePool(apc); // Free the APC object return FALSE; } delay.QuadPart=-100*10000; while(!mem->Executed) { KeDelayExecutionThread(KernelMode,FALSE,&delay); // Wait for the injection to complete } if(!mem->DllBase) { DbgPrint("Error: Unable to inject DLL into target process."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); return FALSE; } DbgPrint("DLL injected at %#x",mem->DllBase); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); // Free the allocated memory KeDetachProcess(); // Detach from target process's address space ObDereferenceObject(Process); // Dereference the target process ObDereferenceObject(Thread); // Dereference the target thread return TRUE; }
NTSTATUS VdmpInitialize( PVDMICAUSERDATA pIcaUserData ) /*++ Routine Description: Initialize the address space of a VDM. Arguments: None, Return Value: NTSTATUS. --*/ { NTSTATUS Status, StatusCopy; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING SectionName; UNICODE_STRING WorkString; ULONG ViewSize; LARGE_INTEGER ViewBase; PVOID BaseAddress; PVOID destination; HANDLE SectionHandle, RegistryHandle; PEPROCESS Process; ULONG ResultLength; ULONG Index; PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor; PKEY_VALUE_FULL_INFORMATION KeyValueBuffer; PCM_ROM_BLOCK BiosBlock; ULONG LastMappedAddress; PVDM_PROCESS_OBJECTS pVdmObjects = NULL; USHORT PagedQuotaCharged = 0; USHORT NonPagedQuotaCharged = 0; HANDLE hThread; PVDM_TIB VdmTib; PAGED_CODE(); Status = VdmpGetVdmTib(&VdmTib, VDMTIB_PROBE); // take from user mode and probe if (!NT_SUCCESS(Status)) { return Status; } if ((KeI386MachineType & MACHINE_TYPE_PC_9800_COMPATIBLE) == 0) { // // This is PC/AT (and FMR in Japan) VDM. // RtlInitUnicodeString( &SectionName, L"\\Device\\PhysicalMemory" ); InitializeObjectAttributes( &ObjectAttributes, &SectionName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, (HANDLE) NULL, (PSECURITY_DESCRIPTOR) NULL ); Status = ZwOpenSection( &SectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes ); if (!NT_SUCCESS(Status)) { return Status; } // // Copy the first page of memory into the VDM's address space // BaseAddress = 0; destination = 0; ViewSize = 0x1000; ViewBase.LowPart = 0; ViewBase.HighPart = 0; Status = ZwMapViewOfSection( SectionHandle, NtCurrentProcess(), &BaseAddress, 0, ViewSize, &ViewBase, &ViewSize, ViewUnmap, 0, PAGE_READWRITE ); if (!NT_SUCCESS(Status)) { ZwClose(SectionHandle); return Status; } // problem with this statement below -- // it could be a non-vdm process and copying memory to address 0 // should be guarded against StatusCopy = STATUS_SUCCESS; try { RtlMoveMemory( destination, BaseAddress, ViewSize ); } except(ExSystemExceptionFilter()) { StatusCopy = GetExceptionCode(); } Status = ZwUnmapViewOfSection( NtCurrentProcess(), BaseAddress ); if (!NT_SUCCESS(Status) || !NT_SUCCESS(StatusCopy)) { ZwClose(SectionHandle); return (NT_SUCCESS(Status) ? StatusCopy : Status); } // // Map Rom into address space // BaseAddress = (PVOID) 0x000C0000; ViewSize = 0x40000; ViewBase.LowPart = 0x000C0000; ViewBase.HighPart = 0; // // First unmap the reserved memory. This must be done here to prevent // the virtual memory in question from being consumed by some other // alloc vm call. // Status = ZwFreeVirtualMemory( NtCurrentProcess(), &BaseAddress, &ViewSize, MEM_RELEASE ); // N.B. This should probably take into account the fact that there are // a handfull of error conditions that are ok. (such as no memory to // release.) if (!NT_SUCCESS(Status)) { ZwClose(SectionHandle); return Status; } // // Set up and open KeyPath // InitializeObjectAttributes( &ObjectAttributes, &CmRegistryMachineHardwareDescriptionSystemName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, (HANDLE)NULL, NULL ); Status = ZwOpenKey( &RegistryHandle, KEY_READ, &ObjectAttributes ); if (!NT_SUCCESS(Status)) { ZwClose(SectionHandle); return Status; } // // Allocate space for the data // KeyValueBuffer = ExAllocatePoolWithTag( PagedPool, KEY_VALUE_BUFFER_SIZE, ' MDV' ); if (KeyValueBuffer == NULL) { ZwClose(RegistryHandle); ZwClose(SectionHandle); return STATUS_NO_MEMORY; } // // Get the data for the rom information // RtlInitUnicodeString( &WorkString, L"Configuration Data" ); Status = ZwQueryValueKey( RegistryHandle, &WorkString, KeyValueFullInformation, KeyValueBuffer, KEY_VALUE_BUFFER_SIZE, &ResultLength ); if (!NT_SUCCESS(Status)) { ZwClose(RegistryHandle); ExFreePool(KeyValueBuffer); ZwClose(SectionHandle); return Status; } ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR) KeyValueBuffer + KeyValueBuffer->DataOffset); if ((KeyValueBuffer->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) || (ResourceDescriptor->PartialResourceList.Count < 2) ) { ZwClose(RegistryHandle); ExFreePool(KeyValueBuffer); ZwClose(SectionHandle); // No rom blocks. return STATUS_SUCCESS; } PartialResourceDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)ResourceDescriptor + sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + ResourceDescriptor->PartialResourceList.PartialDescriptors[0] .u.DeviceSpecificData.DataSize); if (KeyValueBuffer->DataLength < ((PUCHAR)PartialResourceDescriptor - (PUCHAR)ResourceDescriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + sizeof(CM_ROM_BLOCK)) ) { ZwClose(RegistryHandle); ExFreePool(KeyValueBuffer); ZwClose(SectionHandle); return STATUS_ILL_FORMED_SERVICE_ENTRY; } BiosBlock = (PCM_ROM_BLOCK)((PUCHAR)PartialResourceDescriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); Index = PartialResourceDescriptor->u.DeviceSpecificData.DataSize / sizeof(CM_ROM_BLOCK); // // N.B. Rom blocks begin on 2K (not necessarily page) boundaries // They end on 512 byte boundaries. This means that we have // to keep track of the last page mapped, and round the next // Rom block up to the next page boundary if necessary. // LastMappedAddress = 0xC0000; while (Index) { #if 0 DbgPrint( "Bios Block, PhysAddr = %lx, size = %lx\n", BiosBlock->Address, BiosBlock->Size ); #endif if ((Index > 1) && ((BiosBlock->Address + BiosBlock->Size) == BiosBlock[1].Address) ) { // // Coalesce adjacent blocks // BiosBlock[1].Address = BiosBlock[0].Address; BiosBlock[1].Size += BiosBlock[0].Size; Index--; BiosBlock++; continue; } BaseAddress = (PVOID)(BiosBlock->Address); ViewSize = BiosBlock->Size; if ((ULONG)BaseAddress < LastMappedAddress) { if (ViewSize > (LastMappedAddress - (ULONG)BaseAddress)) { ViewSize = ViewSize - (LastMappedAddress - (ULONG)BaseAddress); BaseAddress = (PVOID)LastMappedAddress; } else { ViewSize = 0; } } ViewBase.LowPart = (ULONG)BaseAddress; if (ViewSize > 0) { Status = ZwMapViewOfSection( SectionHandle, NtCurrentProcess(), &BaseAddress, 0, ViewSize, &ViewBase, &ViewSize, ViewUnmap, MEM_DOS_LIM, PAGE_READWRITE ); if (!NT_SUCCESS(Status)) { break; } LastMappedAddress = (ULONG)BaseAddress + ViewSize; } Index--; BiosBlock++; } // // Free up the handles // ZwClose(SectionHandle); ZwClose(RegistryHandle); ExFreePool(KeyValueBuffer); } else {
BOOLEAN InjectDll(PINJECT_INFO InjectInfo) { PEPROCESS Process; PETHREAD Thread; PKINJECT mem; ULONG size; PKAPC_STATE ApcState; PKAPC apc; PVOID buffer; PSYSTEM_PROCESS_INFO pSpi; LARGE_INTEGER delay; buffer=ExAllocatePool(NonPagedPool,1024*1024); if(!buffer) { DbgPrint("Error: Unable to allocate memory for the process thread list."); return FALSE; } //5 SystemProcessInformation, if(!NT_SUCCESS(ZwQuerySystemInformation(5,buffer,1024*1024,NULL))) { DbgPrint("Error: Unable to query process thread list."); ExFreePool(buffer); return FALSE; } pSpi=(PSYSTEM_PROCESS_INFO)buffer; //找到目标进程 while(pSpi->NextEntryOffset) { if(pSpi->UniqueProcessId==InjectInfo->ProcessId) { DbgPrint("Target thread found. TID: %d",pSpi->Threads[0].ClientId.UniqueThread); break; } pSpi=(PSYSTEM_PROCESS_INFO)((PUCHAR)pSpi+pSpi->NextEntryOffset); } // 引用目标进程EProcess, if(!NT_SUCCESS(PsLookupProcessByProcessId(InjectInfo->ProcessId,&Process))) { DbgPrint("Error: Unable to reference the target process."); ExFreePool(buffer); return FALSE; } DbgPrint("Process name: %s",PsGetProcessImageFileName(Process)); DbgPrint("EPROCESS address: %#x",Process); //目标进程主线程 if(!NT_SUCCESS(PsLookupThreadByThreadId(pSpi->Threads[0].ClientId.UniqueThread,&Thread))) { DbgPrint("Error: Unable to reference the target thread."); ObDereferenceObject(Process); ExFreePool(buffer); return FALSE; } DbgPrint("ETHREAD address: %#x",Thread); ExFreePool(buffer); //切入到目标进程 KeAttachProcess(Process); mem=NULL; size=4096; //在目标进程申请内存 if(!NT_SUCCESS(ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,0,&size,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE))) { DbgPrint("Error: Unable to allocate memory in the target process."); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); return FALSE; } DbgPrint("Memory allocated at %#x",mem); mem->LdrLoadDll=LdrLoadDll; wcscpy(mem->Buffer,InjectInfo->DllName); RtlInitUnicodeString(&mem->DllName,mem->Buffer); ApcState=(PKAPC_STATE)((PUCHAR)Thread+ApcStateOffset); ApcState->UserApcPending=TRUE; memcpy((PKINJECT)(mem+1),InjectDllApc,(ULONG)KernelRoutine-(ULONG)InjectDllApc); DbgPrint("APC code address: %#x",(PKINJECT)(mem+1)); //申请apc对象 apc=(PKAPC)ExAllocatePool(NonPagedPool,sizeof(KAPC)); if(!apc) { DbgPrint("Error: Unable to allocate the APC object."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); return FALSE; } KeInitializeApc(apc, Thread, //目标进程主线程 OriginalApcEnvironment, //目标apcz状态 KernelRoutine, //内核apc总入口 NULL, //Rundown Rounine=NULL (PKNORMAL_ROUTINE)((PKINJECT)mem+1), //用户空间的总apc UserMode, //插入到用户apc队列 mem); // 自己的apc队列 DbgPrint("Inserting APC to target thread"); // 插入apc队列 if(!KeInsertQueueApc(apc,NULL,NULL,IO_NO_INCREMENT)) { DbgPrint("Error: Unable to insert APC to target thread."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); ExFreePool(apc); return FALSE; } delay.QuadPart=-100*10000; while(!mem->Executed) { KeDelayExecutionThread(KernelMode,FALSE,&delay); //等待apc执行 } if(!mem->DllBase) { DbgPrint("Error: Unable to inject DLL into target process."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); return FALSE; } DbgPrint("DLL injected at %#x",mem->DllBase); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); ObDereferenceObject(Process); ObDereferenceObject(Thread); return TRUE; }
// injects the function UserApcNormalRoutine() as a user mode APC // into the process selected by Process Pid NTSTATUS InjectApc( HANDLE ProcessId, PVOID User32MessageBoxA ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; HANDLE ProcessHandle = NULL; PEPROCESS ProcessObject = NULL; BOOLEAN Attached = FALSE; BOOLEAN Suspended = FALSE; PCONTEXT_DATA ContextData = NULL; PUCHAR AllocationBase = NULL; SIZE_T AllocationSize; ULONG ShellcodeSize; PUCHAR ShellcodeBase; KAPC_STATE ApcState; // get the size of the shell code that will be copied into user VAS ShellcodeSize = (ULONG)Getx64FunctionSize ( (PVOID)UserApcNormalRoutine ); if ( ! ShellcodeSize ) { DPF(("%s!%s Getx64FunctionSize(UserApcNormalRoutine) FAIL\n", __MODULE__, __FUNCTION__ )); goto Exit; } // Step #1 : Obtain the EPROCESS pointer from ProcessId (PsLookupProcessByProcessId()) // and store it in ProcessObject if (!NT_SUCCESS(Status = PsLookupProcessByProcessId(ProcessId, &ProcessObject))) { DbgPrint("ERROR PsLookupProcessByProcessId (%x)\n", Status); goto Exit; } // Step #2 : Suspend the target process (PsSuspendProcess()) if (!NT_SUCCESS(Status = PsSuspendProcess(ProcessObject))) { DbgPrint("ERROR PsSuspendProcess (%x)\n", Status); goto Exit; } Suspended = TRUE; // Step #3 : Attach to the target process (KeStackAttachProcess()) KeStackAttachProcess(ProcessObject, &ApcState); Attached = TRUE; AllocationSize = ShellcodeSize + sizeof ( CONTEXT_DATA ) ; // Step #4 : Allocate memory in the target process large enough // to hold the shellcode and CONTEXT_DATA (ZwAllocateVirtualMemory()) // and store the result in AllocationBase if (!NT_SUCCESS(Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &AllocationBase, 0, &AllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE))) { DbgPrint("ERROR ZwAllocateVirtualMemory (%x)\n", Status); goto Exit; } ProcessHandle = NULL; ShellcodeBase = AllocationBase; ContextData = (PCONTEXT_DATA)(AllocationBase + ShellcodeSize); // Step #5 : Copy the user mode APC code into the newly allocated // memory (RtlCopyMemory()) i.e. @ ShellCodeBase RtlCopyMemory(ShellcodeBase, (PVOID)UserApcNormalRoutine, ShellcodeSize); //setup the context structure with data that will be required by the APC routine ContextData->ShellCodeBase = ShellcodeBase; ContextData->ShellCodeSize = ShellcodeSize; strncpy ( ContextData->Text, "Hello from Kernel", STRING_SIZE ); strncpy ( ContextData->Caption, "P0wned", STRING_SIZE ); //user32.dll base + offset of MessageBoxA; ContextData->MessageBox = (MESSAGEBOXA)User32MessageBoxA; // queue the APC Status = RequestApc( ProcessId, ShellcodeBase, ContextData ); if ( ! NT_SUCCESS( Status ) ) { DPF(("%s!%s RequestApc() FAIL=%08x\n", __MODULE__, __FUNCTION__, Status )); goto Exit; } Exit : // in case of an error free the memory that was allocated if ( ! NT_SUCCESS ( Status ) ) { if ( AllocationBase ) { AllocationSize = 0; // Step #6 : Free the virtual memory that was allocated in the // target process (ZwFreeVirtualMemory()) ZwFreeVirtualMemory(ProcessHandle, &AllocationBase, &AllocationSize, MEM_RELEASE | MEM_DECOMMIT); } } if ( Attached ) { // Step #7 : Detach from the target process (KeUnstackDetachProcess()) KeUnstackDetachProcess(&ApcState); } if ( Suspended ) { // Step #8 : Resume the target process (PsResumeProcess()) PsResumeProcess(ProcessObject); } if ( ProcessObject ) { // Step #9 : Dereference the process object (ObDereferenceObject()) ObDereferenceObject(ProcessObject); } return Status; }
NTSTATUS VirtualFree(HANDLE hProcess, PVOID VirtualAddress) { SIZE_T RegionSize = 0; return ZwFreeVirtualMemory(hProcess, &VirtualAddress, &RegionSize, MEM_RELEASE); }
NTSTATUS NTAPI IntInitializeVideoAddressSpace(VOID) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory"); NTSTATUS Status; HANDLE PhysMemHandle; PVOID BaseAddress; LARGE_INTEGER Offset; SIZE_T ViewSize; CHAR IVTAndBda[1024+256]; /* Free the 1MB pre-reserved region. In reality, ReactOS should simply support us mapping the view into the reserved area, but it doesn't. */ BaseAddress = 0; ViewSize = 1024 * 1024; Status = ZwFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &ViewSize, MEM_RELEASE); if (!NT_SUCCESS(Status)) { DPRINT1("Couldn't unmap reserved memory (%x)\n", Status); return 0; } /* Open the physical memory section */ InitializeObjectAttributes(&ObjectAttributes, &PhysMemName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenSection(&PhysMemHandle, SECTION_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("Couldn't open \\Device\\PhysicalMemory\n"); return Status; } /* Map the BIOS and device registers into the address space */ Offset.QuadPart = 0xa0000; ViewSize = 0x100000 - 0xa0000; BaseAddress = (PVOID)0xa0000; Status = ZwMapViewOfSection(PhysMemHandle, NtCurrentProcess(), &BaseAddress, 0, ViewSize, &Offset, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE_READWRITE); if (!NT_SUCCESS(Status)) { DPRINT1("Couldn't map physical memory (%x)\n", Status); ZwClose(PhysMemHandle); return Status; } /* Close physical memory section handle */ ZwClose(PhysMemHandle); if (BaseAddress != (PVOID)0xa0000) { DPRINT1("Couldn't map physical memory at the right address (was %x)\n", BaseAddress); return STATUS_UNSUCCESSFUL; } /* Allocate some low memory to use for the non-BIOS * parts of the v86 mode address space */ BaseAddress = (PVOID)0x1; ViewSize = 0xa0000 - 0x1000; Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &BaseAddress, 0, &ViewSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to allocate virtual memory (Status %x)\n", Status); return Status; } if (BaseAddress != (PVOID)0x0) { DPRINT1("Failed to allocate virtual memory at right address (was %x)\n", BaseAddress); return 0; } /* Get the real mode IVT and BDA from the kernel */ Status = NtVdmControl(VdmInitialize, IVTAndBda); if (!NT_SUCCESS(Status)) { DPRINT1("NtVdmControl failed (status %x)\n", Status); return Status; } /* Return success */ return STATUS_SUCCESS; }
SECURITY_STATUS SEC_ENTRY GetSecurityUserInfo( IN PLUID pLogonId, IN ULONG fFlags, OUT PSecurityUserData * ppUserInfo) { NTSTATUS Status, FinalStatus; PVOID GetInfoBuffer = NULL; PVOID GetInfoResponseBuffer = NULL; PMSV1_0_GETUSERINFO_REQUEST GetInfoRequest; PMSV1_0_GETUSERINFO_RESPONSE GetInfoResponse; ULONG ResponseSize; ULONG RegionSize = sizeof(MSV1_0_GETUSERINFO_REQUEST); PSecurityUserData UserInfo = NULL; ULONG UserInfoSize; PUCHAR Where; SECURITY_STATUS scRet; PClient Client = NULL; scRet = IsOkayToExec(&Client); if (!NT_SUCCESS(scRet)) { return(scRet); } // // Allocate virtual memory for the response buffer. // Status = ZwAllocateVirtualMemory( NtCurrentProcess(), &GetInfoBuffer, 0L, &RegionSize, MEM_COMMIT, PAGE_READWRITE ); GetInfoRequest = GetInfoBuffer; if (!NT_SUCCESS(Status)) { scRet = Status; goto Cleanup; } GetInfoRequest->MessageType = MsV1_0GetUserInfo; RtlCopyLuid(&GetInfoRequest->LogonId, pLogonId); Status = LsaCallAuthenticationPackage( Client->hPort, PackageId, GetInfoRequest, RegionSize, &GetInfoResponseBuffer, &ResponseSize, &FinalStatus); GetInfoResponse = GetInfoResponseBuffer; if (!NT_SUCCESS(Status)) { GetInfoResponseBuffer = NULL; scRet = Status; goto Cleanup; } if (!NT_SUCCESS(FinalStatus)) { scRet = FinalStatus; goto Cleanup; } ASSERT(GetInfoResponse->MessageType == MsV1_0GetUserInfo); // // Build a SecurityUserData // UserInfoSize = sizeof(SecurityUserData) + GetInfoResponse->UserName.MaximumLength + GetInfoResponse->LogonDomainName.MaximumLength + GetInfoResponse->LogonServer.MaximumLength + RtlLengthSid(GetInfoResponse->UserSid); scRet = ZwAllocateVirtualMemory( NtCurrentProcess(), &UserInfo, 0L, &UserInfoSize, MEM_COMMIT, PAGE_READWRITE ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } // // Pack in the SID first, to respectalignment boundaries. // Where = (PUCHAR) (UserInfo + 1); UserInfo->pSid = (PSID) (Where); RtlCopySid( UserInfoSize, Where, GetInfoResponse->UserSid ); Where += RtlLengthSid(Where); // // Pack in the strings // PutString( (PSTRING) &UserInfo->UserName, (PSTRING) &GetInfoResponse->UserName, 0, &Where ); PutString( (PSTRING) &UserInfo->LogonDomainName, (PSTRING) &GetInfoResponse->LogonDomainName, 0, &Where ); PutString( (PSTRING) &UserInfo->LogonServer, (PSTRING) &GetInfoResponse->LogonServer, 0, &Where ); *ppUserInfo = UserInfo; UserInfo = NULL; scRet = STATUS_SUCCESS; Cleanup: if (GetInfoRequest != NULL) { ZwFreeVirtualMemory( NtCurrentProcess(), &GetInfoRequest, &RegionSize, MEM_RELEASE ); } if (UserInfo != NULL) { FreeContextBuffer(UserInfo); } if (GetInfoResponseBuffer != NULL) { LsaFreeReturnBuffer(GetInfoResponseBuffer); } return(scRet); }