Анализ принципа binfmt-misc в Linux
Анализ принципа binfmt-misc в Linux

0x00 Что такое binfmt-misc

binfmt-misc(Miscellaneous Binary Формат) — это функция, предоставляемая ядром Linux, похожая на ассоциацию файлов в Windows, но более мощная, чем ассоциация файлов, заключается в том, что она может судить не только по имени суффикса файла, но и по содержимому файла (Magic Bytes)использовать разныепрограмма Открыть。Типичный сценарий использования::использоватьqemuЗапустить другое Архитектура Бинарные файлы на платформе。

В этой статье этот сценарий рассматривается в качестве примера для анализа его конкретного принципа работы.

0x01 Включить binfmt-misc

Чтобы временно включить его, используйте следующую команду:

Язык кода:javascript
копировать
$ sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

Этот метод станет недействительным после перезапуска.,Если вы хотите быть эффективными в течение длительного времени,Можно найти в/etc/fstabДобавьте строку в файл:

Язык кода:javascript
копировать
none  /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0

Вы можете использовать следующую команду, чтобы проверить успешность открытия:

Язык кода:javascript
копировать
$ mount | grep binfmt_misc
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
$ ls -l /proc/sys/fs/binfmt_misc
Общая дозировка 0
--w------- 1 root root 0 февраль   5 22:55 register
-rw-r--r-- 1 root root 0 февраль   5 22:55 status

0x02 Запуск приложений Arm64 в системах x86_64

Сначала подготовьте программу с архитектурой Arm64 (для ее создания можно использовать кросс-платформенную компиляцию Go). После выполнения выдается сообщение об ошибке:

Язык кода:javascript
копировать
bash: ./go-test: Невозможно выполнить двоичный файл: Ошибка формата исполняемого файла

Сейчас,Давайте выполним этоapt install qemu-user-binfmtЗаказ,Затем запустите указанную выше программу Arm64.,Обнаружил, что работает нормально。Установитьqemu-user-binfmtназад,будет внутри/proc/sys/fs/binfmt_miscСоздайте несколько файлов в каталоге,Есть среди них одинqemu-aarch64。Давайте посмотрим на содержимое этого файла:

Язык кода:javascript
копировать
$ cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/libexec/qemu-binfmt/aarch64-binfmt-P
flags: POC
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff

Этот файл описывает файл правил,первая линияenabledУказывает, что правило включено;вторая линияinterpreter /usr/libexec/qemu-binfmt/aarch64-binfmt-Pвыражатьиспользовать/usr/libexec/qemu-binfmt/aarch64-binfmt-Pвыполнить двоичный файл;Третья линияflags: POCФлаг, указывающий на бег,Конкретный смысл заключается в следующем:

  • P: означает persist-argv,Это означает, что при вызове симулятора,Исходные аргументы (argv) будут сохранены. Это полезно в тех случаях, когда некоторым программам необходимо знать свои имена во время выполнения (например, argv[0]).
  • O: Представляет смещение. Это означает, что перед запуском симулятора необходимо считать смещение из двоичного файла. Это смещение будет использоваться как параметр симулятора.
  • C: Представляет учетные данные, что означает, что эмулятор будет работать с тем же идентификатором пользователя и идентификатором группы, что и исходная программа. Это помогает гарантировать, что эмулятор работает с теми же разрешениями, что и исходная программа.

четвертая строкаoffset 0Выражает из0Значение смещения для начала чтения файла;пятая линияmagic 7f454c460201010000000000000000000200b700Представляет магический байт, который соответствует;mask ffffffffffffff00fffffffffffffffffeffffffПредставляет байтовую маску,Используется для игнорирования некоторых неважных байтов в файле.

Это можно увидеть,Это правило будетиспользовать/usr/libexec/qemu-binfmt/aarch64-binfmt-Pвыполнитьarm64Архитектурадвоичный файл,И этот файл на самом деле является мягкой ссылкой,На что на самом деле указывает:/usr/bin/qemu-aarch64

0x03 Создать правила выполнения вручную

В приведенном выше примере,/proc/sys/fs/binfmt_misc/qemu-aarch64документнаходится в УстановитьqemuБиблиотекаизчасавтоматически Установитьвходитьиз。Если вы хотите создать правило вручную,Как это сделать?

Давайте сначала сохраним следующий код в файлmain.goсередина:

Язык кода:javascript
копировать
package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("Program name:", os.Args[0])

    if len(os.Args) > 1 {
        fmt.Println("Arguments:")
        for i, arg := range os.Args[1:] {
            fmt.Printf("Arg %d: %s\n", i+1, arg)
        }
    } else {
        fmt.Println("No arguments provided.")
    }
}

использовать Заказ:go build -o fake-runner ./main.goруководитькомпилировать,и будеткомпилироватьвышелfake-runnerскопировать в/usr/local/binв каталоге。

в это время,мы должны/proc/sys/fs/binfmt_misc/registerсерединав соответствии с:name:type:offset:magic:mask:interpreter:flagsправила написания формата。

  • имя: имя правила
  • type: тип,ВыбиратьE(Сопоставить по расширению)илиM(Сопоставление по магическим байтам файла)№1
  • offset: когдаtypeдляMэффективен, когда,Представляет значение смещения магического байта.
  • magic: когдаtypeдляEчас,выражать要匹配изназадфамилия;когдаtypeдляMчас,Представляет магический байт в шестнадцатеричном формате.
  • mask: когдаtypeдляMэффективен, когда,Маска, представляющая магические байты,Аналогично маскировке IP-адреса
  • интерпретатор: абсолютный путь к файлу интерпретатора
  • flags: Смысл тот же, что и вышеflags一致

假设我们想用fake-runnerОткрытьк12344578файлы, начинающиеся с,Вы можете выполнить следующие команды:

Язык кода:javascript
копировать
# echo ':binfmt-test:M::12345678::/usr/local/bin/fake-runner:P' > /proc/sys/fs/binfmt_misc/register
# cat /proc/sys/fs/binfmt_misc/binfmt-test enabled
interpreter /usr/local/bin/fake-runner
flags: P
offset 0
magic 3132333435363738

Эту команду необходимо запускать с правами root.

Затем используйте команду для создания целевого файла:

Язык кода:javascript
копировать
$ echo 12345678 > /tmp/test.txt
$ chmod 755 /tmp/test.txt
$ /tmp/test.txt hello
Program name: /usr/local/bin/fake-runner
Arguments:
Arg 1: /tmp/test.txt
Arg 2: /tmp/test.txt
Arg 3: hello

удалить规则可киспользовать Заказ:echo -1 > /proc/sys/fs/binfmt_misc/binfmt-test

0x04 Запуск образа Docker архитектуры Arm64 в системе x86_64

Теперь мы используем команду docker для запуска образа Arm64:

Язык кода:javascript
копировать
$ docker run -it arm64v8/ubuntu bash
Unable to find image 'arm64v8/ubuntu:latest' locally
latest: Pulling from arm64v8/ubuntu
005e2837585d: Pull complete 
Digest: sha256:ba545858745d6307f0d1064d0d25365466f78d02f866cf4efb9e1326a4c196ca
Status: Downloaded newer image for arm64v8/ubuntu:latest
standard_init_linux.go:207: exec user process caused "no such file or directory"

После некоторых исследований,Я обнаружил, что пока я выполняю Заказ:apt install qemu-user-static,перезапускdockerКонтейнер нормальный。выполнить это Заказ Изменю/usr/libexec/qemu-binfmt/aarch64-binfmt-PМягкая ссылка на файл/usr/bin/qemu-aarch64-static。Давайте посмотримqemu-aarch64иqemu-aarch64-staticразница:

Язык кода:javascript
копировать
$ readelf -d /usr/bin/qemu-aarch64
Dynamic section at offset 0x3aee38 contains 37 entries:
  отметка        тип                         имя/значение
 0x0000000000000001 (NEEDED)             Общая библиотека: [libz.so.1]
 0x0000000000000001 (NEEDED)             Общая библиотека: [librt.so.1]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libcapstone.so.4]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libglib-2.0.so.0]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libgnutls.so.30]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libgmodule-2.0.so.0]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libm.so.6]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Общая библиотека: [libc.so.6]
 0x000000000000000c (INIT)               0xab000
 0x000000000000000d (FINI)               0x2a83ec
 0x0000000000000019 (INIT_ARRAY)         0x35b8e0
 0x000000000000001b (INIT_ARRAYSZ)       248 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x35b9d8
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x340
 0x0000000000000005 (STRTAB)             0x2a608
 0x0000000000000006 (SYMTAB)             0xa1f0
 0x000000000000000a (STRSZ)              122726 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x3b00c8
 0x0000000000000002 (PLTRELSZ)           11136 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0xa7f68
 0x0000000000000007 (RELA)               0x4b2e0
 0x0000000000000008 (RELASZ)             380040 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000000000001e (FLAGS)              BIND_NOW
 0x000000006ffffffb (FLAGS_1)            Логотип: NOW PIE
 0x000000006ffffffe (VERNEED)            0x4b070
 0x000000006fffffff (VERNEEDNUM)         7
 0x000000006ffffff0 (VERSYM)             0x4856e
 0x000000006ffffff9 (RELACOUNT)          15807
 0x0000000000000000 (NULL)               0x0

$ readelf -d /usr/bin/qemu-aarch64-static
There is no dynamic section in this file.

Это можно увидеть,qemu-aarch64-static не имеет зависимостей от динамических библиотек,То есть,dockerдолжениспользоватьстатическийкомпилироватьизqemuработать。таким образом,Может быть реализован Сейчасx86_64на машинекомпилироватьчерез Архитектура Цель зеркального отображения。

0x05 Компилировать образ Docker для разных архитектур.

Для поддержки нескольких архитектур вам необходимо включить экспериментальную функцию Docker. Способ ее включения следующий:

в файле/etc/docker/daemon.jsonсередина Добавьте следующую конфигурацию

Язык кода:javascript
копировать
{
    "experimental": true
}

Ранназадиспользоватьsysemcrtl restart dockerЗаказ ПерезапускDockerСлужить。

Язык кода:javascript
копировать
$ docker info | grep -i 'experimental'
 Experimental: true

Когда вы видите приведенный выше вывод, это означает, что экспериментальная функция включена.

Напишите следующий Dockerfile:

Язык кода:javascript
копировать
FROM ubuntu:20.04

RUN set -ex && apt update

Затем используйте следующую команду для компиляции образа Arm64.

Язык кода:javascript
копировать
$ sudo docker build --platform linux/arm64 -t ubuntu .
$ sudo docker run -it ubuntu bash
root@616a3dd3a915:/# uname -a
Linux 616a3dd3a915 5.15.34-amd64-desktop #2 SMP Mon May 16 16:31:30 CST 2022 aarch64 aarch64 aarch64 GNU/Linux

поэтому,использовать--platform linux/arm64Просто параметрыкомпилироватьвнеarm64Архитектураиззеркало。

0x06 Запуск исполняемых файлов Windows в Linux

использоватьbinfmt-miscмеханизм может поддерживать прямуюLinuxбеги дальшеWindowsизexeдокумент,Это достигается с помощью вина.

Язык кода:javascript
копировать
$ cat /proc/sys/fs/binfmt_misc/DOSWin
enabled
interpreter /usr/bin/wine
flags: 
offset 0
magic 4d5a
$ ls -l /usr/bin/wine
lrwxrwxrwx 1 root root 19 Октябрь  8 18:09 /usr/bin/wine -> deepin-wine6-stable

deepin-wine6-stable на самом деле является bash-скриптом:

Язык кода:javascript
копировать
#!/bin/bash

name=${0##*/}
bindir=/usr/lib/$name

wine32=/opt/$name/bin/wine
wine64=/opt/$name/bin/wine64

if test -x $wine32 -a "$WINEARCH" != "win64"; then
    wine=$wine32
elif test -x $wine64; then
    wine=$wine64
    if [ "$(dpkg --print-architecture)" = "amd64" -a "$(dpkg --print-foreign-architectures | grep -cx "i386")" -ne 1 ]; then
        echo "it looks like multiarch needs to be enabled.  as root, please"
        echo "execute \"dpkg --add-architecture i386 && apt-get update &&"
        echo "apt-get install $(echo $name | sed s/wine/wine32/)\""
    fi
else
    echo "error: unable to find wine executable.  this shouldn't happen."
    exit 1
fi

if test -z "$WINEPREFIX"; then
    if test "$wine" = "$wine64"; then
        wineprefix=$HOME/.wine64
    else
        wineprefix=$HOME/.wine
    fi
else
    wineprefix=$WINEPREFIX
fi

if test -z "$WINELOADER"; then
    wineloader=$wine
else
    wineloader=$WINELOADER
fi

if test -z "$WINEDEBUG"; then
    winedebug=-all
else
    winedebug=$WINEDEBUG
fi

runtime_path=/opt/deepinwine/runtime-i386

export LD_LIBRARY_PATH="/opt/$name/lib:/opt/$name/lib64:$LD_LIBRARY_PATH"
export WINEDLLPATH=/opt/$name/lib:/opt/$name/lib64

# 32-битному Wine необходимо указать путь к 32-битной среде выполнения.
if [ -f "$runtime_path/init_runtime.sh" -a "$wine" = "$wine32" ];then
    source "$runtime_path/init_runtime.sh"

    PE_FILE="$1"
    if [[ "$1" == *".exe" ]]; then
        PE_FILE=${PE_FILE//\\/\/}
        drive=${PE_FILE:0:2}
        if [[ ${drive} == "c:"* || ${drive} == "C:"* ]]; then
            PE_FILE=${wineprefix}/drive_c${PE_FILE:2}
        fi
    fi

    init_runtime
    if [ -f "$PE_FILE" ];then
        #only 32 bit application need config this envs
        if file "$PE_FILE" | grep -q -e "PE32 "; then
            init_32bit_config
        fi
    fi
    export WINELOADERNOEXEC=1
    winepreloader=/opt/$name/bin/wine-preloader
    WINEPREFIX=$wineprefix WINELOADER=$wineloader WINEDEBUG=$winedebug $winepreloader $wine "$@"
else
    WINEPREFIX=$wineprefix WINELOADER=$wineloader WINEDEBUG=$winedebug $wine "$@"
fi

Поэтому, если вы напрямую введете путь к exe-файлу в командной строке, например, в игре «Сапёр», вы увидите, что система открывает интерфейс игры «Сапер».

0x07 Резюме

binfmt-misc предоставляет гибкий механизм ассоциации файлов, так что некоторые программы, которые не могут быть запущены напрямую, могут запускаться напрямую, как обычные программы Linux (например, кросс-архитектурные программы, Windows exe и т. д.).

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose