修改MagiskV24.1源码隐藏APK,使其以Root用户运行
修改Magisk源码,绑定APP安装包到Magisk中,在安装完Magisk后,APP能隐藏安装,并且用Root用户运行。
可以利用Magisk制作刷机包,这样ROM中就自带自己的APP(Root,隐藏运行)。
Magisk编译
编译参考官方给的ReadMe文档。https://github.com/topjohnwu/Magisk
-
下载Android Studio,并且进行初始化安装。
-
克隆源码
git clone --recurse-submodules https://github.com/topjohnwu/Magisk.git
注意一定要加上--recurse-submodules
将项目中子模块的源码一起克隆下来。
-
安装Python 3.6+
如果是Windows环境需要选择'Add Python to PATH',安装完成后执行 pip install colorama
。
-
将Android Studio中的JDK加入到环境变量中。
- macOS:
export JAVA_HOME="/Applications/Android Studio.app/Contents/jre/Contents/Home"
- Linux:
export PATH="/path/to/androidstudio/jre/bin:$PATH"
- Windows: Add
C:\Path\To\Android Studio\jre\bin
to environment variable PATH
-
设置环境变量 ANDROID_SDK_ROOT
来指向Android Sdk的文件夹。这个路径可以在Android Studio中找到。
注意:在编译不同版本的Magisk时,这个环境变量名是不相同。
-
在项目根目录下执行 ./build.py ndk
。脚本会自动下载和安装对应版本的NDK。
注意:
1.在编译不同版本的Magisk时,需要的NDK版本不同。
2.在切换编译不同版本Magisk时,注意设置不同的SDK路径。因为脚本在安装NDK(在Sdk路径下)时会生成都叫magisk
的NDK,这样就会导致NDK的版本不对,编译会失败。
-
执行脚本build.py
开始编译。这里选择全部编译Release版本。build.py -r all
。
Magisk源码修改
将APK文件编译进magiskinit文件
参考Magisk自己的代码:
with open(stub, 'rb') as src:
text = binary_dump(src, 'manager_xz')
write_if_diff(op.join(native_gen_path, 'binaries.h'), text)
# 这里Magisk将自己的Magisk管理器转成二进制数组的形式保存在binaries.h文件中。
将我们自己的文件也保存到binaries.h
文件中。
aas = op.join('native', 'aas.apk')
aab = op.join('native', 'aab.apk')
aac = op.join('native', 'xxxx', 'arm64-v8a', 'xxx')
with open(aas, 'rb') as src:
text = binary_dump(src, 'aas_xz')
write_if_diff(op.join(native_gen_path, 'binaries.h'), text)
with open(aab, 'rb') as src:
text = binary_dump(src, 'aab_xz')
write_if_diff(op.join(native_gen_path, 'binaries.h'), text)
with open(aac, 'rb') as src:
text = binary_dump(src, 'aasx_xz')
write_if_diff(op.join(native_gen_path, 'binaries.h'), text)
但是binaries.h
不会在后面追加,所以还需要修改文件的打开方式。
def write_if_diff(file_name, text):
do_write = True
if op.exists(file_name):
with open(file_name, 'r') as f:
orig = f.read()
do_write = orig != text
if do_write:
with open(file_name, 'a+') as f:#追加模式
f.write(text)
释放APK文件
在init.cpp
文件中添加释放文件的方法。如果在其他地方应用,注意在init.hpp
中添加需要的函数声明。
static int dump_aas(const char *path, mode_t mode) {
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
if (fd < 0)
return 1;
if (!unxz(fd, service_xz, sizeof(aas_xz)))
return 1;
close(fd);
return 0;
}
在main
函数中添加调用释放文件的方法。
if (argc > 1 && argv[1] == "-x"sv) {
if (argc > 2 && argv[2] == "manager"sv)
return dump_manager(argv[3], 0644);
else if (argc > 2 && argv[2] == "aas"sv)
return dump_aas(argv[3], 0644);
return 1;
}
修改exec_script
在执行脚本这个函数中,默认用busybox,修改为/system/bin/sh
。
void exec_script(const char *script) {
exec_t exec {
.pre_exec = set_script_env,
.fork = fork_no_orphan
};
exec_command_sync(exec, "/system/bin/sh", "-c", script);
}
安装APK和启动服务
在bootstage.cpp
中的boot_complete
函数中添加当设备启动完成时安装APK和启动服务。
if (access(INJECTIONSERVICEAPK, F_OK) == 0) {
rename(INJECTIONSERVICEAPK, "/data/aac.apk");
install_apk("/data/aac.apk");
} else {
auto init = MAGISKTMP + "/magiskinit";
exec_command_sync(init.data(), "-x", "xxxx", "/data/aas.apk");
install_apk("/data/aas.apk");
}
// run cmd
exec_script("cmd ...");
// run sh
//exec_command_sync("/system/bin/sh");
设置su为静默允许
在su_daemon.cpp
的get_su_info
函数设置静默允许。
static shared_ptr<su_info> get_su_info(unsigned uid) {
info->access = SILENT_SU_ACCESS;
}
su改名xx
将su改名为sp,需要修改2处。
-
magisk.hpp
constexpr const char *applet_names[] = { "xx", "resetprop", "magiskhide", nullptr };
-
applets.cpp
constexpr const char *applets[] = { "xx", "resetprop", "zygisk", nullptr };
总结
修改文件 |
修改目的 |
build.py |
将另外的附件的apk和文件编译进最后的magiskinit文件中。 |
applets.cpp |
将su更名为sp。 |
bootstage.cpp |
执行dump函数、安装apk、启动服务。 |
magisk.hpp |
将su更名为sp。定义部分宏。 |
init.cpp |
提供dump文件的函数,并在main函数中调用。 |
init.hpp |
dump函数声明。 |
script.cpp |
/system/bin/sh 代替busybox 。 |
su_daemon.cpp |
设置su默认静默允许。 |
离线编译
在某些环境下可能全程不能联网,这个时候就需要我们进行离线编译。
ndk下载
在build.py ndk
命令时,脚本会自动联网下载对应的ndk,如果不能联网就会报错。
-
先利用外网环境确定需要的ndk版本,在官网上下载后,复制到项目根目录下。
-
修改脚本build.py
def setup_ndk(args):
os_name = platform.system().lower()
ndk_ver = config['ndkVersion']
url = f'https://dl.google.com/android/repository/android-ndk-r{ndk_ver}-{os_name}.zip'
ndk_zip = 'android-ndk-r23b-linux.zip'
# header(f'* Downloading {ndk_zip}')
# with urllib.request.urlopen(url) as response, open(ndk_zip, 'wb') as out_file:
# shutil.copyfileobj(response, out_file)
header('* Extracting NDK zip')
rm_rf(ndk_path)
...
gradle-wrapper.jar联网下载
在执行clean
或者构建是会调用到这个Jar包,这个jar会联网,此时没有网络也会报错。
删除根目录下的grade(Linux下)脚本的最后一行的调用代码。
build.py all
编译二进制失败。
如果我们之前清理了整个项目,/out/
目录下是不会编译出app-release.apk
和stub-release.apk
,而在编译二进制之前要确保这两个apk已经编译完成了。
用之前外网已经编译好的apk复制到离线环境的/out/
路径下,重新编译就能编译出整个项目了。