AI 摘要(由 ChatGPT 总结生成):
本文详细介绍了如何在Android系统上使用NDK交叉编译Python 3的过程。文章涉及了所需工具和库的下载,包括Python、NDK、OpenSSL、LibreSSL、zlib等,并展示了具体的编译步骤。此外,还包括了设置环境变量和部署到Android设备上的方法,最后提供了一个生成Python 3二进制文件的示例,以及如何在Android设备上运行编译后的Python。

前期准备

本次使用的是基于 Android NDK 去交叉编译 Python ,使得在 Android 上也能玩 Python 。编译过程中相关工具必不可少,如下:

本文基于 Debian 系 Linux 系统进行编译操作演示,且交叉编译 Python 的时候最好保证系统上的 Python 版本和要编译的 Python 版本一致,即先编译安装 Linux 版本的,再编译 arm 版本。

为模拟 Android 的文件系统路径,故此处会将 Python 编译至 /data/local/tmp 目录下,创建目录:

mkdir -p /data/local/tmp

此处我们将上述的工具等上传到 /data/local 目录下,此处我们编译一份 Python 3.7 的版本。先将相关压缩包解压,解压命令如下:

# 解压 NDK
unzip android-ndk-r25c-linux.zip

# 解压 OpenSSL
tar -zxvf openssl-1.1.1w.tar.gz

# 解压 zlib
tar -zxvf zlib-1.3.tar.gz

# 解压 Python3.7
tar -xvf Python-3.7.17.tar.xz

# 解压 LibreSSL
tar -zxvf libressl-3.8.1.tar.gz

最终如下图:

image-20230921135837747

下面开始对相关组件等交叉编译,下述操作建议在 root 用户下操作。

交叉编译 zlib

编译该工具是让 Python 支持使用 pip 命令等工具。

zlibconfigure 不支持设置 --host 项,因此我们先直接 configure 一下,然后手动更改生成的 Makefile 文件,相关命令如下:

# 前往 zlib 目录
root@ubuntu:/data/local# cd zlib-1.3/

# 创建 build 和 out 文件夹
root@ubuntu:/data/local/zlib-1.3# mkdir -p build out

# 前往 build 目录
root@ubuntu:/data/local/zlib-1.3# cd build/

# 执行 configure 命令
root@ubuntu:/data/local/zlib-1.3/build# ../configure --prefix=/data/local/zlib-1.3/out
Checking for gcc...
Checking for shared library support...
Building shared library libz.so.1.3 with gcc.
Checking for size_t... Yes.
Checking for off64_t... Yes.
Checking for fseeko... Yes.
Checking for strerror... Yes.
Checking for unistd.h... Yes.
Checking for stdarg.h... Yes.
Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf().
Checking for vsnprintf() in stdio.h... Yes.
Checking for return value of vsnprintf()... Yes.
Checking for attribute(visibility) support... Yes.
root@ubuntu:/data/local/zlib-1.3/build# 

使用 vim 命令打开编辑 Makefile 文件,将其中的 CCARRANLIB 都修改为 arm-linux 交叉编译器的相关参数,也将 LDSHAREDCPP 两项中的 gcc 替换为 CC 修改后的内容,具体修改地方如下:

root@ubuntu:/data/local/zlib-1.3/build# vim Makefile
……
CC=/data/local/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang
……
LDSHARED=/data/local/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang -shared -Wl,-soname,libz.so.1,--version-script,../zlib.map
CPP=/data/local/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang -E
……
AR=/data/local/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
……
RANLIB=/data/local/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib
……

Makefile 文件修改后保存退出,接下来执行下面两条命令,完成交叉编译:

make
make install

编译后的内容在 zlib 源码的 out 目录下。

交叉编译 OpenSSL

编译该工具是使得 Python 支持加密协议。

前往 OpenSSL 目录,将下述脚本保存到 OpenSSL 源码的同目录下,脚本内容如下,部分内容参数请按提示自定义更新:

#!/bin/bash
COMPILE_ROOT="$(dirname $(readlink -f "$0"))"
# NDK 目录,按需更换
export ANDROID_NDK_ROOT=/data/local/android-ndk-r25c
export ANDROID_GCC_ROOT=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
export ANDROID_GCC_PATH=${ANDROID_GCC_ROOT}/bin

BUILD_PATH=${COMPILE_ROOT}/build
OUT_PATH=${COMPILE_ROOT}/out

CROSS_COMPILER=aarch64-linux-android-
CROSS_COMPILER_CLANG=aarch64-linux-android33-

#prepare
mkdir -p ${BUILD_PATH}
mkdir -p ${OUT_PATH}
export PATH=${ANDROID_NDK_ROOT}:${ANDROID_GCC_PATH}:$PATH

export ARCH="aarch64"
export CC="${CROSS_COMPILER_CLANG}clang -pie -fPIE" 
export CPP="${CROSS_COMPILER_CLANG}clang -E  -pie -fPIE"
export CXX="${CROSS_COMPILER_CLANG}clang++  -pie -fPIE"

# 下方的链接文件,新版 NDK 变成了 llvm-xx 的文件格式了,可能旧版的还存在诸如 aarch64-linux-android-xx 的格式文件,若为旧版格式文件,可将下面注释的取消注释,并将 llvm-xx 格式的命令参数反向注释掉,按需修改
#export AS="${CROSS_COMPILER}as"
export LD="${CROSS_COMPILER}ld  -pie -fPIE"
export GDB="${CROSS_COMPILER}gdb"
export STRIP="${CROSS_COMPILER}strip"
#export RANLIB="${CROSS_COMPILER}ranlib"
#export OBJCOPY="${CROSS_COMPILER}objcopy"
#export OBJDUMP="${CROSS_COMPILER}objdump"
#export AR="${CROSS_COMPILER}ar"
#export NM="${CROSS_COMPILER}nm"
export RANLIB="llvm-ranlib"
export AR="llvm-ar"
export NM="llvm-nm"
export OBJCOPY="llvm-objcopy"
export OBJDUMP="llvm-objdump"
export AS="llvm-as"
#export READELF="${CROSS_COMPILER}readelf"
export READELF="llvm-readelf"
export M4=m4
export TARGET_PREFIX=$CROSS_COMPILER
export CXXFLAGS="-D__ANDROID_API__=33 "

cd ${BUILD_PATH}


config_soft(){
    ../config --prefix=${OUT_PATH} -no-asm -no-shared -no-async
}

make_soft(){
    make -j $(nproc)
}

make_soft_install(){
    make install
}

make_clean(){
    make clean
}


case "$1" in
    config_soft)
        config_soft
    ;;
    make_soft)
        make_soft
    ;;
    make_soft_install)
        make_soft_install
    ;;
    make_clean)
        make_clean
    ;;
esac

先使用 config_soft 生成一些文件,命令如下:

root@ubuntu:/data/local/openssl-1.1.1w# vim make_openssl.sh
root@ubuntu:/data/local/openssl-1.1.1w# bash make_openssl.sh config_soft
Operating system: x86_64-whatever-linux2
Configuring OpenSSL version 1.1.1w (0x1010117fL) for linux-x86_64
Using os-specific seed configuration
Creating configdata.pm
Creating Makefile

**********************************************************************
***                                                                ***
***   OpenSSL has been successfully configured                     ***
***                                                                ***
***   If you encounter a problem while building, please open an    ***
***   issue on GitHub <https://github.com/openssl/openssl/issues>  ***
***   and include the output from the following command:           ***
***                                                                ***
***       perl configdata.pm --dump                                ***
***                                                                ***
***   (If you are new to OpenSSL, you might want to consult the    ***
***   'Troubleshooting' section in the INSTALL file first)         ***
***                                                                ***
**********************************************************************
root@ubuntu:/data/local/openssl-1.1.1w# 

然后在 make_softmake_soft_install 完成 OpenSSL 的编译:

root@ubuntu:/data/local/openssl-1.1.1w# bash make_openssl.sh make_soft
……
root@ubuntu:/data/local/openssl-1.1.1w# bash make_openssl.sh make_soft_install
……

若无报错,即完成 OpenSSL 的交叉编译,编译后的内容在 OpenSSL 源码的 out 目录下。

交叉编译 LibreSSL

编译该工具是使得 Python 支持加密协议,相当于 OpenSSL 的替代。

前往 libressl 目录,将下述脚本保存到 libressl 源码的同目录下,脚本内容如下,部分内容参数请按提示自定义更新:

#!/bin/bash
COMPILE_ROOT="$(dirname $(readlink -f "$0"))"
# NDK 目录,按需更换
export ANDROID_NDK_ROOT=/data/local/android-ndk-r25c
export ANDROID_GCC_ROOT=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
export ANDROID_GCC_PATH=${ANDROID_GCC_ROOT}/bin

BUILD_PATH=${COMPILE_ROOT}/build
OUT_PATH=${COMPILE_ROOT}/out

CROSS_COMPILER=aarch64-linux-android-
CROSS_COMPILER_CLANG=aarch64-linux-android33-

#prepare
mkdir -p ${BUILD_PATH}
mkdir -p ${OUT_PATH}
export PATH=${ANDROID_NDK_ROOT}:${ANDROID_GCC_PATH}:$PATH

export ARCH="aarch64"
export CC="${CROSS_COMPILER_CLANG}clang -pie -fPIE" 
export CPP="${CROSS_COMPILER_CLANG}clang -E  -pie -fPIE"
export CXX="${CROSS_COMPILER_CLANG}clang++  -pie -fPIE"

# 下方的链接文件,新版 NDK 变成了 llvm-xx 的文件格式了,可能旧版的还存在诸如 aarch64-linux-android-xx 的格式文件,若为旧版格式文件,可将下面注释的取消注释,并将 llvm-xx 格式的命令参数反向注释掉,按需修改
#export AS="${CROSS_COMPILER}as"
export LD="${CROSS_COMPILER}ld  -pie -fPIE"
export GDB="${CROSS_COMPILER}gdb"
export STRIP="${CROSS_COMPILER}strip"
#export RANLIB="${CROSS_COMPILER}ranlib"
#export OBJCOPY="${CROSS_COMPILER}objcopy"
#export OBJDUMP="${CROSS_COMPILER}objdump"
#export AR="${CROSS_COMPILER}ar"
#export NM="${CROSS_COMPILER}nm"
export RANLIB="llvm-ranlib"
export AR="llvm-ar"
export NM="llvm-nm"
export OBJCOPY="llvm-objcopy"
export OBJDUMP="llvm-objdump"
export AS="llvm-as"
#export READELF="${CROSS_COMPILER}readelf"
export READELF="llvm-readelf"
export M4=m4
export TARGET_PREFIX=$CROSS_COMPILER
export CXXFLAGS="-D__ANDROID_API__=33 "

cd ${BUILD_PATH}


config_soft(){
    ../configure --host=aarch64-linux-android  \
        --host=aarch64-linux \
        --build=x86_64-linux-gnu \
        --target=aarch64-linux-android \
        --prefix=${OUT_PATH}
}

make_soft(){
    make -j $(nproc)
}

make_soft_install(){
    make install
}

make_clean(){
    make clean
}


case "$1" in
    config_soft)
        config_soft
    ;;
    make_soft)
        make_soft
    ;;
    make_soft_install)
        make_soft_install
    ;;
    make_clean)
        make_clean
    ;;
esac

然后编译安装,安装的文件在 out 目录下:

root@ubuntu:/data/local/libressl-3.8.1# vim make_libressl.sh
root@ubuntu:/data/local/libressl-3.8.1# bash make_libressl.sh config_soft
……
root@ubuntu:/data/local/libressl-3.8.1# bash make_libressl.sh make_soft
……
root@ubuntu:/data/local/libressl-3.8.1# bash make_libressl.sh make_soft_install
……

交叉编译 Python

下面就到了交叉编译 Python 的环节了。

此处需注意一下,交叉编译前,系统内需要一份同版本的 Python ,所以我们先编译安装一份当前系统下的 Python ,命令如下:

# 先安装一些库
root@ubuntu:/data/local/Python-3.7.17# apt install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev git libgdbm-dev libdb-dev libpcap-dev libexpat1-dev

# 然后编译安装一份当前版本的 Python 。注意的是,此处不需要真正安装到系统中去,所以我将其安装在源码的 python3_bin 目录下,供下面的脚本需要
# 生成配置文件,--prefix按需修改,若修改,下面的脚本路径也需要你按需自定义
root@ubuntu:/data/local/Python-3.7.17# ./configure --prefix=/data/local/Python-3.7.17/python3_bin

# 编译安装
root@ubuntu:/data/local/Python-3.7.17# make && make install

# 安装操作结束后,清除一下 Python 源代码目录文件的一些编译过程文件
root@ubuntu:/data/local/Python-3.7.17# make clean

然后继续在 Python3.7 源码目录,将下述脚本保存到 Python3 源码的同目录下,脚本内容如下,部分内容参数请按提示自定义更新:

#!/bin/bash
# 此为上述编译后生成的 Python 3 二进制文件所在,并设置一下别名
export PATH=/data/local/Python-3.7.17/python3_bin/bin:$PATH
alias python='python3'
COMPILE_ROOT="$(dirname $(readlink -f "$0"))"
# NDK 路径
export ANDROID_NDK_ROOT=/data/local/android-ndk-r25c
export ANDROID_GCC_ROOT=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64
export ANDROID_GCC_PATH=${ANDROID_GCC_ROOT}/bin

BUILD_PATH=${COMPILE_ROOT}/build
# 生成二进制文件的路径
OUT_PATH=/data/local/tmp/python3

# 若 OpenSSL 不能正常编译加密库,可换成 LibreSSL
OPENSSL_PATH=/data/local/openssl-1.1.1w/out
OPENSSL_LIB_PATH=/data/local/openssl-1.1.1w/out/lib
#OPENSSL_PATH=/data/local/libressl-3.8.1/out
#OPENSSL_LIB_PATH=/data/local/libressl-3.8.1/out/lib


CROSS_COMPILER=aarch64-linux-android-
CROSS_COMPILER_CLANG=aarch64-linux-android33-

#prepare
mkdir -p ${BUILD_PATH}
mkdir -p ${OUT_PATH}
export PATH=${ANDROID_NDK_ROOT}:${ANDROID_GCC_PATH}:$PATH

export ARCH="aarch64"
export CC="${CROSS_COMPILER_CLANG}clang -pie -fPIE" 
export CPP="${CROSS_COMPILER_CLANG}clang -E  -pie -fPIE"
export CXX="${CROSS_COMPILER_CLANG}clang++  -pie -fPIE"

# 下方的链接文件,新版 NDK 变成了 llvm-xx 的文件格式了,可能旧版的还存在诸如 aarch64-linux-android-xx 的格式文件,若为旧版格式文件,可将下面注释的取消注释,并将 llvm-xx 格式的命令参数反向注释掉,按需修改
#export AS="${CROSS_COMPILER}as"
export LD="${CROSS_COMPILER}ld  -pie -fPIE"
export GDB="${CROSS_COMPILER}gdb"
export STRIP="${CROSS_COMPILER}strip"
#export RANLIB="${CROSS_COMPILER}ranlib"
#export OBJCOPY="${CROSS_COMPILER}objcopy"
#export OBJDUMP="${CROSS_COMPILER}objdump"
#export AR="${CROSS_COMPILER}ar"
#export NM="${CROSS_COMPILER}nm"
export RANLIB="llvm-ranlib"
export AR="llvm-ar"
export NM="llvm-nm"
export OBJCOPY="llvm-objcopy"
export OBJDUMP="llvm-objdump"
export AS="llvm-as"
#export READELF="${CROSS_COMPILER}readelf"
export READELF="llvm-readelf"
export M4=m4
export TARGET_PREFIX=$CROSS_COMPILER
export CONFIG_SITE="config.site"
export CXXFLAGS="-D__ANDROID_API__=33 "

cd ${BUILD_PATH}

config_soft(){
    # 此处可在 Android 设备上查看一下是否存在 /dev/ptmx 和 /dev/ptc 设备文件,有就把参数设置成 yes ,无则设为 no 。
    echo -e "ac_cv_file__dev_ptmx=yes\nac_cv_file__dev_ptc=no" > config.site

    ../configure --host=aarch64-linux-android  \
    --host=aarch64-linux \
    --build=x86_64-pc-linux-gnu \
    --target=aarch64-linux-android \
    LDFLAGS="-Wl,--allow-shlib-undefined -D__ANDROID_API__=33 -fPIC -L${OPENSSL_LIB_PATH}" \
    CFLAGS="-D__ANDROID_API__=33  " \
    CPPFLAGS="-D__ANDROID_API__=33" \
    --enable-ipv6 \
    --with-openssl=${OPENSSL_PATH} \
    --prefix=${OUT_PATH}
}

make_soft(){
    make -j $(nproc)
}

make_soft_install(){
    make install
}

make_clean(){
    make clean
}


case "$1" in
    config_soft)
        config_soft
    ;;
    make_soft)
        make_soft
    ;;
    make_soft_install)
        make_soft_install
    ;;
    make_clean)
        make_clean
    ;;
esac

先使用 config_soft 生成一些文件,命令如下:

root@ubuntu:/data/local/Python-3.7.17# vim make_python.sh
root@ubuntu:/data/local/Python-3.7.17# bash make_python.sh config_soft
……

到这一步需要注意,如果其他平台编译时在 build/Modules 文件夹内生成了 Setup 文件,我们需要修改一下里面的部分参数内容,其中 SSL 参数是我们上面脚本里指定的哪个加密库,下方就改成对应的加密库。同时指定一下 zlib 库文件位置:

root@ubuntu:/data/local/Python-3.7.17# vim build/Modules/Setup
……
SSL=/data/local/openssl-1.1.1w/out
_ssl _ssl.c \
    -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
    -L$(SSL)/lib -lssl -lcrypto
……

zlib zlibmodule.c -I/data/local/zlib-1.3/out/include -L/data/local/zlib-1.3/out/lib -lz
……

然后再编译安装生成可执行二进制文件:

root@ubuntu:/data/local/Python-3.7.17# bash make_python.sh make_soft
……
root@ubuntu:/data/local/Python-3.7.17# bash make_python.sh make_soft_install
……

生成成功后接下来就是将 /data/local/tmp 目录下的文件压缩并使用 adb 推到 Android 设备的 /data/local/tmp 目录下:

# 打包 Python 3 文件
root@ubuntu:/data/local/tmp# tar -zcvf python3.tar.gz python3

# adb 将文件推送至手机
adb push python3.tar.gz /data/local/tmp

然后在 Android 系统下解压,即可使用该 Python ,如图:

image-20230921162655368

接下来为更方便的调用,可写个脚本控制相关环境变量,脚本内容如下:

#!/system/bin/env sh
export HOME='/data/local/tmp/python3'
PYTHON_HOME='/data/local/tmp/python3'
export PATH=${PYTHON_HOME}/bin:${PATH}
export LD_LIBRARY_PATH=${PYTHON_HOME}/lib:${LD_LIBRARY_PATH}
export PYTHONPATH=${PYTHONPATH}:${PYTHON_HOME}

python3 "$@"

效果如下:

kali@shell:/data/local/tmp/python3 $ vi python_run.sh
kali@shell:/data/local/tmp/python3 $ chmod +x python_run.sh
kali@shell:/data/local/tmp/python3 $ ./python_run.sh --version
Python 3.7.17
kali@shell:/data/local/tmp/python3 $ ./python_run.sh
Python 3.7.17 (default, Sep 20 2023, 16:55:26)
[Clang 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

至此,基于 NDK 交叉编译的 Python 3 已能够在 Android 上执行。自己在编译过程中发现 pip 模块缺失,可前往 Python 官网下载 get-pip.py 进行安装即可,如下图:

image-20230921163853621


最后的最后,快淦饭了,就让 ChatGPT 给我生成一个标题吧:

image-20230921165230558

个人自己编译的一份成品也将其打包分享给大家,若有兴趣的小伙伴可根据编译的成品 Python 二进制文件去制作成 Magisk 模块使得挂载到设备上使用:

提取链接:
https://pan.baidu.com/s/1Sxs7VxEVPQKSWI_AL0aszg?pwd=6666

提取码:6666

End

本文标题:在 Android 上解锁 Python 魔力:交叉编译 Python 3 的完整指南

本文链接:https://www.isisy.com/1515.html

除非另有说明,本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

声明:转载请注明文章来源。

如果觉得我的文章对你有用,请随意赞赏