首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DeviceIoControl - GetLastError: ERROR_NOACCESS - 998

DeviceIoControl - GetLastError: ERROR_NOACCESS - 998
EN

Stack Overflow用户
提问于 2020-07-21 01:18:47
回答 1查看 438关注 0票数 2

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

代码语言:javascript
复制
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.

编辑

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

代码语言:javascript
复制
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;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-21 02:10:00

在调用DeviceIOControl(IOCTL_PATH_DELETE)时,当传入szInputszOutput时,您正在将单个WideChar类型转换为PWideChar,因此WideChar包含的任何数值都将被错误地解释为内存地址,这是错误的。因此,您最终会传入无效的内存地址,这可以很容易地解释ERROR_NOACCESS错误。

PWideChar(szInput[0])更改为PWideChar(@szInput[0]),或者干脆完全取消类型转换,将@szInput按原样传递。szOutput也是如此。

代码语言:javascript
复制
if not DeviceIOControl(driver, IOCTL_PATH_DELETE, @szInput, SizeOf(szInput), @szOutput, SizeOf(szOutput), BytesReturned, nil) then

另外,在GetLastError()上使用CreateFileW()也是错误的。GetLastError()的返回值是不确定的,不能使用,除非CreateFileW()返回INVALID_HANDLE_VALUE,如果您使用dwCreationDisposition=CREATE_ALWAYSdwCreationDisposition=OPEN_ALWAYS,则为OR。

代码语言:javascript
复制
DriverDevice := CreateFileW(...);
Result := DriverDevice <> INVALID_HANDLE_VALUE;
if not Result then
  Writeln('CreateFileW() - Error: ' + IntToStr(GetLastError))
else
  Writeln('CreateFileW() - Success!');

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

代码语言:javascript
复制
//Path = *(PCWSTR*)ioBuffer;
Path = (PCWSTR)ioBuffer;

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

代码语言:javascript
复制
dprintf("%S\n", Path); 

另外,您的Delphi代码泄漏了CreateServiceW()返回的句柄。你需要打电话给CloseServiceHandle()

代码语言:javascript
复制
hService := CreateServiceW(...);
if hService <> 0 then
  CloseServiceHandle(hService); // <-- ADD THIS!
lpServiceArgVectors := nil;
hService := OpenServiceW(...);
if hService <> 0 then
begin
 ...
end;

然而,没有充分的理由立即关闭创建的服务仅仅是为了重新打开它。使用CreateServiceW()提供的句柄:

代码语言:javascript
复制
hService := CreateServiceW(...);
lpServiceArgVectors := nil;
if hService <> 0 then
begin
 ...
end;
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63006022

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档