본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 15. 09:03

PRoot 없이 Android 15에서 네이티브 glibc (Debian) 바이너리 실행하기

요약

Android 15의 강화된 seccomp 보안 필터로 인해 기존의 PRoot를 사용한 Debian/glibc 바이너리 실행이 어려워졌습니다. 이 글은 patchelf와 LD_PRELOAD= 환경 변수를 활용하여, Root 권한 없이도 네이티브하게 Linux (Debian/glibc) 바이너리를 직접 실행하는 3단계 해결책을 제시합니다. 이를 통해 Android 기기에서 클라우드 의존성 없이 다양한 개발 도구(GCC, Python 등)를 사용하는 진정한 리눅스 개발 환경 구축이 가능해집니다.

핵심 포인트

  • Android 15는 seccomp 필터를 강화하여 PRoot 방식의 시스템 호출을 차단합니다.
  • LD_PRELOAD=와 patchelf를 사용하여 ELF 바이너리의 인터프리터 경로를 수정함으로써 네이티브 실행 환경을 구축할 수 있습니다.
  • Root 권한 없이도 단순 바이너리를 실행하는 Tier 1 방법과, 복잡한 의존성을 처리하는 Root 필요 방식(Tier 2) 등 단계별 접근법을 제공합니다.
  • 기존의 PRoot 실패 원인은 seccomp 차단 외에도 Termux의 Bionic 라이브러리 충돌 및 권한 문제 등이 복합적으로 작용했음을 설명합니다.

🔧 요약 (TL;DR): Android 15가 더 엄격해진 seccomp 필터로 인해 PRoot를 차단했습니다. 약 10시간의 디버깅 끝에, patchelf와 LD_PRELOAD=를 사용하여 Termux에서 네이티브 Linux (Debian/glibc) 바이너리를 직접 실행할 수 있는 해결책을 찾아냈습니다! 🎯 무엇을 달성할 수 있나요? (클릭하여 확장) 이 가이드를 따르면 다음을 수행할 수 있습니다: ✅ GCC, Python, Bun, Git 및 300개 이상의 Debian 패키지를 네이티브로 실행 ✅ Android 휴대폰에서 직접 코드 컴파일 ✅ 클라우드 의존성 없이 Linux 개발 도구 사용 ✅ 모바일에서 진정한 Linux 경험 제공

문제점
Android 15는 seccomp 보안 필터를 크게 강화했습니다. 이제 proot-distro를 통해 Debian/glibc 바이너리를 실행하면 다음과 같은 오류와 함께 실패합니다:
Bad system call (SIGSYS)
set_robust_list: Function not implemented

⚠️ 중요: 이것은 설정 문제가 아닙니다. 커널이 PRoot가 Linux 환경을 에뮬레이션하는 데 필요한 시스템 호출 (syscalls)을 문자 그대로 차단하고 있습니다. 모든 가이드가 "그냥 PRoot를 사용하세요"라고 말했기에, 저는 실제로 작동하는 방법을 찾기 위해 약 10시간을 소비했습니다.

🤔 왜 이것에 관심을 가져야 하나요? (클릭하여 확장)
클라우드 서비스나 복잡한 설정에 의존하지 않고 Android 기기에서 Linux 개발 도구를 실행하고 싶다면, 이 가이드가 여러분을 위한 것입니다! 이 솔루션은 PRoot를 완전히 우회하고, patchelf를 사용하여 ELF 바이너리의 인터프리터 경로를 수정함으로써 바이너리를 네이티브로 실행하기 때문에 작동합니다.

Seccomp 이해하기
🔒 Seccomp란 무엇인가요? (클릭하여 학습)
Seccomp (Secure Computing Mode)는 다음과 같은 Linux 커널 보안 기능입니다:

  • 프로세스가 수행할 수 있는 시스템 호출 (syscalls)을 필터링합니다.
  • 민감한 커널 작업에 대한 액세스를 제한합니다.
  • 프로그램이 할 수 있는 일을 제한하여 취약점 공격을 방지합니다.
    프로그램을 위한 방화벽이라고 생각하면 됩니다. 프로그램이 어떤 "문"을 사용할 수 있는지 결정합니다.

📖 seccomp에 대해 더 알아보기 (Red Hat Documentation)

해결책 — 3단계
사용자의 필요에 따라 세 가지 단계의 접근 방식을 개발했습니다:

📋 모든 해결 단계 보기
| 단계 | 방법 | Root 필요 여부 | 네이티브 수준 | 최적의 용도 |
| :--- | :--- | :--- | :--- | : |
| 1 | LD_PRELOAD= + 직접 바이너리 실행 | ❌ 아니요 | ⭐⭐⭐⭐⭐ | 단순한 바이너리 |
| 2 | 환경 변수를 포함한 su -c 래퍼 (wrapper) | ✅ 예 | ⭐⭐⭐⭐ | 복잡한 바이너리 |
| 3 | 스마트 APT 래퍼 (Smart APT wrapper) | ✅ 예 | ⭐⭐⭐ | 패키지 관리 |

Tier 1 — 가장 네이티브함 (Root 불필요)

바이너리에 patchelf 적용 후:

LD_PRELOAD= /path/to/glibc-binary " $@ "

진정한 네이티브 실행
ELF 바이너리가 glibc를 직접 로드합니다.
LD_PRELOAD= 설정이 Termux가 자신의 Bionic lib를 주입하는 것을 방지합니다.

Tier 2 — 운영 안정성 (Root 필요)
su -c "LD_PRELOAD= LD_LIBRARY_PATH= $ GLIBC/lib/aarch64-linux-gnu: $ GLIBC/usr/lib/aarch64-linux-gnu $ GLIBC/usr/bin/binary "$@" "

복잡한 바이너리에 대해 더 높은 호환성을 제공합니다.
깊은 전이적 의존성 (transitive dependencies)을 처리합니다.

Tier 3 — "그냥 작동함" (Smart APT)
먼저 Termux 저장소를 시도하고, 실패 시 Debian으로 전환하며, 새로운 바이너리를 자동으로 패치하는 투명한 apt install 방식입니다.

근본 원인 — PRoot가 실패하는 이유
🐛 세 가지 문제 (클릭하여 확장)

문제 1: Seccomp 차단
Android 15의 seccomp가 glibc가 시작 시 호출하는 set_robust_list를 차단합니다 → SIGSYS 발생
📖 set_robust_list란 무엇인가?

문제 2: Termux LD_PRELOAD 충돌
Termux는 모든 프로세스에 libtermux-exec-ld-preload.so를 주입합니다. 이 Bionic 라이브러리는 libc.so를 찾지만 → glibc에는 존재하지 않으므로 → 충돌(crash)이 발생합니다.

문제 3: Root가 생성한 심볼릭 링크(Symlink) 권한
chroot 내부에서 (root 권한으로 실행 중) apt에 의해 생성된 심볼릭 링크는 Termux 사용자 UID가 접근할 수 없게 만드는 보안 속성을 상속받습니다.

기기 정보
📱 내 기기 설정 (클릭하여 상세 정보 보기)
💡 Samsung 변형 모델 설명: Exynos (유럽/아시아): Samsung 자체 프로세서를 사용합니다 — 우리의 기기입니다!

Snapdragon (USA/LATAM/China): Qualcomm 프로세서를 사용합니다 — 커널/펌웨어가 다릅니다.

Spec ValueDevice
Samsung Galaxy S10e (SM-G970F) VariantExynos 9820 (International - EMEA)
ProcessorExynos 9820 - 8nm Octa-core
ArchitectureARM64 (AArch64)
Android 15 ROMExtremeROM Nexus by ExtremeXT
RootKernelSU
TerminalTermux (F-Droid)

Prerequisites ✅ Requirements Checklist (Click to expand)
시작하기 전에 다음 사항을 확인하세요:
[ ] KernelSU 또는 Magisk로 루팅된 기기
[ ] F-Droid에서 설치한 Termux (Play 스토어 버전 아님)
[ ] patchelf 설치됨: pkg install patchelf

왜 F-Droid인가요?

  • 더 허용적인 업데이트 주기
  • proot-distro에 대한 완전한 접근 권한
  • 커스텀 ROM과의 더 나은 호환성

📖 F-Droid에 대해 더 알아보기

Installation Guide

Step 1: Install Debian rootfs

필수 패키지 설치

pkg install proot-distro rsync -y

Debian 설치

proot-distro install debian

경로 정의

ROOTFS = "$PREFIX/var/lib/proot-distro/installed-rootfs/debian"
GLIBC = "$HOME/glibc-root"

기본 패키지 설치

proot-distro login debian -- bash -c "apt-get update && apt-get install -y gcc g++ make python3 bun curl unzip zip ca-certificates"

📖 proot-distro란 무엇인가요? | rsync란 무엇인가요?

Step 2: Extract rootfs to native location

mkdir -p "$GLIBC"
rsync -a "$ROOTFS/" "$GLIBC/"

⚠️ Critical: Fix Symlinks (Click to expand)
루트(Root) 권한으로 생성된 심볼릭 링크 (Symlinks)는 Termux UID 접근을 차단하는 보안 컨텍스트를 상속받습니다. 이 수정 작업은 필수입니다!

#!/usr/bin/env python3
"""
Termux UID 호환성을 위한 심볼릭 링크 수정
"""
import os, subprocess

rootfs = os.path.expanduser("~/glibc-root")

for dirpath, dirs, files in os.walk(rootfs):
    for name in files:
        path = os.path.join(dirpath, name)
        if os.path.islink(path):
            target = None
            try:
                target = os.readlink(path)
            except:
                result = subprocess.run(["su", "-c", f"readlink {path}"], capture_output=True, text=True)
                target = result.stdout.strip()
            
            if target:
                try:
                    os.unlink(path)
                except:
                    subprocess.

run(["su", "-c", f"rm -f {path}"], capture_output=True)
os.symlink(target, path)
print(" ✓ Symlinks repaired. ")

Step 3: Fix the dynamic linker
GLIBC = "$HOME/glibc-root"
LOADER = "$GLIBC/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1"
mkdir -p "$GLIBC/lib64"
ln -sf "$LOADER" "$GLIBC/lib64/ld-linux-aarch64.so.1"
ln -sf "$LOADER" "$GLIBC/lib/ld-linux-aarch64.so.1"
📖 ld-linux.so에 대해 알아보기

Step 4: Mass patchelf — make all binaries self-contained
GLIBC = "$HOME/glibc-root"
LOADER = "$GLIBC/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1"
RPATH = "$GLIBC/lib/aarch64-linux-gnu:$GLIBC/usr/lib/aarch64-linux-gnu"
OUT = "$PREFIX/bin"
for bin in "$GLIBC/usr/bin/"* "$GLIBC/bin/"; do
[[ -f "$bin" && -x "$bin" ]] || continue
name=$(basename "$bin")
-glibc cp "$bin" "$OUT/$name"
patchelf --set-interpreter "$LOADER"
--set-rpath "$RPATH"
"$OUT/$name" 2>/dev/null || rm -f "$OUT/$name"
done
echo "✓ Patched $(ls $OUT/
-glibc 2>/dev/null | wc -l) binaries"
📖 patchelf란 무엇인가?

단계 5: 소유권 수정
su -c "chown -R $( id -u ) : $( id -g ) $HOME /glibc-root"
su -c "find $HOME /glibc-root -type d -exec chmod 755 {} ; "

단계 6: Smart APT 래퍼 (wrapper) 생성
cat > ~/apt-debian << ' SCRIPT '
#!/data/data/com.termux/files/usr/bin/bash

apt-debian v3 — Debian에서 설치하고 자동으로 patchelf를 수행합니다

GLIBC="$HOME/glibc-root"
LOADER="$GLIBC/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1"
RPATH="$GLIBC/lib/aarch64-linux-gnu:$GLIBC/usr/lib/aarch64-linux-gnu"

case "$1" in
install)
shift
BEFORE=$(find "$GLIBC/usr/bin" "$GLIBC/bin" -maxdepth 1 -type f -executable 2>/dev/null | sort)
su -c "cp /system/etc/resolv.conf $GLIBC/etc/resolv.conf 2>/dev/null || \
echo 'nameserver 8.8.8.8' > $GLIBC/etc/resolv.conf"
su -c "chroot $GLIBC /usr/bin/apt-get install -y $* "
AFTER=$(find "$GLIBC/usr/bin" "$GLIBC/bin" -maxdepth 1 -type f -executable 2>/dev/null | sort)
NEW=$(comm -13 <(echo "$BEFORE") <(echo "$AFTER"))

for bin in $NEW ; do
    name="$(basename $bin)-glibc"
    cp "$bin" "$PREFIX/bin/$name"
    patchelf --set-interpreter "$LOADER" --set-rpath "$RPATH" "$PREFIX/bin/$name" 2>/dev/null
    chmod +x "$PREFIX/bin/$name"
    echo "✓ $name available"
done
;;

update)
su -c "chroot $GLIBC /usr/bin/apt-get update"
;;
*)
echo "Usage: apt-debian {install|update} [packages]"
;;
esac
SCRIPT
chmod +x ~/apt-debian
mv ~/apt-debian "$PREFIX/bin/apt-debian"

단계 7: PATH에 추가
echo 'export PATH="$HOME/.glibc-bin:$PATH"' >> ~/.bashrc
echo 'export GLIBC_ROOT="$HOME/glibc-root"' >> ~/.bashrc
source ~/.bashrc

테스트 🧪
설치 확인 (클릭하여 확장)

테스트 명령예상 출력
LD_PRELOAD= gcc-glibc --versiongcc (Debian 14.2.0-6) 14.2.0
bun --version1.x.x
apt-debian install htop && htopInteractive process manager

빠른 테스트

GCC 테스트

LD_PRELOAD= gcc-glibc --version

Bun 테스트

bun --version

APT 래퍼 테스트

apt-debian install htop && htop

알려진 제한 사항 ⚠️
중요 참고 사항 (클릭하여 확장)
루트 권한 필요 — su -c 폴백 (fallback) 방식 사용

KernelSU/Magisk 루트 권한이 필요합니다. Tier 1은 루트 권한 없이(rootless) 작동하지만, 복잡한 바이너리에서는 실패할 수 있습니다. LD_PRELOAD= 반드시 삭제되어야 함 — Termux는 glibc를 충돌시키는 libtermux-exec-ld-preload.so를 주입합니다. 래퍼(wrapper)를 사용하지 않는다면 항상 LD_PRELOAD= 로 실행하십시오. 심볼릭 링크(Symlink) 복구 필수 — apt는 루트 권한으로 심볼릭 링크를 생성하며, 이들은 Termux UID 접근을 차단하는 보안 컨텍스트를 상속받습니다. 사용 가능한 바이너리 📦 즉시 작동하는 항목 (클릭하여 확장)

바이너리패키지공식 사이트
✅ GCC 14gcc-glibcgcc.gnu.org
✅ Python 3.13python3.13-glibcpython.org
✅ Bunbunbun.sh
✅ Gitgit-glibcgit-scm.com
✅ htophtop-glibchtop.dev

apt-debian install 명령을 통해 300개 이상의 Debian aarch64 패키지를 사용할 수 있습니다.

ELF와 동적 링커(Dynamic Linker) 이해하기 📚 기술적 배경 (클릭하여 학습)

ELF란 무엇인가? ELF (Executable and Linkable Format)는 Linux 시스템에서 실행 파일을 위한 표준 바이너리 형식입니다. 이는 운영체제(OS)에 다음을 알려줍니다:

  • 프로그램을 메모리에 로드하는 방법
  • 코드와 데이터를 찾는 위치
  • 필요한 라이브러리
  • 프로그램을 실행하는 방법
    📖 ELF에 대해 더 알아보기

동적 링커(Dynamic Linker)란 무엇인가? 동적 링커 (ld-linux.so)는 Linux 프로그램을 실행할 때 가장 먼저 실행되는 요소입니다.

역할:

  • 프로그램을 메모리에 로드합니다.
  • 필요한 라이브러리를 찾습니다.
  • 심볼 (Symbols)을 해결합니다.
  • 프로그램을 실행할 준비를 합니다.

📖 동적 링커 (Dynamic linker) 문서

Samsung 펌웨어 플래싱 (Firmware Flashing) 참조
📱 펌웨어를 플래싱해야 하는 경우 (클릭하여 확장)

도구 (Tool)플랫폼 (Platform)링크 (Link)
OdinWindows 전용 PCWikipedia
HeimdallLinux/macOSGitHub
ErosAndroid (PC 불필요!)GitHub / XDA

Galaxy S10e (SM-G970F) 리소스

요약 (Summary)구성 요소 (Component)기술 (Technology)참조 (Reference)
터미널 (Terminal)TermuxGitHub
ROMExtremeROM NexusAndroid 15
루팅 (Root)KernelSU
프로세서 (Processor)Exynos 9820
배포판 (Distribution)Debianglibc
호환성 계층 (Compatibility Layer)patchelfELF 수정
실행 방법 (Execution Method)LD_PRELOAD= bypass네이티브 실행 (Native execution)
기기 (Device)Samsung Galaxy S10e (SM-G970F) - Exynos 9820ARM64/AArch64

리소스 및 참조 (Resources & References)

📱 기기 및 하드웨어 (Device & Hardware)

주제 (Topic)링크 (Link)
Samsung Galaxy S10e (SM-G970F) - ExynosGSMArena
Exynos 9820 ProcessorWikipedia
AArch64/ARM64 ArchitectureWikipedia
XDA Forum - Galaxy S10eXDA Forums

🔧 개발 도구 (Development Tools)

도구 (Tool)공식 사이트 (Official Site)
Termuxtermux.dev / F-Droid
patchelfGitHub
proot-distroGitHub / F-Droid
Bunbun.sh
GCCgcc.gnu.org
Pythonpython.org
Gitgit-scm.com
htophtop.dev

📚 Linux 개념 (Linux Concepts)

주제 (Topic)링크 (Link)
ELF FormatWikipedia
SeccompRed Hat Docs
Dynamic Linkerman7.org
rsyncrsync.samba.org

🔐 루팅 및 ROM 프로젝트 (Root & ROM Project)

링크 (Link)
KernelSUkernelsu.org
Magisktopjohnwu.github.io/Magisk
ExtremeROM NexusGitHub

🔧 펌웨어 도구 (Firmware Tools)

도구 (Tool)링크 (Link)
OdinWikipedia
HeimdallGitHub
ErosGitHub

크레딧 (Credits)
❤️ 특별 감사 (Special Thanks) (클릭하여 확장)
이 기사는 여러 놀라운 도구와 커뮤니티의 도움으로 제작되었습니다:

AI 어시스턴트 (AI Assistants)도구 (Tool)역할 (Role)링크 (Link)
Gemini (Google AI)터미널 디버깅에 사용됨gemini.google.com
Claude (Anthropic)복잡한 기술적 과제 해결claude.ai
MiniMax Agent기사 서식 지정 및 교정agent.minimax.io
ROM & Root 스택 (ROM & Root Stack)프로젝트 설명 (Project Description)링크 (Link)
ExtremeROM NexusExtremeXT 제작 커스텀 ROMGitHub
KernelSU루팅 솔루션 (Root solution)kernelsu.org
Termux 도구 (Termux Tool)설명 (Description)링크 (Link)
Termux놀라운 터미널

이 모든 것을 가능하게 하는 에뮬레이터 termux.dev / GitHub 🔧 Termux에서 전적으로 개발됨 — Samsung Galaxy S10e (SM-G970F) · Exynos 9820 · Android 15 · ExtremeXT · KernelSU 이 글이 도움이 되었다면 💚를 눌러주시고 다른 사람들과 공유해 주세요! 질문이 있으신가요? 댓글로 자유롭게 물어봐 주세요!

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0