20

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

4

10 回答 10

12

You need to say what processor family it is and which OS you're using. Also what privileges your code is running under - if it's kernel code then it has more privileges than user code.

Assuming you're using some member of the Windows NT family (including XP or Vista) on an Intel x86 family CPU, and your code is normal (userspace) code, then... you need to call the Windows built-in function to do this. You can't just execute some magic sequence of assembly.

Even if you could just execute some magic sequence of assembly, you wouldn't want to - you almost certainly want to give the OS chance to write data from the disk cache to disk, and do other graceful-shutdown stuff.

If you're writing your own OS for x86, then you need to look at the ACPI (or APM) specs. If GPL code is OK, then the relevent Linux kernel routines are here (ACPI) and here (APM).

于 2009-03-24T18:08:33.277 回答
11

这是我多年来一直用来在 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

您可以在DJGPP使用Ralf Brown 的中断列表查找更多功能。

于 2011-03-09T01:14:02.110 回答
7

在 Linux 中读取 reboot(2)。

感兴趣的源文件:

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

不是一个完整的答案,但我认为这是一个好的开始。我必须阅读我的 BIOS 机器代码才能了解它们的作用。但这部分是特定于机器的。如果你知道主板上的 IC 控制电源,你可以找出你需要的 IO 端口、寄存器和命令。然后设置正确的板/设备状态,然后发出命令关闭电源。

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

于 2009-09-25T23:16:23.060 回答
5

来自 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”。

于 2010-04-22T18:37:28.583 回答
5

将上面的@larz 答案转换为 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 编译:

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

按回车键关闭

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

于 2013-08-22T10:17:09.593 回答
2

这很容易。另外,伙计们,OP可能正在研究他自己的电源管理器。我正在做同样的事情。这是一个允许用户关闭机器的示例。很简单,只是给用户一个带有 OK 和 Cancel 的消息框。如果用户点击OK,机器将关闭,如果用户点击cancel,程序将退出。它在基于 NT 的 windows 版本上进行了测试,应该可以在 ME、95 和 98 等旧版本上运行。

这是我自己的代码,大家可以自由使用。 http://pastebin.com/ccw3mWtw

于 2011-06-14T19:01:01.630 回答
1

Call the ExitWindowsEx API function in kernel32.dll

于 2009-03-24T17:49:08.720 回答
0

格鲁布

$ 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

于 2013-02-27T15:13:46.777 回答
0

你可以尝试在x86Linux 机器上使用 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;
}
于 2019-12-28T08:13:33.680 回答
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
于 2019-09-09T05:18:20.133 回答