EnglishFrenchGermanItalianPortugueseSpanish

Ребутни меня жестко

В некоторых ситуациях возникает потребность перезагрузить операционную систему прямо из ядра. Когда-то давно я был озадачен такой проблемой, так как существующие способы меня не устраивали по разным причинам. Пришлось копать, искать и спрашивать. В результате были найдены следующие варианты.

В режиме пользователя можно использовать функцию ExitWindowsEx (она ведет в NtShutdownSystem):

BOOL WINAPI ExitWindowsEx(
                                       __in UINT    uFlags,
                                       __in DWORD dwReason
);

Все достаточно подробно описано в MSDN и, конечно, не забываем про включенную Shutdown привилегию.

Давайте рассмотрим варианты, которые нам доступны из режима ядра. Один из них — это использование функции NtShutdownSystem. Конечно, она недокументированная. Реализация для Windows XP выглядит так (вот такой забавный switch, видимо из-за оптимизаций):

NTSTATUS __stdcall NtShutdownSystem(SHUTDOWN_ACTION Action)
{
        POWER_ACTION SystemAction;
 
        if ( Action )
        {
                if ( Action == 1 ) // ShutdownReboot
                {
                        SystemAction = 5; // PowerActionShutdownReset
                }
                else // ShutdownPowerOff
                {
                        if ( Action != 2 )
                                return STATUS_INVALID_PARAMETER;
                        SystemAction = 6; // PowerActionShutdownOff
                }
        }
        else // ShutdownNoReboot
        {
                SystemAction = 4; // PowerActionShutdown
        }
 
        return NtSetSystemPowerState(SystemAction, PowerSystemSleeping3, 0xC0000004u);
}

typedef enum _POWER_ACTION {
        PowerActionNone            = 0,
        PowerActionReserved,
        PowerActionSleep,
        PowerActionHibernate,
        PowerActionShutdown,
        PowerActionShutdownReset,
        PowerActionShutdownOff,
        PowerActionWarmEject
} POWER_ACTION, *PPOWER_ACTION;

Вышеуказанные функции нужно использовать тогда, когда вам необходимо все сделать красиво и чисто.

Следующий вариант — это использовать функцию HalReturnToFirmware. Она также описана в MSDN.

VOID HalReturnToFirmware(IN FIRMWARE_REENTRY Routine);

На вход функция может принимать параметр HalRebootRoutine, что нам собственно и нужно. Честно говоря, меня смущает то, что написано в MSDN:

Requirements

Versions: Available in Microsoft Windows Server 2003 and Windows XP.

DLL: Requires Hal.dll.

Под рукой у меня нет Hal.dll от Windows 2000, так что проверить экспортируется ли она или нет, я не могу, а память меня подводит.

Третий вариант — это спровоцировать BSOD. Шучу, шучу, но близко к правде. Вызовем KeBugcheckEx с параметром POWER_FAILURE_SIMULATE. KeBugcheckEx — это обыкновенная обертка над KeBugcheck2:

int __stdcall KeBugCheck2(int BugCheckCode, )
{
 
        if ( BugCheckCode == POWER_FAILURE_SIMULATE )
        {
                KiScanBugCheckCallbackList();
                HalReturnToFirmware(3); // HalRebootRoutine
        }
}

Знакомая картина, но помнится мне, что на каких-то системах вместо перезагрузки я получал самый натуральный BSOD с POWER_FAILURE_SIMULATE. Однако поехали дальше.

Мне, как любителю минимализма хотелось чего-нибудь быстрого, без проверок. Хоп и готово. Не знаю, что может быть быстрее этого:

WRITE_PORT_UCHAR( (PUCHAR )0x64, 0xFE ); // пишем RESET
                                         // в контроллер клавиатуры

При таких перезагрузках не забывайте предупреждать ваших пользователей о том, чтобы они сохранили свои документы.

Кто какие способы знает еще?

Читайте также:

Share

10 comments to Ребутни меня жестко

  • n0name

    > Под рукой у меня нет Hal.dll от Windows 2000, так что проверить экспортируется ли она или нет, я не могу, а память меня подводит.
    врут, есть такой экспорт, причем даже делаюший то, что требуется.

    Я знаю еще пару способов:
    1. Triple fault.
    2. Jump to BIOS

    • SWW

      Отличные способы, но насколько я понимаю Jump to BIOS будет помуторнее Triple fault. Последний к тому же элегантнее всего того, что я видел. Спасибо! Надо будет дополнить статью.

      • n0name

        мне Triple fault больше всего нравится.
        Мало ли где мой код будет исполняться, может там и клавы не будет.

  • Ск4ыр

    mov al, 0xFE
    out 0×64, al

    Посылает код reset в порт контроллера клавиатуры. Не коросплатформенно, но зато не привязано к особенностям конкретной ОС =)

    • SWW

      Эм, а ты внимательно читал статью? :)

      WRITE_PORT_UCHAR( (PUCHAR )0×64, 0xFE );

      Кстати, кроссплатформенность мне и не была нужна. Пока что, во-всяком случае.

  • asmfan

    >VOID HalReturnToFirmware(IN FIRMWARE_REENTRY Routine);

    typedef enum _FIRMWARE_REENTRY
    {
    HalHaltRoutine,
    HalPowerDownRoutine,
    HalRestartRoutine,
    HalRebootRoutine,
    HalInteractiveModeRoutine,
    HalMaximumRoutine
    } FIRMWARE_REENTRY, *PFIRMWARE_REENTRY;

  • psv

    Самый жесткий вариант — напрямую через чипсет рубануть, тоже команда типа
    WRITE_PORT_UCHAR( (PUCHAR )0×1, PMBASE+Power );
    не скажу на память адреса смещения, где-то в пределах 0х800, надо читать ICHXXX, можно погасить, можно ребутнуть. Жестче некуда, но адреса плавают, надо в спеках копаться, через клавиатуру изящней конечно.
    Может чего забыл, а через один из CRX -регистров разве нельзя?

  • medstrax

    К сожалению ребут и через triple fault, и через out 64h,FEh чреваты непредсказуемым результатом. На большинстве чипов трипл фолт и сброс через контроллер клавы вызывает INIT#. Инит на проце, который не BootStrap — приводит к дауну. Есть правда определенное кол-во чипов, где INIT# вызывается вместе с RESET#. Гарантированной техники здесь вроде нет. Единственное — я бы попробовал
    резет через порт CF9h, однако я не уверен что ВСЕ чипы поддерживают фишку

  • medstrax

    Добавлю. Для SMM-триппера INIT# поровну, SMBASE не меняется

Leave a Reply

  

  

  

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">