精华内容
下载资源
问答
  • windows内核错误处理

    千次阅读 2015-02-11 15:23:01
    人总会犯错误,错误恢复是软件工程的一部分。程序中总会发生异常情况,其中一些源自程序中的Bug,或者在我们的代码中或者在调用我们代码的用户模式应用程序中。另一些涉及到系统装载或硬件的瞬间状态。无论什么原因...

    错误处理


    人总会犯错误,错误恢复是软件工程的一部分。程序中总会发生异常情况,其中一些源自程序中的Bug,或者在我们的代码中或者在调用我们代码的用户模式应用程序中。另一些涉及到系统装载或硬件的瞬间状态。无论什么原因,代码必须能对不寻常的情况作出恰当的反应。在这一节中,我将描述三种错误处理形式:状态代码、结构化异常处理,和bug check。一般,内核模式支持例程通过返回状态代码来报告意外错误。对于正常情况,它们将返回布尔值或者数值而不是正式的状态代码。结构化异常处理为异常事件发生后的清除工作提供了一个标准化方法,它可以避免因为异常事件而导致系统崩溃,异常事件是指诸如被零除或参考无效指针等的意外错误。Bug check实际上就是致命错误的内部名称,对于这种错误,唯一的解决办法就是重启动系统。

    状态代码

    内核模式支持例程(以及你的代码)通过向其调用者返回一个状态代码来表明调用是否成功。NTSTATUS是一个由多个子域组成的32位整数,如图3-2。高两位(Severity)指出状态的严重性——成功、信息、警告、错误。客户位(Customer)是一个标志,完成的IRP将携带一个表明完成状态的状态代码,如果这个状态代码中的Customer标志被设置,那么这个状态代码将被不修改地传回应用程序(应用程序通过调用GetLastError函数获得)。通常,状态代码在返给应用程序前要翻译成Win32错误代码(Win32错误代码可以在KBase Q113996文章中查到)。facility代码指出该状态是由哪个系统部件导致的,一般用于减少开发组之间的代码关联。剩下的16位代码指出实际的状态。


    图3-2. NTSTATUS代码的格式

    我们应该总是检测例程的返回状态。为了不让大量的错误处理代码干扰例子代码所表达的实际意图,我经常省略代码片段中错误检测部分,但你在实际练习中不要效仿我。

    如果状态码高位为0,那么不管其它位是否设置,该状态代码仍旧代表成功。所以,绝对不要用状态代码与0比较来判断操作是否成功,应该使用NT_SUCCESS宏:

    NTSTATUS status = SomeFunction(...);
    if(!NT_SUCCESS(status))
    {
      <handle error>
    }

    不仅要检测调用例程的返回状态,还要向调用你的例程返回状态代码。在上一章中,我讲述了两个驱动程序例程,DriverEntryAddDevice,它们都定义了NTSTATUS返回代码。所以,如果这些例程成功,则应返回STATUS_SUCCESS。如果在某个地方出错,应返回一个适当的错误状态代码,有时函数返回的状态代码就是出错函数返给你的状态代码。

    例如,下面是AddDevice函数的一些初始化代码,包括完整的错误检测代码:

    NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)
    {
      NTSTATUS status;
      PDEVICE_OBJECT fdo;
      status = IoCreateDevice(DriverObject,
                              sizeof(DEVICE_EXTENSION),
                              NULL,
                              FILE_DEVICE_UNKNOWN,
                              0,
                              FALSE,
                              &fdo);
      if (!NT_SUCCESS(status))										<--1
      {
        KdPrint(("IoCreateDevice failed - %X\n", status));							<--2
        return status;
      }
      PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
      pdx->DeviceObject = fdo;
      pdx->Pdo = pdo;
      pdx->state = STOPPED;
      IoInitializeRemoveLock(&pdx->RemoveLock, 0, 0, 255);							<--3
      status = IoRegisterDeviceInterface(pdo, &GUID_SIMPLE, NULL, &pdx->ifname);
      if (!NT_SUCCESS(status))										<--4
      {
        KdPrint(("IoRegisterDeviceInterface failed - %X\n", status));
        IoDeleteDevice(fdo);
        return status;
      }
        ...
    }
    1. 如果IoCreateDevice失败,我们就把这个状态代码返回给上层调用者。注意代码中NT_SUCCESS宏的使用。
    2. 打印出任何错误状态信息是一个好的习惯,尤其是在调试驱动程序时。我将在本章后面讨论如何使用KdPrint
    3. IoInitializeRemoveLock是一个VOID函数,这意味着它不会失败。所以没有必要检测它的状态代码,该函数在第六章讨论。
    4. 如果IoRegisterDeviceInterface失败,我们就需要在返回前做些清除工作;即我们必须删除刚创建的设备对象。

    并不是所有被调用例程导致的错误都要处理,有些错误是可以忽略的。例如,在第八章电源管理中,我将提到带有IRP_MN_POWER_SEQUENCE子类型的电源管理请求,使用它可以避免上电过程中不必要的状态恢复过程。这个请求不仅对你是可选的,而且总线驱动程序在实现该请求上也是可选的。所以如果该请求执行失败,你不用做任何处理,继续其它工作。同样,你也可以忽略IoAllocateErrorLogEntry产生的错误,因为不能向错误登记表添加一条记录根本不是什么严重错误。

    结构化异常处理

    Windows NT提供了一种处理异常情况的方法,它可以帮助我们避免潜在的系统崩溃。结构化异常处理与编译器的代码生成器紧密集成,它允许你在自己的代码段周围加上保护语句,如果被保护代码段中的任何语句出现异常,系统将自动调用异常处理程序。结构化异常处理还便于你提供清除语句,不管控制以何种方式离开被保护代码段,清除代码都会被执行。

    许多读者并不熟悉结构化异常方法,所以我在这里先解释一些基本概念。使用这个方法可以写出更好更稳固的代码。在许多情况下,WDM驱动程序例程接收到的参数都是经过其它代码严格检验的,一般不会成为导致异常的原因。但我们仍要遵循这样基本原则:对用户模式虚拟内存直接引用的代码段应该用结构化异常帧保护起来。这样的引用通常发生在调用MmProbeAndLockPagesProbeForRead,和ProbeForWrite函数时。

    注意
    结构化异常机制可以使内核模式代码在访问一个非法的用户模式地址后避免系统崩溃。但它不能捕捉其它处理器异常,例如被零除或试图访问非法的内核模式地址。从这一点上看,这种机制在内核模式中不象在用户模式中那样具有通用性。

    内核模式程序通过在内存堆栈上建立异常帧来实现结构化异常,这个堆栈就是程序用于参数传递、子程序调用,和分配自动变量所使用的内存堆栈,我不将详细描述这个机制的内部过程,因为该机制在不同的Windows NT平台上会不同。然而,这个机制与在用户模式程序中使用的结构化异常机制相同,你可以在这两个地方找到对这个机制的详细描述,Matt Pietrek的文章“A Crash Course on the Depths of Win32 Structured Exception Handling”Microsoft Systems Journal (January 1997)。Jeff Richter在《Programming Applications for Microsoft Windows, Fourth Edition (Microsoft Press, 1999)》中的专题讨论。

    当异常发生时,操作系统通过扫描堆栈异常帧来寻找相应的异常处理程序。图3-3描绘了这个逻辑流程。每个异常帧都指定一个过滤函数,系统调用这个过滤函数来回答这样的问题:“你能处理这个异常吗?”,当系统找到对应的异常处理程序时,它就回卷堆栈异常帧以恢复处理程序所需要的上下文。回卷过程包括调用同一组过滤函数,并指定一个有这样含义的参数:“我们正在回卷;如果你回答:是,那么立即接管控制”,如果没有代码处理这个异常,那么这里将是一个默认处理例程,该例程使系统崩溃。

    图3-3. 结构化异常处理逻辑

    当使用Microsoft编译器时,你可以使用C/C++的Microsoft扩展,它隐藏了使用某些操作系统原语的复杂性。例如,用__try语句指定被保护代码段,用__finally语句指定终止处理程序,用__except语句指定异常处理程序。

    注意
    最好总使用带有双下划线的关键字,如 __try__finally、和 __except。在C编译单元中,DDK头文件WARNING.H也把 tryfinally、和 except宏定义成这些双下划线的关键字。DDK例子程序使用这些宏而不是直接使用带双下划线的关键字。有一点需要注意:在C++编译单元中, try语句必须与 catch语句成对出现,这是一个完全不同的异常机制,是C++语言的一部分。C++异常机制不能用于驱动程序中,除非你自己从运行时间库中复制出某些基础结构。Microsoft不推荐那样做,因为这将增加驱动程序的内存消耗并增大执行文件的大小。

    Try-Finally块

    try-finally块开始解释结构化异常处理最为容易,用它你可以写出象下面这样的清除代码:

    __try
    {
      <guarded body>
    }
    __finally
    {
      <termination handler>
    }

    在这段伪代码中,被保护体<guarded body>是一系列语句和子例程。通常,这些语句会有副作用,如果没有副作用,就没有必要使用一个try-finally块,因为没有东西需要清除。终止处理程序<termination handler>包含一些恢复语句,用于部分或全部恢复被保护体产生的副作用。

    语法上,try-finally按下面方式工作。首先,计算机执行被保护体<guarded body>。由于某种原因控制离开被保护体,计算机执行终止处理程序。如图3-4。

    图3-4. try-finally中的控制流程

    这里有一个简单的例子:

    LONG counter = 0;
    __try
    {
      ++counter;
    }
    __finally
    {
      --counter;
    }
    KdPrint(("%d\n", counter));

    首先,被保护体执行并把counter变量的值从0增加到1。当控制穿过被保护体右括号后,终止处理程序执行,又把counter减到0。打印出的值将为0。

    下面是一个稍复杂的修改:

    VOID RandomFunction(PLONG pcounter)
    {
      __try
      {
        ++*pcounter;
        return;
      }
      __finally
      {
        --*pcounter;
      }
    }

    该函数的结果是:pcounter指向的整型值不变,不管控制以何种原因离开被保护体,包括通过return语句或goto语句,终止处理程序都将执行。开始,被保护体增加计数器值并执行一个return语句,接着清除代码执行并减计数器值,之后该子程序才真正返回。

    下面例子可以加深你对try-finally语句的理解:

    static LONG counter = 0;
    __try
    {
      ++counter;
      BadActor();
    }
    __finally
    {
      --counter;
    }

    这里我们调用了BadActor函数,我假定该函数将导致某种异常,这将触发堆栈回卷。作为回卷“执行和异常堆栈”过程的一部分,操作系统将调用我们的恢复代码并把counter恢复到以前的值。然后操作系统继续回卷堆栈,所以不论我们在__finally块后有什么代码都得不到执行。

    Try-Except块

    结构化异常处理的另一种使用方式是try-except块:

    __try
    {
      <guarded body>
    }
    __except(<filter expression>)
    {
      <exception handler>
    }

    try-except块中的被保护代码可能会导致异常。你可能调用了象MmProbeAndLockPages这类的内核模式服务函数,这些函数使用来自用户模式的指针,而这些指针并没有做过明确的有效性检测。也许是因为其它原因。但不管什么原因,如果程序在通过被保护代码段时没有发生任何错误,那么控制将转到异常处理代码后面继续执行,你可以认为这是正常情况。如果在你的代码中或任何你调用的子例程中发生了异常,操作系统将回卷堆栈,并对__except语句中的过滤表达式求值。结果将是下面三个值中的一个:

    • EXCEPTION_EXECUTE_HANDLER 数值上等于1,告诉操作系统把控制转移到你的异常处理代码。如果控制走到处理程序的右大括号之外(如执行了return语句或goto语句),那么控制将转到紧接着异常处理代码的后面继续执行。(我看过了平台SDK中关于异常控制返回点的文档,但那不正确)
    • EXCEPTION_CONTINUE_SEARCH 数值上等于0,告诉操作系统你不能处理该异常。系统将继续扫描堆栈以寻找其它处理程序。如果没有找到为该异常提供的处理程序,系统立即崩溃。
    • EXCEPTION_CONTINUE_EXECUTION 数值上等于-1,告诉操作系统返回到异常发生的地方。关于这个值我稍后再谈。

    图3-5显示了try-except块中可能出现的控制路径。

    图3-5. try-except块中的控制流程

    例如,下面代码演示了如何防止接收非法指针。(见光盘中的SEHTEST例子)

    PVOID p = (PVOID) 1;
    __try
    {
      KdPrint(("About to generate exception\n"));
      ProbeForWrite(p, 4, 4);
      KdPrint(("You shouldn't see this message\n"));
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      KdPrint(("Exception was caught\n"));
    }
    KdPrint(("Program kept control after exception\n"));

    ProbeForWrite测试一个数据区域是否有效。在这个例子中,它将导致一个异常,因为我们提供的指针参数没有以4字节边界对齐。然后,异常处理程序得到控制。最后,异常处理完成后控制将转到异常处理程序后面的代码。

    在上面的例子中,如果你返回EXCEPTION_CONTINUE_SEARCH,操作系统将继续回卷堆栈以寻找适合的异常处理程序。这时,异常处理程序和跟在它后面的代码都得不到控制,此时或者系统崩溃或者由更高级的处理程序接管控制。

    不能在内核模式中返回EXCEPTION_CONTINUE_EXECUTION,因为你没有办法改变导致异常的情况,所以就不能实现重试。

    注意,你不能用结构化异常捕获算术异常、页故障,和非法指针引用等等。你必须保证你的代码不产生这样的异常。

    异常过滤表达式

    你也许会惊奇,仅对一个能产生三种值的表达式求值,如何能执行麻烦的错误检测和修正。你可以用C/C++的逗号操作符把多个表达式串联起来:

    __except(expr-1, ... EXCEPTION_CONTINUE_SEARCH){}

    逗号操作符总是放弃它左边的表达式而对右边表达式求值。所以,最后一个表达式的值就是整个表达式的求值结果。

    你可以使用C/C++条件操作符来执行更复杂的表达式计算:

    __except(<some-expr> ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)

    如果some_expr表达式的值为TRUE,则执行你自己的处理程序。否则,通知操作系统继续寻找堆栈中的其它异常处理程序。

    当然,你也可以写一个返回EXCEPTION_Xxx值的子程序:

    LONG EvaluateException()
    {
      if (<some-expr>)
        return EXCEPTION_EXECUTE_HANDLER;
      else
        return EXCEPTION_CONTINUE_SEARCH;
    }
     
    ...
    __except(EvaluateException())
    ...

    如果你需要获得更多的关于异常的信息,有两个函数可以在__except的求值表达式中调用,它们可以提供本次异常的相关信息。实际上,这两个函数是在Microsoft编译器的内部实现的,所以仅能用于特定时刻:

    • GetExceptionCode() 返回当前异常的数值代码。该值是一个NTSTATUS值。该函数仅在__except表达式和其后的异常处理代码中有效。
    • GetExceptionInformation() 返回EXCEPTION_POINTERS结构的地址,该结构包含异常的所有详细信息,在哪发生、发生时寄存器的内容,等等。该函数仅在__except表达式中有效。

    由于这两个函数在使用上的限制,你可以以调用某过滤函数的形式使用它们,象下面这样:

    LONG EvaluateException(NTSTATUS status, PEXCEPTION_POINTERS xp)
    {
      ...
    }
    ...
    __except(EvaluateException(GetExceptionCode(), GetExceptionInformation()))
    ...

    生成异常

    程序中的bug可以导致异常并使系统调用异常处理机制。应用程序开发者应该熟悉Win32 API中的RaiseException函数,它可以生成任意异常。在WDM驱动程序中,你可以调用表3-1列出的例程。由于下面规则,我不能给你举一个使用这些函数的例子:

        仅当你知道存在一个异常处理代码并知道你真正在做什么时,才可以在非任意线程上下文下生成一个异常。

    表3-1. 用于生成异常的服务函数

    服务函数

    描述

    ExRaiseStatus

    用指定状态代码触发异常

    ExRaiseAccessViolation

    触发STATUS_ACCESS_VIOLATION异常

    ExRaiseDatatypeMisalignment

    触发STATUS_DATATYPE_MISALIGNMENT异常

    特别地,不要通过触发异常来告诉你的调用者你在普通执行状态中的信息,你完全可以返回状态代码。应该尽量避免使用异常,因为堆栈回卷机制非常消耗资源。

    一些真实环境中的例子

    尽管建立异常帧然后撕去异常帧会非常消耗资源,但在特殊情况下,驱动程序必须使用结构化异常语法。并且,在一些时间不是特别重要的场合中,如果想要得到更好的程序也可以使用结构化异常机制。

    有一个地方你必须使用结构化异常处理机制,那就是当调用MmProbeAndLockPages函数锁定被MDL(内存描述符表)使用的内存页时,必须建立一个异常处理例程。对于WDM驱动程序,这个问题不经常出现,因为通常你使用的MDL都已经被其它程序探测并锁定(probe-and-lock)过。但是,由于你可以定义使用METHOD_NEITHER缓冲方法的I/O控制(IOCTL)操作,所以你必须按下面方式写代码:

    PMDL mdl = MmCreateMdl(...);
    __try
    {
      MmProbeAndLockPages(mdl, ...);
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      NTSTATUS status = GetExceptionCode();
      ExFreePool((PVOID) mdl);
      return CompleteRequest(Irp, status, 0);
    }

    CompleteRequest是用于实现I/O请求完成机制的辅助函数。在第五章我将详细解释I/O请求和完成I/O请求。ExFreePool是一个内核模式服务例程,它释放由MmCreateMdl等函数创建的内存块。

    另一个真实环境中的例子,考虑一下我在本章前面提到的关于AddDevice函数的错误处理代码。当你进入这个函数后,所有累积的副作用在发现一个错误后都必须消除。结构化异常处理可以使这个函数更具维护性。下面代码略去了一些不相关代码而着重错误处理:

    NTSTATUS AddDevice(...)
    {
      NTSTATUS status = STATUS_UNSUCCESSFUL;
      PDEVICE_OBJECT fdo;
      PDEVICE_EXTENSION pdx;
      status = IoCreateDevice(..., &fdo);
      if (!NT_SUCCESS(status))
        return status;
      __try
      {
        pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
        ...
        IoInitializeRemoveLock(&pdx->RemoveLock, ...);
        status = IoRegisterDeviceInterface(..., &pdx->ifname);
        if (!NT_SUCCESS(status))
          return status;
        ...
      }
      __finally
      {
        if (!NT_SUCCESS(status))
        {
          ...
          if (pdx->ifname.Buffer)
            RtlFreeUnicodeString(&pdx->ifname);
          IoDeleteDevice(fdo);
        }
      }
      return status;
    }

    这里的关键思想是:一旦我们发现某个服务函数执行失败,我们仅仅执行一个return status语句。return status语句触发了终止处理程序的执行,这个处理程序消除了所有累积的副作用。为了利用这种技术,必须先做两件事:第一,由于终止处理程序总是被执行,即便被保护代码无错误发生时也是这样,所以必须知道何时消除副作用何时不用。在这里我们通过测试status变量。如果状态为成功,我们不必做任何清除工作,否则,我们必须彻底清除由于异常给程序带来的副作用。要做的第二件事是了解需要清除哪一个副作用。我们把所有可能产生副作用的变量都初始化为NULL。如果在寄存一个设备接口时失败,那么pdx->ifname中将不会存在一个串,从而也不需要释放操作,如此等等。

    在上面情况中使用try-finally块的一个最大好处是易于代码修改。你可以在IoCreateDevice调用和IoRegisterDeviceInterface调用间加入任何语句,这些语句在成功执行后也可能对函数造成副作用。正确的清除操作就是在终止处理程序中加入与产生副作用相反的补偿语句。相反,如果不用结构化异常块语句,那么你必须在每次状态代码测试后都加入明确的清除代码,这更容易导致错误,你可能从这样的地方退出函数,因此不得不记住每个加入了清除语句的代码位置。

    如果要分配一块内存,我们只需向AddDevice直接插入一些语句即可(粗体部分):

    NTSTATUS AddDevice(...)
    {
      NTSTATUS status = STATUS_UNSUCCESSFUL;
      PDEVICE_OBJECT fdo;
      PDEVICE_EXTENSION pdx;
      status = IoCreateDevice(..., &fdo);
      if (!NT_SUCCESS(status))
        return status;
      __try
      {
        pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
        ...
        pdx->DeviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)
          ExAllocatePool(NonPagedPool, sizeof(USB_DEVICE_DESCRIPTOR));
        if (!pdx->DeviceDescriptor)
          return STATUS_INSUFFICIENT_RESOURCES; 
        IoInitializeRemoveLock(&pdx->RemoveLock, ...);
        status = IoRegisterDeviceInterface(..., &pdx->ifname);
        if (!NT_SUCCESS(status))
          return status;
        ...
      }
      __finally
      {
        if (!NT_SUCCESS(status))
        {
          ...
          if (pdx->ifname.Buffer)
            RtlFreeUnicodeString(&pdx->ifname);
          if (pdx->DeviceDescriptor)
            ExFreePool((PVOID) pdx->DeviceDescriptor); 
          IoDeleteDevice(fdo);
        }
      }
      return status;
    }

    如果不使用结构化异常,那么在剩下的程序中,你必须在每个返回错误的代码后面都加入一个ExFreePool调用。

    Bug Checks

    Bug check是系统检测到的错误,一旦发现这种错误,系统立即以一种可控制的方式关闭。许多内核模式部件运行时都进行一致性检测,如果某个系统部件发现一个不可恢复的错误,将生成一个bug check。如果可能,所有内核模式部件都先登记遇到的错误,然后继续运行,而不是调用KeBugCheckEx,除非这种错误将使系统本身变得不可靠。程序可以在任何IRQL上调用KeBugCheckEx。如果程序发现一个不可恢复的错误,并且该程序继续运行将会破坏系统,那么该程序就调用KeBugCheckEx函数,这个函数将使系统以一种可控制的方式关闭。

    当内核模式中出现不可恢复错误时,会出现一个称为死亡蓝屏(BSOD blue screen of death)的画面,驱动程序开发者应该十分熟悉它。图3-6就是一个例子(出自手写,因为在这种情况下根本不可能运行屏幕截取软件)。在内部,这种错误被称为bug check,它的主要特征是,系统尽可能以正常的方式关闭并弹出一个死亡蓝屏。一旦死亡蓝屏出现,则表明系统已经死掉必须重启动。

    图3-6. “死亡蓝屏”

    可以按下面方式调用KeBugCheckEx:

    KeBugCheckEx(bugcode, info1, info2, info3, info4);

    bugcode是一个数值,指出出错的原因,info1info2等是整型参数,将出现在死亡蓝屏中以帮助程序员了解错误细节。该函数从不返回(!)。

    我不将解释死亡蓝屏中的信息。你可以在Art Baker的《The Windows NT Device Driver Book (Prentice Hall, 1997)》17.3段中找到更多的信息。Microsoft自己的bugcheck代码在DDK头文件bugcodes.h中列出;对该代码的更完整解释以及各种参数的含义可以在KBase文章Q103059 “Descriptions of Bug Codes for Windows NT”中找到。

    如果需要,你也可以创建自己的bugcheck代码。Microsoft定义的值是从1(APC_INDEX_MISMATCH)到0xDE(POOL_CORRUPTION_IN_FILE_AREA)之间的整数。为了创建你自己的bugcheck代码,你需要定义一个整型常量(类似STATUS_SEVERITY_SUCCESS的状态代码),并指出customer标志或非0的facility代码。例如:

    #define MY_BUGCHECK_CODE 0x002A0001
    ...
    KeBugCheckEx(MY_BUGCHECK_CODE, 0, 0, 0, 0);

    使用非0的facility代码(例子中为42)或customer标志(例子中为0)是为了与Microsoft使用的代码区分开。

    现在,我已经告诉你如何生成自己的BSOD,那么我们什么时候使用它呢?回答是决不,或者仅在驱动程序的内部调试中使用。我们不可能写出这样的驱动程序,它发现了一个错误并且只有通过关闭系统才能解决。更好的做法是记录这个错误(使用错误登记工具,将在第九章中描述)并返回一个状态码。

    展开全文
  • windows远程桌面连接时,显示发生身份验证错误,给函数提供的身份无效,不能远程桌面。 初次看到这个错误的时候懵了。访问给的地址一看,发现大概意思是不安全了,微软要更新一下 凭据安全支持提供程序协议 ...
  • 磁盘打不开设备硬件出现致命错误,导致请求失败,是因为这个I盘的文件系统内部结构损坏导致的。要恢复里面的数据就必须要注意,这个盘不能格式化,否则数据会进一步损坏。具体的恢复方法看正文
  • Windows错误配置提权

    千次阅读 2020-02-12 18:14:52
    Windows错误配置提权 系统服务权限配置错误 PowerUp.ps1实战利用 MSF下实战利用 Windows错误配置提权 当攻击者使用其他提权方法无法提权时,就会利用系统中的配置错误来提权。Windows操作系统中的常见配置错误...
    展开全文
  • Windows 10出现错误代码0xc0000001如何解决?

    万次阅读 多人点赞 2019-09-12 18:23:43
    Windows 10开机出现错误代码0xc0000001,是让许多用户苦恼的问题。那是不是遇到这种状况就只能重装系统呢?其实可以先尝试其他的解决方法。 目录 一、Windows 10出现错误代码:0xc0000001的原因分析 二、...

     

    概要
    Windows 10开机出现错误代码0xc0000001,是让许多用户苦恼的问题。那是不是遇到这种状况就只能重装系统呢?其实可以先尝试其他的解决方法。

    windows10出现0xc0000001错误

    目录

    原因分析

    错误代码:0xc0000001表示引导设备可能存在某些问题,或者某些引导文件已损坏。如果计算机的引导扇区发生某些问题,也可能发生这种情况。系统文件损坏或内存损坏是比较常见的原因,最近硬件软件的更改也可能是原因之一。

    0xc0000001错误

    解决方法

    解决方法一:在安全模式中卸载可能有问题的软件

    ①、重启电脑,在启动时按住【Shift+F8】键,打开恢复界面。

    恢复界面

    ②、依次选择界面中的【高级选项>疑难解答>启动设置>重启】

    启动设置

    重启

    ③、待电脑重新启动后,进入启动设置菜单,此时选择安全模式启动

    安全模式

    ④、在开始菜单选择【设定】,选择【应用和功能】,将近期安装的软件卸载,然后重启电脑即可。

    如果是新安装的软件导致的故障,此方法即可解决。

    卸载软件

    解决方法二:通过Windows 恢复环境进行启动修复

    ①、首先用另一台正常启动的电脑在官网下载Windows 10 Media Creation工具
    下载地址:https://www.microsoft.com/en-gb/software-download/windows10

    ②、下载完成后,双击打开工具,同意使用协议,选择【为另一台电脑创建安装介质(U盘、DVD或ISO文件)】

    为另一台电脑创建安装介质

    ③、选择要使用的介质U盘(要保证C盘空间为8G,否则会提示错误。)

    选择U盘为介质

    ④、等待Windows 10安装文件下载,下载完成后,会把安装内容写入U盘中。

    等待下载安装文件

    ⑤、把U盘连接到目标电脑上,并从U盘启动(在BIOS设定修改开机顺序为CD-ROM Drive)。

    BIOS修改开机顺序

    ⑥、成功从U盘启动进入Windows 10安装界面,点击左下角的【修复计算机】

    选择修复计算机

    ⑦、进入Windows RE后,选择【疑难解答>高级选项>启动修复】,按照屏幕上的指示说明完成启动修复即可。

    启动修复

    解决方法三:通过Windows 恢复环境进行系统复原

    复原系统需要管理员账户,如果您没有管理员账户,请先新建一个。另外,进行系统复原,可能会导致后面的文件丢失,建议先备份重要文件。

    ①、参考以上方法二制作Windows 10安装盘,进入Windows 10安装界面后,选择左下角【修复计算机】

    选择修复计算机

    ②、进入Windows RE后,选择【疑难解答>高级选项>系统复原】,输入管理员账户密码,按照提示复原到此前正常系统即可。

    系统复原

    提示:
    担心文件丢失?都叫兽™ 系统救援助您一臂之力!使用都叫兽™ 系统救援创建的启动光盘/USB启动后,使用里面data transfer功能,快速转移您的重要文件,防止数据丢失。

    推荐下载:

    • 都叫兽™ 系统救援

      大小:148MB语言:简体中文

      系统:Windows 2K/XP/7/8/10

       马上下载

    转移文件

    解决方法四:进行磁盘检测,查看是否有坏道

    ①、将磁盘拆除,用外置硬盘盒链接到其他电脑。在别的电脑下载免费的磁盘检测工具:HDD-SCAN,打开工具对磁盘进行扫描。

    扫描磁盘

    ②、等待扫描,查看磁盘哪里出现坏道。如果是0,63,204800的扇区出现坏道就要特别注意了。处理坏道的具体方法请参考“磁盘的坏道检查与修复”文章。

    检测到磁盘坏道

    都叫兽结语:

    今天的分享就到这里,希望能给你带来帮助,记得给我们转发点赞哦!想要获取更多资讯和干货,请关注都叫兽软件熊掌号。

    展开全文
  • 然后进入“恢复”界面,错误代码:0xc0000001. 二、解决方案与过程 可行的解决方案直接见方案三和方案五。 方案一:重启电脑(并没能解决问题) 方案二:在“恢复”界面【Enter】重试 “恢复”界面,【Enter】重试...

    一、遇到问题经过

    今早Windows正常重新启动更新,等更新结束重新启动笔记本就起不来了。
    先是下图的蓝屏,终止代码:Critical_service_failed
    重启后的蓝屏图片
    然后进入“恢复”界面,错误代码:0xc0000001.
    “恢复”界面

    二、解决方案与过程

    可行的解决方案直接见方案三方案五


    方案一:重启电脑(并没能解决问题)

    方案二:在“恢复”界面【Enter】重试

    “恢复”界面,【Enter】重试,进入下图界面:
    SuportAssist界面

    方案三:扫蓝屏图片上的二维码

    扫描二维码,根据 Micorsoft 的蓝屏错误疑难解答进行操作。

    我在安装更新后遇到的“蓝屏重启”问题,根据操作过程,重构其后我未进入到 WinRE 界面,但是我相信这应该是一条可行的方案。

    方案四:致电客服

    先前重启可以解决蓝屏问题,进入到正常使用状态。我天真的想,客服应该遇到过很多这样的情况吧,也许致电客服可以得到专业的指导,让笔记本快速恢复正常吧。

    致电的结果是:客服解决不了,短信提供给我维修点的联系方式及地址。联系维修点,向工作人员提供终止代码和错误代码,工作人员表示如果数据未进行备份,不要自己操作了,需要将笔记本送至维修点进行维修鉴定,可能是硬盘或软件问题。

    方案五:在“恢复”界面【F8】指定启动设置

    “恢复”界面,按键【F8】指定启动设置,而后按键【F4】启用安全模式。

    就好了…

    三、总结

    经验:日常更新漏洞导致的这样的问题,可以F8进入安全模式,卸载最近安装的更新。

    记录下这次的处理过程和经验,作为积累。

    希望下次自己遇到这样的问题不慌,认真的看清楚问题,尝试解决,也希望它不要经常蓝屏!

    展开全文
  • 由于Windows10更新频繁,且使用流量上网,遂通过各种手段将自动更新禁用了,决定阶段性使用手动更新,但是在把自动更新禁用取消掉以后发现无法更新,提示错误错误代码为“0x8024002e”,下面记录一下处理过程。...
  • Windows错误代码全表

    千次阅读 2017-09-11 18:00:38
    代码 错误信息解释  0 操作成功完成。  1 函数不正确。  2 系统找不到指定的文件。  3 系统找不到指定的路径。  4 系统无法打开文件。  5 拒绝访问。  6 句柄无效。  7 存储控制块被损坏。  8 存储空间不足...
  • 常见Windows错误代码含义

    千次阅读 2017-11-21 10:29:21
    MS Windows Error Messages  Code Error Message  0 操作成功完成。  1 功能错误。  2 系统找不到指定的文件。  3 系统找不到指定的路径。  4 系统无法打开文件。  5 拒绝访问。  6 ...
  • Windows异常处理机制

    千次阅读 2019-08-22 21:49:22
    异常是CPU或者程序发生的某种错误,异常处理就是异常产生之后Windows对于产生的错误的一段处理程序。异常分为硬件异常和软件异常。 1.1 硬件异常 硬件异常是由CPU发现的异常,比如说除零异常、内存访问异常,...
  • Windows Error Code(windows错误代码详解)

    千次阅读 2017-12-11 15:05:59
    0 操作成功完成。...8 存储空间不足,无法处理此命令。 9 存储控制块地址无效。 10 环境错误。 11 试图加载格式错误的程序。 12 访问码无效。 13 数据无效。 14 存储器不足,无法完成此操作。 15 系统找
  • 使用Windows 10计算机时,有时您可能会注意到操作中心上出现了错误消息' 重新启动以修复驱动器错误。单击以重新启动您的PC '。即使您单击它,并且系统重新启动,问题也将继续困扰您。要自行解决此错误,请执行以下...
  • 电脑开机出现下面的错误: 首先尝试正常启动能否开机,如果不行 然后尝试按F8通过最后一次启动看是否可以启动起来 如果还是不行,测试一下内存条,按TAB键切换到内存条测试,如果内存条没有问题,那么肯定是系统有...
  • Windows 11 已修复 AMD CPU 性能问题

    千次阅读 热门讨论 2021-10-21 10:56:14
    10月5日,微软终于发布了Windows 11正式版本。Windows 11被微软称为“10年以来最重要的版本更新之一”,说实话Windows 11还是有点让人失望。 且不论Windows 11其他新功能的特点与实用性,就以微软官方一直宣称...
  • WINDOWS XP在系统不当操作或者系统崩溃的时候会自动重新启动蓝屏是系统为重启的原因和错误的地方作解释接下来系统会自动运行CHECK工具来修正这些问题所以这个问题不必特别处理只需要在恢复后注意操作就可以了电脑...
  • 讲述WINDOWS错误处理与参考的系列文章(二)
  • 请使用Windows控制面板中的“程序和功能”选项修复Microsoft Office。 二、解决方法 运行 regedit 进入注册表编辑器 定位到HKEY_CURRENT_USER \ SOFTWARE \ Microsoft \ Office \ 16.0 \ Word \ Options 新建...
  • 上一篇,我们说到了... 接下来要补充的就是错误信息大全,这样我们就能快速方便地查找到错误代码所对应的错误信息了,目前微软WINDOWS系统的错误信息代码编号已经从0排到了15999,而且还在不断地增长,以下列出的均为
  • Windows Api函数使用出现的错误

    千次阅读 2018-07-16 13:13:50
    Windows Api函数使用出现的错误码 作者:Mrzhu007 日期:2018-06-02 博客地址: 金色世界 信息常数 常数值 对应信息 ERROR_SUCCESS 0 操作成功完成。 NO_ERROR 0 操作成功完成。 ERROR_...
  • 0 操作成功完成。 1 功能错误。...8 存储空间不足,无法处理此命令。 9 存储控制块地址无效。 10 环境错误。 11 试图加载格式错误的程序。 12 访问码无效。 13 数据无效。 14 存储器不足,无法完
  • 运行Windows网络疑难解答 检查您的IP地址设置 检查您的ISP的状态 尝试一些命令提示符命令 禁用安全软件 更新无线驱动程序 重置您的网络 这个错误是什么意思? 在我们继续之前,我们应该在您看到此错误时解释网络上...
  • Windows 错误代码

    千次阅读 2018-11-30 12:56:28
    Server 4.0 Error Messages Code Error Message 0 操作成功完成。 1 函数不正确。...存储空间不足,无法处理此命令。 9 存储控制块地址无效。 10 环境不正确。...
  • 1、启动服务:OracleOraDb11g_home1TNSListener 2、启动数据库:OracleServiceORCL服务
  • 最近电脑一直蓝屏,一直在找问题,但是没有按照正确的思路来分析处理。 大致步骤这里写一下: 1.出现蓝屏,重启看Windows日志 2.找到事件描述 3.安装Debugging Tools分析.dmp文件,找到蓝屏错误 4.百度蓝屏解决...
  • Windows 系统错误代码

    万次阅读 2016-06-15 14:49:09
    0-操作成功完成。...8-存储空间不足,无法处理此命令。 9-存储控制块地址无效。 10-环境不正确。 11-试图加载格式不正确的程序。 12-访问码无效。 13-数据无效。 14-存储空间不足,无法完成此操作。 15-
  • windows 错误代码2

    千次阅读 2017-08-22 18:09:41
    KB4605-接收的 KB4606-平均响应时间 (毫秒)4607-网络错误4608-访问的文件4609-后台处理的打印作业4610-系统出错4611-密码违规4612-权限违规4613-访问的通信设备4614-启动的会话4615-重新连接的会话4616-启动失败的...
  • Windows 系统错误代码大全

    千次阅读 2014-12-30 10:41:59
    一、系统错误代码: 0000 操作已成功完成。  0001 错误的函数。  0002 系统找不到指定的文件。  0003 系统找不到指定的路径。  0004 系统无法打开文件。  0005 拒绝访问。  0006 句柄无效。  ...
  • 但是在磁盘替换过程中,Windows管理员有一些规律可循。 首先,需要确定有故障的磁盘。Windows Server 2012 R2提供了一些磁盘故障的参考资料和一些识别数据,包括Event Viewer日志、Server Manager中的Physical Disks...
  • 莫名奇妙的错误。由于是在 cmd 下出现的,我又有随手关窗口的习惯,没办法找到原始的错误记录了,只能凭印象说说。 最初是打开 cmd 想用 pip 更新几个 package,结果报错,大意是找不到 pip 的 script。 非常怪。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 139,984
精华内容 55,993
关键字:

windows错误恢复如何处理