【问题标题】:DeviceIoControl - GetLastError: ERROR_NOACCESS - 998DeviceIoControl - GetLastError: ERROR_NOACCESS - 998
【发布时间】:2020-11-10 07:58:40
【问题描述】:

我有一个用 C 编写的内核驱动程序,它需要 PCWSTR 类型的文本。什么是相当于发送控制代码的 Delphi 类型?我尝试使用以下代码发送,但GetLastError 报告ERROR_NOACCESS。如何解决?

program Driverloader;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Windows,
  WinSvc,
  SysUtils;

function InstallAndStartDriver(DriverPath, DriverName: WideString; out DriverDevice: THandle): Boolean;
var
  hSCManager, hService: THandle;
  lpServiceArgVectors: PWideChar;
begin
  Result := False;
  hSCManager := 0;
  hSCManager := OpenSCManagerW(nil, nil, SC_MANAGER_ALL_ACCESS);
  if hSCManager <> 0 then
  begin
    try
      Writeln('OpenSCManagerW() - OK');
      hService := 0;
      hService := CreateServiceW(hSCManager, PWideChar(DriverName), PWideChar(DriverName), SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, PWideChar(DriverPath), nil, nil, nil, nil, nil);
      hService := 0;
      lpServiceArgVectors := nil;
      hService := OpenServiceW(hSCManager, PWideChar(DriverName), SERVICE_ALL_ACCESS);
      if hService <> 0 then
      begin
        try
          Writeln('OpenServiceW() - OK');
          if StartServiceW(hService, 0, PWideChar(lpServiceArgVectors)) then
          begin
            Writeln('StartServiceW() - OK');
            Result := True;
          end;
        finally
          CloseServiceHandle(hService);
        end;
      end;
    finally
      CloseServiceHandle(hSCManager);
    end;
  end;
  if Result the
  begin
    DriverDevice := CreateFileW(PWideChar('\\.\' + DriverName), GENERIC_READ or GENERIC_WRITE, 0, PSECURITY_DESCRIPTOR(nil), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    Result := GetLastError() = ERROR_SUCCESS;
    Writeln('CreateFileW() - ' + IntToStr(GetLastError));
  end;
end;

function CTL_CODE(DeviceType, _Function, Method, Access: Cardinal): Cardinal;
begin
  Result := (DeviceType shl 16) or (Access shl 14) or (_Function shl 2) or (Method);
end;

var
  driver: THandle;
  BytesReturned, IOCTL_PATH_DELETE: Cardinal;
  szInput, szOutput: array[0..255] of WideChar;
begin
  try
    IOCTL_PATH_DELETE := CTL_CODE(FILE_DEVICE_UNKNOWN, $500, METHOD_BUFFERED, FILE_ANY_ACCESS);

    lstrcpy(szInput, '\??\C:\Program Files\Software Folder');

    if InstallAndStartDriver(IncludeTrailingPathDelimiter(GetCurrentDir) + 'MyDriver.sys', 'MyDriver', driver) then
    begin
      Writeln('InstallAndStartDriver() - OK');
      Sleep(2000);

      if not DeviceIOControl(driver, IOCTL_PATH_DELETE, PWideChar(szInput[0]), SizeOf(szInput), PWideChar(szOutput[0]), SizeOf(szOutput) * MAXBYTE, BytesReturned, nil) then
        Writeln('DeviceIOControl() - Error: ' + IntToStr(GetLastError))
      else
        Writeln('Success! - ' + szOutput);
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

编辑

在内核驱动程序“Dispatch”方法上接收文本:

NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    PIO_STACK_LOCATION irpStack;
    PVOID ioBuffer;
    ULONG ioControlCode;
    NTSTATUS ntStatus;
    PCWSTR Path;

    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;

    irpStack = IoGetCurrentIrpStackLocation(Irp);

    ioBuffer = Irp->AssociatedIrp.SystemBuffer;

    switch (irpStack->MajorFunction) {

        case IRP_MJ_DEVICE_CONTROL:

            ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

            switch (ioControlCode) {

                case IOCTL_PATH_DELETE: {
                    Path = *(PCWSTR*)ioBuffer; // <-- fails and stop here

                    dprintf("%s\n", Path);

                    break;
                }

                default:
                    Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;

                    break;
            }

            break;
    }

    ntStatus = Irp->IoStatus.Status;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return ntStatus;
}

【问题讨论】:

    标签: delphi delphi-10.3-rio deviceiocontrol


    【解决方案1】:

    在调用DeviceIOControl(IOCTL_PATH_DELETE) 时,当您传入szInputszOutput 时,您将单个WideChar 类型转换为PWideChar,所以无论@ 987654326@ contains 会被误解为内存地址,这是错误的。所以你最终会传入无效的内存地址,这很容易导致ERROR_NOACCESS 错误。

    PWideChar(szInput[0]) 更改为PWideChar(@szInput[0]) 或干脆完全摆脱类型转换,按原样传递@szInput。与szOutput 相同。

    if not DeviceIOControl(driver, IOCTL_PATH_DELETE, @szInput, SizeOf(szInput), @szOutput, SizeOf(szOutput), BytesReturned, nil) then
    

    另外,您在CreateFileW() 上使用GetLastError() 是错误的。 GetLastError() 的返回值是indeterminate,除非CreateFileW() 返回INVALID_HANDLE_VALUE,或者如果您使用dwCreationDisposition=CREATE_ALWAYSdwCreationDisposition=OPEN_ALWAYS,您都没有使用它们,否则将无法使用。

    DriverDevice := CreateFileW(...);
    Result := DriverDevice <> INVALID_HANDLE_VALUE;
    if not Result then
      Writeln('CreateFileW() - Error: ' + IntToStr(GetLastError))
    else
      Writeln('CreateFileW() - Success!');
    

    更新:您的内核驱动程序需要一个指向以空字符结尾的宽字符串的指针。但是您的 Delphi 代码正在传递一个指向以空字符结尾的字符串的指针。这就是您的内核代码崩溃的原因。您需要删除内核代码中不必要的间接级别:

    //Path = *(PCWSTR*)ioBuffer;
    Path = (PCWSTR)ioBuffer;
    

    另外,您对dprintf() 的调用期待一个窄字符串,但您传递给它的是一个宽字符串。要打印宽字符串,需要使用%S而不是%s,例如:

    dprintf("%S\n", Path); 
    

    附带说明,您的 Delphi 代码泄露了 CreateServiceW() 返回的句柄。您需要拨打CloseServiceHandle():

    hService := CreateServiceW(...);
    if hService <> 0 then
      CloseServiceHandle(hService); // <-- ADD THIS!
    lpServiceArgVectors := nil;
    hService := OpenServiceW(...);
    if hService <> 0 then
    begin
     ...
    end;
    

    但是,没有充分的理由立即关闭已创建的服务以重新打开它。使用CreateServiceW() 给你的句柄:

    hService := CreateServiceW(...);
    lpServiceArgVectors := nil;
    if hService <> 0 then
    begin
     ...
    end;
    

    【讨论】:

    • "passing szInput by itself",这不会编译。
    • if not DeviceIOControl(driver, IOCTL_PATH_DELETE, szInput, SizeOf(szInput), szOutput, SizeOf(szOutput), BytesReturned, nil) then - 不编译。
    • @Davison 你能说得更具体点吗?您遇到什么错误?
    • 您在答案中插入的DeviceIoControl() 行未与szInputszOutput 编译为array[0..255] of WideChar;
    • @Davison 我问你实际的编译器错误。在您的 Delphi 版本中,DeviceIoControl() 的声明是什么样的?
    猜你喜欢
    • 2018-01-07
    • 1970-01-01
    • 1970-01-01
    • 2013-02-11
    • 2017-02-05
    • 2014-06-15
    • 2012-07-12
    • 1970-01-01
    • 2017-10-08
    相关资源
    最近更新 更多