How can I shutdown the computer using only assembly code?
In Linux read reboot(2).
sources files of interest:
kernel/sys.c kernel/exit.c and arch/x86/kernel/apm.c
not a complete answer but i think it's a good start. I'll have to read my BIOS machine code to see what they do. but this part is machine specific. maby if you know wich IC contol power on your motherboard you can figure out wich IO port, register and command you need. then setup proper board/devices states and then issue command to turn the power off.
BIOS manage power via INT 15h ah=53h ( so called Advanced Power Management aka APM ) function al=07 used in Linux is the set power state cmd. parameters bx=0001h mean all devices and cx=0003k mean stop.
$ bzr branch http://bzr.savannah.gnu.org/r/grub/trunk/grub
$ vi grub/grub-core/commands/acpihalt.c +303
or here on a Github mirror:
https://github.com/dajhorn/grub/blob/trunk/grub/grub-core/commands/acpihalt.c#L303
This is the 29 byte program that I have been using to turn the computer off in DOS mode for years.
;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
You can lookup more functions with Ralf Brown’s Interrupt List at DJGPP.
You can try using shellcode for x86
Linux machine, this is not malicious code you know, just for fun. This shellcode only executes /sbin/poweroff
only tested on Debian version 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;
}
Or this shellcode executes shutdown -h now
(run with 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;
}
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).
Converting @larz answer above to nasm assembly is done as follows:
Prerequisites: Bochs, Nasm
This example was run on debian wheezy with standard packages.
Code (filename: 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 configuration file (filename: .bochsrc) in the same directory as code (shutdown.asm)
display_library: sdl
floppya: 1_44=boot_sect.img, status=inserted
boot: a
*Note I am using the sdl library for bochs which is a seperate package from bochs itself
Running bochs (from the same directory as before):
bochs
Hit enter to shutdown
*Note I am not sure that all the lines between the Shutdown label and WaitForEnter label are neccessary