;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Copyright (c) 1998-2001 Microsoft Corporation ;; ;; Module Name: ;; ;; whnt32.tpl ;; ;; Abstract: ;; ;; This template defines the thunks for the NT api set. ;; ;; Author: ;; ;; 6-Oct-98 mzoran ;; ;; Revision History: ;; 8-9-99 [askhalid] added call to CpuNotify___ for dll load/unload and call to CpuFlushInstructionCache ;; for NtAllocateVirtualMemory NtProtectVirtualMemory and NtFlushInstructionCache. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [Macros] MacroName=CallNameFromApiName NumArgs=1 Begin= @MArg(1) End= [EFunc] TemplateName=NtAccessCheckByType NoType=ObjectTypeList PreCall= ObjectTypeList = whNT32ShallowThunkAllocObjectTypeList32TO64((NT32OBJECT_TYPE_LIST *)ObjectTypeListHost,ObjectTypeListLength); @NL End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;; Thunking Registry APIs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtCreateKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtDeleteKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtDeleteValueKey Begin= @GenApiThunk(Wow64@ApiName) End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Registry routines ;; Special handling is needed since they can be asynchronous. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The following is the list of structures passed. ;; None of them are pointer dependent. ;; List taken from ntos\config\mtapi.c TemplateName=NtEnumerateKey Case=(KeyBasicInformation,PKEY_BASIC_INFORMATION) Case=(KeyNodeInformation,PKEY_NODE_INFORMATION) Case=(KeyFullInformation,PKEY_FULL_INFORMATION) Begin= @GenDebugNonPtrDepCases(Wow64@ApiName,KeyInformationClass) End= ;; The following is the list of structures passed. ;; None of them are pointer dependent. ;; List taken from ntos\config\mtapi.c TemplateName=NtEnumerateValueKey Case=(KeyValueBasicInformation,PKEY_VALUE_BASIC_INFORMATION) Case=(KeyValueFullInformation,PKEY_VALUE_FULL_INFORMATION) Case=(KeyValuePartialInformation,PKEY_VALUE_PARTIAL_INFORMATION) Begin= @GenDebugNonPtrDepCases(Wow64@ApiName,KeyValueInformationClass) End= TemplateName=NtFlushKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtInitializeRegistry Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtNotifyChangeMultipleKeys NoType=SlaveObjects PreCall= {@Indent(@NL @NL try { @NL NT32OBJECT_ATTRIBUTES *Entries32 = (NT32OBJECT_ATTRIBUTES *)SlaveObjectsHost; @NL ULONG TempEntryCount = Count; @NL POBJECT_ATTRIBUTES Entries64 = (POBJECT_ATTRIBUTES)Wow64AllocateTemp(sizeof(OBJECT_ATTRIBUTES) * Count); @NL SlaveObjects = Entries64; @NL @NL for(;TempEntryCount > 0; TempEntryCount--, Entries32++, Entries64++) { @NL Entries64->Length = sizeof (OBJECT_ATTRIBUTES); @NL; Entries64->ObjectName = Wow64ShallowThunkAllocUnicodeString32TO64(Entries32->ObjectName); @NL Entries64->SecurityQualityOfService = (PVOID)Entries32->SecurityQualityOfService; @NL Entries64->SecurityDescriptor = (PVOID)Entries32->SecurityDescriptor; @NL Entries64->Attributes = (ULONG)Entries32->Attributes; @NL Entries64->RootDirectory = (HANDLE)Entries32->RootDirectory; @NL }@NL } except( NULL, EXCEPTION_EXECUTE_HANDLER){ @NL return GetExceptionCode (); @NL } @NL )}@NL Wow64WrapApcProc(&ApcRoutine, &ApcContext); End= Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtLoadKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtLoadKey2 Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtOpenKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtQueryKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtQueryValueKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtReplaceKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtRestoreKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtSaveKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtSaveMergedKeys Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtSetValueKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtUnloadKey Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtQueryOpenSubKeys Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtClose Begin= @GenApiThunk(Wow64@ApiName) End= ;; to reflect registrykey security if applicable TemplateName=NtSetSecurityObject Begin= @GenApiThunk(Wow64@ApiName) End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtAccessCheckByTypeAndAuditAlarm NoType=ObjectTypeList PreCall= ObjectTypeList = whNT32ShallowThunkAllocObjectTypeList32TO64((NT32OBJECT_TYPE_LIST *)ObjectTypeListHost,ObjectTypeListLength); @NL End= TemplateName=NtAccessCheckByTypeResultList NoType=ObjectTypeList PreCall= ObjectTypeList = whNT32ShallowThunkAllocObjectTypeList32TO64((NT32OBJECT_TYPE_LIST *)ObjectTypeListHost,ObjectTypeListLength); @NL End= TemplateName=NtAccessCheckByTypeResultListAndAuditAlarm NoType=ObjectTypeList PreCall= ObjectTypeList = whNT32ShallowThunkAllocObjectTypeList32TO64((NT32OBJECT_TYPE_LIST *)ObjectTypeListHost,ObjectTypeListLength); @NL End= TemplateName=NtAdjustGroupsToken NoType=PreviousState Header= @NoFormat( NTSTATUS whNT32AdjustGroupToken( IN HANDLE TokenHandle, IN BOOLEAN ResetToDefault, IN PTOKEN_GROUPS NewState, IN ULONG BufferLength, OUT PVOID PreviousState, IN PULONG ReturnLength ) { NTSTATUS Status; PTOKEN_GROUPS LocalPreviousState; if(BufferLength != 0 && PreviousState != NULL) { LocalPreviousState = Wow64AllocateTemp(BufferLength); } else { LocalPreviousState = (PTOKEN_GROUPS)PreviousState; } Status = NtAdjustGroupsToken(TokenHandle, ResetToDefault, NewState, BufferLength, LocalPreviousState, ReturnLength ); if(NT_ERROR(Status) || BufferLength == 0 || PreviousState == NULL) { return Status; } //Thunk the PreviousState WriteReturnLengthStatus(ReturnLength, &Status, whNT32DeepThunkTokenGroups64TO32Length(LocalPreviousState)); whNT32DeepThunkTokenGroups64TO32((NT32TOKEN_GROUPS*)PreviousState, LocalPreviousState); return Status; } ) End= PreCall= PreviousState = (PTOKEN_GROUPS)PreviousStateHost; @NL End= Begin= @GenApiThunk(whNT32AdjustGroupToken) End= TemplateName=NtFilterToken NoType=SidsToDisable NoType=RestrictedSids PreCall= SidsToDisable = whNT32ShallowThunkAllocTokenGroups32TO64((NT32TOKEN_GROUPS *)SidsToDisableHost); @NL RestrictedSids = whNT32ShallowThunkAllocTokenGroups32TO64((NT32TOKEN_GROUPS *)RestrictedSidsHost); @NL End= TemplateName=NtQueryInformationAtom Case=(AtomBasicInformation,PATOM_BASIC_INFORMATION) Case=(AtomTableInformation,PATOM_TABLE_INFORMATION) Begin= @GenDebugNonPtrDepCases(@ApiName,AtomInformationClass) End= TemplateName=NtQueryDirectoryObject Header= @NoFormat( NTSTATUS whNT32QueryDirectoryObject( IN HANDLE DirectoryHandle, OUT PVOID Buffer, IN ULONG Length, IN BOOLEAN ReturnSingleEntry, IN BOOLEAN RestartScan, IN OUT PULONG Context, OUT PULONG ReturnLength ) { NTSTATUS Status; ULONG TempBufferLength, TempBufferReturnedLength; PVOID TempBuffer; ULONG SystemContext; ULONG GrabbedEntries, TotalSizeNeeded, SizeNeeded, EntriesToReturn, BytesToReturn, c; POBJECT_DIRECTORY_INFORMATION DirInfo64; NT32OBJECT_DIRECTORY_INFORMATION *DirInfo32; WCHAR *Strings; TempBufferLength = 0x800; try { do { TempBufferLength <<= 1; TempBuffer = Wow64AllocateTemp(TempBufferLength); // Grab the entire list of objects starting with the context specified from the app. // Note that the context is equal to the next entry number. SystemContext = *Context; Status = NtQueryDirectoryObject(DirectoryHandle, TempBuffer, TempBufferLength, ReturnSingleEntry, RestartScan, &SystemContext, &TempBufferReturnedLength); if(NT_ERROR(Status) && Status != STATUS_BUFFER_TOO_SMALL) { WriteReturnLength(ReturnLength, 0); return Status; } } while(Status != STATUS_NO_MORE_ENTRIES && Status != STATUS_SUCCESS); if (STATUS_NO_MORE_ENTRIES == Status) { WOWASSERT(SystemContext == *Context); WOWASSERT(sizeof(*DirInfo64) == TempBufferReturnedLength) WriteReturnLength(ReturnLength, 0); return Status; } DirInfo64 = (POBJECT_DIRECTORY_INFORMATION)TempBuffer; BytesToReturn = TotalSizeNeeded = sizeof(NT32OBJECT_DIRECTORY_INFORMATION); GrabbedEntries = 0; EntriesToReturn = 0; Status = STATUS_NO_MORE_ENTRIES; while(!(DirInfo64->Name.Buffer == NULL && DirInfo64->TypeName.Buffer == NULL)) { GrabbedEntries++; //The kernel will terminate the strings, so that doesn't need to be done here. SizeNeeded = sizeof(NT32OBJECT_DIRECTORY_INFORMATION) + DirInfo64->Name.Length + DirInfo64->TypeName.Length + sizeof(UNICODE_NULL) + sizeof(UNICODE_NULL); TotalSizeNeeded += SizeNeeded; if(Length >= TotalSizeNeeded) { EntriesToReturn++; BytesToReturn += SizeNeeded; } Status = STATUS_SUCCESS; DirInfo64++; } if (Length < BytesToReturn) { // If only one entry was asked for, fail the API and set the desired return length. if(ReturnSingleEntry) { WriteReturnLength(ReturnLength, BytesToReturn); return STATUS_BUFFER_TOO_SMALL; } Status = STATUS_MORE_ENTRIES; } //Copy the entries out to the buffer. DirInfo32 = (NT32OBJECT_DIRECTORY_INFORMATION *)Buffer; Strings = (WCHAR *)(DirInfo32 + EntriesToReturn + 1); DirInfo64 = (POBJECT_DIRECTORY_INFORMATION)TempBuffer; for(c=0; c < EntriesToReturn; c++) { DirInfo32->Name.Length = DirInfo64->Name.Length; DirInfo32->Name.MaximumLength = DirInfo64->Name.MaximumLength; DirInfo32->Name.Buffer = (NT32PWCHAR)PtrToUlong(Strings); RtlCopyMemory((PVOID)Strings, DirInfo64->Name.Buffer, DirInfo64->Name.Length); Strings += (DirInfo64->Name.Length / sizeof(WCHAR)); *Strings++ = UNICODE_NULL; DirInfo32->TypeName.Length = DirInfo64->TypeName.Length; DirInfo32->TypeName.MaximumLength = DirInfo64->TypeName.MaximumLength; DirInfo32->TypeName.Buffer = (NT32PWCHAR)PtrToUlong(Strings); RtlCopyMemory((PVOID)Strings, DirInfo64->TypeName.Buffer, DirInfo64->TypeName.Length); Strings += (DirInfo64->TypeName.Length / sizeof(WCHAR)); *Strings++ = UNICODE_NULL; DirInfo32++; DirInfo64++; } // Clear the last entry RtlZeroMemory(DirInfo32, sizeof(NT32OBJECT_DIRECTORY_INFORMATION)); // Context is actually the number of the next entry to recieve. This needs to be adjusted since // the entire list may not have been sent to the app. WOWASSERT(SystemContext >= GrabbedEntries); *Context = SystemContext - (GrabbedEntries - EntriesToReturn); WriteReturnLength(ReturnLength, BytesToReturn); } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode (); } return Status; } ) End= Begin= #define WriteReturnLength(rl, length) WriteReturnLengthSilent((rl), (length)) @GenApiThunk(whNT32QueryDirectoryObject) #undef WriteReturnLength End= TemplateName=NtQueryEvent Case=(EventBasicInformation,PEVENT_BASIC_INFORMATION) Begin= @GenDebugNonPtrDepCases(@ApiName,EventInformationClass) End= TemplateName=NtQueryInformationJobObject Case=(JobObjectBasicAccountingInformation,PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION) Case=(JobObjectBasicLimitInformation,PJOBOBJECT_BASIC_LIMIT_INFORMATION) Case=(JobObjectBasicUIRestrictions,PJOBOBJECT_BASIC_UI_RESTRICTIONS) Case=(JobObjectBasicProcessIdList) Case=(JobObjectEndOfJobTimeInformation,PJOBOBJECT_END_OF_JOB_TIME_INFORMATION) Case=(JobObjectExtendedLimitInformation,PJOBOBJECT_EXTENDED_LIMIT_INFORMATION) Case=(JobObjectSecurityLimitInformation) SpecialQueryCase= case JobObjectSecurityLimitInformation: { @Indent( @NL // PJOBOBJECT_SECURITY_LIMIT_INFORMATION @NL PCHAR Buffer; @NL ULONG BufferSize; @NL ULONG RequiredLength; @NL NT32JOBOBJECT_SECURITY_LIMIT_INFORMATION *SecurityLimit32; @NL PJOBOBJECT_SECURITY_LIMIT_INFORMATION SecurityLimit64; @NL @NL @NL BufferSize = max(JobObjectInformationLength * 2, 0xFFFFFFFF); @NL Buffer = Wow64AllocateTemp(BufferSize); @NL RetVal = NtQueryInformationJobObject(JobHandle, JobObjectInformationClass, Buffer, BufferSize, ReturnLength); @NL if (!NT_ERROR(RetVal)) { @Indent( @NL SecurityLimit64 = (PJOBOBJECT_SECURITY_LIMIT_INFORMATION)Buffer; @NL SecurityLimit32 = (NT32JOBOBJECT_SECURITY_LIMIT_INFORMATION *)JobObjectInformation; @NL RequiredLength = sizeof(NT32JOBOBJECT_SECURITY_LIMIT_INFORMATION); @NL if (ARGUMENT_PRESENT(SecurityLimit64->SidsToDisable)) { @Indent( @NL RequiredLength += whNT32DeepThunkTokenGroups64TO32Length(SecurityLimit64->SidsToDisable); @NL }) @NL if (ARGUMENT_PRESENT(SecurityLimit64->PrivilegesToDelete)) { @Indent( @NL RequiredLength += sizeof(ULONG) + (SecurityLimit64->PrivilegesToDelete->PrivilegeCount * sizeof(ULONG)); }) @NL if (ARGUMENT_PRESENT(SecurityLimit64->RestrictedSids)) { @Indent( @NL RequiredLength += whNT32DeepThunkTokenGroups64TO32Length(SecurityLimit64->RestrictedSids); @NL }) @NL if (RequiredLength > JobObjectInformationLength) { @Indent( @NL RetVal = STATUS_BUFFER_OVERFLOW; @NL }) @NL else { @Indent( @NL SIZE_T Size = sizeof(NT32JOBOBJECT_SECURITY_LIMIT_INFORMATION); @NL WriteReturnLength(ReturnLength, RequiredLength); @NL SecurityLimit32->SecurityLimitFlags = SecurityLimit64->SecurityLimitFlags; @NL SecurityLimit32->JobToken = (NT32HANDLE)SecurityLimit64->JobToken; @NL if (ARGUMENT_PRESENT(SecurityLimit64->SidsToDisable)) { @Indent( @NL PCHAR CopyDest = (PCHAR)SecurityLimit32 + Size; @NL Size += whNT32DeepThunkTokenGroups64TO32Length(SecurityLimit64->SidsToDisable); @NL whNT32DeepThunkTokenGroups64TO32((NT32TOKEN_GROUPS *)CopyDest, SecurityLimit64->SidsToDisable); @NL SecurityLimit32->SidsToDisable = (NT32PTOKEN_GROUPS)CopyDest; @NL }) @NL else { @Indent( @NL SecurityLimit32->SidsToDisable = (NT32PTOKEN_GROUPS)SecurityLimit64->SidsToDisable; @NL }) @NL if (ARGUMENT_PRESENT(SecurityLimit64->PrivilegesToDelete)) { @Indent( @NL PCHAR CopyDest = (PCHAR)SecurityLimit32 + Size; @NL SIZE_T SizeTokenPrivileges = sizeof(ULONG) + (sizeof(LUID_AND_ATTRIBUTES) * SecurityLimit64->PrivilegesToDelete->PrivilegeCount); @NL RtlCopyMemory(CopyDest, SecurityLimit64->PrivilegesToDelete, SizeTokenPrivileges); @NL SecurityLimit32->PrivilegesToDelete = (NT32PTOKEN_PRIVILEGES)CopyDest; @NL Size += SizeTokenPrivileges; @NL }) @NL else { @Indent( @NL SecurityLimit32->PrivilegesToDelete = (NT32PTOKEN_PRIVILEGES)SecurityLimit64->PrivilegesToDelete; @NL }) @NL if (ARGUMENT_PRESENT(SecurityLimit64->RestrictedSids)) { @Indent( @NL PCHAR CopyDest = (PCHAR)SecurityLimit32 + Size; @NL Size += whNT32DeepThunkTokenGroups64TO32Length(SecurityLimit64->RestrictedSids); @NL whNT32DeepThunkTokenGroups64TO32((NT32TOKEN_GROUPS*)CopyDest, SecurityLimit64->RestrictedSids); @NL SecurityLimit32->RestrictedSids = (NT32PTOKEN_GROUPS)CopyDest; @NL }) @NL else { @Indent( @NL SecurityLimit32->RestrictedSids = (NT32PTOKEN_GROUPS)SecurityLimit64->RestrictedSids; @NL }) @NL }) @NL )} @NL })@NL case JobObjectBasicProcessIdList: @Indent( @NL { PJOBOBJECT_BASIC_PROCESS_ID_LIST JobProcessIdList64 = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)JobObjectInformation; struct NT32_JOBOBJECT_BASIC_PROCESS_ID_LIST *JobProcessIdList32 = (struct NT32_JOBOBJECT_BASIC_PROCESS_ID_LIST *)JobObjectInformation; ULONG JobObjectInformationLength64 = JobObjectInformationLength; ULONG ActualReturnLength64; ULONG i; if ((ARGUMENT_PRESENT (JobProcessIdList64) != 0) && (JobObjectInformationLength64 >= sizeof (struct NT32_JOBOBJECT_BASIC_PROCESS_ID_LIST))) { ULONG ProcessIds = (((JobObjectInformationLength64 - sizeof (struct NT32_JOBOBJECT_BASIC_PROCESS_ID_LIST)) * sizeof (ULONG_PTR)) / sizeof(ULONG)); JobObjectInformationLength64 = ProcessIds + sizeof (JOBOBJECT_BASIC_PROCESS_ID_LIST); JobProcessIdList64 = Wow64AllocateTemp (JobObjectInformationLength64); if (JobProcessIdList64 == NULL) { return STATUS_NO_MEMORY; } } RetVal = NtQueryInformationJobObject( JobHandle, JobObjectInformationClass, JobProcessIdList64, JobObjectInformationLength64, &ActualReturnLength64); @NL if (NT_SUCCESS (RetVal)) { JobProcessIdList32->NumberOfAssignedProcesses = JobProcessIdList64->NumberOfAssignedProcesses; JobProcessIdList32->NumberOfProcessIdsInList = JobProcessIdList64->NumberOfProcessIdsInList; JobProcessIdList32->ProcessIdList[0] = (ULONG)JobProcessIdList64->ProcessIdList[0]; for (i = 1 ; i < JobProcessIdList64->NumberOfProcessIdsInList ; i++) { JobProcessIdList32->ProcessIdList[i] = (ULONG)JobProcessIdList64->ProcessIdList[i]; } if (ARGUMENT_PRESENT(ReturnLength) != 0) { *ReturnLength = sizeof (struct NT32_JOBOBJECT_BASIC_PROCESS_ID_LIST) + ((JobProcessIdList32->NumberOfProcessIdsInList - 1) * sizeof(ULONG)); } } } break;)@NL End= Begin= #define WriteReturnLength(rl, length) WriteReturnLengthStatus((rl), &RetVal, (length)) @GenQueryThunk(@ApiName,JobObjectInformationClass,JobObjectInformation,JobObjectInformationLength,ReturnLength,ULONG) #undef WriteReturnLength End= ;; None of these structures are pointer dependent. ;; List taken from ntos\io\complete.c TemplateName=NtQueryIoCompletion Case=(IoCompletionBasicInformation,PIO_COMPLETION_BASIC_INFORMATION) Begin= @GenDebugNonPtrDepCases(@ApiName,IoCompletionInformationClass) End= TemplateName=NtCreateProcess Also=NtCreateProcessEx Begin= @GenApiThunk(@ApiName) End= PostCall= @NoFormat( if (!NT_ERROR(RetVal) && SectionHandle) { PEB Peb64; PEB32 Peb32; PPEB32 pPeb32; SIZE_T Size; HANDLE Process = *ProcessHandle; ULONG_PTR Wow64Info; PROCESS_BASIC_INFORMATION pbi; CHILD_PROCESS_INFO ChildInfo; // Check the image type to determine if the process is already 32-bit // or not. RetVal = NtQueryInformationProcess(Process, ProcessWow64Information, &Wow64Info, sizeof(Wow64Info), NULL); if (!NT_SUCCESS(RetVal) || Wow64Info != 0) { // Either error or the process's image is 32-bit and nothing // more needs to be done. goto Done; } RetVal = NtQueryInformationProcess(Process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); if (!NT_SUCCESS(RetVal)) { goto Done; } // Read in the process's PEB64 RetVal = NtReadVirtualMemory(Process, pbi.PebBaseAddress, &Peb64, sizeof(Peb64), NULL); if (!NT_SUCCESS(RetVal)) { goto Error; } // Thunk the PEB64 to a PEB32 ThunkPeb64ToPeb32(&Peb64, &Peb32); // Allocate space for a PEB32 in the low 2gb of the process pPeb32 = NULL; Size = PAGE_SIZE; RetVal = NtAllocateVirtualMemory(Process, &pPeb32, 0x7fffffff, // ZeroBits &Size, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!NT_SUCCESS(RetVal)) { goto Error; } // Write the PEB32 into the process RetVal = NtWriteVirtualMemory(Process, pPeb32, &Peb32, sizeof(Peb32), NULL); if (!NT_SUCCESS(RetVal)) { goto Error; } // // Gather up some data that will be needed for the NtCreateThread // call which creates the initial thread. // ChildInfo.Signature = CHILD_PROCESS_SIGNATURE; ChildInfo.TailSignature = CHILD_PROCESS_SIGNATURE; ChildInfo.pPeb32 = pPeb32; RetVal = NtQuerySection(SectionHandle, SectionImageInformation, &ChildInfo.ImageInformation, sizeof(ChildInfo.ImageInformation), NULL); if (!NT_SUCCESS(RetVal)) { goto Error; } // // Stuff the information into the child process, immediately after // the PEB64 in memory // NtWriteVirtualMemory(Process, ((BYTE*)pbi.PebBaseAddress) + PAGE_SIZE - sizeof(ChildInfo), &ChildInfo, sizeof(ChildInfo), NULL); if (!NT_SUCCESS(RetVal)) { goto Error; } LOGPRINT((TRACELOG, "@ApiName: Peb32 at %p ChildInfo at %p\n", ChildInfo.pPeb32, ((BYTE*)pbi.PebBaseAddress) + PAGE_SIZE - sizeof(ChildInfo))); goto Done; Error: NtTerminateProcess(Process, RetVal); Done:; } ) End= TemplateName=NtTerminateProcess PreCall= // Handle the special case of NtTerminateProcess() getting called@NL // to terminate all threads but the current one@NL if (!ProcessHandle) {@NL CpuProcessTerm(ProcessHandle);@NL }@NL // KERNEL32 call this function with NtCurrentProcess when exiting. @NL // This is as good as any place to put shutdown code. @NL if (NtCurrentProcess() == ProcessHandle) {@Indent(@NL Wow64Shutdown(ProcessHandle); @NL )}@NL End= ; The input and output types are aways the same with this function. TemplateName=NtPowerInformation Case=(SystemPowerPolicyAc,PSYSTEM_POWER_POLICY) Case=(SystemPowerPolicyDc,PSYSTEM_POWER_POLICY) Case=(AdministratorPowerPolicy,PADMINISTRATOR_POWER_POLICY) Case=(VerifySystemPolicyAc,PSYSTEM_POWER_POLICY) Case=(VerifySystemPolicyDc,PSYSTEM_POWER_POLICY) Case=(SystemPowerPolicyCurrent,PSYSTEM_POWER_POLICY) Case=(SystemPowerCapabilities,PSYSTEM_POWER_CAPABILITIES) Case=(SystemBatteryState,PSYSTEM_BATTERY_STATE) Case=(SystemPowerStateHandler,PVOID) Case=(ProcessorStateHandler,PVOID) Case=(SystemReserveHiberFile,PBOOLEAN) Case=(SystemPowerInformation,PSYSTEM_POWER_INFORMATION) Case=(ProcessorInformation,PPROCESSOR_POWER_INFORMATION) Begin= // ProcessorInformation is dependent on the number of processors, but no good method exists // to emulate this since it returns a record for each bit that is set in the active processor mask. // Since the 32bit mask returned to the app is bogus, this API is difficult to emulate. // Fortunately, the only code that uses these APIs are control panel applications and they are going // to be 64bit. @GenDebugNonPtrDepCases(@ApiName,InformationLevel) End= TemplateName=NtQueryInformationProcess Case=(ProcessBasicInformation) Case=(ProcessQuotaLimits,PQUOTA_LIMITS) Case=(ProcessIoCounters,PULONG) Case=(ProcessVmCounters) Case=(ProcessTimes,PKERNEL_USER_TIMES) Case=(ProcessBasePriority,KPRIORITY*) Case=(ProcessRaisePriority,PULONG) Case=(ProcessDebugPort,PHANDLE) Case=(ProcessExceptionPort,PHANDLE) Case=(ProcessAccessToken,PPROCESS_ACCESS_TOKEN) Case=(ProcessLdtInformation,PULONG) ; this is really PROCESS_LDT_INFORMATION but that isn't defined on Alpha Case=(ProcessLdtSize,PULONG) ; this is really PROCESS_LDT_SIZE but that isn't defined on alpha Case=(ProcessDefaultHardErrorMode,PULONG) Case=(ProcessPooledUsageAndLimits,PPOOLED_USAGE_AND_LIMITS) Case=(ProcessWorkingSetWatch) Case=(ProcessEnableAlignmentFaultFixup,BOOLEAN *) Case=(ProcessPriorityClass,PPROCESS_PRIORITY_CLASS) Case=(ProcessWx86Information,PHANDLE) Case=(ProcessHandleCount,PULONG) Case=(ProcessAffinityMask) Case=(ProcessPriorityBoost,PULONG) Case=(ProcessDeviceMap,PPROCESS_DEVICEMAP_INFORMATION) Case=(ProcessSessionInformation,PPROCESS_SESSION_INFORMATION) Case=(ProcessForegroundInformation,PPROCESS_FOREGROUND_BACKGROUND) Case=(ProcessWow64Information,PULONG_PTR) Case=(ProcessLUIDDeviceMapsEnabled,PULONG) Case=(ProcessDebugFlags) Case=(ProcessImageFileName) Case=(ProcessHandleTracing) SpecialQueryCase= @NoFormat( case ProcessBasicInformation: { PROCESS_BASIC_INFORMATION pbi; if (ProcessInformationLengthHost != sizeof(NT32PROCESS_BASIC_INFORMATION)) { RetVal = STATUS_INFO_LENGTH_MISMATCH; break; } RetVal = NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &pbi, sizeof(pbi), (PULONG)ReturnLengthHost); if (!NT_ERROR(RetVal)) { NT32PROCESS_BASIC_INFORMATION *pbi32 = (NT32PROCESS_BASIC_INFORMATION*)ProcessInformationHost; NTSTATUS st; ULONG_PTR Wow64Info; // Copy back the "easy" fields pbi32->ExitStatus = pbi.ExitStatus; pbi32->AffinityMask = Wow64ThunkAffinityMask64TO32(pbi.AffinityMask); pbi32->UniqueProcessId = (NT32ULONG_PTR)pbi.UniqueProcessId; pbi32->InheritedFromUniqueProcessId = (NT32ULONG_PTR)pbi.InheritedFromUniqueProcessId; // PebBaseAddress is special. If the process is 32-bit then // return the PEB32 pointer. If the process is 64-bit but has no // threads, create a PEB32 and return a pointer to it. Lastly, // if the process is 64-bit and has threads, return a bad pointer // so 32-bit apps don't get all confused. Most nicely check the // return value from NtReadVirtualMemory() and gracefully fail if // the read fails. st = NtQueryInformationProcess(ProcessHandle, ProcessWow64Information, &Wow64Info, sizeof(Wow64Info), NULL); if (NT_ERROR(st)) { // // Query failed for some reason. Return a bad pointer but don't // fail the API call. // LOGPRINT((TRACELOG, "whNtQueryInformationProcess: ProcessWow64Information failed status %X, return 0 for PEB\n", st)); pbi32->PebBaseAddress = 0; break; } else if (Wow64Info) { // // Process is 32-bit. The PEB32 pointer is Wow64Info // LOGPRINT((TRACELOG, "whNtQueryInformationProcess: Process is 32bit returning %x as PEB32\n", (ULONG)Wow64Info)); pbi32->PebBaseAddress = (ULONG)Wow64Info; } else { // // Process is 64-bit. If the process has no threads, then // we're in the middle of a 32-bit CreateProcess() and it's OK to // temporarily create a PEB32 in the process. // CHILD_PROCESS_INFO ChildInfo; PEB32 ChildPeb32; SIZE_T BytesRead; // // Assume failure, that we don't want to report back a PEB32 address // pbi32->PebBaseAddress = 0; // Read in the process's PEB64 st = NtReadVirtualMemory(ProcessHandle, ((BYTE*)pbi.PebBaseAddress) + PAGE_SIZE - sizeof(ChildInfo), &ChildInfo, sizeof(ChildInfo), NULL); if (!NT_SUCCESS(st)) { LOGPRINT((TRACELOG, "whNtQueryInformationProcess: could not read the child info, status %X.\n", st)); st = STATUS_SUCCESS; break; } // // Verify the signatures at the head and tail of the ChildInfo // structure are correct. The memory the ChildInfo struct is // stored in is "borrowed". It may be reused by the process to // store process handles. We validate that the structure appears // to atleast look correct before dereferencing it. // if ((ChildInfo.Signature != CHILD_PROCESS_SIGNATURE) || (ChildInfo.TailSignature != CHILD_PROCESS_SIGNATURE)) { LOGPRINT((TRACELOG, "whNtQueryInformationProcess: ChildInfo signatures don't match\n")); st = STATUS_SUCCESS; break; } // // Now try and read the PEB32, again this is to verify the // PEB32 pointer looks good. // st = NtReadVirtualMemory( ProcessHandle, ChildInfo.pPeb32, &ChildPeb32, sizeof(ChildPeb32), &BytesRead); if (!NT_SUCCESS(st)) { LOGPRINT((TRACELOG, "whNtQueryInformationProcess: Couldn't validate 32bit PEB\n")); LOGPRINT((TRACELOG, "whNtQueryInformationProcess: Returned %p bytes of %p requested\n", BytesRead, sizeof(ChildPeb32))); st = STATUS_SUCCESS; break; } // Tell the caller where the PEB32 is LOGPRINT((TRACELOG, "whNtQueryInformationProcess: process is 64bit and has a fake 32bit peb at %p.\n", ChildInfo.pPeb32)); pbi32->PebBaseAddress = (NT32PPEB)ChildInfo.pPeb32; } } break; } case ProcessHandleTracing: @NL { PPROCESS_HANDLE_TRACING_QUERY Pht64; NT32PROCESS_HANDLE_TRACING_QUERY *Pht32 = (NT32PROCESS_HANDLE_TRACING_QUERY *)ProcessInformation; ULONG StacksLeft; NT32PROCESS_HANDLE_TRACING_ENTRY *NextTrace32; PPROCESS_HANDLE_TRACING_ENTRY NextTrace64; ULONG Length64; ULONG ReturnLength64; ULONG Count; if (ProcessInformationLength < FIELD_OFFSET (NT32PROCESS_HANDLE_TRACING_QUERY, HandleTrace)) { return STATUS_INFO_LENGTH_MISMATCH; } StacksLeft = ((ProcessInformationLength - FIELD_OFFSET (NT32PROCESS_HANDLE_TRACING_QUERY, HandleTrace)) / sizeof (Pht32->HandleTrace[0])); // // Allocate as much as we need here // try { Length64 = (StacksLeft * sizeof (Pht64->HandleTrace[0])) + (FIELD_OFFSET (PROCESS_HANDLE_TRACING_QUERY, HandleTrace)); Pht64 = Wow64AllocateTemp (Length64); Pht64->Handle = (HANDLE) LongToPtr (Pht32->Handle); RetVal = NtQueryInformationProcess (ProcessHandle, ProcessInformationClass, Pht64, Length64, &ReturnLength64); // // If all is well // if (NT_SUCCESS (RetVal)) { Pht32->TotalTraces = Pht64->TotalTraces; NextTrace32 = (NT32PROCESS_HANDLE_TRACING_ENTRY *)&Pht32->HandleTrace[0]; NextTrace64 = &Pht64->HandleTrace[0]; for (Count = 0 ; Count < Pht64->TotalTraces ; Count++) { NextTrace32->Handle = PtrToLong (NextTrace64->Handle); @ForceType(PostCall,((PCLIENT_ID)&NextTrace64->ClientId),((NT32CLIENT_ID *)&NextTrace32->ClientId),PCLIENT_ID,OUT) @NL NextTrace32->Type = NextTrace64->Type; for (StacksLeft = 0 ; StacksLeft < (sizeof (NextTrace64->Stacks) / sizeof (NextTrace64->Stacks[0])) ; StacksLeft++) { NextTrace32->Stacks[StacksLeft] = PtrToUlong (NextTrace64->Stacks[StacksLeft]); } NextTrace32++; NextTrace64++; } // // Update the return length // if (ARGUMENT_PRESENT (ReturnLengthHost)) { *ReturnLength = ((PCHAR)NextTrace32 - (PCHAR)Pht32); } } else { // // We may have returned the actual length // Pht32->TotalTraces = Pht64->TotalTraces; if (ARGUMENT_PRESENT (ReturnLengthHost)) { *ReturnLength = ((Pht64->TotalTraces * sizeof (Pht32->HandleTrace[0])) + FIELD_OFFSET (NT32PROCESS_HANDLE_TRACING_QUERY, HandleTrace)); } } } except (EXCEPTION_EXECUTE_HANDLER) { RetVal = GetExceptionCode (); } break; } case ProcessWorkingSetWatch: @NL @Indent( WOWASSERT(TRUE); @NL return STATUS_NOT_IMPLEMENTED; @NL ) @NL case ProcessAffinityMask: @NL { ULONG_PTR Affinity64; if (ProcessInformationLength != sizeof(ULONG)) { RetVal = STATUS_INFO_LENGTH_MISMATCH; break; } RetVal = NtQueryInformationProcess(ProcessHandle, ProcessAffinityMask, &Affinity64, sizeof(Affinity64), NULL); *(PULONG)ProcessInformation = Wow64ThunkAffinityMask64TO32(Affinity64); } case ProcessImageFileName: { ULONG ReturnLengthLocal; PUNICODE_STRING32 ProcessInformation32 = (PUNICODE_STRING32)ProcessInformation; PUNICODE_STRING ProcessInformation64 = (PUNICODE_STRING)ProcessInformation32; if (ProcessInformationLength > 0) { ProcessInformationLength += (sizeof (UNICODE_STRING) - sizeof (UNICODE_STRING32)); ProcessInformation64 = Wow64AllocateTemp (ProcessInformationLength); } RetVal = NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation64, ProcessInformationLength, ReturnLength ); if (NT_SUCCESS (RetVal)) { if (ProcessInformation32 != NULL) { @ForceType(PostCall,ProcessInformation64,ProcessInformation32,PUNICODE_STRING,OUT) @NL try { RtlCopyMemory (ProcessInformation32+1, ProcessInformation64+1, ProcessInformation64->MaximumLength); ProcessInformation32->Buffer = (PWCHAR)(ProcessInformation32+1); } except (EXCEPTION_EXECUTE_HANDLER) { RetVal = GetExceptionCode (); } } } } break; case ProcessDebugFlags: { PVOID Peb32; RetVal = NtQueryInformationProcess(ProcessHandle, ProcessWow64Information, &Peb32, sizeof(Peb32), NULL); if (NT_SUCCESS(RetVal) && Peb32) { RetVal = NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength); } else { RetVal = STATUS_INVALID_INFO_CLASS; } break; } case ProcessVmCounters: @NL @Indent( { VM_COUNTERS_EX VmCountersEx64; if (ProcessInformationLength == sizeof (NT32VM_COUNTERS)) { ProcessInformationLength = sizeof (VM_COUNTERS); RetVal = STATUS_SUCCESS; } else if (ProcessInformationLength == sizeof (NT32VM_COUNTERS_EX)) { ProcessInformationLength = sizeof (VM_COUNTERS_EX); RetVal = STATUS_SUCCESS; } else { RetVal = STATUS_INFO_LENGTH_MISMATCH; } if (NT_SUCCESS (RetVal)) { RetVal = NtQueryInformationProcess (ProcessHandle, ProcessInformationClass, &VmCountersEx64, ProcessInformationLength, ReturnLength ); if (NT_SUCCESS (RetVal)) { // // Thunk the return length // if (ARGUMENT_PRESENT(ReturnLengthHost)) { if (*ReturnLength == sizeof (VM_COUNTERS_EX)) { *ReturnLength = sizeof (NT32VM_COUNTERS_EX); } else if (*ReturnLength == sizeof (VM_COUNTERS)) { *ReturnLength = sizeof (NT32VM_COUNTERS); } else { // // Invalid case // WOWASSERT (FALSE); } } if (ProcessInformationLength == sizeof (VM_COUNTERS_EX)) { @ForceType(PostCall,((PVM_COUNTERS_EX)(&VmCountersEx64)),(NT32VM_COUNTERS_EX *)ProcessInformation,PVM_COUNTERS_EX,OUT) @NL } else if (ProcessInformationLength == sizeof (VM_COUNTERS)) { @ForceType(PostCall,((PVM_COUNTERS_EX)(&VmCountersEx64)),(NT32VM_COUNTERS *)ProcessInformation,PVM_COUNTERS,OUT) @NL } else { // // Invalid case // WOWASSERT (FALSE); } } } break; } ) End= Begin= #define WriteReturnLength(rl, length) WriteReturnLengthStatus((rl), &RetVal, (length)) @GenQueryThunk(@ApiName,ProcessInformationClass,ProcessInformation,ProcessInformationLength,ReturnLength,ULONG) #undef WriteReturnLength End= TemplateName=NtQueryInformationThread Case=(ThreadTimes,PKERNEL_USER_TIMES) Case=(ThreadQuerySetWin32StartAddress,PULONG) Case=(ThreadPerformanceCount,PLARGE_INTEGER) Case=(ThreadAmILastThread,PULONG) Case=(ThreadPriorityBoost,PULONG) Case=(ThreadIsIoPending,PULONG) Case=(ThreadDescriptorTableEntry) Case=(ThreadBasicInformation) SpecialQueryCase= case ThreadDescriptorTableEntry: @NL @Indent( return Wow64GetThreadSelectorEntry(ThreadHandle, ThreadInformation, ThreadInformationLength, ReturnLength); @NL break; @NL )@NL case ThreadBasicInformation: @Indent( @NL return @CallApi(whNtQueryInformationThreadBasicInformation,RetVal) break; @NL )@NL End= Header= NTSTATUS @NL whNtQueryInformationThreadBasicInformation(IN HANDLE ThreadHandle, IN THREADINFOCLASS ThreadInformationClass, OUT PVOID ThreadInformationHost, IN ULONG ThreadInformationLength, OUT PULONG ReturnLength OPTIONAL ) @NL { @Indent( @NL NTSTATUS Status; @NL PTHREAD_BASIC_INFORMATION ThreadInformation; @NL @Types(Locals,ThreadInformation,PTHREAD_BASIC_INFORMATION) if (ThreadInformationHost == NULL) { @Indent( @NL WriteReturnLength(ReturnLength, sizeof(NT32THREAD_BASIC_INFORMATION)); @NL return STATUS_INVALID_PARAMETER; @NL }) @NL if (ThreadInformationLength != sizeof(NT32THREAD_BASIC_INFORMATION)) { @Indent( @NL WriteReturnLength(ReturnLength, sizeof(NT32THREAD_BASIC_INFORMATION)); @NL return STATUS_INFO_LENGTH_MISMATCH; @NL }) @NL @Types(PreCall,ThreadInformation,PTHREAD_BASIC_INFORMATION) Status = Wow64QueryBasicInformationThread(ThreadHandle,(PTHREAD_BASIC_INFORMATION)ThreadInformation); @NL @Types(PostCall,ThreadInformation,PTHREAD_BASIC_INFORMATION) if (ReturnLength) { @Indent( @NL WriteReturnLength(ReturnLength, sizeof(NT32THREAD_BASIC_INFORMATION)); @NL }) @NL return Status; @NL }) @NL End= Begin= #define WriteReturnLength(rl, length) WriteReturnLengthSilent((rl), (length)) @GenQueryThunk(NtQueryInformationThread,ThreadInformationClass,ThreadInformation,ThreadInformationLength,ReturnLength,ULONG) #undef WriteReturnLength End= TemplateName=NtQueryInformationToken Case=(TokenUser,PTOKEN_USER) Case=(TokenGroups,PTOKEN_GROUPS) Case=(TokenPrivileges,PTOKEN_PRIVILEGES) Case=(TokenOwner,PTOKEN_OWNER) Case=(TokenPrimaryGroup,PTOKEN_PRIMARY_GROUP) Case=(TokenDefaultDacl,PTOKEN_DEFAULT_DACL) Case=(TokenSource,PTOKEN_SOURCE) Case=(TokenType,PTOKEN_TYPE) Case=(TokenImpersonationLevel,PSECURITY_IMPERSONATION_LEVEL) Case=(TokenStatistics,PTOKEN_STATISTICS) Case=(TokenRestrictedSids,PTOKEN_GROUPS) Case=(TokenSessionId,PULONG) Case=(TokenSandBoxInert,PULONG) Case=(TokenGroupsAndPrivileges) SpecialQueryCase= @Indent( @NL case TokenGroupsAndPrivileges: { PTOKEN_GROUPS_AND_PRIVILEGES TokenInformation64; struct NT32_TOKEN_GROUPS_AND_PRIVILEGES *TokenInformation32 = (struct NT32_TOKEN_GROUPS_AND_PRIVILEGES *)TokenInformation; struct NT32_SID_AND_ATTRIBUTES *Sids; PCHAR Sid, Start; NTSTATUS NtStatus; INT AllocSize = 0, SidLength; ULONG i, RetInfoLen; ULONG ReturnLength64; AllocSize += LENGTH + sizeof(struct _TOKEN_GROUPS_AND_PRIVILEGES) - sizeof(struct NT32_TOKEN_GROUPS_AND_PRIVILEGES); TokenInformation64 = Wow64AllocateTemp(AllocSize); if (TokenInformation64 == NULL) { RtlRaiseStatus (STATUS_NO_MEMORY); } NtStatus = NtQueryInformationToken (TokenHandle, TokenInformationClass, TokenInformation64, AllocSize, &ReturnLength64); if (NT_ERROR (NtStatus)) { WriteReturnLength (ReturnLength, ReturnLength64); return NtStatus; } if (WOW64_ISPTR (TokenInformation32)) { if (ReturnLength64 > TokenInformationLength) { return STATUS_INFO_LENGTH_MISMATCH; } TokenInformation32->SidCount = TokenInformation64->SidCount; TokenInformation32->Sids = (struct NT32SID_AND_ATTRIBUTES *)((PCHAR)(TokenInformation32) + sizeof(struct NT32_TOKEN_GROUPS_AND_PRIVILEGES)); Sids = TokenInformation32->Sids; Sid = (PCHAR) (Sids + (TokenInformation32->SidCount)); Start = (PCHAR)Sids; for (i=0 ; iSidCount ; i++) { Sids[i].Sid = Sid; Sids[i].Attributes = TokenInformation64->Sids[i].Attributes; SidLength = RtlLengthSid(TokenInformation64->Sids[i].Sid); RtlCopyMemory(Sid, TokenInformation64->Sids[i].Sid, SidLength); Sid += SidLength; } TokenInformation32->SidLength = ((PCHAR)Sid - (PCHAR)Sids); if (TokenInformation32->SidLength == 0) { TokenInformation32->Sids = 0; } TokenInformation32->RestrictedSidCount = TokenInformation64->RestrictedSidCount; TokenInformation32->RestrictedSids = (struct NT32_SID_AND_ATTRIBUTES *)Sid; Sids = (struct NT32_SID_AND_ATTRIBUTES *)Sid; Start = (PCHAR)Sids; Sid = (PCHAR) (Sids + (TokenInformation32->RestrictedSidCount)); for (i=0 ; iRestrictedSidCount ; i++) { Sids[i].Sid = Sid; Sids[i].Attributes = TokenInformation64->RestrictedSids[i].Attributes; SidLength = RtlLengthSid(TokenInformation64->RestrictedSids[i].Sid); RtlCopyMemory(Sid, TokenInformation64->RestrictedSids[i].Sid, SidLength); Sid += SidLength; } TokenInformation32->RestrictedSidLength = ((PCHAR)Sid - Start); if (TokenInformation32->RestrictedSidLength == 0) { TokenInformation32->RestrictedSids = 0; } TokenInformation32->PrivilegeCount = TokenInformation64->PrivilegeCount; TokenInformation32->PrivilegeLength = TokenInformation64->PrivilegeLength; if (TokenInformation32->PrivilegeCount > 0) { TokenInformation32->Privileges = (struct NT32LUID_AND_ATTRIBUTES *)Sid; RtlCopyMemory (Sid, TokenInformation64->Privileges, TokenInformation32->PrivilegeCount * sizeof(NT32LUID_AND_ATTRIBUTES)); Sid += TokenInformation32->PrivilegeCount; } else { TokenInformation32->Privileges = 0; } RtlCopyMemory (&TokenInformation32->AuthenticationId, &TokenInformation64->AuthenticationId, sizeof (TokenInformation64->AuthenticationId)); RetInfoLen = (Sid - (PCHAR)TokenInformation32); } else { RetInfoLen = ReturnLength64; } // // update the return length // WriteReturnLength (ReturnLength, RetInfoLen); RetVal = NtStatus; } break; ) @NL Begin= #define WriteReturnLength(rl, length) WriteReturnLengthStatus((rl), &RetVal, (length)) @GenQueryThunk(@ApiName,TokenInformationClass,TokenInformation,TokenInformationLength,ReturnLength,ULONG) #undef WriteReturnLength End= TemplateName=NtQueryMutant Case=(MutantBasicInformation,PMUTANT_BASIC_INFORMATION) Begin= @GenDebugNonPtrDepCases(@ApiName,MutantInformationClass) End= TemplateName=NtQueryObject Case=(ObjectBasicInformation,POBJECT_BASIC_INFORMATION) Case=(ObjectNameInformation) Case=(ObjectTypeInformation) Case=(ObjectTypesInformation) Case=(ObjectHandleFlagInformation,POBJECT_HANDLE_FLAG_INFORMATION) SpecialQueryCase= @NoFormat( case ObjectNameInformation: @NL @Indent({ SIZE_T AllocSize = 0; POBJECT_NAME_INFORMATION NameInformation; struct NT32_OBJECT_NAME_INFORMATION *Name32 = (struct NT32_OBJECT_NAME_INFORMATION *)ObjectInformation; AllocSize += LENGTH + sizeof(OBJECT_NAME_INFORMATION) - sizeof(struct NT32_OBJECT_NAME_INFORMATION); NameInformation = Wow64AllocateTemp(AllocSize); RetVal=NtQueryObject(Handle, ObjectNameInformation, NameInformation, AllocSize, ReturnLength ); if (!NT_ERROR(RetVal)) { // Thunk the Name (a UNICODE_STRING) by hand... the Buffer // pointer actually points to the first byte past the end of // the OBJECT_TYPE_INFORMATION struct. try { Name32->Name.Length = NameInformation->Name.Length; Name32->Name.MaximumLength = NameInformation->Name.MaximumLength; Name32->Name.Buffer = PtrToUlong(Name32+1); RtlCopyMemory((PVOID)Name32->Name.Buffer, NameInformation->Name.Buffer, NameInformation->Name.Length); ((PWSTR)Name32->Name.Buffer)[ (NameInformation->Name.Length/sizeof(WCHAR)) ] = UNICODE_NULL; WriteReturnLength(ReturnLength, sizeof(struct NT32_OBJECT_NAME_INFORMATION) + Name32->Name.MaximumLength); } except (EXCEPTION_EXECUTE_HANDLER) { RetVal = GetExceptionCode (); } } } break;) case ObjectTypeInformation: @NL @Indent({ SIZE_T AllocSize = 0; POBJECT_TYPE_INFORMATION TypeInformation; struct NT32_OBJECT_TYPE_INFORMATION *Type32 = (struct NT32_OBJECT_TYPE_INFORMATION *)ObjectInformation; AllocSize += LENGTH + sizeof(OBJECT_TYPE_INFORMATION) - sizeof(struct NT32_OBJECT_TYPE_INFORMATION); TypeInformation = Wow64AllocateTemp(AllocSize); LENGTH = (NT32SIZE_T)AllocSize; RetVal=NtQueryObject(Handle, ObjectTypeInformation, TypeInformation, Length, ReturnLength ); if (!NT_ERROR(RetVal)) { // Thunk the TypeName (a UNICODE_STRING) by hand... the Buffer // pointer actually points to the first byte past the end of // the OBJECT_TYPE_INFORMATION struct. try { Type32->TypeName.Length = TypeInformation->TypeName.Length; Type32->TypeName.MaximumLength = TypeInformation->TypeName.MaximumLength; Type32->TypeName.Buffer = PtrToUlong(Type32+1); RtlCopyMemory((PVOID)Type32->TypeName.Buffer, TypeInformation->TypeName.Buffer, TypeInformation->TypeName.Length); // NULL out the UNICODE string ((PWSTR)(Type32->TypeName.Buffer))[ Type32->TypeName.Length/sizeof(WCHAR) ] = UNICODE_NULL; // Thunk the other fields in the OBJECT_TYPE_INFORMATION by a simple // copy RtlCopyMemory(&Type32->TotalNumberOfObjects, &TypeInformation->TotalNumberOfObjects, sizeof(NT32OBJECT_TYPE_INFORMATION)-FIELD_OFFSET(struct NT32_OBJECT_TYPE_INFORMATION, TotalNumberOfObjects)); WriteReturnLength(ReturnLength, sizeof(struct NT32_OBJECT_TYPE_INFORMATION) + Type32->TypeName.MaximumLength); } except (EXCEPTION_EXECUTE_HANDLER) { RetVal = GetExceptionCode (); } } } break;) case ObjectTypesInformation: @NL @Indent({ SIZE_T AllocSize = 0; SIZE_T OldLength = 0; PULONG TypesInformation; ULONG n; // figure out how many OBJECT_TYPE_INFORMATIONs the caller had space for, and // grow the 64-bit temp size to handle 'n' 64-bit OBJECT_TYPE_INFORMATIONs. n = (LENGTH-sizeof(ULONG)) / sizeof(struct NT32_OBJECT_TYPE_INFORMATION); AllocSize += LENGTH + n*(sizeof(OBJECT_TYPE_INFORMATION) - sizeof(struct NT32_OBJECT_TYPE_INFORMATION)); TypesInformation = Wow64AllocateTemp(AllocSize); OldLength = LENGTH; LENGTH = (NT32SIZE_T)AllocSize; RetVal=NtQueryObject(Handle, ObjectTypesInformation, TypesInformation, Length, ReturnLength ); // Note: if this fails with STATUS_INFO_LENGTH_MISMATCH, it will return // back the 64-bit ReturnLength value. That should be OK for a 32-bit // app to use if it needs to allocate a bigger buffer for a second call. if (!NT_ERROR(RetVal)) { POBJECT_TYPE_INFORMATION Type64; struct NT32_OBJECT_TYPE_INFORMATION *Type32; try { // Copy over the count of objects *(PULONG)ObjectInformation = *TypesInformation; Type64 = (POBJECT_TYPE_INFORMATION) (ALIGN_UP(((ULONG)(TypesInformation+1)), PVOID)); Type32 = (struct NT32_OBJECT_TYPE_INFORMATION*)( ((PULONG)ObjectInformation)+1 ); for (n = 0; n<*TypesInformation; n++) { // Thunk the TypeName (a UNICODE_STRING) by hand... the Buffer // pointer actually points to the first byte past the end of // the OBJECT_TYPE_INFORMATION struct. Type32->TypeName.Length = Type64->TypeName.Length; Type32->TypeName.MaximumLength = Type64->TypeName.MaximumLength; Type32->TypeName.Buffer = PtrToUlong((Type32+1)); RtlCopyMemory((PVOID)Type32->TypeName.Buffer, Type64->TypeName.Buffer, Type64->TypeName.Length); ((PWSTR)(Type32->TypeName.Buffer))[ Type64->TypeName.Length/sizeof(WCHAR) ] = UNICODE_NULL; // Thunk the other fields in the OBJECT_TYPE_INFORMATION by a simple // copy RtlCopyMemory(&Type32->TotalNumberOfObjects, &Type64->TotalNumberOfObjects, sizeof(struct NT32_OBJECT_TYPE_INFORMATION)-FIELD_OFFSET(struct NT32_OBJECT_TYPE_INFORMATION, TotalNumberOfObjects)); // Move the pointers forward Type64 = (POBJECT_TYPE_INFORMATION)( (PCHAR)(Type64+1) + ALIGN_UP(Type64->TypeName.MaximumLength, PVOID)); Type32 = (struct NT32_OBJECT_TYPE_INFORMATION *)( (PCHAR)(Type32+1) + ALIGN_UP(Type32->TypeName.MaximumLength, ULONG)); } WriteReturnLength(ReturnLength, (ULONG)( (PBYTE)Type32 - (PBYTE)ObjectInformation )); } except (EXCEPTION_EXECUTE_HANDLER) { RetVal = GetExceptionCode (); } } } break;) ) Begin= #define WriteReturnLength(rl, length) WriteReturnLengthSilent((rl), (length)) @GenQueryThunk(@ApiName,ObjectInformationClass,ObjectInformation,Length,ReturnLength,ULONG) #undef WriteReturnLength End= TemplateName=NtQuerySection Case=(SectionBasicInformation,PSECTION_BASIC_INFORMATION) Case=(SectionImageInformation,PSECTION_IMAGE_INFORMATION) Header= End= Begin= #define WriteReturnLength(rl, length) WriteReturnLengthSilent((PULONG)(rl), (ULONG)(length)) @GenQueryThunk(@ApiName,SectionInformationClass,SectionInformation,SectionInformationLength,ReturnLength,SIZE_T) #undef WriteReturnLength End= PostCall= @NoFormat( if (!NT_ERROR(RetVal) && SectionInformationClass == SectionImageInformation) { struct NT32_SECTION_IMAGE_INFORMATION *pSecInfo32 = (struct NT32_SECTION_IMAGE_INFORMATION *)SectionInformation; #if defined(_AMD64_) if (pSecInfo32->Machine == IMAGE_FILE_MACHINE_AMD64) #elif defined(_IA64_) if (pSecInfo32->Machine == IMAGE_FILE_MACHINE_IA64) #else #error "No Target Architecture" #endif { // Image section is 64-bit. Lie about a number of the fields // so RtlCreateUserProcess and CreateProcessW are happy. pSecInfo32->TransferAddress = 0x81231234; // bogus nonzero value pSecInfo32->MaximumStackSize = 1024*1024; // max stack size = 1meg pSecInfo32->CommittedStackSize = 64*1024; // 64k commit } } ) End= TemplateName=NtQuerySecurityObject NoType=SecurityDescriptor Header= @NoFormat( NTSTATUS whNT32QuerySecurityObject( IN HANDLE Handle, IN SECURITY_INFORMATION SecurityInformation, OUT PVOID SecurityDescriptor, IN ULONG Length, OUT PULONG LengthNeeded ) { NTSTATUS Status; SECURITY_DESCRIPTOR *Descriptor64; NT32SECURITY_DESCRIPTOR *Descriptor32; Status = NtQuerySecurityObject(Handle, SecurityInformation, (PSECURITY_DESCRIPTOR)SecurityDescriptor, Length, LengthNeeded ); if (NT_ERROR(Status) || !SecurityDescriptor) { return Status; } Descriptor64 = (SECURITY_DESCRIPTOR *)SecurityDescriptor; try { if (Descriptor64->Control & SE_SELF_RELATIVE) { //Descriptor is self-relative, no thunking needed. return Status; } Descriptor32 = (NT32SECURITY_DESCRIPTOR *)SecurityDescriptor; //Copy up the lower fields. //Note that the destination structure is small. Descriptor32->Owner = (NT32PSID)Descriptor64->Owner; Descriptor32->Group = (NT32PSID)Descriptor64->Group; Descriptor32->Sacl = (NT32PSID)Descriptor64->Sacl; Descriptor32->Dacl = (NT32PSID)Descriptor64->Dacl; } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode (); } return Status; } ) End= PreCall= SecurityDescriptor = (PSECURITY_DESCRIPTOR)SecurityDescriptorHost; @NL Begin= @GenApiThunk(whNT32QuerySecurityObject) End= TemplateName=NtQuerySystemInformation Case=(SystemBasicInformation,PSYSTEM_BASIC_INFORMATION) Case=(SystemProcessorInformation,PSYSTEM_PROCESSOR_INFORMATION) Case=(SystemEmulationBasicInformation,PSYSTEM_BASIC_INFORMATION) Case=(SystemEmulationProcessorInformation,PSYSTEM_PROCESSOR_INFORMATION) Case=(SystemPerformanceInformation,PSYSTEM_PERFORMANCE_INFORMATION) Case=(SystemTimeOfDayInformation,PSYSTEM_TIMEOFDAY_INFORMATION) Case=(SystemCallCountInformation,PSYSTEM_CALL_COUNT_INFORMATION) Case=(SystemDeviceInformation,PSYSTEM_DEVICE_INFORMATION) Case=(SystemProcessorPerformanceInformation) Case=(SystemFlagsInformation,PSYSTEM_FLAGS_INFORMATION) Case=(SystemModuleInformation,PRTL_PROCESS_MODULES) Case=(SystemLocksInformation,PRTL_PROCESS_LOCKS) Case=(SystemStackTraceInformation,PRTL_PROCESS_BACKTRACES) Case=(SystemPagedPoolInformation,PSYSTEM_POOL_INFORMATION) Case=(SystemNonPagedPoolInformation,PSYSTEM_POOL_INFORMATION) Case=(SystemHandleInformation,PSYSTEM_HANDLE_INFORMATION) Case=(SystemObjectInformation,PSYSTEM_OBJECTTYPE_INFORMATION) Case=(SystemPageFileInformation,PSYSTEM_PAGEFILE_INFORMATION) Case=(SystemFileCacheInformation,PSYSTEM_FILECACHE_INFORMATION) Case=(SystemPoolTagInformation,PSYSTEM_POOLTAG_INFORMATION) Case=(SystemInterruptInformation,PSYSTEM_INTERRUPT_INFORMATION) Case=(SystemDpcBehaviorInformation,PSYSTEM_DPC_BEHAVIOR_INFORMATION) Case=(SystemFullMemoryInformation,PSYSTEM_MEMORY_INFORMATION) Case=(SystemTimeAdjustmentInformation,PSYSTEM_QUERY_TIME_ADJUST_INFORMATION) Case=(SystemSummaryMemoryInformation,PSYSTEM_MEMORY_INFORMATION) Case=(SystemExceptionInformation,PSYSTEM_EXCEPTION_INFORMATION) Case=(SystemKernelDebuggerInformation,PSYSTEM_KERNEL_DEBUGGER_INFORMATION) Case=(SystemContextSwitchInformation,PSYSTEM_CONTEXT_SWITCH_INFORMATION) Case=(SystemRegistryQuotaInformation,PSYSTEM_REGISTRY_QUOTA_INFORMATION) Case=(SystemCurrentTimeZoneInformation,PRTL_TIME_ZONE_INFORMATION) Case=(SystemLookasideInformation,PSYSTEM_LOOKASIDE_INFORMATION) Case=(SystemProcessorIdleInformation,PSYSTEM_PROCESSOR_IDLE_INFORMATION) Case=(SystemLostDelayedWriteInformation,PULONG) Case=(SystemRangeStartInformation,ULONG_PTR*) Case=(SystemComPlusPackage,PULONG) Case=(SystemPerformanceTraceInformation) Case=(SystemCallTimeInformation) Case=(SystemPathInformation) Case=(SystemVdmInstemulInformation) Case=(SystemVdmBopInformation) Case=(SystemProcessInformation) Case=(SystemExtendedProcessInformation) Header= @NoFormat( NTSTATUS whNT32ThunkProcessInformationEx ( IN PSYSTEM_PROCESS_INFORMATION ProcessInformation, IN BOOLEAN ExtendedProcessInformation, IN OUT NT32SYSTEM_PROCESS_INFORMATION **ProcessInformation32, OUT PULONG SystemInformationLength32 ) @NL { PSYSTEM_THREAD_INFORMATION ThreadInfo; PSYSTEM_EXTENDED_THREAD_INFORMATION ThreadInfoEx; NT32SYSTEM_PROCESS_INFORMATION *ProcessInfo32 = *ProcessInformation32; NT32SYSTEM_THREAD_INFORMATION *ThreadInfo32; NT32SYSTEM_EXTENDED_THREAD_INFORMATION *ThreadInfoEx32; PVOID pvLast; ULONG NumberOfThreads; ULONG BufferLength = *SystemInformationLength32; // // Check if the user has enough space // if (BufferLength < sizeof (NT32SYSTEM_PROCESS_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } BufferLength = BufferLength - sizeof (NT32SYSTEM_PROCESS_INFORMATION); @ForceType(PostCall,ProcessInformation,ProcessInfo32,SYSTEM_PROCESS_INFORMATION*,OUT) NumberOfThreads = ProcessInformation->NumberOfThreads; ThreadInfo = (PSYSTEM_THREAD_INFORMATION) (ProcessInformation + 1); ThreadInfoEx = (PSYSTEM_EXTENDED_THREAD_INFORMATION) (ProcessInformation + 1); ThreadInfo32 = (NT32SYSTEM_THREAD_INFORMATION *) (ProcessInfo32 + 1); ThreadInfoEx32 = (NT32SYSTEM_EXTENDED_THREAD_INFORMATION *) (ProcessInfo32 + 1); pvLast = (ProcessInfo32 + 1); if (ExtendedProcessInformation) { if (BufferLength < (sizeof (PSYSTEM_EXTENDED_THREAD_INFORMATION) * NumberOfThreads)) { return STATUS_INFO_LENGTH_MISMATCH; } BufferLength = BufferLength - (sizeof (PSYSTEM_EXTENDED_THREAD_INFORMATION) * NumberOfThreads); } else { if (BufferLength < (sizeof (PSYSTEM_THREAD_INFORMATION) * NumberOfThreads)) { return STATUS_INFO_LENGTH_MISMATCH; } BufferLength = BufferLength - (sizeof (PSYSTEM_THREAD_INFORMATION) * NumberOfThreads); } while (NumberOfThreads > 0) { if (ExtendedProcessInformation) { @ForceType(PostCall,ThreadInfoEx,ThreadInfoEx32,PSYSTEM_EXTENDED_THREAD_INFORMATION,OUT) ThreadInfoEx = ThreadInfoEx + 1; ThreadInfoEx32 = ThreadInfoEx32 + 1; pvLast = ThreadInfoEx32; } else { @ForceType(PostCall,ThreadInfo,ThreadInfo32,PSYSTEM_THREAD_INFORMATION,OUT) ThreadInfo = ThreadInfo + 1; ThreadInfo32 = ThreadInfo32 + 1; pvLast = ThreadInfo32; } NumberOfThreads--; } if (ProcessInformation->ImageName.Buffer != NULL) { if (BufferLength < ProcessInformation->ImageName.MaximumLength) { return STATUS_INFO_LENGTH_MISMATCH; } BufferLength = BufferLength - ProcessInformation->ImageName.MaximumLength; RtlCopyMemory (pvLast, ProcessInformation->ImageName.Buffer, ProcessInformation->ImageName.MaximumLength ); ProcessInfo32->ImageName.Buffer = pvLast; pvLast = (PCHAR)pvLast + ProcessInformation->ImageName.MaximumLength; } else { ProcessInfo32->ImageName.Buffer = NULL; } pvLast = ROUND_UP ((ULONG_PTR)pvLast, sizeof(ULONGLONG)); if (ProcessInformation->NextEntryOffset == 0) ProcessInfo32->NextEntryOffset = 0; else ProcessInfo32->NextEntryOffset = (ULONG) ((PCHAR)pvLast - (PCHAR)ProcessInfo32); *ProcessInformation32 = pvLast; *SystemInformationLength32 = BufferLength; return STATUS_SUCCESS; } NTSTATUS whNT32QuerySystemProcessInformationEx ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation32, IN ULONG SystemInformationLength32, OUT PULONG ReturnLength32 OPTIONAL ) @NL { NTSTATUS NtStatus; ULONG SystemInformationLength; ULONG ReturnLength; BOOLEAN ExtendedProcessInformation; PCHAR SystemInformationHost = (PCHAR)SystemInformation32; PSYSTEM_PROCESS_INFORMATION SystemInformation; // // Allocate enough input buffer // SystemInformationLength = (SystemInformationLength32 + 0x400); SystemInformation = Wow64AllocateTemp (SystemInformationLength); if (SystemInformation == NULL) { return STATUS_NO_MEMORY; } NtStatus = NtQuerySystemInformation ( SystemInformationClass, SystemInformation, SystemInformationLength, &ReturnLength ); if (NT_SUCCESS (NtStatus)) { if (SystemInformationClass == SystemExtendedProcessInformation) { ExtendedProcessInformation = TRUE; } else { ExtendedProcessInformation = FALSE; } // // Thunk back the output to the caller. // try { while (TRUE) { NtStatus = whNT32ThunkProcessInformationEx ( SystemInformation, ExtendedProcessInformation, (NT32SYSTEM_PROCESS_INFORMATION **)&SystemInformation32, &SystemInformationLength32 ); if (NT_SUCCESS (NtStatus)) { if (SystemInformation->NextEntryOffset == 0) { break; } SystemInformation = (PSYSTEM_PROCESS_INFORMATION) ((PCHAR)SystemInformation + SystemInformation->NextEntryOffset); } else { break; } } // // If all is good, let's update the output if present // if (NT_SUCCESS (NtStatus)) { if (ARGUMENT_PRESENT (ReturnLength32)) { *ReturnLength32 = ((PCHAR)SystemInformation32 - (PCHAR)SystemInformationHost); } } } except (EXCEPTION_EXECUTE_HANDLER) { NtStatus = GetExceptionCode (); } } return NtStatus; } // SystemProcessorPerformanceInformation will return information about the processors in the system. // On NT64, the maximum number of processors has increased to 64 instead of 32. Fortunately, // the system will stop returning information when the client buffer is filled up. So a 32bit // app will request preformance information on 32 processors, and the system will give them // back information on 32 processors as expected. NTSTATUS whNT32QuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ) { PWOW64_SYSTEM_INFORMATION EmulatedSysInfo; NTSTATUS RetVal = STATUS_SUCCESS; EmulatedSysInfo = Wow64GetEmulatedSystemInformation(); switch(SystemInformationClass) { case SystemBasicInformation: if (SystemInformationLength != sizeof(SYSTEM_BASIC_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } if (SystemInformation == NULL) { return STATUS_INVALID_PARAMETER; } RtlCopyMemory(SystemInformation, &EmulatedSysInfo->BasicInfo, sizeof(SYSTEM_BASIC_INFORMATION)); WriteReturnLength(ReturnLength, sizeof(SYSTEM_BASIC_INFORMATION)); return RetVal; break; case SystemProcessorInformation: if (SystemInformationLength != sizeof(SYSTEM_PROCESSOR_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } if (SystemInformation == NULL) { return STATUS_INVALID_PARAMETER; } RtlCopyMemory(SystemInformation, &EmulatedSysInfo->ProcessorInfo, sizeof(SYSTEM_PROCESSOR_INFORMATION) ); WriteReturnLength(ReturnLength, sizeof(SYSTEM_PROCESSOR_INFORMATION)); return RetVal; break; case SystemRangeStartInformation: if (SystemInformationLength != sizeof(ULONG_PTR)) { return STATUS_INFO_LENGTH_MISMATCH; } if (SystemInformation == NULL) { return STATUS_INVALID_PARAMETER; } RtlCopyMemory(SystemInformation, &EmulatedSysInfo->RangeInfo, sizeof(ULONG_PTR)); // WriteReturnLength(ReturnLength, sizeof(ULONG_PTR)); WriteReturnLength(ReturnLength, sizeof(ULONG)); return RetVal; default: return NtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength ); } } ) End= SpecialQueryCase= case SystemPerformanceTraceInformation: @NL case SystemCallTimeInformation: @NL case SystemPathInformation: @NL @Indent( // Note: Not implemented in the kernel. @NL return STATUS_NOT_IMPLEMENTED; @NL ) case SystemVdmInstemulInformation: @NL case SystemVdmBopInformation: @NL @Indent( // Note: not supported since VDM is not supported. @NL return STATUS_NOT_IMPLEMENTED; @NL ) case SystemProcessorPerformanceInformation: { NTSTATUS NtStatus; PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcessorPerformanceInformation64; NT32SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *ProcessorPerformanceInformation32; ULONG EntriesCount; ULONG ReturnLength64; ProcessorPerformanceInformation32 = (NT32SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *)SystemInformation; if (SystemInformationLength < sizeof (NT32SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } EntriesCount = SystemInformationLength / sizeof (NT32SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); if (ARGUMENT_PRESENT (ProcessorPerformanceInformation32)) { ProcessorPerformanceInformation64 = Wow64AllocateTemp (EntriesCount * sizeof (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); if (ProcessorPerformanceInformation64 == NULL) { return STATUS_NO_MEMORY; } } else { ProcessorPerformanceInformation64 = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)ProcessorPerformanceInformation32; } NtStatus = whNT32QuerySystemInformation ( SystemInformationClass, ProcessorPerformanceInformation64, EntriesCount * sizeof (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), &ReturnLength64 ); if (NT_SUCCESS (NtStatus)) { ASSERT ((ReturnLength64 / sizeof (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) <= EntriesCount); ReturnLength64 = ReturnLength64 / sizeof (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); try { EntriesCount = ReturnLength64; while (ReturnLength64 > 0) { @ForceType(PostCall,ProcessorPerformanceInformation64,ProcessorPerformanceInformation32,PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION,OUT); @NL ProcessorPerformanceInformation64++; ProcessorPerformanceInformation32++; ReturnLength64--; } if (ARGUMENT_PRESENT (ReturnLength)) { *ReturnLength = EntriesCount * sizeof (NT32SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); } } except (EXCEPTION_EXECUTE_HANDLER) { NtStatus = GetExceptionCode (); } } return NtStatus; } break; case SystemProcessInformation: case SystemExtendedProcessInformation: return whNT32QuerySystemProcessInformationEx ( SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength ); break; End= Begin= #define WriteReturnLength(rl, length) WriteReturnLengthStatus((rl), &RetVal, (length)) @GenQueryThunk(whNT32QuerySystemInformation,SystemInformationClass,SystemInformation,SystemInformationLength,ReturnLength,ULONG) #undef WriteReturnLength End= TemplateName=NtWow64GetNativeSystemInformation Case=(SystemBasicInformation,PSYSTEM_BASIC_INFORMATION) Case=(SystemProcessorInformation,PSYSTEM_PROCESSOR_INFORMATION) Case=(SystemEmulationBasicInformation,PSYSTEM_BASIC_INFORMATION) Case=(SystemEmulationProcessorInformation,PSYSTEM_PROCESSOR_INFORMATION) Begin= #define WriteReturnLength(rl, length) WriteReturnLengthStatus((rl), &RetVal, (length)) @GenQueryThunk(NtQuerySystemInformation,SystemInformationClass,NativeSystemInformation,InformationLength,ReturnLength,ULONG) #undef WriteReturnLength End= TemplateName=NtQuerySemaphore Case=(SemaphoreBasicInformation,PSEMAPHORE_BASIC_INFORMATION) Begin= @GenDebugNonPtrDepCases(@ApiName,SemaphoreInformationClass) End= TemplateName=NtQueryVirtualMemory Case=(MemoryBasicInformation,PMEMORY_BASIC_INFORMATION) Case=(MemoryWorkingSetInformation,PMEMORY_WORKING_SET_INFORMATION) Case=(MemoryMappedFilenameInformation,POBJECT_NAME_INFORMATION) Begin= #define WriteReturnLength(rl, length) WriteReturnLengthSilent((PULONG)(rl), (ULONG)(length)) @GenQueryThunk(@ApiName,MemoryInformationClass,MemoryInformation,MemoryInformationLength,ReturnLength,SIZE_T) #undef WriteReturnLength End= TemplateName=NtQueryVirtualMemory64 Case=(MemoryBasicInformation,PUCHAR) Case=(MemoryWorkingSetInformation,PMEMORY_WORKING_SET_INFORMATION) Case=(MemoryMappedFilenameInformation,POBJECT_NAME_INFORMATION) Begin= #define WriteReturnLength(rl, length) WriteReturnLengthSilent((rl), (length)) @GenQueryThunk(@ApiName,MemoryInformationClass,MemoryInformation,MemoryInformationLength,ReturnLength,SIZE_T) #undef WriteReturnLength End= TemplateName=NtQueryVolumeInformationFile Case=(FileFsVolumeInformation,PFILE_FS_VOLUME_INFORMATION) Case=(FileFsLabelInformation,PFILE_FS_LABEL_INFORMATION) Case=(FileFsSizeInformation,PFILE_FS_SIZE_INFORMATION) Case=(FileFsDeviceInformation,PFILE_FS_DEVICE_INFORMATION) Case=(FileFsAttributeInformation,PFILE_FS_ATTRIBUTE_INFORMATION) Case=(FileFsControlInformation,PFILE_FS_CONTROL_INFORMATION) Case=(FileFsFullSizeInformation,PFILE_FS_FULL_SIZE_INFORMATION) Case=(FileFsObjectIdInformation,PFILE_FS_OBJECTID_INFORMATION) Case=(FileFsDriverPathInformation,PFILE_FS_DRIVER_PATH_INFORMATION) Begin= @GenDebugNonPtrDepCases(@ApiName,FsInformationClass) End= TemplateName=NtRaiseHardError NoType=Parameters Header= @NoFormat( NTSTATUS whNT32RaiseHardError( IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PVOID Parameters, //these parameters are not thunked yet(PULONG). IN ULONG ValidResponseOptions, OUT PULONG Response ) { ULONG ParameterCount; PULONG Parameters32; PULONG_PTR Parameters64; Parameters32 = (PULONG)Parameters; Parameters64 = Wow64AllocateTemp(NumberOfParameters * sizeof(ULONG_PTR)); for(ParameterCount=0; ParameterCount < NumberOfParameters; ParameterCount++) { if (UnicodeStringParameterMask & (1< 0) && (ARGUMENT_PRESENT (UserJobSet) != 0)) { ULONG JobIndex; NT32JOB_SET_ARRAY *UserJobSet32 = (NT32JOB_SET_ARRAY *)UlongToPtr(UserJobSetHost); UserJobSet = Wow64AllocateTemp (NumJob * sizeof (JOB_SET_ARRAY)); if (UserJobSet == NULL) { return STATUS_NO_MEMORY; } try { for (JobIndex = 0 ; JobIndex < NumJob ; JobIndex++) { UserJobSet[JobIndex].Flags = UserJobSet32[JobIndex].Flags; UserJobSet[JobIndex].MemberLevel = UserJobSet32[JobIndex].MemberLevel; UserJobSet[JobIndex].JobHandle = LongToPtr(UserJobSet32[JobIndex].JobHandle); } } except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode (); } } End= Begin= @GenApiThunk(@ApiName) End= TemplateName=NtSetInformationObject Case=(ObjectHandleFlagInformation,POBJECT_HANDLE_FLAG_INFORMATION) Begin= @GenDebugNonPtrDepCases(@ApiName,ObjectInformationClass) End= TemplateName=NtSetInformationProcess Header= @NoFormat( NTSTATUS whNtSetInformationProcessEnableAlignmentFaultFixup(IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, IN PVOID ProcessInformationHost, IN ULONG ProcessInformationLength ) { @Indent( @NL // Force enabling of alignment fixup since 32bit NT silently ignored this setting and always // fixed up alignment faults. BOOLEAN b = TRUE; if (!ProcessInformationHost) { return STATUS_INVALID_PARAMETER; } if (sizeof(BOOLEAN) != ProcessInformationLength) { return STATUS_INFO_LENGTH_MISMATCH; } return NtSetInformationProcess(ProcessHandle, ProcessInformationClass, &b, sizeof(BOOLEAN)); } NTSTATUS whNtSetInformationProcessDefaultHardErrorMode(IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, IN PVOID ProcessInformationHost, IN ULONG ProcessInformationLength ) { @Indent( @NL // Force enabling of alignment fixup since 32bit NT silently ignored this setting and always // fixed up alignment faults. ULONG ul; if (!ProcessInformationHost) { return STATUS_INVALID_PARAMETER; } if (sizeof(ULONG) != ProcessInformationLength) { return STATUS_INFO_LENGTH_MISMATCH; } ul = *(ULONG *)ProcessInformationHost | PROCESS_HARDERROR_ALIGNMENT_BIT; return NtSetInformationProcess(ProcessHandle, ProcessInformationClass, &ul, sizeof(ULONG)); } NTSTATUS whNtSetInformationProcessAffinityMask( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, IN PVOID ProcessInformation, IN ULONG ProcessInformationLength ) { ULONG_PTR AffinityMask; if ((NULL == ProcessInformation) || (ProcessInformationLength != sizeof(ULONG))) { // Let the NT Api fail this call with the correct return code. return NtSetInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength); } AffinityMask = Wow64ThunkAffinityMask32TO64(*(PULONG)ProcessInformation); return NtSetInformationProcess(ProcessHandle, ProcessInformationClass, &AffinityMask, sizeof(AffinityMask)); } ) End= Case=(ProcessBasicInformation) Case=(ProcessWorkingSetWatch) Case=(ProcessEnableAlignmentFaultFixup) Case=(ProcessAffinityMask) Case=(ProcessDefaultHardErrorMode) Case=(ProcessQuotaLimits,PQUOTA_LIMITS) Case=(ProcessIoCounters,PULONG) Case=(ProcessVmCounters,PVM_COUNTERS) Case=(ProcessTimes,PKERNEL_USER_TIMES) Case=(ProcessBasePriority,KPRIORITY*) Case=(ProcessRaisePriority,PULONG) Case=(ProcessDebugPort,PHANDLE) Case=(ProcessExceptionPort,PHANDLE) Case=(ProcessAccessToken,PPROCESS_ACCESS_TOKEN) Case=(ProcessLdtInformation) Case=(ProcessLdtSize) Case=(ProcessPooledUsageAndLimits,PPOOLED_USAGE_AND_LIMITS) Case=(ProcessUserModeIOPL) Case=(ProcessPriorityClass,PPROCESS_PRIORITY_CLASS) Case=(ProcessWx86Information,PHANDLE) Case=(ProcessHandleCount,PULONG) Case=(ProcessPriorityBoost,PULONG) Case=(ProcessDeviceMap,PPROCESS_DEVICEMAP_INFORMATION) Case=(ProcessSessionInformation,PPROCESS_SESSION_INFORMATION) Case=(ProcessForegroundInformation,PPROCESS_FOREGROUND_BACKGROUND) Case=(ProcessHandleTracing,PPROCESS_HANDLE_TRACING_ENABLE) Case=(ProcessWow64Information,PULONG_PTR) SpecialSetCase= case ProcessWorkingSetWatch: @NL @Indent( WOWASSERT(TRUE); return STATUS_NOT_IMPLEMENTED; ) case ProcessEnableAlignmentFaultFixup: @NL @Indent( @CallApi(whNtSetInformationProcessEnableAlignmentFaultFixup,RetVal) break; ) case ProcessAffinityMask: @NL @Indent( @CallApi(whNtSetInformationProcessAffinityMask,RetVal) break; ) case ProcessDefaultHardErrorMode: @NL @Indent( @CallApi(whNtSetInformationProcessDefaultHardErrorMode,RetVal) break; ) Begin= @GenSetThunk(@ApiName,ProcessInformationClass,ProcessInformation,ProcessInformationLength) End= TemplateName=NtSetInformationThread Header= @NoFormat( NTSTATUS whNtSetInformationThreadAffinityMask( IN HANDLE ThreadHandle, IN THREADINFOCLASS ThreadInformationClass, IN PVOID ThreadInformation, IN ULONG ThreadInformationLength ) { ULONG Affinity32; ULONG_PTR Affinity64; NTSTATUS StatusApi, StTemp; HANDLE ProcessHandle; THREAD_BASIC_INFORMATION ThreadInfo; PROCESS_BASIC_INFORMATION ProcessInfo; OBJECT_ATTRIBUTES ObjectAttributes; if (NULL == ThreadInformation) { return STATUS_INVALID_PARAMETER; } if (sizeof(ULONG) != ThreadInformationLength) { return STATUS_INFO_LENGTH_MISMATCH; } Affinity32 = *(PULONG)ThreadInformation; Affinity64 = Wow64ThunkAffinityMask32TO64(Affinity32); StatusApi = NtSetInformationThread(ThreadHandle, ThreadInformationClass, &Affinity64, sizeof(Affinity64)); if (StatusApi != STATUS_INVALID_PARAMETER) { return StatusApi; } //Attempt to bash the thread affinity into being a subset of the process affinity. //This should only happen if process the process affinty or thread affinity //had some of the upper bits set set by some external entity and the app is trying //to compute the thread affinity by subtracting bits from the process affinity. //So query the process affinity, and try to mask off the bits. If we don't have //permission to query the process affinity, fail the API. StTemp = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &ThreadInfo, sizeof(ThreadInfo), NULL); if (!NT_SUCCESS(StTemp)) { return StatusApi; } InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL ); StTemp = NtOpenProcess(&ProcessHandle, PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, &ObjectAttributes, //ObjectAttributes &(ThreadInfo.ClientId) ); if (!NT_SUCCESS(StTemp)) { return StatusApi; } StTemp = NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &ProcessInfo, sizeof(ProcessInfo), NULL); if (!NT_SUCCESS(StTemp)) { goto done; } // Try to set the Affinity mask again after anding it with the process affinity. // If this also fails, nothing more can be done. Just exit. Affinity64 &= ProcessInfo.AffinityMask; StatusApi = NtSetInformationThread(ThreadHandle, ThreadInformationClass, &Affinity64, sizeof(Affinity64)); done: NtClose(ProcessHandle); return StatusApi; } End= Case=(ThreadPriority,KPRIORITY*) Case=(ThreadBasePriority,PLONG) Case=(ThreadEnableAlignmentFaultFixup,PBOOLEAN) Case=(ThreadImpersonationToken,PHANDLE) Case=(ThreadQuerySetWin32StartAddress,PULONG_PTR) Case=(ThreadIdealProcessor,PULONG) Case=(ThreadPriorityBoost,PULONG) Case=(ThreadZeroTlsCell,PULONG) Case=(ThreadSetTlsArrayAddress,PVOID*) Case=(ThreadHideFromDebugger) Case=(ThreadAffinityMask) SpecialSetCase= case ThreadAffinityMask: @Indent( @NL @CallApi(whNtSetInformationThreadAffinityMask,RetVal) break; @NL )@NL case ThreadHideFromDebugger: @Indent( @NL @CallApi(@ApiName,RetVal); break; @NL )@NL End= Begin= @GenSetThunk(@ApiName,ThreadInformationClass,ThreadInformation,ThreadInformationLength) End= TemplateName=NtSetInformationToken Case=(TokenOwner,PTOKEN_OWNER) Case=(TokenPrimaryGroup,PTOKEN_PRIMARY_GROUP) Case=(TokenDefaultDacl,PTOKEN_DEFAULT_DACL) Case=(TokenSessionId,PULONG) Case=(TokenSessionReference,PULONG) Begin= @GenSetThunk(@ApiName,TokenInformationClass,TokenInformation,TokenInformationLength) End= TemplateName=NtSetSystemInformation Case=(SystemFlagsInformation,PSYSTEM_FLAGS_INFORMATION) Case=(SystemTimeAdjustmentInformation,PSYSTEM_SET_TIME_ADJUST_INFORMATION) Case=(SystemTimeSlipNotification,PHANDLE) Case=(SystemRegistryQuotaInformation,PSYSTEM_REGISTRY_QUOTA_INFORMATION) Case=(SystemPrioritySeperation,PULONG) Case=(SystemExtendServiceTableInformation,PUNICODE_STRING) Case=(SystemFileCacheInformation,PSYSTEM_FILECACHE_INFORMATION) Case=(SystemDpcBehaviorInformation,PSYSTEM_DPC_BEHAVIOR_INFORMATION) Case=(SystemSessionCreate,PULONG) Case=(SystemSessionDetach,PULONG) Case=(SystemComPlusPackage,PULONG) Case=(SystemUnloadGdiDriverInformation) Case=(SystemLoadGdiDriverInformation) SpecialSetCase= //Only valid from kmode. @NL case SystemUnloadGdiDriverInformation: @NL case SystemLoadGdiDriverInformation: @NL return STATUS_PRIVILEGE_NOT_HELD; @NL End= Begin= @GenSetThunk(@ApiName,SystemInformationClass,SystemInformation,SystemInformationLength) End= TemplateName=NtWaitForMultipleObjects NoType=Handles Locals= HANDLE *TempHandles; @NL NT32HANDLE *TempHandlesHost; @NL UINT TempIndex; @NL End= PreCall= TempHandlesHost = (NT32HANDLE *)HandlesHost; @NL TempHandles = Wow64AllocateTemp(sizeof(HANDLE) * Count); @NL try { @NL for(TempIndex = 0; TempIndex < Count; TempIndex++) { @NL @Indent( TempHandles[TempIndex] = (HANDLE)TempHandlesHost[TempIndex]; @NL ) } @NL } except (EXCEPTION_EXECUTE_HANDLER) { @NL return GetExceptionCode (); @NL } @NL Handles = (HANDLE *)TempHandles; @NL End= PostCall= End= TemplateName=NtCompactKeys NoType=KeyArray Locals= HANDLE *TempHandles; @NL NT32HANDLE *TempHandlesHost; @NL UINT TempIndex; @NL End= PreCall= TempHandlesHost = (NT32HANDLE *)KeyArrayHost; @NL TempHandles = Wow64AllocateTemp(sizeof(HANDLE) * Count); @NL try { @NL for(TempIndex = 0; TempIndex < Count; TempIndex++) { @NL @Indent( TempHandles[TempIndex] = (HANDLE)TempHandlesHost[TempIndex]; @NL ) } @NL } except (EXCEPTION_EXECUTE_HANDLER) { @NL return GetExceptionCode (); @NL } @NL KeyArray = (HANDLE *)TempHandles; @NL End= PostCall= End= ;; These APIs take an APC routine. TemplateName=NtQueueApcThread PreCall= Wow64WrapApcProc(&ApcRoutine, &ApcArgument1); End= TemplateName=NtSetTimer PreCall= Wow64WrapApcProc(&TimerApcRoutine, &TimerContext); End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; IO Routines ;; Special handling is needed since they can be asynchronous. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [Macros] MacroName=AsynchronousIoPrecall NumArgs=0 Begin= Wow64WrapApcProc(&ApcRoutine, &ApcContext); @NL { @Indent( @NL NTSTATUS Status; @NL IO_STATUS_BLOCK IosbTemp; @NL FILE_MODE_INFORMATION ModeInfo; @NL @NL // Determine if the file is opened for asynchronous access. @NL Status = NtQueryInformationFile(FileHandle, &IosbTemp, &ModeInfo, sizeof(ModeInfo), FileModeInformation); @NL // This API will only return STATUS_SUCCESS on success; @NL if (STATUS_SUCCESS != Status) { @Indent( @NL RtlRaiseStatus(Status); @NL )} @NL if (!((ModeInfo.Mode & FILE_SYNCHRONOUS_IO_ALERT) || (ModeInfo.Mode & FILE_SYNCHRONOUS_IO_NONALERT))) { @Indent( @NL // In this case, the operation will be asynchronous and a 32bit IO_STATUS_BLOCK will be passed. @NL // Signal the kernel that a 32bit Iosb is being passed in. @NL ApcRoutine = (PIO_APC_ROUTINE)((LONG_PTR)ApcRoutine | 1); @NL // Signal the thunk that a 32bit Iosb is being passed in. @NL IoStatusBlock = (PIO_STATUS_BLOCK)IoStatusBlockHost; @NL AsynchronousIo = TRUE; @NL )} @NL if (ModeInfo.Mode & FILE_SYNCHRONOUS_IO_ALERT) { AlertableIo = TRUE; } )} @NL End= [EFunc] TemplateName=NtLockFile Also=NtReadFile Also=NtWriteFile Also=NtNotifyChangeDirectoryFile Locals= BOOLEAN AsynchronousIo = FALSE; BOOLEAN AlertableIo = FALSE; End= PreCall= @AsynchronousIoPrecall End= TemplateName=NtFsControlFile Also=NtDeviceIoControlFile Locals= BOOLEAN AsynchronousIo = FALSE; BOOLEAN AlertableIo = FALSE; BOOLEAN BuffersRealigned = FALSE; PVOID OriginalInputBuffer; PVOID OriginalOutputBuffer; ULONG Ioctl = pBaseArgs[5]; HANDLE OriginalEvent; End= PreCall= @AsynchronousIoPrecall {@Indent( @NL OriginalInputBuffer = InputBuffer; OriginalOutputBuffer = OutputBuffer; if (IS_IOCTL_REALIGNMENT_REQUIRED (Ioctl)) { if ((InputBuffer != NULL) && (InputBufferLength > 0)) { if (((ULONG_PTR)InputBuffer & ((MAX_NATURAL_ALIGNMENT) - 1)) != 0) { InputBuffer = Wow64AllocateTemp (InputBufferLength); if (InputBuffer == NULL) { RtlRaiseStatus (STATUS_NO_MEMORY); } RetVal = STATUS_SUCCESS; try { RtlCopyMemory (InputBuffer, OriginalInputBuffer, InputBufferLength ); } except (EXCEPTION_EXECUTE_HANDLER) { RetVal = GetExceptionCode (); } if (!NT_SUCCESS (RetVal)) { return RetVal; } BuffersRealigned = TRUE; } } if ((OutputBuffer != NULL) && (OutputBufferLength > 0)) { if (((ULONG_PTR)OutputBuffer & ((MAX_NATURAL_ALIGNMENT) - 1)) != 0) { OutputBuffer = Wow64AllocateTemp (OutputBufferLength); if (OutputBuffer == NULL) { RtlRaiseStatus (STATUS_NO_MEMORY); } BuffersRealigned = TRUE; } } if ((BuffersRealigned == TRUE) && (AsynchronousIo == TRUE)) { OriginalEvent = Event; RetVal = NtCreateEvent (&Event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ); if (!NT_SUCCESS (RetVal)) { RtlRaiseStatus (RetVal); } } } )} @NL End= PostCall= {@Indent( @NL if (BuffersRealigned == TRUE) { if (NT_SUCCESS (RetVal)) { if (RetVal == STATUS_PENDING) { if (AsynchronousIo == TRUE) { RetVal = NtWaitForSingleObject (Event, AlertableIo, NULL); } if (NT_SUCCESS (RetVal)) { if (OutputBuffer != OriginalOutputBuffer) { try { RtlCopyMemory (OriginalOutputBuffer, OutputBuffer, OutputBufferLength ); } except (EXCEPTION_EXECUTE_HANDLER) { RetVal = GetExceptionCode (); } if (!NT_SUCCESS (RetVal)) { RtlRaiseStatus (RetVal); } } if (OriginalEvent != NULL ) { NtSetEvent (OriginalEvent, NULL ); } } } } if (AsynchronousIo == TRUE) { NtClose (Event); } } )} @NL End= TemplateName=NtReadFileScatter Also=NtWriteFileGather Begin= @GenUnsupportedNtApiThunk End= ;; The following is the list of structures passed. ;; None of them are pointer dependent. ;; List taken from ntos\io\dir.c TemplateName=NtQueryDirectoryFile Case=(FileDirectoryInformation,PFILE_DIRECTORY_INFORMATION) Case=(FileFullDirectoryInformation,PFILE_FULL_DIR_INFORMATION) Case=(FileBothDirectoryInformation,PFILE_BOTH_DIR_INFORMATION) Case=(FileNamesInformation,PFILE_NAMES_INFORMATION) Case=(FileObjectIdInformation,PFILE_OBJECT_INFORMATION) Case=(FileQuotaInformation,PFILE_QUOTA_INFORMATION) Case=(FileReparsePointInformation,FILE_REPARSE_POINT_INFORMATION) Case=(FileIdBothDirectoryInformation,PFILE_ID_BOTH_DIR_INFORMATION) Case=(FileIdFullDirectoryInformation,PFILE_ID_FULL_DIRECTORY_INFORMATION) Case=(FileValidDataLengthInformation,PFILE_VALID_DATA_LENGTH_INFORMATION) Locals= BOOL bRealigned=FALSE; PVOID *pTempFileInfo; BOOLEAN AsynchronousIo = FALSE; BOOLEAN AlertableIo = FALSE; End= PreCall= @AsynchronousIoPrecall //[LARGE_INTEGER ALIGNMENT FIXEX] if ( (SIZE_T)(FileInformation) & (0x07) ) { // allocate a buffer with correct alignment, to pass to the Win64 API pTempFileInfo = FileInformation; FileInformation = Wow64AllocateTemp(Length); try { RtlCopyMemory(FileInformation, pTempFileInfo, Length); } except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode (); } bRealigned = TRUE; } End= Begin= @GenDebugNonPtrDepCases(@ApiName,FileInformationClass) End= PostCall= if (!NT_ERROR(RetVal) && bRealigned) { RtlCopyMemory((PVOID)pTempFileInfo, FileInformation, Length); } End= ;; The following is the list of structures passed. ;; None of them are pointer dependent. ;; List taken from ntos\io\iodata.c TemplateName=NtQueryInformationFile Case=(FileBasicInformation,PFILE_BASIC_INFORMATION) Case=(FileStandardInformation,PFILE_STANDARD_INFORMATION) Case=(FileInternalInformation,PFILE_INTERNAL_INFORMATION) Case=(FileEaInformation,PFILE_EA_INFORMATION) Case=(FileAccessInformation,PFILE_ACCESS_INFORMATION) Case=(FileNameInformation,PFILE_NAME_INFORMATION) Case=(FilePositionInformation,PFILE_POSITON_INFORMATION) Case=(FileModeInformation,PFILE_MODE_INFORMATION) Case=(FileAlignmentInformation,PFILE_ALIGNMENT_INFORMATION) Case=(FileAllInformation,PFILE_ALL_INFORMATION) Case=(FileAlternateNameInformation,PFILE_NAME_INFORMATION) Case=(FileStreamInformation,PFILE_STREAM_INFORMATION) Case=(FilePipeInformation,PFILE_PIPE_INFORMATION) Case=(FilePipeLocalInformation,PFILE_PIPE_LOCAL_INFORMATION) Case=(FilePipeRemoteInformation,PFILE_PIPE_REMOTE_INFORMATION) Case=(FileMailslotQueryInformation,PFILE_MAILSLOT_QUERY_INFORMATION) Case=(FileCompressionInformation,PFILE_COMPRESSION_INFORMATION) Case=(FileObjectIdInformation,PFILE_OBJECTID_INFORMATION) Case=(FileQuotaInformation,PFILE_QUOTA_INFORMATION) Case=(FileReparsePointInformation,PFILE_REPARSE_POINT_INFORMATION) Case=(FileNetworkOpenInformation,PFILE_NETWORK_OPEN_INFORMATION) Case=(FileAttributeTagInformation,PFILE_ATTRIBUTE_TAB_INFORMATION) Locals= BOOL bRealigned=FALSE; PVOID *pTempFileInfo; End= PreCall= //[LARGE_INTEGER ALIGNMENT FIXEX] if ( (SIZE_T)(FileInformation) & (0x07) ) { // allocate a buffer with correct alignment, to pass to the Win64 API pTempFileInfo = FileInformation; FileInformation = Wow64AllocateTemp(Length); try { RtlCopyMemory(FileInformation, pTempFileInfo, Length); } except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode (); } bRealigned = TRUE; } End= Begin= @GenDebugNonPtrDepCases(@ApiName,FileInformationClass) End= PostCall= if (!NT_ERROR(RetVal) && bRealigned) { RtlCopyMemory((PVOID)pTempFileInfo, FileInformation, Length); } End= TemplateName=NtSetInformationFile Case=(FileBasicInformation,PFILE_BASIC_INFORMATION) Case=(FileRenameInformation,PFILE_RENAME_INFORMATION) Case=(FileLinkInformation,PFILE_LINK_INFORMATION) Case=(FileDispositionInformation,PFILE_DISPOSITION_INFORMATION) Case=(FilePositionInformation,PFILE_POSITION_INFORMATION) Case=(FileModeInformation,PFILE_MODE_INFORMATION) Case=(FileAllocationInformation,PFILE_ALLOCATION_INFORMATION) Case=(FileEndOfFileInformation,PFILE_END_OF_FILE_INFORMATION) Case=(FilePipeInformation,PFILE_PIPE_INFORMATION) Case=(FilePipeRemoteInformation,PFILE_PIPE_REMOTE_INFORMATION) Case=(FileMailslotSetInformation,PFILE_MAILSLOT_SET_INFORMATION) Case=(FileObjectIdInformation,PFILE_OBJECTID_INFORMATION) Case=(FileCompletionInformation,PFILE_COMPLETION_INFORMATION) Case=(FileMoveClusterInformation,PFILE_MOVE_CLUSTER_INFORMATION) Case=(FileQuotaInformation,PFILE_QUOTA_INFORMATION) Case=(FileTrackingInformation,PFILE_TRACKING_INFORMATION) Case=(FileValidDataLengthInformation,PFILE_VALID_DATA_LENGTH_INFORMATION) Case=(FileShortNameInformation,PFILE_NAME_INFORMATION) Locals= BOOL bRealigned=FALSE; PVOID *pTempFileInfo; End= PreCall= //[LARGE_INTEGER ALIGNMENT FIXEX] if ( (SIZE_T)(FileInformation) & (0x07) ) { // allocate a buffer with correct alignment, to pass to the Win64 API pTempFileInfo = FileInformation; FileInformation = Wow64AllocateTemp(Length); try { RtlCopyMemory(FileInformation, pTempFileInfo, Length); } except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode (); } bRealigned = TRUE; } End= Begin= @GenSetThunk(@ApiName,FileInformationClass,FileInformation,Length) End= PostCall= if (!NT_ERROR(RetVal) && bRealigned) { RtlCopyMemory((PVOID)pTempFileInfo, FileInformation, Length); } End= TemplateName=NtSetVolumeInformationFile Case=(FileFsVolumeInformation,PFILE_FS_VOLUME_INFORMATION) Case=(FileFsLabelInformation,PFILE_FS_LABEL_INFORMATION) Case=(FileFsSizeInformation,PFILE_FS_SIZE_INFORMATION) Case=(FileFsDeviceInformation,PFILE_FS_DEVICE_INFORMATION) Case=(FileFsAttributeInformation,PFILE_FS_ATTRIBUTE_INFORMATION) Case=(FileFsControlInformation,PFILE_FS_CONTROL_INFORMATION) Case=(FileFsFullSizeInformation,PFILE_FS_FULL_SIZE_INFORMATION) Case=(FileFsObjectIdInformation,PFILE_FS_OBJECTID_INFORMATION) Begin= @GenDebugNonPtrDepCases(@ApiName,FsInformationClass) End= TemplateName=NtQueryMultipleValueKey NoType=ValueEntries PreCall= {@Indent(@NL @NL try { @NL NT32KEY_VALUE_ENTRY *Entries32 = (NT32KEY_VALUE_ENTRY *)ValueEntriesHost; @NL ULONG TempEntryCount = EntryCount; @NL PKEY_VALUE_ENTRY Entries64 = (PKEY_VALUE_ENTRY)Wow64AllocateTemp(sizeof(KEY_VALUE_ENTRY) * EntryCount); @NL ValueEntries = Entries64; @NL @NL for(;TempEntryCount > 0; TempEntryCount--, Entries32++, Entries64++) { @NL Entries64->ValueName = Wow64ShallowThunkAllocUnicodeString32TO64(Entries32->ValueName); @NL Entries64->DataLength = (ULONG)Entries32->DataLength; @NL Entries64->DataOffset = (ULONG)Entries32->DataOffset; @NL Entries64->Type = (ULONG)Entries32->Type; @NL }@NL } except( NULL, EXCEPTION_EXECUTE_HANDLER){ @NL return GetExceptionCode (); @NL } @NL )}@NL End= Begin= @GenApiThunk(Wow64@ApiName) End= PostCall= {@Indent(@NL @NL try { @NL NT32KEY_VALUE_ENTRY *Entries32 = (NT32KEY_VALUE_ENTRY *)ValueEntriesHost; @NL ULONG TempEntryCount = EntryCount; @NL PKEY_VALUE_ENTRY Entries64 = ValueEntries;@NL @NL for(;TempEntryCount > 0; TempEntryCount--, Entries32++, Entries64++) { @NL (ULONG)Entries32->DataLength = Entries64->DataLength; @NL (ULONG)Entries32->DataOffset = Entries64->DataOffset; @NL (ULONG)Entries32->Type = Entries64->Type; @NL }@NL } except( NULL, EXCEPTION_EXECUTE_HANDLER){ @NL return GetExceptionCode (); @NL } @NL )}@NL End= ;;All of the data passed is non pointer dependent. ;;list taken from ntos\config\ntapi.c TemplateName=NtSetInformationKey Case=(KeyWriteTimeInformation,PLARGE_INTEGER) Begin= @GenDebugNonPtrDepCases(Wow64@ApiName,KeySetInformationClass) End= ;;These functions are asynchronous, but fortunately the Buffer is not used. ;;The IO_STATUS_BLOCK will be thunked in the kernel. TemplateName=NtNotifyChangeKey NoType=IoStatusBlock PreCall= IoStatusBlock = (PIO_STATUS_BLOCK)IoStatusBlockHost; @NL Wow64WrapApcProc(&ApcRoutine, &ApcContext); End= Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtNotifyChangeKeys NoType=IoStatusBlock NoType=SlaveObjects PreCall= IoStatusBlock = (PIO_STATUS_BLOCK)IoStatusBlockHost; @NL if (0 == Count) { @Indent( @NL SlaveObjects = (POBJECT_ATTRIBUTES)SlaveObjectsHost; @NL )} @NL else { @Indent( @NL if (Count > 1) { @Indent( @NL // The kernel does not support a count > 1 @NL RtlRaiseStatus(STATUS_INVALID_PARAMTER); @NL )} @NL // Count must be 1 @NL SlaveObjects = (POBJECT_ATTRIBUTES)Wow64ShallowThunkAllocObjectAttributes32TO64(SlaveObjectsHost); @NL )} @NL End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Many of the thread control functions are implemented in Wow64. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtContinue Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtSuspendThread Begin= @GenApiThunk(Wow64SuspendThread) End= TemplateName=NtGetContextThread Begin= @GenApiThunk(Wow64GetContextThread) End= TemplateName=NtSetContextThread Begin= @GenApiThunk(Wow64SetContextThread) End= TemplateName=NtCreateThread Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtTerminateThread Begin= @GenApiThunk(Wow64@ApiName) End= TemplateName=NtRaiseException NoType=ExceptionRecord NoType=ContextRecord PreCall= ExceptionRecord = (PEXCEPTION_RECORD)ExceptionRecordHost; @NL ContextRecord = (PCONTEXT)ContextRecordHost; @NL End= Begin= @GenApiThunk(Wow64KiRaiseException) End= TemplateName=NtCallbackReturn Begin= @GenApiThunk(Wow64@ApiName) End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Memory-Management ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtProtectVirtualMemory PreCall= if ( WOW64IsCurrentProcess ( ProcessHandle ) && @NL ( NewProtect & ( PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY ) ) ) { @NL try { @NL CpuFlushInstructionCache ( *BaseAddress, *(ULONG *) RegionSize ); @NL } except (EXCEPTION_EXECUTE_HANDLER) { @NL return GetExceptionCode (); @NL } @NL } @NL End= TemplateName=NtAllocateVirtualMemory PreCall= if (AllocationType & MEM_WRITE_WATCH) { // WOW64 does not suport WriteWatch. See the NtGetWriteWatch thunk. return STATUS_NOT_SUPPORTED; } if (NULL == *BaseAddress && 0 == ZeroBits) { @NL // Force the address to be below 2gb, in case the target process @NL // is 64-bit. @NL ZeroBits = 0x7fffffff; @NL } @NL End= PostCall= if ( ( !NT_ERROR(RetVal) ) && WOW64IsCurrentProcess ( ProcessHandle ) && ( Protect & ( PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY ) ) ) { @NL try { @NL CpuFlushInstructionCache ( *BaseAddress, *(ULONG *) RegionSize ); @NL } except (EXCEPTION_EXECUTE_HANDLER) { @NL return GetExceptionCode (); @NL } @NL } @NL End= TemplateName=NtMapViewOfSection Locals= PVOID ArbitraryUserPointer; @NL PTEB Teb = NtCurrentTeb(); @NL PTEB32 Teb32 = NtCurrentTeb32(); @NL SECTION_IMAGE_INFORMATION Info; @NL WCHAR* DllName; UNICODE_STRING NtNameStr = {0, 0, NULL}; RTL_UNICODE_STRING_BUFFER DosNameStrBuf; End= PreCall= // Copy the 32-bit ArbitraryUserPointer into the 64-bit Teb. It @NL // contains a pointer to the unicode filename of the image being @NL // mapped. @NL ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer; @NL // // Find real (redirected) image name // RtlInitUnicodeStringBuffer(&DosNameStrBuf, 0, 0); DllName = (PVOID)Teb32->NtTib.ArbitraryUserPointer; __try { if (RtlDosPathNameToNtPathName_U(DllName, &NtNameStr, NULL, NULL)) { ULONG Len = NtNameStr.Length; Wow64RedirectFileName(NtNameStr.Buffer, &Len); NtNameStr.Length = Len; if ( NT_SUCCESS(RtlAssignUnicodeStringBuffer(&DosNameStrBuf, &NtNameStr)) && NT_SUCCESS(RtlNtPathNameToDosPathName(0, &DosNameStrBuf, NULL, NULL))) { DllName = DosNameStrBuf.String.Buffer; } } } __except (EXCEPTION_EXECUTE_HANDLER) { // Suppress all exceptions here } Teb->NtTib.ArbitraryUserPointer = DllName; if (NULL == *BaseAddress && 0 == ZeroBits) { @NL // Force the address to be below 2gb, in case the target process @NL // is 64-bit. @NL ZeroBits = 0x7fffffff; @NL } @NL // 32-bit NT has a bug where the alignment check for *SectionOffset @NL // is only 32-bit even though it is a LARGE_INTEGER. 64-bit NT @NL // does a more aggressive check, so double-buffer here. @NL End= PostCall= Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer; @NL if (!NT_ERROR(RetVal)) { @NL if (WOW64IsCurrentProcess(ProcessHandle)) { @NL CpuNotifyDllLoad ( DllName, *BaseAddress, *(ULONG *) ViewSize ); @NL } @NL // For non-x86 images, be sure to return a mismatch warning @NL if (!Wow64IsModule32bitHelper(NtCurrentProcess(), @NL (ULONG64)(*BaseAddress))) { @NL RetVal = STATUS_IMAGE_MACHINE_TYPE_MISMATCH; @NL } @NL } @NL if (NtNameStr.Buffer) RtlFreeHeap(RtlProcessHeap(), 0, NtNameStr.Buffer); RtlFreeUnicodeStringBuffer(&DosNameStrBuf); End= TemplateName=NtUnmapViewOfSection PostCall= if ( ( !NT_ERROR(RetVal) ) && WOW64IsCurrentProcess ( ProcessHandle ) ) @NL CpuNotifyDllUnload ( BaseAddress ); End= TemplateName=NtFlushInstructionCache PostCall= if ( ( !NT_ERROR(RetVal) ) && WOW64IsCurrentProcess ( ProcessHandle ) ) @NL CpuFlushInstructionCache ( BaseAddress, Length ); End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; NT debugger UI APIs ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtWow64DebuggerCall Begin= @ApiProlog @NoFormat( NTSTATUS RetVal = STATUS_SUCCESS; // Don't log this one, as our logging competes with the BREAKPOINT_PRINT logging //LOGPRINT((TRACELOG, "wh@ApiName(@ApiNum) api thunk: @IfArgs(@ArgList(@ArgName: %x@ArgMore(,)))\n"@IfArgs(, @ArgList((@ArgHostName)@ArgMore(,))))); @NL switch (ServiceClassHost) { case 0: // BREAKPOINT_BREAK from sdk\inc\nti386.h WOWASSERT(FALSE); // This should never be hit from usermode break; case 1: // BREAKPOINT_PRINT: // Arg2Host, Output->Length, is ignored DbgPrintEx(Arg3Host, // ComponentId Arg4Host, // Level "%s", (PCHAR)Arg1Host);// String to print break; case 2: // BREAKPOINT_PROMPT: // Arg2Host, Output->Length, is ignored RetVal = DbgPrompt((PCHAR)Arg1Host, // Output->Buffer (PCHAR)Arg3Host, // Input->Buffer Arg4Host); // Input->MaximumLength break; case 3: // BREAKPOINT_LOAD_SYMBOLS case 4: // BREAKPOINT_UNLOAD_SYMBOLS WOWASSERT(FALSE); // This should never be hit from usermode break; default: WOWASSERT(FALSE); break; } return RetVal; } End= TemplateName=NtWaitForDebugEvent NoType=WaitStateChange Locals= DBGUI_WAIT_STATE_CHANGE WaitStateChangeCopy; @NL NT32DBGUI_WAIT_STATE_CHANGE *WaitStateChangeDest; @NL End= PreCall= if (ARGUMENT_PRESENT(WaitStateChangeHost)) { @Indent( @NL WaitStateChange = &WaitStateChangeCopy; @NL WaitStateChangeDest = (NT32DBGUI_WAIT_STATE_CHANGE *)WaitStateChangeHost; @NL )} @NL else { @Indent( @NL WaitStateChange = (DBGUI_WAIT_STATE_CHANGE *)WaitStateChangeHost; @NL )} @NL wait_again: @NL End= PostCall= if (!NT_ERROR(RetVal) && ARGUMENT_PRESENT(WaitStateChange) && RetVal != STATUS_TIMEOUT && RetVal != STATUS_USER_APC && RetVal != STATUS_ALERTED && RetVal != DBG_NO_STATE_CHANGE) { @Indent( @NL WaitStateChangeDest->NewState = WaitStateChange->NewState; @NL @ForceType(PostCall,(&WaitStateChange->AppClientId),(&WaitStateChangeDest->AppClientId),PCLIENT_ID,OUT) @NL switch(WaitStateChange->NewState) { @Indent( @NL case DbgIdle: @NL LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgIdle\n"));@NL goto do_nothing; @NL case DbgReplyPending: @NL @Indent( LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgReplyPending\n")); @NL do_nothing: // Nothing else to do in this case. @NL break; @NL ) @NL case DbgCreateThreadStateChange: @NL @Indent( LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgCreateThreadWaitStateChange\n"));@NL @ForceType(PostCall,(&WaitStateChange->StateInfo.CreateThread),(&WaitStateChangeDest->StateInfo.CreateThread),PDBGUI_CREATE_THREAD,OUT) @NL break; @NL ) @NL case DbgCreateProcessStateChange: @NL @Indent( LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgCreateProcessWaitStateChange\n"));@NL @ForceType(PostCall,(&WaitStateChange->StateInfo.CreateProcessInfo),(&WaitStateChangeDest->StateInfo.CreateProcessInfo),PDBGUI_CREATE_PROCESS,OUT) @NL break; @NL ) @NL case DbgExitThreadStateChange: @NL @Indent( LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgExitThreadWaitStateChange\n"));@NL WOWASSERT(sizeof(NT32DBGKM_EXIT_THREAD) == sizeof(DBGKM_EXIT_THREAD)); @NL RtlCopyMemory(&WaitStateChangeDest->StateInfo.ExitThread, &WaitStateChange->StateInfo.ExitThread, sizeof(DBGKM_EXIT_THREAD)); @NL break; @NL ) @NL case DbgExitProcessStateChange: @NL @Indent( LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgExitProcessWaitStateChange\n")); @NL WOWASSERT(sizeof(NT32DBGKM_EXIT_PROCESS) == sizeof(DBGKM_EXIT_PROCESS)); @NL RtlCopyMemory(&WaitStateChangeDest->StateInfo.ExitProcess, &WaitStateChange->StateInfo.ExitProcess,sizeof(DBGKM_EXIT_PROCESS)); @NL break; @NL ) @NL case DbgExceptionStateChange: @NL LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgBreakpointWaitStateChange\n")); @NL goto do_exception; @NL case DbgBreakpointStateChange: @NL LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgBreakpointWaitStateChange\n")); @NL // // 32-bit x86 debuggers shouldn't expect to receive // native hard coded break points, so bypass them // if ((NT_SUCCESS(Wow64SkipOverBreakPoint(&WaitStateChange->AppClientId, &WaitStateChange->StateInfo.Exception.ExceptionRecord))) && (NT_SUCCESS(NtDebugContinue(DebugObjectHandle, &WaitStateChange->AppClientId, DBG_CONTINUE)))) { LOGPRINT((TRACELOG, "Bypassing native breakpoint at %lx\n", WaitStateChange->StateInfo.Exception.ExceptionRecord.ExceptionAddress)); goto wait_again; } LOGPRINT((ERRORLOG, "32-bit Debugger couldn't skip native breakpoint at %lx\n", WaitStateChange->StateInfo.Exception.ExceptionRecord.ExceptionAddress)); goto do_exception; @NL case DbgSingleStepStateChange: @NL @Indent( LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgSingleStepWaitStateChange\n")); @NL do_exception: WaitStateChangeDest->StateInfo.Exception.FirstChance = WaitStateChange->StateInfo.Exception.FirstChance; @NL ThunkExceptionRecord64To32((&WaitStateChange->StateInfo.Exception.ExceptionRecord),((PEXCEPTION_RECORD32)(&WaitStateChangeDest->StateInfo.Exception.ExceptionRecord)));@NL // BUG, BUG. Do not thunk the entire exception chain at this point. @NL // It appears that NTSD does not use the entire chain, so a hack to get it @NL // is not worth the risk of bugs that it might introduce. Leave it alone for now. @NL break; @NL ) @NL case DbgLoadDllStateChange: @NL @Indent( LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgLoadDllWaitStateChange\n")); @NL if (!Wow64IsModule32bit(&WaitStateChange->AppClientId, (ULONG64)WaitStateChange->StateInfo.LoadDll.BaseOfDll) && (NT_SUCCESS(NtDebugContinue(DebugObjectHandle, &WaitStateChange->AppClientId, DBG_CONTINUE)))) { LOGPRINT((TRACELOG, "Bypassing 64-bit load Dll messege. \n")); goto wait_again; } @ForceType(PostCall,(&WaitStateChange->StateInfo.LoadDll),(&WaitStateChangeDest->StateInfo.LoadDll),PDBGKM_LOAD_DLL,OUT) @NL break; @NL ) @NL case DbgUnloadDllStateChange: @NL @Indent( LOGPRINT((TRACELOG, "DbgUiWaitWaitStateChange: DbgUnloadDllWaitStateChange\n")); @NL @ForceType(PostCall,(&WaitStateChange->StateInfo.UnloadDll),(&WaitStateChangeDest->StateInfo.UnloadDll),PDBGKM_UNLOAD_DLL,OUT) @NL break; @NL ) @NL default: @NL @Indent( LOGPRINT((ERRORLOG, "Unknown DBGUI_WAIT_STATE_CHANGE of %x\n", WaitStateChange->NewState)); WOWASSERT(FALSE); @NL ) @NL )} @NL )} @NL End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; A few CSR thunks that are in NTDLL ;; Most are placeholders and will be going away very soon ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtWow64CsrClientConnectToServer Locals= End= PostCall= {@NL // Copy setting from 64Bit PEB to the 32Bit PEB @NL PPEB32 peb32; peb32 = (PPEB32)(NtCurrentTeb32()->ProcessEnvironmentBlock); @NL peb32->ReadOnlySharedMemoryBase = PtrToUlong(NtCurrentPeb()->ReadOnlySharedMemoryBase); @NL peb32->ReadOnlySharedMemoryHeap = PtrToUlong(NtCurrentPeb()->ReadOnlySharedMemoryHeap); @NL peb32->ReadOnlyStaticServerData = PtrToUlong(NtCurrentPeb()->ReadOnlyStaticServerData); @NL }@NL End= Begin= @GenApiThunk(CsrClientConnectToServer) End= TemplateName=NtWow64CsrNewThread Begin= @GenApiThunk(CsrNewThread) End= TemplateName=NtWow64CsrIdentifyAlertableThread Begin= @GenApiThunk(CsrNewThread) End= TemplateName=NtWow64CsrClientCallServer Begin= @GenPlaceHolderThunk(CsrClientCallServer) End= TemplateName=NtWow64CsrAllocateCaptureBuffer Begin= @GenPlaceHolderThunk(CsrAllocateCaptureBuffer) End= TemplateName=NtWow64CsrFreeCaptureBuffer Begin= @GenPlaceHolderThunk(CsrFreeCaptureBuffer) End= TemplateName=NtWow64CsrAllocateMessagePointer Begin= @GenPlaceHolderThunk(CsrAllocateMessagePointer) End= TemplateName=NtWow64CsrCaptureMessageBuffer Begin= @GenPlaceHolderThunk(CsrCaptureMessageBuffer) End= TemplateName=NtWow64CsrCaptureMessageString Begin= @GenPlaceHolderThunk(CsrCaptureMessageString) End= TemplateName=NtWow64CsrSetPriorityClass Begin= @GenApiThunk(CsrSetPriorityClass) End= TemplateName=NtWow64CsrAllocateCapturePointer Begin= @GenPlaceHolderThunk(CsrAllocateCapturePointer) End= TemplateName=NtWow64CsrGetProcessId Begin= @GenPlaceHolderThunk(CsrGetProcessId) End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; These APIs are only called by the user mode PNP manager ;; which will be in 64bit code in NT64. Since no user apps call ;; them and the structures passed across are rather nasty they will ;; not be supported here. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtGetPlugPlayEvent Begin= @GenUnsupportedNtApiThunk End= ; case PlugPlayControlEnumerateDevice: ; case PlugPlayControlRegisterNewDevice: ; case PlugPlayControlDeregisterDevice: ; case PlugPlayControlInitializeDevice: ; case PlugPlayControlStartDevice: ; case PlugPlayControlEjectDevice: ; case PlugPlayControlUnlockDevice: PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ; case PlugPlayControlQueryAndRemoveDevice: PPLUGPLAY_CONTROL_QUERY_AND_REMOVE_DATA ; case PlugPlayControlUserResponse: PPLUGPLAY_CONTROL_USER_RESPONSE_DATA ; case PlugPlayControlGenerateLegacyDevice PPLUGPLAY_CONTROL_LEGACY_DEVGEN_DATA ; case PlugPlayControlDetectResourceConflict PPLUGPLAY_CONTROL_DEVICE_RESOURCE_DATA ; case PlugPlayControlQueryConflictList PPLUGPLAY_CONTROL_CONFLICT_DATA ; case PlugPlayControlGetInterfaceDeviceList PPLUGPLAY_CONTROL_INTERFACE_LIST_DATA ; case PlugPlayControlProperty PPLUGPLAY_CONTROL_PROPERTY_DATA ; case PlugPlayControlDeviceClassAssociation PPLUGPLAY_CONTROL_CLASS_ASSOCIATION_DATA ; case PlugPlayControlGetRelatedDevice PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA ; case PlugPlayControlGetInterfaceDeviceAlias PPLUGPLAY_CONTROL_INTERFACE_ALIAS_DATA ; case PlugPlayControlDeviceStatus PPLUGPLAY_CONTROL_STATUS_DATA ; case PlugPlayControlGetDeviceDepth PPLUGPLAY_CONTROL_DEPTH_DATA ; case PlugPlayControlQueryDeviceRelations PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA ; case PlugPlayControlTargetDeviceRelation PPLUGPLAY_CONTROL_TARGET_RELATION_DATA ; case PlugPlayControlRequestEject PLUGPLAY_CONTROL_REQUEST_EJECT TemplateName=NtPlugPlayControl Begin= @GenUnsupportedNtApiThunk End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; All channel APIs currently return STATUS_NOT_IMPLEMENTED ;; They will not be supported here either. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtCreateChannel Also=NtOpenChannel Also=NtListenChannel Also=NtSendWaitReplyChannel Also=NtReplyWaitSendChannel Also=NtSetContextChannel Begin= @GenUnsupportedNtApiThunk End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; LPC functions are supported, but the caller must be aware ;; that the header has changed. See ntlpcapi.h for more info. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;These APIs are nothing special. TemplateName=NtCreatePort Also=NtCreateWaitablePort Also=NtSecureConnectPort Begin= @GenApiThunk(@ApiName) End= ; These APIs take messages. TemplateName=NtListenPort Also=NtAcceptConnectPort Also=NtCompleteConnectPort Also=NtRequestPort Also=NtReplyPort Also=NtReplyWaitReplyPort Also=NtReplyWaitReceivePort Also=NtReplyWaitReceivePortEx Also=NtImpersonateClientOfPort Also=NtReadRequestData Also=NtWriteRequestData Begin= @GenApiThunk(@ApiName) End= TemplateName=NtRequestWaitReplyPort Locals= PPORT_MESSAGE OriginalRequestMessage; PPORT_MESSAGE OriginalReplyMessage; UNALIGNED PORT_MESSAGE *UnalignedMessage; ULONG RequestTotalLength, ReplyTotalLength; End= PreCall= OriginalRequestMessage = RequestMessage; OriginalReplyMessage = ReplyMessage; if ((RequestMessage != NULL) && (((ULONG_PTR)RequestMessage & ((MAX_NATURAL_ALIGNMENT) - 1)) != 0)) { UnalignedMessage = RequestMessage; RequestTotalLength = UnalignedMessage->u1.s1.TotalLength; RequestMessage = Wow64AllocateTemp (RequestTotalLength); if (RequestMessage == NULL) { RtlRaiseStatus (STATUS_NO_MEMORY); } RtlCopyMemory (RequestMessage, OriginalRequestMessage, RequestTotalLength); } if ((ReplyMessage != NULL) && (((ULONG_PTR)ReplyMessage & ((MAX_NATURAL_ALIGNMENT) - 1)) != 0)) { if (OriginalReplyMessage == OriginalRequestMessage) { ReplyMessage = RequestMessage; ReplyTotalLength = RequestTotalLength; } else { UnalignedMessage = ReplyMessage; ReplyTotalLength = sizeof (PORT_MESSAGE) + PORT_MAXIMUM_MESSAGE_LENGTH + sizeof(ULONGLONG); ReplyMessage = Wow64AllocateTemp (ReplyTotalLength); if (ReplyMessage == NULL) { RtlRaiseStatus (STATUS_NO_MEMORY); } ReplyMessage->u1.s1.TotalLength = UnalignedMessage->u1.s1.TotalLength; } } End= Begin= @GenApiThunk(@ApiName) End= PostCall= if (OriginalRequestMessage != RequestMessage) { RtlCopyMemory (OriginalRequestMessage, RequestMessage, RequestTotalLength); } if ((OriginalReplyMessage != ReplyMessage) && (ReplyMessage != RequestMessage)) { UnalignedMessage = ReplyMessage; RtlCopyMemory (OriginalReplyMessage, ReplyMessage, UnalignedMessage->u1.s1.TotalLength); } End= ;; This API doesn't have any query fields defined. TemplateName=NtQueryInformationPort Begin= @GenApiThunk(@ApiName) End= ;; This API has more restrictive alignment checking on Win64 than it ;; did on Win32. TemplateName=NtQueryFullAttributesFile Locals= FILE_NETWORK_OPEN_INFORMATION FileInformationLocal; End= PreCall= FileInformation = &FileInformationLocal; End= PostCall= try { RtlCopyMemory((PVOID)FileInformationHost, &FileInformationLocal, sizeof(FileInformationLocal)); } except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode (); } End= TemplateName=NtWriteVirtualMemory PreCall= if (BaseAddress == Buffer && !WOW64IsCurrentProcess(ProcessHandle)) { MEMORY_BASIC_INFORMATION mbi; MEMORY_BASIC_INFORMATION mbiChild; PROCESS_BASIC_INFORMATION pbi; PVOID pLdr; NTSTATUS st; PIMAGE_NT_HEADERS32 NtHeaders; PIMAGE_SECTION_HEADER SectionTable, LastSection, FirstSection, Section; ULONG_PTR SrcVirtualAddress, DestVirtualAddress; ULONG SubSectionSize; // From mi\mi.h: #define MI_ROUND_TO_SIZE(LENGTH,ALIGNMENT) \ (((LENGTH) + ((ALIGNMENT) - 1)) & ~((ALIGNMENT) - 1)) #define PAGE_SIZE_X86 (0x1000) // Attempt to write to some child process, but the address in // this process matches the address in the child. If the address // is within the exe, then this is probably Cygnus. It creates // the child suspended, writes a global var into the child exe, // then resumes the child. Unfortunately, Wx86/WOW64 haven't // reformatted the image yet, so the write goes to the wrong place. st = NtQueryVirtualMemory(NtCurrentProcess(), BaseAddress, MemoryBasicInformation, &mbi, sizeof(mbi), NULL); if (!NT_SUCCESS(st)) { // looks bad, the API call is probably going to fail goto SkipHack; } if (mbi.Type != SEC_IMAGE || mbi.AllocationBase != NtCurrentPeb()->ImageBaseAddress) { // Address isn't within the exe goto SkipHack; } st = NtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryBasicInformation, &mbiChild, sizeof(mbiChild), NULL); if (!NT_SUCCESS(st)) { goto SkipHack; } if (mbi.AllocationBase != mbiChild.AllocationBase || mbi.RegionSize != mbiChild.RegionSize || mbi.Type != mbiChild.Type) { // Possibly different exes in parent and child goto SkipHack; } st = NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); if (!NT_SUCCESS(st)) { goto SkipHack; } st = NtReadVirtualMemory(ProcessHandle, (PVOID)((ULONG_PTR)pbi.PebBaseAddress+FIELD_OFFSET(PEB, Ldr)), &pLdr, sizeof(pLdr), NULL); if (!NT_SUCCESS(st)) { goto SkipHack; } if (pLdr) { // The child process' 64-bit loader sn't initialized. // Assume the parent has already resumed it and knows // what is going on. goto SkipHack; } // Now... figure out where the write really needs to go NtHeaders = (PIMAGE_NT_HEADERS32)RtlImageNtHeader(mbi.AllocationBase); SectionTable = IMAGE_FIRST_SECTION(NtHeaders); LastSection = SectionTable + NtHeaders->FileHeader.NumberOfSections; if (SectionTable->PointerToRawData == SectionTable->VirtualAddress) { // If the first section does not need to be moved then we exclude it // from condideration in passes 1 and 2 FirstSection = SectionTable + 1; } else { FirstSection = SectionTable; } for (Section = FirstSection; Section < LastSection; Section++) { SrcVirtualAddress = (ULONG_PTR)mbi.AllocationBase + Section->PointerToRawData; DestVirtualAddress = (ULONG_PTR)mbi.AllocationBase + (ULONG_PTR)Section->VirtualAddress; // Compute the subsection size SubSectionSize = Section->SizeOfRawData; if (Section->Misc.VirtualSize && SubSectionSize > MI_ROUND_TO_SIZE(Section->Misc.VirtualSize, PAGE_SIZE_X86)) { SubSectionSize = MI_ROUND_TO_SIZE(Section->Misc.VirtualSize, PAGE_SIZE_X86); } if (SubSectionSize != 0 && Section->PointerToRawData != 0) { // subsection has some meaning if ((ULONG_PTR)BaseAddress >= DestVirtualAddress && (ULONG_PTR)BaseAddress < DestVirtualAddress+SubSectionSize) { // the pointer points to within this Destination // range for this subsection. Adjust it to point // into the source range. BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - DestVirtualAddress + SrcVirtualAddress); LOGPRINT((TRACELOG, "whNtWriteVirtualMemory: Adjusted BaseAddress is %p\n", BaseAddress)); break; } } } SkipHack:; } End= ;; per LandyW and Patrick Dussud (owner of the call to this API in msjava), ;; wow64 will not support this. The problem is that the mm uses native ;; page granularity, and we don't have a good way to convert the dirty ;; bits to 4k granularity. The only way to make this API work is to ;; have mm maintain 4k granularity itself. TemplateName=NtGetWriteWatch Begin= @GenUnsupportedNtApiThunk End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; VDM is not supported on NT64 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtVdmControl Begin= @GenUnsupportedNtApiThunk End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Debugging the kernel from a 32bit app is unsupported. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtSystemDebugControl Begin= @GenUnsupportedNtApiThunk End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; AWE functions are not supported on wow64 since ;; they are strongly page size dependent. They will ;; mostly be called from large scale database servers which ;; would benefit from porting. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TemplateName=NtMapUserPhysicalPages Also=NtAllocateUserPhysicalPages Also=NtFreeUserPhysicalPages Also=NtMapUserPhysicalPagesScatter Begin= @GenUnsupportedNtApiThunk End= ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; File header ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [Code] TemplateName=whnt32 CGenBegin= @NoFormat( /* * genthunk generated code: Do Not Modify * PlaceHolderThunk for kernel transitions from ntdll.dll * */ #define _WOW64DLLAPI_ #define SECURITY_USERMODE // needed when including spmlpc.h // For alpha 64 we emulate 4k pages for compatibility w/ intel #define _WHNT32_C_ #include "nt32.h" #include "cgenhdr.h" #include #include #include #include #include #include #if defined(_X86_) #include #include #elif defined(_AMD64_) #include #elif defined(_IA64_) #include #include #else #error "No Target Architecture" #endif #include #include #include "wow64.h" #include "wow64cpu.h" #include "thnkhlpr.h" #include "wow64warn.h" #include "va.h" ASSERTNAME; #if defined(WOW64DOPROFILE) #define APIPROFILE(apinum) (ptewhnt32[(apinum)].HitCount++) #else #define APIPROFILE(apinum) #endif #define _NTBASE_API_ 1 // Return NTSTATUS exception codes for the NtBase APIs #define ROUND_UP(n,size) (((ULONG)(n) + (size - 1)) & ~(size - 1)) #pragma warning(disable : 4311) //Disable 'type cast' pointer truncation warning #pragma warning(disable : 4244) #pragma warning(disable : 4242) #pragma warning(disable : 4047) #if defined(WOW64DOPROFILE) WOW64SERVICE_PROFILE_TABLE_ELEMENT ptewhnt32[]; #endif ) #if defined(WOW64DOPROFILE) @NL @ApiList(#define @ApiName_PROFILE_SUBLIST NULL @NL) #endif @NL #define IS_IOCTL_REALIGNMENT_REQUIRED(Ioctl) ((DEVICE_TYPE_FROM_CTL_CODE(Ioctl) == FILE_DEVICE_FILE_SYSTEM) && ((Ioctl & 3) == METHOD_NEITHER)) @NL @NoFormat( ULONG whNT32DeepThunkSidAndAttributesArray64TO32Length( IN ULONG ArrayLength, IN PSID_AND_ATTRIBUTES Source ) { ULONG RequiredLength = 0; if (!ArrayLength) return RequiredLength; while(ArrayLength-- > 0) { RequiredLength += sizeof(NT32SID_AND_ATTRIBUTES); RequiredLength += RtlLengthSid(Source->Sid); Source++; } return RequiredLength; } ULONG whNT32DeepThunkSidAndAttributesArray32TO64Length( IN ULONG ArrayLength, IN NT32SID_AND_ATTRIBUTES *Source ) { ULONG RequiredLength = 0; if (!ArrayLength) return RequiredLength; while(ArrayLength-- > 0) { RequiredLength += sizeof(SID_AND_ATTRIBUTES); RequiredLength += RtlLengthSid((PSID)Source->Sid); Source++; } return RequiredLength; } NT32SID_AND_ATTRIBUTES * whNT32DeepThunkSidAndAttributesArray64TO32( IN ULONG ArrayLength, OUT NT32SID_AND_ATTRIBUTES *Dest, IN PSID_AND_ATTRIBUTES Source ) { PSID SidDest; NT32SID_AND_ATTRIBUTES *OriginalDest = Dest; if (!ArrayLength) return (NT32SID_AND_ATTRIBUTES *)NULL; SidDest = (PSID)(Dest + ArrayLength); while(ArrayLength-- > 0) { ULONG SidLength; SidLength = RtlLengthSid(Source->Sid); RtlCopySid(SidLength, SidDest, Source->Sid); Dest->Sid = (NT32PSID)SidDest; Dest->Attributes = Source->Attributes; Dest++; Source++; SidDest = (PSID)((PBYTE)SidDest + SidLength); } return OriginalDest; } PSID_AND_ATTRIBUTES whNT32DeepThunkSidAndAttributesArray32TO64( IN ULONG ArrayLength, OUT PSID_AND_ATTRIBUTES Dest, IN NT32SID_AND_ATTRIBUTES *Source ) { PSID SidDest; PSID_AND_ATTRIBUTES OriginalDest = Dest; if (!ArrayLength) return NULL; SidDest = (PSID)(Dest + ArrayLength); while(ArrayLength-- > 0) { ULONG SidLength; SidLength = RtlLengthSid((PSID)Source->Sid); RtlCopySid(SidLength, SidDest, (PSID)Source->Sid); Dest->Sid = (PSID)SidDest; Dest->Attributes = Source->Attributes; Dest++; Source++; SidDest = (PSID)((PBYTE)SidDest + SidLength); } return OriginalDest; } ULONG whNT32DeepThunkTokenGroups64TO32Length( IN PTOKEN_GROUPS Src ) { if (!Src) return 0; return sizeof(ULONG) + whNT32DeepThunkSidAndAttributesArray64TO32Length(Src->GroupCount, Src->Groups); } ULONG whNT32DeepThunkTokenGroups32TO64Length( IN NT32TOKEN_GROUPS *Src ) { if (!Src) return 0; return sizeof(ULONG) + whNT32DeepThunkSidAndAttributesArray32TO64Length(Src->GroupCount, (NT32SID_AND_ATTRIBUTES*)Src->Groups); } NT32TOKEN_GROUPS * whNT32DeepThunkTokenGroups64TO32( OUT NT32TOKEN_GROUPS *Dst, IN PTOKEN_GROUPS Src ) { if (!Src) return (NT32TOKEN_GROUPS *)Src; Dst->GroupCount = Src->GroupCount; whNT32DeepThunkSidAndAttributesArray64TO32(Src->GroupCount, (NT32SID_AND_ATTRIBUTES*)Dst->Groups, Src->Groups); return Dst; } PTOKEN_GROUPS whNT32DeepThunkTokenGroups32TO64( OUT PTOKEN_GROUPS Dst, IN NT32TOKEN_GROUPS *Src ) { if (!Src) return (PTOKEN_GROUPS)Src; Dst->GroupCount = Src->GroupCount; whNT32DeepThunkSidAndAttributesArray32TO64(Src->GroupCount, Dst->Groups, (NT32SID_AND_ATTRIBUTES*)Src->Groups); return Dst; } PTOKEN_GROUPS whNT32ShallowThunkAllocTokenGroups32TO64( IN NT32TOKEN_GROUPS *Src ) { PTOKEN_GROUPS Dest; ULONG GroupCount; UINT c; if(!Src) { return (PTOKEN_GROUPS)Src; } GroupCount = Src->GroupCount; Dest = Wow64AllocateTemp(sizeof(ULONG) + sizeof(SID_AND_ATTRIBUTES) * GroupCount); Dest->GroupCount = GroupCount; for(c=0; cGroups[c].Sid = (PSID)Src->Groups[c].Sid; Dest->Groups[c].Attributes = Src->Groups[c].Attributes; } return Dest; } POBJECT_TYPE_LIST whNT32ShallowThunkAllocObjectTypeList32TO64( IN NT32OBJECT_TYPE_LIST *Src, ULONG Elements ) { POBJECT_TYPE_LIST Dest; SIZE_T c; if (0 == Elements || !Src) { return NULL; } Dest = Wow64AllocateTemp(sizeof(OBJECT_TYPE_LIST)*Elements); for(c=0;c