使用组件关闭计算机

时间:2009-03-24 17:38:53

标签: assembly shutdown

如何仅使用汇编代码关闭计算机?

10 个答案:

答案 0 :(得分:10)

您需要说明它是什么处理器系列以及您正在使用的操作系统。还有你的代码运行的特权 - 如果它是内核代码,那么它拥有比用户代码更多的特权。

假设您在Intel x86系列CPU上使用Windows NT系列的某些成员(包括XP或Vista),并且您的代码是正常(用户空间)代码,那么......您需要调用Windows内置的在功能上做到这一点。你不能只执行一些神奇的装配序列。

即使你只能执行一些神奇的汇编序列,你也不会想要 - 你几乎肯定想让操作系统有机会将数据从磁盘缓存写入磁盘,并且其他优雅关闭的东西。

如果您正在为x86编写自己的操作系统,那么您需要查看ACPI(或APM)规范。如果GPL代码没问题,则相关的Linux内核例程为here (ACPI)here (APM)

答案 1 :(得分:9)

这是我用来在DOS模式下关闭电脑多年的29字节程序。

;Connect to APM API
MOV     AX,5301
XOR     BX,BX
INT     15

;Try to set APM version (to 1.2)
MOV     AX,530E
XOR     BX,BX
MOV     CX,0102
INT     15

;Turn off the system
MOV     AX,5307
MOV     BX,0001
MOV     CX,0003
INT     15

;Exit (for good measure and in case of failure)
RET

lookup可以使用Ralf Brown’s Interrupt List DJGPP更多功能。

答案 2 :(得分:6)

在Linux中读取reboot(2)。

感兴趣的文件:

kernel / sys.c kernel / exit.c和arch / x86 / kernel / apm.c

不是一个完整的答案,但我认为这是一个好的开始。我将不得不阅读我的BIOS机器代码,看看他们做了什么。但这部分是机器特定的。如果您知道主板上的IC控制电源,您可以找出所需的IO端口,寄存器和命令。然后设置正确的板/设备状态,然后发出命令关闭电源。

BIOS通过INT 15h ah = 53h管理电源(所谓的高级电源管理又称APM) 在Linux中使用的函数al = 07是设置电源状态cmd。参数bx = 0001h表示所有设备,cx = 0003k表示停止。

答案 3 :(得分:4)

将上面的@larz答案转换为nasm程序集如下:

先决条件:Bochs,Nasm

这个例子是在带有标准软件包的debian wheezy上运行的。

代码(文件名:shutdown.asm):

    org 0x7c00
    jmp main

Shutdown:
    mov ax, 0x1000
    mov ax, ss
    mov sp, 0xf000
    mov ax, 0x5307
    mov bx, 0x0001
    mov cx, 0x0003
    int 0x15

WaitForEnter:
    mov ah, 0
    int 0x16
    cmp al, 0x0D
    jne WaitForEnter
    ret

main:   
    call WaitForEnter
    call Shutdown

times 510-($-$$) db 0
dw 0xaa55

Nasm compliation:

nasm -f bin -o boot_sect.img shutdown.asm

Bochs配置文件(文件名:.bochsrc)与代码(shutdown.asm)在同一目录中

display_library: sdl
floppya: 1_44=boot_sect.img, status=inserted
boot: a

*注意我正在使用bochs的sdl库,这是bochs本身的单独包装

运行bochs(与之前相同的目录):

bochs

按Enter键关闭

*注意我不确定Shutdown标签和WaitForEnter标签之间的所有行都是必需的

答案 4 :(得分:3)

来自arch / x86 / kernel / amp.c:

/**
 * apm_power_off - ask the BIOS to power off
 *
 * Handle the power off sequence. This is the one piece of code we
 * will execute even on SMP machines. In order to deal with BIOS
 * bugs we support real mode APM BIOS power off calls. We also make
 * the SMP call on CPU0 as some systems will only honour this call
 * on their first cpu.
 */

static void apm_power_off(void)
{
 unsigned char po_bios_call[] = {
  0xb8, 0x00, 0x10, /* movw  $0x1000,ax  */
  0x8e, 0xd0,  /* movw  ax,ss       */
  0xbc, 0x00, 0xf0, /* movw  $0xf000,sp  */
  0xb8, 0x07, 0x53, /* movw  $0x5307,ax  */
  0xbb, 0x01, 0x00, /* movw  $0x0001,bx  */
  0xb9, 0x03, 0x00, /* movw  $0x0003,cx  */
  0xcd, 0x15  /* int   $0x15       */
 };

 /* Some bioses don't like being called from CPU != 0 */
 if (apm_info.realmode_power_off) {
  set_cpus_allowed_ptr(current, cpumask_of(0));
  machine_real_restart(po_bios_call, sizeof(po_bios_call));
 } else {
  (void)set_system_power_state(APM_STATE_OFF);
 }
}

代码现在位于apm_32.c。搜索“apm_power_off”。

答案 5 :(得分:2)

这很容易。另外,伙计们,OP可能正在为他自己的电源经理工作。我正在做同样的事情。 这是一个允许用户关闭机器的示例。很简单,只需给用户一个OK和取消的消息框。如果用户点击OK,机器将关闭,如果用户点击取消,程序将退出。它是在基于NT的Windows版本上测试的,应该适用于旧版本,如ME,95和98.

这是我自己的代码,每个人都可以自由使用它。 http://pastebin.com/ccw3mWtw

答案 6 :(得分:1)

调用kernel32.dll中的ExitWindowsEx API函数

答案 7 :(得分:1)

您可以尝试在x86 Linux机器上使用shellcode,这不是恶意代码,只是为了好玩。此shellcode仅执行/sbin/poweroff,仅在Debian版本5.0.5上经过测试。

#include <stdio.h>
#include <string.h>

char *shellcode = "\x31\xc0\x50\x68\x72\x6f\x66"
                  "\x66\x68\x70\x6f\x77\x65\x68"
                  "\x6e\x2f\x2f\x2f\x68\x2f\x73"
                  "\x62\x69\x89\xe3\x50\x53\x89"
                  "\xe1\xb0\x0b\xcd\x80\x31\xc0"
                  "\x50\x89\xe3\xb0\x01\xcd\x80";

int main(int argc, char *argv[]) {
    printf("shellcode length ->  %d bytes\n", (int)strlen(shellcode));
    int (*ret)()=(int(*)())shellcode;
    ret();

    return 0;
}

或者此shellcode执行shutdown -h now(以root运行):

#include <stdio.h>
#include <string.h>

char *shellcode =  "\x31\xc0\x31\xd2\x50\x66\x68\x2d"
                   "\x68\x89\xe7\x50\x6a\x6e\x66\xc7"
                   "\x44\x24\x01\x6f\x77\x89\xe7\x50"
                   "\x68\x64\x6f\x77\x6e\x68\x73\x68"
                   "\x75\x74\x68\x6e\x2f\x2f\x2f\x68"
                   "\x2f\x73\x62\x69\x89\xe3\x52\x56"
                   "\x57\x53\x89\xe1\xb0\x0b\xcd\x80";

int main(int argc, char *argv[]) {
    printf("shellcode length ->  %d bytes\n", (int)strlen(shellcode));
    int (*ret)()=(int(*)())shellcode;
    ret();

    return 0;
}

答案 8 :(得分:0)

GRUB

$ bzr branch http://bzr.savannah.gnu.org/r/grub/trunk/grub
$ vi grub/grub-core/commands/acpihalt.c +303

或者在Github镜像上:

https://github.com/dajhorn/grub/blob/trunk/grub/grub-core/commands/acpihalt.c#L303

答案 9 :(得分:0)

使用此代码的32位操作系统:

BITS 32

global _start
section .text

_start:

; Local variables:
;
; [ebp-4] Address of ntdll.dll
; [ebp-8] Address of ntdll.dll's export table
; [ebp-12] Space for RtlAdjustPrivilege's output

push ebp
mov ebp,esp
sub esp,12

; Save registers

push ebx
push esi
push edi

jmp get_delta_offset ; Get the delta offset

get_delta_offset2:
    pop ebx
    jmp start ; Jump to main code

get_delta_offset:
    call get_delta_offset2

data:
    NtShutdownSystem_s db "NtShutdownSystem"
    NtShutdownSystem_len equ $-NtShutdownSystem_s

    RtlAdjustPrivilege_s db "RtlAdjustPrivilege"
    RtlAdjustPrivilege_len equ $-RtlAdjustPrivilege_s

get_function_address:

    ; Save registers

    push ebx
    push esi
    push edi

    mov eax,[ebp-8]
    mov ebx,[eax+0x20] ; ebx now points to the export names array

    add ebx,[ebp-4]
    xor eax,eax

    .get_function_address_loop:
        mov esi,edx ; esi now points to the function
        mov edi,[ebx+eax*4]
        add edi,[ebp-4] ; edi now points to the export name

        push ecx ; Save the function name length
        cld ; Clear the direction flag

        rep cmpsb ; Do the comparison
        pop ecx ; Restore the length

        je .get_function_address_end
        inc eax

        cmp eax,[ebx+0x14]
        jl .get_function_address_loop

    .get_function_address_fail:
        pop edi
        pop esi
        pop ebx

        xor eax,eax
        ret

    .get_function_address_end:
        mov ebx,[ebp-8]
        mov ecx,[ebx+0x1c]

        add ecx,[ebp-4] ; ecx now points to the function addresses array

        mov edx,[ebx+0x24]
        add edx,[ebp-4] ; edx now points to the ordinals array

        movzx eax,word [edx+eax*2] ; eax now holds the ordinal
        mov eax,[ecx+eax*4] ; eax now holds the RVA of the function

        add eax,[ebp-4] ; eax now holds the address of the function

        ; Restore registers

        pop edi
        pop esi
        pop ebx

        ret

start:

xor ecx,ecx
mov eax,[fs:ecx+0x30] ; eax now points to the PEB

mov eax,[eax+0xc] ; eax now points to loader data
mov eax,[eax+0x14]

mov eax,[eax+ecx]
mov eax,[eax+0x10] ; eax now holds the address of ntdll.dll

mov [ebp-4],eax ; Save the address of ntdll.dll

add eax,[eax+0x3c] ; eax now points to the PE header
mov eax,[eax+0x78] ; eax now points to the export directory
add eax,[ebp-4] ; eax now points to the export table

mov [ebp-8],eax
xor ecx,ecx

mov cl,NtShutdownSystem_len
mov edx,ebx

add ebx,ecx ; Move to next string
call get_function_address

test eax,eax
je exit

mov esi,eax
xor ecx,ecx

mov cl,RtlAdjustPrivilege_len
mov edx,ebx

call get_function_address

test eax,eax
je exit

mov edi,eax
xor eax,eax

; Enable SeShutdownPrivilege

lea ecx,[ebp-12]

push ecx
push eax ; CurrentThread = FALSE
push 1 ; Enable = TRUE
push 19 ; SeShutdownPrivilege

call edi ; Call RtlAdjustPrivilege
xor eax,eax

push eax ; ShutdownNoReboot
call esi ; Call NtShutdownSystem

exit:

pop edi
pop esi
pop ebx

mov esp,ebp
pop ebp
ret