Example #1
0
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;
    }
}
Example #2
0
/*
* 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;
}
Example #3
0
/*
* 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;
}
Example #4
0
File: xbox.c Project: adsr/agar
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;
}
Example #5
0
/*
* 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;
}
Example #6
0
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
             );
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
/*
 * @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;
}
Example #10
0
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 );
}
Example #11
0
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 );
            }
        }
    }
}
Example #12
0
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;
}
Example #13
0
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;
    }
}