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

admin 2024年5月14日22:43:03评论2 views字数 12378阅读41分15秒阅读模式

前期准备

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

  • Python :前往官网下载对应版本源码,链接如下:https://www.python.org
  • NDK :交叉编译需要的工具,本文编译工具采用的是截止写文前最新的 NDK 25 ,下载链接如下(需科学网):https://developer.android.google.cn/ndk/downloads?hl=zh-cn
  • OpenSSL :加密库,链接如下:https://www.openssl.org/source/
  • LibreSSL :加密库(高版本 Python 编译使用 OpenSSL 库有时出现一些问题),该库同 OpenSSL ,相当于替代库,链接如下:https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/
  • zlib :编译需要的库,链接如下:https://www.zlib.net/
  • gcc :系统的 gcc 版本需高于 8 ,若不满足,请更换系统或升级 gcc 版本。
  • 以及中途可能遇到的库等,基本可使用 apt 命令安装。

本文基于 Debian 系系统进行编译操作演示,且交叉编译 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

最终如下图:

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

下面开始对相关组件等交叉编译,下述操作建议在 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.
……
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
……
root@ubuntu:/data/local/openssl-1.1.1w#

然后在 make_softmake_install_soft 完成 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=yesnac_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

然后解压,即可使用该 Python ,如图:

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

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

#!/system/bin/env sh
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 进行安装即可,如下图:

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

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

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

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

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

提取码:6666

点击下方 阅读原文 即可直达博客。

原文始发于微信公众号(小杨学安全):在 Android 上解锁 Python 魔力:交叉编译 Python 3 的完整指南

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月14日22:43:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   在 Android 上解锁 Python 魔力:交叉编译 Python 3 的完整指南https://cn-sec.com/archives/2137813.html

发表评论

匿名网友 填写信息