mov $0x58, %al # 2 bytes: b0 58
mov $0xfee1dead, %ebx # 5 bytes: bb ad de e1 fe
mov $0x28121969, %ecx # 5 bytes: b9 69 19 12 28
mov $0x4321fedc, %edx # 5 bytes: ba dc fe 21 43
int $0x80 # 2 bytes: cd 80
루트로 실행해야합니다.
이것은 전원 버튼을 누르는 것과 같으며 PC를 안전하게 끄는 방법은 아닙니다. sync
최소한 파일 손상의 위험을 최소화하려면이 프로그램을 실행하기 전에 열려있는 모든 응용 프로그램을 닫고 모든 파일 시스템 버퍼를 플러시 하도록 실행하십시오.
시운전
$ as -o poweroff.o poweroff.s
$ ld -o poweroff poweroff.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
$ sudo sh -c 'sync && ./poweroff'
root's password:
어둠이 뒤 따랐다.
작동 원리
int $0x80
소프트웨어 인터럽트를 호출합니다. x86과 x64에서 모두 작동하지만 10 년 이상 사용되지 않아 프로덕션 코드에서 사용해서는 안됩니다. x64 코드가 syscall
대신 사용되어야합니다 . x86은을 사용해야 sysenter
하지만 코드 골프에는 너무 번거 롭습니다.
syscall의 결과 조치는 레지스터 EAX-EDX, ESI 및 EDI에 따라 다릅니다. 리눅스 시스템 콜 참조 를 통해 사용할 수있는 모든 시스템 콜을 보여줍니다 int $0x80
.
EAX 보유하는 경우 (88) 0x58을 , 재부팅 도 잠을하거나 컴퓨터를 최대 절전 모드뿐만 아니라 위해 전원을 차단하는 데 사용 넣을 수있는,라고 커널을 전환하고 비활성화 또는 활성화 Ctrl 키를 - Alt를 - 델의 키 콤보를.
프로그램의 시작에서 -와 함께 컴파일 as
또는 gcc -nostdlib
대부분의 레지스터로 설정 -, 우리는 우리가 프로그램의 시작 부분에서 실제로 걸 확인 할 수 있습니다 0 . 여기에는 EAX가 포함되어 있으므로 EAX mov $0x58, %al
의 하위 8 비트를 0x58 로 설정하여 EAX 자체를 0x58 로 설정할 수 있습니다 . 이렇게하면 레지스터를 수동으로 0으로 xor %eax, %eax
만드는 것보다 2 바이트를 절약 하고 32 비트로 0x58mov $0x58, %eax
을 인코딩 하는 straighforward로 한 바이트를 더 절약 할 수 있습니다.
재부팅 할 처음 두 인수 는 실수로 재부팅되는 것을 방지하기 위해 매직 번호이며 레지스터 EBX 및 ECX에서 읽습니다. 이 숫자가 특정 상수와 같지 않으면 재부팅 은 모든 작업을 수행하지 않습니다.
첫 번째 매직 넘버는 0xfee1dead ( 죽은 느낌 )와 같아야 하며 , 아마도 PC의 전원 끄기 / 죽음을 의미합니다.
두 번째 마법 수는 네 개의 다른 상수와 같을 수 있지만 후자의 세 개는 고대 버전의 Linux에서는 작동하지 않았습니다. 그들 모두는 PC의 후속 전원 켜기 / 탄생을 나타내는 것으로 보입니다.
0x28121969 는 Linus Torvalds의 생일 (1969 년 12 월 28 일)을 나타냅니다.
0x05121996 은 Patricia Torvalds의 생일 (1996 년 12 월 5 일)을 나타냅니다.
0x16041998 은 Daniela Torvalds의 생일을 나타냅니다 (1998 년 4 월 16 일).
0x20112000 은 Celeste Torvalds의 생일 (2000 년 11 월 20 일)을 나타냅니다.
패트리샤, 다니엘라, 셀레스트 토발즈는 리누스 토발즈의 세 딸입니다.
EDX 레지스터는 우리가 원하는 "재부팅"유형을 선택합니다. 0x4321fedc 는 RB_POWER_OFF 이며 PC를 종료하고 전원을 끕니다.
마지막으로, ESI 레지스터의 값은 RB_POWER_OFF에 대해 무시됩니다 . EDI 레지스터의 값은 재부팅에 의해 완전히 무시됩니다 .
대체 버전, x64 전용, 19 바이트
x64에서는 동일한 바이트 수에 대해 적절한 syscall을 사용할 수 있습니다.
mov $0xa9, %al # 2 bytes: b0 a9
mov $0xfee1dead, %edi # 5 bytes: bf ad de e1 fe
mov $0x28121969, %esi # 5 bytes: be 69 19 12 28
mov $0x4321fedc, %edx # 5 bytes: ba dc fe 21 43
syscall # 2 bytes: 0f 05
유일한 차이점은 명령어 ( syscall
vs int $0x80
), __NR_REBOOT 값 ( 0xa9 vs 0x58 ) 및 관련 레지스터에 있습니다.