Skip to content

Instantly share code, notes, and snippets.

@5ec1cff
5ec1cff / test.md
Last active January 17, 2022 04:02
test

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

ssssssssssssssssssssssssssssssssssssssssssssssssssssssss

fffffffffffffffffffff

@5ec1cff
5ec1cff / zygisk.md
Last active May 8, 2024 02:16
Zygisk 源码分析 #Magisk #Zygisk

Zygisk 源码分析

以下分析基于 Magisk 76ddfeb93a8b3612cd68988323f422e996751e16

由于 Magisk 更新太快了,决定弃坑,自己去看源码罢!

Zygisk 注入到 Zygote 进程

Zygisk 加载是通过替换 app_process ,修改 LD_PRELOAD ,再执行原 app_process 实现的。

@5ec1cff
5ec1cff / dialog_in_system.md
Last active February 28, 2022 12:46
#Xposed Xposed 通过系统服务弹窗

Xposed 通过系统服务弹窗

想用 Xposed 实现一个纯注入系统的「去你大爷的内置浏览器」,需要实现一个「询问」功能,也就是启动内置浏览器 Activity 的时候并不总是替换,而是询问用户应该是用内置浏览器打开还是用户浏览器(显然内置浏览器往往不是 exported 的,因此不会出现在系统选择器中)。

既然是询问,肯定要有一个 Window 和用户交互,但是应该如何呈现这个 Window 很伤脑筋。一开始尝试把要启动的 Intent 用模块的 Activity 替换,模仿系统的 ResolverActivity 「转发」Intent,但是注意到这样处理多用户(工作空间)可能就有些棘手,此外「转发」也很麻烦。

于是换一种思路:hook 系统服务侧的 startActivity ,发现启动「内置浏览器」的 Intent 后,直接返回 0 (START_SUCCESS) ,同时显示一个 dialog 询问用户,根据用户操作再恢复 intent 的发送。

这个 dialog 自然是在系统服务最方便,但是系统服务不像普通的 app ,它没有 Activity ,又怎么弹 Dialog 呢?

@5ec1cff
5ec1cff / magisk_v242_hide_in_miui.md
Last active March 4, 2022 15:32
MIUI 12.5 下使用 Magisk v24.2 随机包名

最近把 Magisk 从 alpha 升级到了 24.2 ,不过 Alpha 频道有一个提醒:

https://t.me/magiskalpha/457

MIUI设备在升级 官方 v24.2 后可能会无法隐藏/还原Magisk app,这是MIUI系统本身的问题,请向MIUI反馈PackageInstaller API ( https://developer.android.com/reference/android/content/pm/PackageInstaller ) 无法正常工作。
临时解决办法:关闭MIUI优化后重试。

自己用的刚好是 MIUI 12.5 ,试了一下,尝试随机包名安装后一直提示失败。

查了一下源码,引入这个改进是这个提交:

@5ec1cff
5ec1cff / isolate_data.md
Created March 7, 2022 11:34
在 Android 11+ 中开启 data 和 Android/data 隔离

探测包名是 Android 应用安全措施的重要方法,而手段也多种多样。常规的通过 PMS 查询包名的方法已经有 HMA 帮忙隐藏,且随着 Android 版本更新也逐渐限制应用任意地获取包名(虽然可以声明需要查询的类型),但还有一种更阴险的方式,就是利用 /data/data 目录或 /sdcard/Android/data 的漏洞——它们下面的目录都是以包名命名的应用数据目录,尽管这两个目录不能直接列出,但是任何应用都具有这个目录的 x 权限(否则无法访问自己的数据目录),因此如果已知需要探测的包名,就可以通过 stat 等系统调用判断目录是否存在,进而确定包名的存在(成功或 Permission Denied 都表明文件存在)。这种方法并不能通过简单的 hook 防止(尤其是绕过库函数直接 syscall 的情况)。

不过 Android 11 实际上还引入了一些措施来防止包名的泄露,那就是通过文件系统层面的措施,将 data 和 Android/data 下的包名直接隔离,每个应用的进程基本上只能看到属于自己 uid 的数据目录。

检查下面两个 prop :

getprop persist.zygote.app_data_isolation
getprop persist.sys.vold_app_data_isolation_enabled
@5ec1cff
5ec1cff / window.md
Created March 12, 2022 15:48
消失的 window service

Window Manager Service 是 Android 的重要服务,各种窗口(Activity, toast, Dialog, 系统 UI 等)都通过这个服务注册和管理。

经常玩系统隐藏 API 的都知道这个实际上是一个名为 window 的 Binder 服务,通过 ServiceManager.getService("window") 就能拿到它的 BinderProxy ,进而转为 android.view.IWindowManager 直接调用 API

但是当你在 app 的 shell 下尝试获取这个服务,却会发现根本无法找到(以下在 Termux 中测试):

image

对比 activity 服务:

@5ec1cff
5ec1cff / README.md
Last active May 8, 2023 03:16
Android 获取当前焦点窗口的 pid, uid, 包名 等信息

说明

使用 frida 的时候经常需要通过 pid 附加到进程,因为 frida 自带的 -n 参数实在太不好用了——本来 Android 的「进程名」概念是很清楚的,在 Manifest 就能看到,要是不清楚也可以通过 packageName 或者 cmdline 来替代,但 frida 却非要让「应用的名字」作为注入应用主进程的唯一标识,什么包名、命令行,统统不认,遇到中文应用名就很麻烦;此外,这个操作似乎还要注入系统服务,从而导致 stop server 后发生各种诡异崩溃,因此我不太喜欢用这个参数。然而每次都要打开 shell ,输入 ps -ef | grep 找应用的 pid 很是麻烦,并且对于多进程的应用并非总是能「猜对」它的进程名的。于是写了这个脚本,至少可以确定当前看到的这个窗口属于哪个进程(没焦点的就不好说了)。

脚本运行在 Android 上的 shell (建议 /system/bin/sh),在主机端只要简单用 adb shell 之类的封装一下用起来就很方便了。

脚本主要利用 dumpsys window 的 mFocusedWindow 取得当前焦点窗口的 hash ,并查找 hash 对应窗口的 Session 信息获取 uid 和 pid 。

仅在 Android 11 上通过测试,adb 权限即可。

@5ec1cff
5ec1cff / generate.py
Last active April 3, 2023 11:35
Generate windows registry of context menu of IDEs in JB ToolBox
import os
# find icons in %AppData%\Microsoft\Windows\Start Menu\Programs\JetBrains Toolbox
template_add = r'''Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Directory\Background\shell\{prog_name}]
@="Open with {name}"
"Icon"="\"{current}\\icons\\{prog_name}.ico\""
@5ec1cff
5ec1cff / background.js
Last active August 3, 2023 13:23
Yet Another Saucenao Search Extension
function injector(url) {
console.log("injected");
let im = document.querySelector("img");
function loaded() {
let canvas = document.createElement("canvas");
canvas.width = im.naturalWidth;
canvas.height = im.naturalHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(im, 0, 0);