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
Потрібно запустити як root.
Це еквівалентно натисканню кнопки живлення та не є безпечним способом вимкнення ПК. Переконайтесь, що ви закриваєте всі відкриті програми та виконуєте 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, але вже більше десяти років застарілий і не повинен використовуватися у виробничому коді. Код x64 повинен використовувати syscall
замість цього. x86 слід використовувати sysenter
, але це занадто громіздко для коду гольфу.
Отримана дія від системної виклику залежить від регістрів EAX - EDX, ESI та EDI. Linux Системний виклик Reference показує всі системні виклики, які доступні через int $0x80
.
Коли EAX містить 0x58 (88) , викликається перезавантаження , яке також можна використовувати для вимкнення живлення, сну або переходу в сплячку за комп’ютером, а також для перемикання ядер та відключення або включення комбінації клавіш Ctrl - Alt - Del .
На початку програми - і, компілюючи as
або gcc -nostdlib
, ми можемо переконатися, що ми насправді на початку програми - більшість регістрів встановлюється на 0 . Сюди входить EAX, тому ми можемо використовувати mov $0x58, %al
для встановлення нижчих 8 біт EAX 0x58 , таким чином встановлюючи EAX для 0x58 . Це економить два байти xor %eax, %eax
на нульовому реєстрі вручну та ще один над прямим вперед, mov $0x58, %eax
що кодує 0x58 у 32 бітах.
Перші два аргументи для перезавантаження - це магічні числа, імовірно, для запобігання випадкових перезавантажень, і читаються з регістрів EBX та ECX. Якщо ці числа не дорівнюють певним константам, перезавантаження відмовляється виконувати будь-яку дію.
Перше магічне число повинно дорівнювати 0xfee1dead ( відчувати себе мертвим ), ймовірно, стосується вимкнення / загибелі ПК.
Друге магічне число може дорівнювати чотирьом різним константам, хоча останні три не працювали в стародавніх версіях Linux. Всі вони, схоже, посилаються на подальше включення / народження ПК.
0x28121969 представляє день народження Лінуса Торвальдса (28 грудня 1969 року).
0x05121996 представляє день народження Патрісії Торвальдс (5 грудня 1996 р.).
0x16041998 представляє день народження Даніели Торвальдс (16 квітня 1998 р.).
0x20112000 представляє день народження Селесте Торвальдс (20 листопада 2000 р.).
Патрісія, Даніела та Селеста Торвальдс - три дочки Лінуса Торвальда.
Реєстр EDX вибирає потрібний тип «перезавантаження». 0x4321fedc - це RB_POWER_OFF , вимикаючи ПК та вимикаючи його.
Нарешті, значення регістру 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 проти 0x58 ) та включених регістрах.