static DWORD NtOpenObject(OBJECT_TYPE type, PHANDLE phandle, DWORD access, LPCWSTR path) { UNICODE_STRING ustr; RtlInitUnicodeString(&ustr, path); OBJECT_ATTRIBUTES open_struct = { sizeof(OBJECT_ATTRIBUTES), 0x00, &ustr, 0x40 }; if (type != FILE_OBJECT) access |= STANDARD_RIGHTS_READ; IO_STATUS_BLOCK ioStatusBlock; switch (type) { case DIRECTORY_OBJECT: return NtOpenDirectoryObject(phandle, access, &open_struct); case SYMBOLICLINK_OBJECT: return NtOpenSymbolicLinkObject(phandle, access, &open_struct); case MUTANT_OBJECT: return NtOpenMutant(phandle, access, &open_struct); case SECTION_OBJECT: return NtOpenSection(phandle, access, &open_struct); case EVENT_OBJECT: return NtOpenEvent(phandle, access, &open_struct); case SEMAPHORE_OBJECT: return NtOpenSemaphore(phandle, access, &open_struct); case TIMER_OBJECT: return NtOpenTimer(phandle, access, &open_struct); case KEY_OBJECT: return NtOpenKey(phandle, access, &open_struct); case EVENTPAIR_OBJECT: return NtOpenEventPair(phandle, access, &open_struct); case IOCOMPLETION_OBJECT: return NtOpenIoCompletion(phandle, access, &open_struct); case FILE_OBJECT: return NtOpenFile(phandle, access, &open_struct, &ioStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0); default: return ERROR_INVALID_FUNCTION; } }
/* * supQueryKnownDllsLink * * Purpose: * * Expand KnownDlls symbolic link. * * Only internal use, returns FALSE on any error. * */ BOOL supQueryKnownDllsLink( PUNICODE_STRING ObjectName, PVOID *lpKnownDllsBuffer ) { BOOL bResult; HANDLE hLink; SIZE_T memIO; ULONG bytesNeeded; NTSTATUS status; UNICODE_STRING KnownDlls; OBJECT_ATTRIBUTES Obja; LPWSTR lpDataBuffer = NULL; BOOL cond = FALSE; bResult = FALSE; hLink = NULL; do { InitializeObjectAttributes(&Obja, ObjectName, OBJ_CASE_INSENSITIVE, NULL, NULL); status = NtOpenSymbolicLinkObject(&hLink, SYMBOLIC_LINK_QUERY, &Obja); if (!NT_SUCCESS(status)) break; KnownDlls.Buffer = NULL; KnownDlls.Length = 0; KnownDlls.MaximumLength = 0; bytesNeeded = 0; status = NtQuerySymbolicLinkObject(hLink, &KnownDlls, &bytesNeeded); if ((status != STATUS_BUFFER_TOO_SMALL) || (bytesNeeded == 0)) break; if (bytesNeeded >= MAX_USTRING) { bytesNeeded = MAX_USTRING - sizeof(UNICODE_NULL); } memIO = bytesNeeded + sizeof(UNICODE_NULL); lpDataBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, memIO); if (lpKnownDllsBuffer) { KnownDlls.Buffer = lpDataBuffer; KnownDlls.Length = (USHORT)bytesNeeded; KnownDlls.MaximumLength = (USHORT)bytesNeeded + sizeof(UNICODE_NULL); bResult = NT_SUCCESS(NtQuerySymbolicLinkObject(hLink, &KnownDlls, NULL)); if (bResult) { if (lpKnownDllsBuffer) { *lpKnownDllsBuffer = lpDataBuffer; } } } } while (cond); if (hLink != NULL) NtClose(hLink); return bResult; }
/* * supQueryLinkTarget * * Purpose: * * Copying in the input buffer target of a symbolic link. * * Return FALSE on any error. * */ BOOL supQueryLinkTarget( _In_opt_ HANDLE hRootDirectory, _In_ PUNICODE_STRING ObjectName, _Inout_ LPWSTR Buffer, _In_ DWORD cbBuffer //size of buffer in bytes ) { BOOL bResult = FALSE; HANDLE hLink = NULL; DWORD cLength = 0; NTSTATUS status; UNICODE_STRING InfoString; OBJECT_ATTRIBUTES Obja; if ( (ObjectName == NULL) || (Buffer == NULL) || (cbBuffer < sizeof(UNICODE_NULL)) ) { return bResult; } InitializeObjectAttributes(&Obja, ObjectName, OBJ_CASE_INSENSITIVE, hRootDirectory, NULL); status = NtOpenSymbolicLinkObject(&hLink, SYMBOLIC_LINK_QUERY, &Obja); if (!NT_SUCCESS(status) || (hLink == NULL)) { return bResult; } cLength = (cbBuffer - sizeof(UNICODE_NULL)); if (cLength >= MAX_USTRING) { cLength = MAX_USTRING - sizeof(UNICODE_NULL); } InfoString.Buffer = Buffer; InfoString.Length = (USHORT)cLength; InfoString.MaximumLength = (USHORT)(cLength + sizeof(UNICODE_NULL)); status = NtQuerySymbolicLinkObject(hLink, &InfoString, NULL); bResult = (NT_SUCCESS(status)); NtClose(hLink); return bResult; }
char* AG_XBOX_GetDeviceFromLogicalDrive(const char *drive) { HANDLE h; ANSI_STRING szDevice; ANSI_STRING szDrive; OBJECT_ATTRIBUTES attr; ULONG size; char devBuf[256]; char driveL[3]; char driveP[7]; if(!drive || strlen(drive) < 2 || !isalpha(drive[0]) || drive[1] != ':') { return NULL; } Strlcpy(driveL, drive, sizeof(driveL)); Snprintf(driveP, sizeof(driveP), "\\??\\%s", driveL); RtlInitAnsiString(&szDrive, driveP); szDevice.Buffer = devBuf; szDevice.Length = 0xf; szDevice.MaximumLength = 256; InitializeObjectAttributes(&attr, &szDrive, OBJ_CASE_INSENSITIVE, NULL); if(SUCCEEDED(NtOpenSymbolicLinkObject(&h, &attr))) { if(SUCCEEDED(NtQuerySymbolicLinkObject(h, &szDevice, &size))) { Strlcpy(devBuf, szDevice.Buffer, size + 1); CloseHandle(h); return TryStrdup(devBuf); } CloseHandle(h); } return NULL; }
/* * propOpenCurrentObject * * Purpose: * * Opens currently viewed object depending on type * */ BOOL propOpenCurrentObject( _In_ PROP_OBJECT_INFO *Context, _Inout_ PHANDLE phObject, _In_ ACCESS_MASK DesiredAccess ) { BOOL bResult; HANDLE hObject, hDirectory; NTSTATUS status; UNICODE_STRING ustr; OBJECT_ATTRIBUTES obja; IO_STATUS_BLOCK iost; bResult = FALSE; if (Context == NULL) { return bResult; } //we don't know who is it if (Context->TypeIndex == TYPE_UNKNOWN) { SetLastError(ERROR_UNSUPPORTED_TYPE); return bResult; } if (phObject == NULL) { SetLastError(ERROR_OBJECT_NOT_FOUND); return bResult; } if (Context->lpObjectName == NULL) { SetLastError(ERROR_OBJECT_NOT_FOUND); return bResult; } if (Context->lpCurrentObjectPath == NULL) { SetLastError(ERROR_OBJECT_NOT_FOUND); return bResult; } //ports not supported if ( (Context->TypeIndex == TYPE_PORT) || (Context->TypeIndex == TYPE_FLTCOMM_PORT) || (Context->TypeIndex == TYPE_FLTCONN_PORT) || (Context->TypeIndex == TYPE_WAITABLEPORT) ) { SetLastError(ERROR_UNSUPPORTED_TYPE); return bResult; } hDirectory = NULL; if (DesiredAccess == 0) { DesiredAccess = 1; } //handle directory type if (Context->TypeIndex == TYPE_DIRECTORY) { //if this is root, then root hDirectory = NULL if (_strcmpi(Context->lpObjectName, L"\\") != 0) { //else open directory that holds this object hDirectory = supOpenDirectoryForObject(Context->lpObjectName, Context->lpCurrentObjectPath); if (hDirectory == NULL) { SetLastError(ERROR_OBJECT_NOT_FOUND); return bResult; } } //open object in directory RtlSecureZeroMemory(&ustr, sizeof(ustr)); RtlInitUnicodeString(&ustr, Context->lpObjectName); InitializeObjectAttributes(&obja, &ustr, OBJ_CASE_INSENSITIVE, hDirectory, NULL); hObject = NULL; status = NtOpenDirectoryObject(&hObject, DesiredAccess, &obja); //DIRECTORY_QUERY for query SetLastError(RtlNtStatusToDosError(status)); bResult = ((NT_SUCCESS(status)) && (hObject != NULL)); if (bResult && phObject) { *phObject = hObject; } //dont forget to close directory handle if it was opened if (hDirectory != NULL) { NtClose(hDirectory); } return bResult; } //handle window station type if (Context->TypeIndex == TYPE_WINSTATION) { hObject = OpenWindowStation(Context->lpObjectName, FALSE, DesiredAccess); //WINSTA_READATTRIBUTES for query bResult = (hObject != NULL); if (bResult && phObject) { *phObject = hObject; } return bResult; } //handle desktop type if (Context->TypeIndex == TYPE_DESKTOP) { hObject = OpenDesktop(Context->lpObjectName, 0, FALSE, DesiredAccess); //DESKTOP_READOBJECTS for query bResult = (hObject != NULL); if (bResult && phObject) { *phObject = hObject; } return bResult; } //open directory which current object belongs hDirectory = supOpenDirectoryForObject(Context->lpObjectName, Context->lpCurrentObjectPath); if (hDirectory == NULL) { SetLastError(ERROR_OBJECT_NOT_FOUND); return bResult; } RtlSecureZeroMemory(&ustr, sizeof(ustr)); RtlInitUnicodeString(&ustr, Context->lpObjectName); InitializeObjectAttributes(&obja, &ustr, OBJ_CASE_INSENSITIVE, hDirectory, NULL); status = STATUS_UNSUCCESSFUL; hObject = NULL; //handle supported objects switch (Context->TypeIndex) { case TYPE_DEVICE: //FILE_OBJECT status = NtCreateFile(&hObject, DesiredAccess, &obja, &iost, NULL, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0);//generic access rights break; case TYPE_MUTANT: status = NtOpenMutant(&hObject, DesiredAccess, &obja); //MUTANT_QUERY_STATE for query break; case TYPE_KEY: status = NtOpenKey(&hObject, DesiredAccess, &obja); //KEY_QUERY_VALUE for query break; case TYPE_SEMAPHORE: status = NtOpenSemaphore(&hObject, DesiredAccess, &obja); //SEMAPHORE_QUERY_STATE for query break; case TYPE_TIMER: status = NtOpenTimer(&hObject, DesiredAccess, &obja); //TIMER_QUERY_STATE for query break; case TYPE_EVENT: status = NtOpenEvent(&hObject, DesiredAccess, &obja); //EVENT_QUERY_STATE for query break; case TYPE_EVENTPAIR: status = NtOpenEventPair(&hObject, DesiredAccess, &obja); //generic access break; case TYPE_SYMLINK: status = NtOpenSymbolicLinkObject(&hObject, DesiredAccess, &obja); //SYMBOLIC_LINK_QUERY for query break; case TYPE_IOCOMPLETION: status = NtOpenIoCompletion(&hObject, DesiredAccess, &obja); //IO_COMPLETION_QUERY_STATE for query break; case TYPE_SECTION: status = NtOpenSection(&hObject, DesiredAccess, &obja); //SECTION_QUERY for query break; case TYPE_JOB: status = NtOpenJobObject(&hObject, DesiredAccess, &obja); //JOB_OBJECT_QUERY for query break; } SetLastError(RtlNtStatusToDosError(status)); NtClose(hDirectory); bResult = ((NT_SUCCESS(status)) && (hObject != NULL)); if (bResult && phObject) { *phObject = hObject; } return bResult; }
VOID CacheFile( WCHAR *FileName, CHAR cMountPoint ) { WCHAR destination[260]; WCHAR *pszFileName; CHAR bMarkedForCaching = FALSE; WCHAR* slash; WCHAR deviceName[260], dosName[260]; HANDLE directoryHandle; HANDLE linkHandle; OBJECT_ATTRIBUTES objAttrib; UNICODE_STRING directoryName; UNICODE_STRING driveLetter; UNICODE_STRING linkTarget; destination[0] = cMountPoint; destination[1] = ':'; destination[2] = '\\'; destination[3] = '\0'; pszFileName = String_FindLastChar(FileName, '\\') + 1; if (!bMarkedForCaching) // file was a member of a folder marked for caching { String_Concatenate(destination, g_szLastDir); String_Concatenate(destination, L"\\"); } String_Concatenate(destination, pszFileName); File_Copy(FileName, destination, CopyProgress); String_Copy(dosName, FileName); slash = String_FindFirstChar(dosName, '\\'); *slash = L'\0'; UnicodeString_Init(&directoryName, L"\\??"); objAttrib.Length = sizeof(OBJECT_ATTRIBUTES); objAttrib.RootDirectory = NULL; objAttrib.ObjectName = &directoryName; objAttrib.Attributes = OBJ_CASE_INSENSITIVE; objAttrib.SecurityDescriptor = NULL; objAttrib.SecurityQualityOfService = NULL; NtOpenDirectoryObject(&directoryHandle, DIRECTORY_QUERY, &objAttrib); UnicodeString_Init(&driveLetter, dosName); objAttrib.Length = sizeof(OBJECT_ATTRIBUTES); objAttrib.RootDirectory = directoryHandle; objAttrib.ObjectName = &driveLetter; objAttrib.Attributes = OBJ_CASE_INSENSITIVE; objAttrib.SecurityDescriptor = NULL; objAttrib.SecurityQualityOfService = NULL; NtOpenSymbolicLinkObject(&linkHandle, SYMBOLIC_LINK_QUERY, &objAttrib); linkTarget.Length = 0; linkTarget.MaximumLength = 260 * sizeof(WCHAR); linkTarget.Buffer = deviceName; NtQuerySymbolicLinkObject(linkHandle, &linkTarget, NULL); deviceName[linkTarget.Length / sizeof(WCHAR)] = L'\0'; String_Concatenate(deviceName, L"\\"); String_Concatenate(deviceName, slash + 1); R0QueueFile( deviceName, String_GetLength(deviceName) + 1 ); }
NTSTATUS GetSourcePaths( PUNICODE_STRING SourcePath, PUNICODE_STRING SourceRootPath, PUNICODE_STRING SourceRootDir) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING LinkName; UNICODE_STRING SourceName; WCHAR SourceBuffer[MAX_PATH] = {L'\0'}; HANDLE Handle; NTSTATUS Status; ULONG Length; PWCHAR Ptr; RtlInitUnicodeString(&LinkName, L"\\SystemRoot"); InitializeObjectAttributes(&ObjectAttributes, &LinkName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenSymbolicLinkObject(&Handle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) return Status; SourceName.Length = 0; SourceName.MaximumLength = MAX_PATH * sizeof(WCHAR); SourceName.Buffer = SourceBuffer; Status = NtQuerySymbolicLinkObject(Handle, &SourceName, &Length); NtClose(Handle); if (NT_SUCCESS(Status)) { RtlCreateUnicodeString(SourcePath, SourceName.Buffer); /* strip trailing directory */ Ptr = wcsrchr(SourceName.Buffer, L'\\'); if (Ptr) { RtlCreateUnicodeString(SourceRootDir, Ptr); *Ptr = 0; } else RtlCreateUnicodeString(SourceRootDir, L""); RtlCreateUnicodeString(SourceRootPath, SourceName.Buffer); } NtClose(Handle); return STATUS_SUCCESS; }
BOOL GetDeviceObject( WCHAR wcDrive, // drive letter to get info about PUNICODE_STRING pustrLinkTarget) // Output buffer { BOOL bResult; HANDLE hSymbolicLink; #if 0 WCHAR wszLinkName[sizeof(L"\\DosDevices\\A:")]; #else WCHAR wszLinkName[sizeof(L"A:\\")]; #endif UNICODE_STRING ustrLinkName; OBJECT_ATTRIBUTES LinkAttributes; UserAssert( wcDrive >= L'A' && wcDrive <= L'Z' ); UserAssert( pustrLinkTarget != NULL ); /* * Construct the link name by calling RtlDosPathNameToNtPathName, and * strip of the trailing backslash. At the end of this, ustrLinkName * should be of the form \DosDevices\X: */ #if 0 wsprintfW( wszLinkName, L"\\DosDevices\\%lc:", wcDrive ); RtlInitUnicodeString(&ustrLinkName, wszLinkName); #else wsprintfW( wszLinkName, L"%lc:\\", wcDrive); RtlInitUnicodeString(&ustrLinkName, NULL); bResult = RtlDosPathNameToNtPathName_U(wszLinkName, &ustrLinkName, NULL, NULL); if (!bResult) { goto CantDoIt; } ustrLinkName.Length -= sizeof(WCHAR); #endif /* * Get the symbolic link object */ InitializeObjectAttributes(&LinkAttributes, &ustrLinkName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); bResult = NT_SUCCESS( NtOpenSymbolicLinkObject(&hSymbolicLink, GENERIC_READ, &LinkAttributes)); if (!bResult) { goto CantDoIt; } /* * Find out if the device specified is DFS DeviceObject */ pustrLinkTarget->MaximumLength -= sizeof(WCHAR); bResult = NT_SUCCESS( NtQuerySymbolicLinkObject(hSymbolicLink, pustrLinkTarget, NULL)); pustrLinkTarget->MaximumLength += sizeof(WCHAR); if (bResult) { *((WCHAR *)((PSTR)(pustrLinkTarget->Buffer) + pustrLinkTarget->Length)) = UNICODE_NULL; } NtClose(hSymbolicLink); CantDoIt: /* * Free the string buffer that was allocated by RtlDosPathNameToNtPathName_U */ #if 1 if (ustrLinkName.Buffer) { RtlFreeHeap(RtlProcessHeap(), 0, ustrLinkName.Buffer); } #endif return bResult; }
/* * @implemented */ DWORD WINAPI QueryDosDeviceW( LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax ) { POBJECT_DIRECTORY_INFORMATION DirInfo; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString; HANDLE DirectoryHandle; HANDLE DeviceHandle; ULONG ReturnLength; ULONG NameLength; ULONG Length; ULONG Context; BOOLEAN RestartScan; NTSTATUS Status; UCHAR Buffer[512]; PWSTR Ptr; /* Open the '\??' directory */ RtlInitUnicodeString (&UnicodeString, L"\\??"); InitializeObjectAttributes (&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenDirectoryObject (&DirectoryHandle, DIRECTORY_QUERY, &ObjectAttributes); if (!NT_SUCCESS (Status)) { WARN ("NtOpenDirectoryObject() failed (Status %lx)\n", Status); BaseSetLastNTError (Status); return 0; } Length = 0; if (lpDeviceName != NULL) { /* Open the lpDeviceName link object */ RtlInitUnicodeString (&UnicodeString, (PWSTR)lpDeviceName); InitializeObjectAttributes (&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, DirectoryHandle, NULL); Status = NtOpenSymbolicLinkObject (&DeviceHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes); if (!NT_SUCCESS (Status)) { WARN ("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status); NtClose (DirectoryHandle); BaseSetLastNTError (Status); return 0; } /* Query link target */ UnicodeString.Length = 0; UnicodeString.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR); UnicodeString.Buffer = lpTargetPath; ReturnLength = 0; Status = NtQuerySymbolicLinkObject (DeviceHandle, &UnicodeString, &ReturnLength); NtClose (DeviceHandle); NtClose (DirectoryHandle); if (!NT_SUCCESS (Status)) { WARN ("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status); BaseSetLastNTError (Status); return 0; } TRACE ("ReturnLength: %lu\n", ReturnLength); TRACE ("TargetLength: %hu\n", UnicodeString.Length); TRACE ("Target: '%wZ'\n", &UnicodeString); Length = UnicodeString.Length / sizeof(WCHAR); if (Length < ucchMax) { /* Append null-charcter */ lpTargetPath[Length] = UNICODE_NULL; Length++; } else { TRACE ("Buffer is too small\n"); BaseSetLastNTError (STATUS_BUFFER_TOO_SMALL); return 0; } } else { RestartScan = TRUE; Context = 0; Ptr = lpTargetPath; DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer; while (TRUE) { Status = NtQueryDirectoryObject (DirectoryHandle, Buffer, sizeof (Buffer), TRUE, RestartScan, &Context, &ReturnLength); if (!NT_SUCCESS(Status)) { if (Status == STATUS_NO_MORE_ENTRIES) { /* Terminate the buffer */ *Ptr = UNICODE_NULL; Length++; Status = STATUS_SUCCESS; } else { Length = 0; } BaseSetLastNTError (Status); break; } if (!wcscmp (DirInfo->TypeName.Buffer, L"SymbolicLink")) { TRACE ("Name: '%wZ'\n", &DirInfo->Name); NameLength = DirInfo->Name.Length / sizeof(WCHAR); if (Length + NameLength + 1 >= ucchMax) { Length = 0; BaseSetLastNTError (STATUS_BUFFER_TOO_SMALL); break; } memcpy (Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length); Ptr += NameLength; Length += NameLength; *Ptr = UNICODE_NULL; Ptr++; Length++; } RestartScan = FALSE; } NtClose (DirectoryHandle); } return Length; }
VOID DumpObjectDirs( IN PCH DirName, IN ULONG Level ) { OBJECT_ATTRIBUTES ObjectAttributes; STRING Name; HANDLE Handle; ULONG Context, Length; NTSTATUS Status; BOOLEAN RestartScan; POBJECT_DIRECTORY_INFORMATION DirInfo; CHAR DirInfoBuffer[ 256 ]; CHAR SubDirName[ 128 ]; STRING LinkName; STRING LinkTarget; HANDLE LinkHandle; RtlInitString( &Name, DirName ); InitializeObjectAttributes( &ObjectAttributes, &Name, OBJ_OPENIF | OBJ_CASE_INSENSITIVE, NULL, NULL ); NtCreateDirectoryObject( &Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes ); DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer; RestartScan = TRUE; while (TRUE) { Status = NtQueryDirectoryObject( Handle, (PVOID)DirInfo, sizeof( DirInfoBuffer ), TRUE, RestartScan, &Context, &Length ); if (!NT_SUCCESS( Status )) { break; } DbgPrint( "%s%s%Z - %Z", DirName, Level ? "\\" : "", &DirInfo->Name, &DirInfo->TypeName ); if (RtlEqualString( &DirInfo->TypeName, &DirTypeName, TRUE )) { DbgPrint( "\n" ); strcpy( SubDirName, DirName ); if (Level) { strcat( SubDirName, "\\" ); } strcat( SubDirName, DirInfo->Name.Buffer ); DumpObjectDirs( SubDirName, Level+1 ); } else if (RtlEqualString( &DirInfo->TypeName, &LinkTypeName, TRUE )) { strcpy( SubDirName, DirName ); if (Level) { strcat( SubDirName, "\\" ); } strcat( SubDirName, DirInfo->Name.Buffer ); RtlInitString( &LinkName, SubDirName ); InitializeObjectAttributes( &ObjectAttributes, &LinkName, 0, NULL, NULL ); Status = NtOpenSymbolicLinkObject( &LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes ); if (!NT_SUCCESS( Status )) { DbgPrint( " - unable to open symbolic link (%X)\n", Status ); } else { LinkTarget.MaximumLength = sizeof( SubDirName ); LinkTarget.Length = 0; LinkTarget.Buffer = SubDirName; Status = NtQuerySymbolicLinkObject( LinkHandle, &LinkTarget ); if (!NT_SUCCESS( Status )) { DbgPrint( " - unable to query symbolic link target (%X)\n", Status ); } else { DbgPrint( " => %Z\n", &LinkTarget ); } NtClose( LinkHandle ); } } else { DbgPrint( "\n" ); } RestartScan = FALSE; } NtClose( Handle ); }
VOID LsapAdtInitializeDriveLetters( VOID ) /*++ Routine Description: Initializes an array of symbolic link to drive letter mappings for use by auditing code. Arguments: None. Return Value: None. --*/ { UNICODE_STRING LinkName; PUNICODE_STRING DeviceName; OBJECT_ATTRIBUTES Obja; HANDLE LinkHandle; NTSTATUS Status; ULONG i; PWCHAR p; PWCHAR DeviceNameBuffer; ULONG MappingIndex = 0; WCHAR wszDosDevices[sizeof(L"\\DosDevices\\A:") + 1]; wcscpy(wszDosDevices, L"\\DosDevices\\A:"); RtlInitUnicodeString(&LinkName, wszDosDevices); p = (PWCHAR)LinkName.Buffer; // // Make p point to the drive letter in the LinkName string // p = p+12; for( i=0 ; i<26 ; i++ ){ *p = (WCHAR)'A' + (WCHAR)i; InitializeObjectAttributes( &Obja, &LinkName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenSymbolicLinkObject( &LinkHandle, SYMBOLIC_LINK_QUERY, &Obja ); if (NT_SUCCESS( Status )) { // // Open succeeded, Now get the link value // DriveMappingArray[MappingIndex].DriveLetter = *p; DeviceName = &DriveMappingArray[MappingIndex].DeviceName; DeviceNameBuffer = LsapAllocateLsaHeap( MAXIMUM_FILENAME_LENGTH ); DeviceName->Length = 0; DeviceName->MaximumLength = MAXIMUM_FILENAME_LENGTH; DeviceName->Buffer = DeviceNameBuffer; Status = NtQuerySymbolicLinkObject( LinkHandle, DeviceName, NULL ); NtClose(LinkHandle); if ( NT_SUCCESS(Status) ) { MappingIndex++; } else { LsapFreeLsaHeap( DeviceNameBuffer ); RtlInitUnicodeString( DeviceName, NULL ); } } } }
NTSTATUS NTAPI INIT_FUNCTION IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock, OUT PANSI_STRING NtBootPath) { OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; CHAR Buffer[256], AnsiBuffer[256]; WCHAR ArcNameBuffer[64]; ANSI_STRING TargetString, ArcString, TempString; UNICODE_STRING LinkName, TargetName, ArcName; HANDLE LinkHandle; /* Create the Unicode name for the current ARC boot device */ sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName); RtlInitAnsiString(&TargetString, Buffer); Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE); if (!NT_SUCCESS(Status)) return FALSE; /* Initialize the attributes and open the link */ InitializeObjectAttributes(&ObjectAttributes, &TargetName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) { /* We failed, free the string */ RtlFreeUnicodeString(&TargetName); return FALSE; } /* Query the current \\SystemRoot */ ArcName.Buffer = ArcNameBuffer; ArcName.Length = 0; ArcName.MaximumLength = sizeof(ArcNameBuffer); Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL); if (!NT_SUCCESS(Status)) { /* We failed, free the string */ RtlFreeUnicodeString(&TargetName); return FALSE; } /* Convert it to Ansi */ ArcString.Buffer = AnsiBuffer; ArcString.Length = 0; ArcString.MaximumLength = sizeof(AnsiBuffer); Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE); AnsiBuffer[ArcString.Length] = ANSI_NULL; /* Close the link handle and free the name */ ObCloseHandle(LinkHandle, KernelMode); RtlFreeUnicodeString(&TargetName); /* Setup the system root name again */ RtlInitAnsiString(&TempString, "\\SystemRoot"); Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE); if (!NT_SUCCESS(Status)) return FALSE; /* Open the symbolic link for it */ InitializeObjectAttributes(&ObjectAttributes, &LinkName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) return FALSE; /* Destroy it */ NtMakeTemporaryObject(LinkHandle); ObCloseHandle(LinkHandle, KernelMode); /* Now create the new name for it */ sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName); /* Copy it into the passed parameter and null-terminate it */ RtlCopyString(NtBootPath, &ArcString); Buffer[strlen(Buffer) - 1] = ANSI_NULL; /* Setup the Unicode-name for the new symbolic link value */ RtlInitAnsiString(&TargetString, Buffer); InitializeObjectAttributes(&ObjectAttributes, &LinkName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE); if (!NT_SUCCESS(Status)) return FALSE; /* Create it */ Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes, &ArcName); /* Free all the strings and close the handle and return success */ RtlFreeUnicodeString(&ArcName); RtlFreeUnicodeString(&LinkName); ObCloseHandle(LinkHandle, KernelMode); return TRUE; }
int __cdecl main(int argc, char *argv[]) { static PH_COMMAND_LINE_OPTION options[] = { { FI_ARG_HELP, L"h", NoArgumentType }, { FI_ARG_ACTION, L"a", MandatoryArgumentType }, { FI_ARG_NATIVE, L"N", NoArgumentType }, { FI_ARG_PATTERN, L"p", MandatoryArgumentType }, { FI_ARG_CASESENSITIVE, L"C", NoArgumentType }, { FI_ARG_OUTPUT, L"o", MandatoryArgumentType }, { FI_ARG_FORCE, L"f", NoArgumentType }, { FI_ARG_LENGTH, L"L", MandatoryArgumentType } }; PH_STRINGREF commandLine; NTSTATUS status = STATUS_SUCCESS; if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) return 1; PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); if (!PhParseCommandLine( &commandLine, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), PH_COMMAND_LINE_IGNORE_FIRST_PART, FiCommandLineCallback, NULL ) || FiArgHelp) { FiPrintHelp(); return 0; } if (!FiArgFileName && ( FiArgAction && PhEqualString2(FiArgAction, L"dir", TRUE) )) { FiArgFileName = PhCreateStringFromUnicodeString(&NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath); } if (!FiArgAction) { FiPrintHelp(); return 1; } else if (PhEqualString2(FiArgAction, L"map", TRUE)) { WCHAR deviceNameBuffer[7] = L"\\??\\ :"; ULONG i; WCHAR targetNameBuffer[0x100]; UNICODE_STRING targetName; targetName.Buffer = targetNameBuffer; targetName.MaximumLength = sizeof(targetNameBuffer); for (i = 0; i < 26; i++) { HANDLE linkHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING deviceName; deviceNameBuffer[4] = (WCHAR)('A' + i); deviceName.Buffer = deviceNameBuffer; deviceName.Length = 6 * sizeof(WCHAR); InitializeObjectAttributes( &oa, &deviceName, OBJ_CASE_INSENSITIVE, NULL, NULL ); if (NT_SUCCESS(NtOpenSymbolicLinkObject( &linkHandle, SYMBOLIC_LINK_QUERY, &oa ))) { if (NT_SUCCESS(NtQuerySymbolicLinkObject( linkHandle, &targetName, NULL ))) { wprintf(L"%c: %.*s\n", 'A' + i, targetName.Length / 2, targetName.Buffer); } NtClose(linkHandle); } } } else if (!FiArgFileName) { wprintf(L"Error: file name missing.\n"); FiPrintHelp(); return 1; } else if (PhEqualString2(FiArgAction, L"hash", TRUE)) { HANDLE fileHandle; LARGE_INTEGER fileSize; IO_STATUS_BLOCK isb; ULONG mode; if (!FiArgOutput) mode = HASH_MD5; else if (PhEqualString2(FiArgOutput, L"md5", TRUE)) mode = HASH_MD5; else if (PhEqualString2(FiArgOutput, L"sha1", TRUE)) mode = HASH_SHA1; else if (PhEqualString2(FiArgOutput, L"crc32", TRUE)) mode = HASH_CRC32; else { wprintf(L"Invalid hash algorithm. Possibilities: md5, sha1, crc32\n"); return 1; } if (FiCreateFile( &fileHandle, FILE_GENERIC_READ, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY )) { if (NT_SUCCESS(status = PhGetFileSize(fileHandle, &fileSize))) { MD5_CTX md5Context; A_SHA_CTX shaContext; ULONG crc; UCHAR buffer[PAGE_SIZE * 4]; ULONG64 bytesRemaining; bytesRemaining = fileSize.QuadPart; switch (mode) { case HASH_MD5: MD5Init(&md5Context); break; case HASH_SHA1: A_SHAInit(&shaContext); break; case HASH_CRC32: crc = 0; break; } while (bytesRemaining) { status = NtReadFile( fileHandle, NULL, NULL, NULL, &isb, buffer, sizeof(buffer), NULL, NULL ); if (!NT_SUCCESS(status)) break; switch (mode) { case HASH_MD5: MD5Update(&md5Context, buffer, (ULONG)isb.Information); break; case HASH_SHA1: A_SHAUpdate(&shaContext, buffer, (ULONG)isb.Information); break; case HASH_CRC32: crc = PhCrc32(crc, buffer, isb.Information); break; } bytesRemaining -= (ULONG)isb.Information; } if (status == STATUS_END_OF_FILE) status = STATUS_SUCCESS; switch (mode) { case HASH_MD5: { MD5Final(&md5Context); wprintf(L"%s", PhBufferToHexString(md5Context.digest, 16)->Buffer); } break; case HASH_SHA1: { UCHAR hash[20]; A_SHAFinal(&shaContext, hash); wprintf(L"%s", PhBufferToHexString(hash, 20)->Buffer); } break; case HASH_CRC32: { wprintf(L"%08x", crc); } break; } if (!NT_SUCCESS(status)) wprintf(L"Warning: I/O error encountered: %s\n", PhGetNtMessage(status)->Buffer); } NtClose(fileHandle); } if (!NT_SUCCESS(status)) { wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer); return 1; } } else if (PhEqualString2(FiArgAction, L"execute", TRUE)) { if (FiArgNative) { if (!NT_SUCCESS(status = PhCreateProcess( FiFormatFileName(FiArgFileName)->Buffer, FiArgOutput ? &FiArgOutput->sr : NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL ))) { wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer); return 1; } } else { if (!NT_SUCCESS(status = PhCreateProcessWin32( FiArgFileName->Buffer, PhGetString(FiArgOutput), NULL, NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath.Buffer, PH_CREATE_PROCESS_NEW_CONSOLE, NULL, NULL, NULL ))) { wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer); return 1; } } } else if (PhEqualString2(FiArgAction, L"del", TRUE)) { HANDLE fileHandle; if (FiCreateFile( &fileHandle, DELETE | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT )) { FILE_DISPOSITION_INFORMATION dispositionInfo; IO_STATUS_BLOCK isb; dispositionInfo.DeleteFile = TRUE; if (!NT_SUCCESS(status = NtSetInformationFile(fileHandle, &isb, &dispositionInfo, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation))) { wprintf(L"Error deleting file: %s\n", PhGetNtMessage(status)->Buffer); } NtClose(fileHandle); } } else if (PhEqualString2(FiArgAction, L"touch", TRUE)) { HANDLE fileHandle; if (FiCreateFile( &fileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { NtClose(fileHandle); } } else if (PhEqualString2(FiArgAction, L"mkdir", TRUE)) { HANDLE fileHandle; if (FiCreateFile( &fileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FiArgFileName, FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { NtClose(fileHandle); } } else if (PhEqualString2(FiArgAction, L"rename", TRUE)) { HANDLE fileHandle; PPH_STRING newFileName; if (!FiArgOutput) { wprintf(L"Error: new file name missing.\n"); FiPrintHelp(); return 1; } newFileName = FiFormatFileName(FiArgOutput); if (FiCreateFile( &fileHandle, DELETE | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { PFILE_RENAME_INFORMATION renameInfo; ULONG renameInfoSize; IO_STATUS_BLOCK isb; renameInfoSize = FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) + (ULONG)newFileName->Length; renameInfo = PhAllocate(renameInfoSize); renameInfo->ReplaceIfExists = FiArgForce; renameInfo->RootDirectory = NULL; renameInfo->FileNameLength = (ULONG)newFileName->Length; memcpy(renameInfo->FileName, newFileName->Buffer, newFileName->Length); status = NtSetInformationFile(fileHandle, &isb, renameInfo, renameInfoSize, FileRenameInformation); PhFree(renameInfo); if (!NT_SUCCESS(status)) { wprintf(L"Error renaming file: %s\n", PhGetNtMessage(status)->Buffer); } NtClose(fileHandle); } } else if (PhEqualString2(FiArgAction, L"copy", TRUE)) { HANDLE fileHandle; HANDLE outFileHandle; LARGE_INTEGER fileSize; FILE_BASIC_INFORMATION basicInfo; if (!FiArgOutput) { wprintf(L"Error: output file name missing.\n"); FiPrintHelp(); return 1; } if (FiCreateFile( &fileHandle, FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT ) && FiCreateFile( &outFileHandle, FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | SYNCHRONIZE, FiArgOutput, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, !FiArgForce ? FILE_CREATE : FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT )) { #define COPY_BUFFER_SIZE 0x10000 IO_STATUS_BLOCK isb; PVOID buffer; ULONG64 bytesToCopy = FiArgLength; if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize))) { PhSetFileSize(outFileHandle, &fileSize); } buffer = PhAllocatePage(COPY_BUFFER_SIZE, NULL); if (!buffer) { wprintf(L"Error allocating buffer.\n"); return 1; } while (bytesToCopy) { status = NtReadFile( fileHandle, NULL, NULL, NULL, &isb, buffer, bytesToCopy >= COPY_BUFFER_SIZE ? COPY_BUFFER_SIZE : (ULONG)bytesToCopy, NULL, NULL ); if (status == STATUS_END_OF_FILE) { break; } else if (!NT_SUCCESS(status)) { wprintf(L"Error reading from file: %s\n", PhGetNtMessage(status)->Buffer); break; } status = NtWriteFile( outFileHandle, NULL, NULL, NULL, &isb, buffer, (ULONG)isb.Information, // number of bytes read NULL, NULL ); if (!NT_SUCCESS(status)) { wprintf(L"Error writing to output file: %s\n", PhGetNtMessage(status)->Buffer); break; } bytesToCopy -= (ULONG)isb.Information; } PhFreePage(buffer); // Copy basic attributes over. if (NT_SUCCESS(NtQueryInformationFile( fileHandle, &isb, &basicInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ))) { NtSetInformationFile( outFileHandle, &isb, &basicInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ); } NtClose(fileHandle); NtClose(outFileHandle); } } else if (PhEqualString2(FiArgAction, L"dir", TRUE)) { HANDLE fileHandle; UNICODE_STRING pattern; PPH_STRING totalSize, totalAllocSize; if (FiCreateFile( &fileHandle, FILE_LIST_DIRECTORY | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { FipDirFileCount = 0; FipDirDirCount = 0; FipDirTotalSize = 0; FipDirTotalAllocSize = 0; if (FiArgPattern) PhStringRefToUnicodeString(&FiArgPattern->sr, &pattern); PhEnumDirectoryFile( fileHandle, FiArgPattern ? &pattern : NULL, FipEnumDirectoryFileForDir, NULL ); NtClose(fileHandle); totalSize = PhFormatUInt64(FipDirTotalSize, TRUE); totalAllocSize = PhFormatUInt64(FipDirTotalAllocSize, TRUE); wprintf( L"%12I64u file(s) %11s bytes\n" L"%12I64u dir(s) %11s bytes allocated\n", FipDirFileCount, totalSize->Buffer, FipDirDirCount, totalAllocSize->Buffer ); PhDereferenceObject(totalSize); PhDereferenceObject(totalAllocSize); } } else if (PhEqualString2(FiArgAction, L"streams", TRUE)) { HANDLE fileHandle; PVOID streams; PFILE_STREAM_INFORMATION stream; if (FiCreateFile( &fileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { if (NT_SUCCESS(PhEnumFileStreams(fileHandle, &streams))) { stream = PH_FIRST_STREAM(streams); while (stream) { PPH_STRING size, allocationSize; size = PhFormatUInt64(stream->StreamSize.QuadPart, TRUE); allocationSize = PhFormatUInt64(stream->StreamAllocationSize.QuadPart, TRUE); wprintf( L"%11s %11s %.*s\n", size->Buffer, allocationSize->Buffer, stream->StreamNameLength / 2, stream->StreamName ); PhDereferenceObject(size); PhDereferenceObject(allocationSize); stream = PH_NEXT_STREAM(stream); } } NtClose(fileHandle); } } else { wprintf(L"Error: invalid action \"%s\".\n", FiArgAction->Buffer); FiPrintHelp(); return 1; } }