PVOID UserCreateHeap( HANDLE hSection, PVOID pvBaseAddress, DWORD dwSize) { PVOID pUserBase; ULONG ulViewSize; LARGE_INTEGER liOffset; PEPROCESS Process = PsGetCurrentProcess(); RTL_HEAP_PARAMETERS HeapParams; NTSTATUS Status; /* * Map the section into the current process and commit the * first page of the section. */ ulViewSize = 0; liOffset.QuadPart = 0; pUserBase = NULL; Status = MmMapViewOfSection(hSection, Process, &pUserBase, 0, PAGE_SIZE, &liOffset, &ulViewSize, ViewUnmap, SEC_NO_CHANGE, PAGE_EXECUTE_READ); if (!NT_SUCCESS(Status)) return NULL; MmUnmapViewOfSection(Process, pUserBase); /* * We now have a committed page to create the heap in. */ RtlZeroMemory(&HeapParams, sizeof(HeapParams)); HeapParams.Length = sizeof(HeapParams); HeapParams.InitialCommit = PAGE_SIZE; HeapParams.InitialReserve = dwSize; HeapParams.CommitRoutine = UserCommitMemory; return RtlCreateHeap( HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, pvBaseAddress, dwSize, PAGE_SIZE, NULL, &HeapParams ); }
VOID NTAPI EngUnmapSectionView( _In_ PVOID pvBits, _In_ ULONG cjOffset, _In_ HANDLE hSecure) { NTSTATUS Status; /* Unsecure the memory */ EngUnsecureMem(hSecure); /* Calculate the real start of the section view */ pvBits = (PUCHAR)pvBits - (cjOffset & (MM_ALLOCATION_GRANULARITY - 1)); /* Unmap the section view */ Status = MmUnmapViewOfSection(PsGetCurrentProcess(), pvBits); ASSERT(NT_SUCCESS(Status)); }
VOID LpcpDeletePort ( IN PVOID Object ) /*++ Routine Description: This routine is the callback used for deleting a port object. Arguments: Object - Supplies a pointer to the port object being deleted Return Value: None. --*/ { PETHREAD CurrentThread; PLPCP_PORT_OBJECT Port = Object; PLPCP_PORT_OBJECT ConnectionPort; LPC_CLIENT_DIED_MSG ClientPortClosedDatagram; PLPCP_MESSAGE Msg; PLIST_ENTRY Head, Next; HANDLE CurrentProcessId; NTSTATUS Status; LARGE_INTEGER RetryInterval = {(ULONG)(-10 * 1000 * 100), -1}; // 100 milliseconds PAGED_CODE(); CurrentThread = PsGetCurrentThread (); // // If the port is a server communication port then make sure that if // there is a dangling client thread that we get rid of it. This // handles the case of someone calling NtAcceptConnectPort and not // calling NtCompleteConnectPort // if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) { PETHREAD ClientThread; LpcpAcquireLpcpLockByThread(CurrentThread); if ((ClientThread = Port->ClientThread) != NULL) { Port->ClientThread = NULL; LpcpReleaseLpcpLock(); ObDereferenceObject( ClientThread ); } else { LpcpReleaseLpcpLock(); } } // // Send an LPC_PORT_CLOSED datagram to whoever is connected // to this port so they know they are no longer connected. // if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram ); ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime ); ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED; ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0; ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime; Status = LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram ); while (Status == STATUS_NO_MEMORY) { KeDelayExecutionThread(KernelMode, FALSE, &RetryInterval); Status = LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram ); } } // // If connected, disconnect the port, and then scan the message queue // for this port and dereference any messages in the queue. // LpcpDestroyPortQueue( Port, TRUE ); // // If we had mapped sections into the server or client communication ports, // we need to unmap them in the context of that process. // if ( (Port->ClientSectionBase != NULL) || (Port->ServerSectionBase != NULL) ) { // // If the client has a port memory view, then unmap it // if (Port->ClientSectionBase != NULL) { MmUnmapViewOfSection( Port->MappingProcess, Port->ClientSectionBase ); } // // If the server has a port memory view, then unmap it // if (Port->ServerSectionBase != NULL) { MmUnmapViewOfSection( Port->MappingProcess, Port->ServerSectionBase ); } // // Removing the reference added while mapping the section // ObDereferenceObject( Port->MappingProcess ); Port->MappingProcess = NULL; } // // Dereference the pointer to the connection port if it is not // this port. // LpcpAcquireLpcpLockByThread(CurrentThread); ConnectionPort = Port->ConnectionPort; if (ConnectionPort) { CurrentProcessId = CurrentThread->Cid.UniqueProcess; Head = &ConnectionPort->LpcDataInfoChainHead; Next = Head->Flink; while (Next != Head) { Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry ); Next = Next->Flink; if (Port == ConnectionPort) { // // If the Connection port is going away free all queued messages // RemoveEntryList( &Msg->Entry ); InitializeListHead( &Msg->Entry ); LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED ); // // In LpcpFreeToPortZone the LPC lock is released and reacquired. // Another thread might free the LPC message captured above // in Next. We need to restart the search at the list head. // Next = Head->Flink; } else if ((Msg->Request.ClientId.UniqueProcess == CurrentProcessId) && ((Msg->SenderPort == Port) || (Msg->SenderPort == Port->ConnectedPort) || (Msg->SenderPort == ConnectionPort))) { // // Test whether the message come from the same port and process // LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u) Port: %lx\n", PsGetCurrentProcess()->ImageFileName, Msg, Msg->Request.MessageId, Msg->Request.CallbackId, ConnectionPort )); RemoveEntryList( &Msg->Entry ); InitializeListHead( &Msg->Entry ); LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED ); // // In LpcpFreeToPortZone the LPC lock is released and reacquired. // Another thread might free the LPC message captured above // in Next. We need to restart the search at the list head. // Next = Head->Flink; } } LpcpReleaseLpcpLock(); if (ConnectionPort != Port) { ObDereferenceObject( ConnectionPort ); } } else { LpcpReleaseLpcpLock(); } if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) && (ConnectionPort->ServerProcess != NULL)) { ObDereferenceObject( ConnectionPort->ServerProcess ); ConnectionPort->ServerProcess = NULL; } // // Free any static client security context // LpcpFreePortClientSecurity( Port ); // // And return to our caller // return; }
VOID NTAPI LpcpDeletePort(IN PVOID ObjectBody) { LARGE_INTEGER Timeout; PETHREAD Thread; PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody; PLPCP_PORT_OBJECT ConnectionPort; PLPCP_MESSAGE Message; PLIST_ENTRY ListHead, NextEntry; HANDLE Pid; CLIENT_DIED_MSG ClientDiedMsg; PAGED_CODE(); LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags); Timeout.QuadPart = -1000000; /* Check if this is a communication port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT) { /* Acquire the lock */ KeAcquireGuardedMutex(&LpcpLock); /* Get the thread */ Thread = Port->ClientThread; if (Thread) { /* Clear it */ Port->ClientThread = NULL; /* Release the lock and dereference */ KeReleaseGuardedMutex(&LpcpLock); ObDereferenceObject(Thread); } else { /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); } } /* Check if this is a client-side port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT) { /* Setup the client died message */ ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg); ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime); ClientDiedMsg.h.u2.ZeroInit = 0; ClientDiedMsg.h.u2.s2.Type = LPC_PORT_CLOSED; ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime; /* Send it */ for (;;) { /* Send the message */ if (LpcRequestPort(Port, &ClientDiedMsg.h) != STATUS_NO_MEMORY) break; /* Wait until trying again */ KeDelayExecutionThread(KernelMode, FALSE, &Timeout); } } /* Destroy the port queue */ LpcpDestroyPortQueue(Port, TRUE); /* Check if we had views */ if ((Port->ClientSectionBase) || (Port->ServerSectionBase)) { /* Check if we had a client view */ if (Port->ClientSectionBase) { /* Unmap it */ MmUnmapViewOfSection(Port->MappingProcess, Port->ClientSectionBase); } /* Check for a server view */ if (Port->ServerSectionBase) { /* Unmap it */ MmUnmapViewOfSection(Port->MappingProcess, Port->ServerSectionBase); } /* Dereference the mapping process */ ObDereferenceObject(Port->MappingProcess); Port->MappingProcess = NULL; } /* Acquire the lock */ KeAcquireGuardedMutex(&LpcpLock); /* Get the connection port */ ConnectionPort = Port->ConnectionPort; if (ConnectionPort) { /* Get the PID */ Pid = PsGetCurrentProcessId(); /* Loop the data lists */ ListHead = &ConnectionPort->LpcDataInfoChainHead; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the message */ Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry); NextEntry = NextEntry->Flink; /* Check if this is the connection port */ if (Port == ConnectionPort) { /* Free queued messages */ RemoveEntryList(&Message->Entry); InitializeListHead(&Message->Entry); LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); /* Restart at the head */ NextEntry = ListHead->Flink; } else if ((Message->Request.ClientId.UniqueProcess == Pid) && ((Message->SenderPort == Port) || (Message->SenderPort == Port->ConnectedPort) || (Message->SenderPort == ConnectionPort))) { /* Remove it */ RemoveEntryList(&Message->Entry); InitializeListHead(&Message->Entry); LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); /* Restart at the head */ NextEntry = ListHead->Flink; } } /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); /* Dereference the object unless it's the same port */ if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort); /* Check if this is a connection port with a server process */ if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) && (ConnectionPort->ServerProcess)) { /* Dereference the server process */ ObDereferenceObject(ConnectionPort->ServerProcess); ConnectionPort->ServerProcess = NULL; } } else { /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); } /* Free client security */ LpcpFreePortClientSecurity(Port); LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port); }
NTSTATUS MuInitializeUserModeHelper ( PMU_GLOBAL_DATA GlobalData ) { NTSTATUS status; HANDLE file, proc, dllsec; SIZE_T imgsize = 0; PVOID secobj, dllbase = NULL; LARGE_INTEGER secofs; UNICODE_STRING fp; IO_STATUS_BLOCK iosb; OBJECT_ATTRIBUTES oa; WCHAR path[MAX_PATH]; wcscpy(path, MU_ROOTDIR_SYSTEM32); wcscat(path, MU_FILENAME_HELPER_DLL); RtlInitUnicodeString(&fp, path); InitializeObjectAttributes(&oa, &fp, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); status = ZwOpenFile(&file, GENERIC_READ, &oa, &iosb, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); if (NT_SUCCESS(status)) { status = ZwCreateSection(&dllsec, SECTION_ALL_ACCESS, NULL, NULL, PAGE_EXECUTE_READWRITE, SEC_IMAGE, file); ZwClose(file); if (!NT_SUCCESS(status)) return status; status = ObReferenceObjectByHandle(dllsec, SECTION_ALL_ACCESS, *MmSectionObjectType, KernelMode, &secobj, NULL); ZwClose(dllsec); if (NT_SUCCESS(status)) { secofs.QuadPart = 0; status = MmMapViewOfSection(secobj, PsGetCurrentProcess(), &dllbase, 0, 0, &secofs, &imgsize, ViewShare, 0, PAGE_EXECUTE_READWRITE); if (NT_SUCCESS(status)) { status = MuLinkDll(GlobalData, dllbase); MmUnmapViewOfSection(PsGetCurrentProcess(), dllbase); } if (!NT_SUCCESS(status)) { ObDereferenceObject(secobj); secobj = NULL; } GlobalData->DllSection = secobj; GlobalData->DllImageSize = imgsize; GlobalData->DllImageBase = dllbase; } } return status; }
BOOL APIENTRY EngMapSection( IN PVOID pvSection, IN BOOL bMap, IN HANDLE hProcess, OUT PVOID* pvBaseAddress) { NTSTATUS Status; PENGSECTION pSection = pvSection; PEPROCESS pepProcess; /* Get a pointer to the process */ Status = ObReferenceObjectByHandle(hProcess, PROCESS_VM_OPERATION, NULL, KernelMode, (PVOID*)&pepProcess, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Could not access process %p, Status=0x%lx\n", hProcess, Status); return FALSE; } if (bMap) { /* Make sure the section isn't already mapped */ ASSERT(pSection->pvMappedBase == NULL); /* Map the section into the process address space */ Status = MmMapViewOfSection(pSection->pvSectionObject, pepProcess, &pSection->pvMappedBase, 0, pSection->cjViewSize, NULL, &pSection->cjViewSize, 0, 0, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to map a section Status=0x%x\n", Status); } } else { /* Make sure the section is mapped */ ASSERT(pSection->pvMappedBase); /* Unmap the section from the process address space */ Status = MmUnmapViewOfSection(pepProcess, pSection->pvMappedBase); if (NT_SUCCESS(Status)) { pSection->pvMappedBase = NULL; } else { DPRINT1("Failed to unmap a section @ %p Status=0x%x\n", pSection->pvMappedBase, Status); } } /* Dereference the process */ ObDereferenceObject(pepProcess); /* Set the new mapping base and return bool status */ *pvBaseAddress = pSection->pvMappedBase; return NT_SUCCESS(Status); }
VOID LpcpDeletePort ( IN PVOID Object ) /*++ Routine Description: This routine is the callback used for deleting a port object. Arguments: Object - Supplies a pointer to the port object being deleted Return Value: None. --*/ { PLPCP_PORT_OBJECT Port = Object; PLPCP_PORT_OBJECT ConnectionPort; LPC_CLIENT_DIED_MSG ClientPortClosedDatagram; PLPCP_MESSAGE Msg; PLIST_ENTRY Head, Next; HANDLE CurrentProcessId; PAGED_CODE(); // // If the port is a server communication port then make sure that if // there is a dangling client thread that we get rid of it. This // handles the case of someone calling NtAcceptConnectPort and not // calling NtCompleteConnectPort // LpcpPortExtraDataDestroy( Port ); if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) { PETHREAD ClientThread; LpcpAcquireLpcpLock(); if ((ClientThread = Port->ClientThread) != NULL) { Port->ClientThread = NULL; LpcpReleaseLpcpLock(); ObDereferenceObject( ClientThread ); } else { LpcpReleaseLpcpLock(); } } // // Send an LPC_PORT_CLOSED datagram to whoever is connected // to this port so they know they are no longer connected. // if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram ); ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime ); ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED; ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0; ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime; LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram ); } // // If connected, disconnect the port, and then scan the message queue // for this port and dereference any messages in the queue. // LpcpDestroyPortQueue( Port, TRUE ); // // If the client has a port memory view, then unmap it // if (Port->ClientSectionBase != NULL) { MmUnmapViewOfSection( PsGetCurrentProcess(), Port->ClientSectionBase ); } // // If the server has a port memory view, then unmap it // if (Port->ServerSectionBase != NULL) { MmUnmapViewOfSection( PsGetCurrentProcess(), Port->ServerSectionBase ); } // // Dereference the pointer to the connection port if it is not // this port. // if (ConnectionPort = Port->ConnectionPort) { CurrentProcessId = PsGetCurrentThread()->Cid.UniqueProcess; LpcpAcquireLpcpLock(); Head = &ConnectionPort->LpcDataInfoChainHead; Next = Head->Flink; while (Next != Head) { Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry ); Next = Next->Flink; if (Msg->Request.ClientId.UniqueProcess == CurrentProcessId) { LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u) Port: %lx\n", PsGetCurrentProcess()->ImageFileName, Msg, Msg->Request.MessageId, Msg->Request.CallbackId, ConnectionPort )); RemoveEntryList( &Msg->Entry ); LpcpFreeToPortZone( Msg, TRUE ); } } LpcpReleaseLpcpLock(); if (ConnectionPort != Port) { ObDereferenceObject( ConnectionPort ); } } if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) && (ConnectionPort->ServerProcess != NULL)) { ObDereferenceObject( ConnectionPort->ServerProcess ); ConnectionPort->ServerProcess = NULL; } // // Free any static client security context // LpcpFreePortClientSecurity( Port ); // // And return to our caller // return; }