0%

遍历Java List

requestHeaders是一个Java的List对象,遍历其内容如下:

1
2
3
log += "  request.headers: " + rObject.$methods.find("toString").call(rObject, requestHeaders) + "\n";
for (var i = 0; i < requestHeaders.size(); i++)
log += " headers[" + i + "]: " + requestHeaders.get(i) + "\n";

输出:

1
2
request.headers: [com.sankuai.meituan.retrofit2.Header@a671e8]
headers[0]: com.sankuai.meituan.retrofit2.Header@a671e8

Hook Native

静态注册或动态注册的Native函数,第二个参数总是一个jobject,标识了调用者的信息;

例如Java层有以下声明代码:

1
private native String TestNative(int arg1, int arg2, String arg3);

在Frida hook时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const nativeHook_TestNative = {
onEnter: function (args) {
this.env = args[0];
//this.caller = args[1]; // jobject of the caller.
this.arg1 = args[2];
this.arg2 = args[3];
this.arg3 = args[4];
this.tag = "nativeHook_TestNative";
this.log = "";
this.log += "> - - - - - - - - <\n";
this.log += this.tag + " Enter.\n";
this.log += " JNIEnv: " + this.env + "\n";
this.log += " arg1: " + this.arg1 + "\n";
this.log += " arg2: " + this.arg2 + "\n";
this.log += " arg3: " + this.arg3 + ", " + GetStringUTFChars(this.env, this.arg3, NULL).readCString() + "\n";
console.log(this.log);
},
onLeave: function (ret) {
const tid = gettid();
this.log = this.tag + " Leave.\n";
this.log += " ret: " + ret + ", str:" + GetStringUTFChars(this.env, ret, NULL).readCString() + "\n";
this.log += "^ - - - - - - - - ^\n";
console.log(this.log);
}
};

简介

配合使用集成开发环境编辑器(例如:JetBrains IDEA或Visual Code)编写TypeScript脚本来规范化、模块化并提供自动补全你的代码,让你的开发效率大大提升。

部署

1
2
3
4
$ git clone git://github.com/oleavr/frida-agent-example.git
$ cd frida-agent-example/
$ npm install
$ npm run watch
  • 集成开发环境打开frida-agent-example目录

编辑frida-agent-example/index.ts文件并保存

npm run watch会监控index.ts文件并在项目根目录下生成_agent.js目标脚本。

  • Frida注入
1
$ frida -U -f com.example.android --runtime=v8 --no-pause -l _agent.js

关闭SELinux

1
2
3
4
5
6
7
8
9
10
11
12
13
project system/core/
diff --git a/init/init.cpp b/init/init.cpp
index 93fe944..acbcf66 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -913,6 +913,7 @@ static bool selinux_is_disabled(void)

static bool selinux_is_enforcing(void)
{
+ return false;
if (ALLOW_DISABLE_SELINUX) {
return selinux_status_from_cmdline() == SELINUX_ENFORCING;
}

adbd 取消授权

ALLOW_ADBD_NO_AUTHro.adb.secure是且的关系,编译release版时ALLOW_ADBD_NO_AUTH被置为0;这将导致release版的ro.adb.secure无论置1还是0都是不起作用的;

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index 45a2158..b526c1b 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -239,9 +239,9 @@ int adb_main(int is_daemon, int server_port)
// descriptor will always be open.
adbd_cloexec_auth_socket();

- if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
+
auth_required = false;
- }
+

adbd ROOT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
project system/core/
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index 45a2158..99050db 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -109,6 +109,7 @@ static void drop_capabilities_bounding_set_if_needed() {
}

static bool should_drop_privileges() {
+ return false;
#if defined(ALLOW_ADBD_ROOT)
char value[PROPERTY_VALUE_MAX];

@@ -287,12 +288,12 @@ int adb_main(int is_daemon, int server_port)

D("Local port disabled\n");
} else {
- if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) {
- // b/12587913: fix setcon to allow const pointers
- if (setcon((char *)root_seclabel) < 0) {
- exit(1);
- }
- }
+
+
+
+
+
+
std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
if (install_listener(local_name, "*smartsocket*", NULL, 0)) {
exit(1);

简介

以下内容如无特殊说明均基于IPv4的TCP/IP方式通讯。

因各种原因Android设备的WIFI功能无法进行网络连接或连接不稳定,经常出现掉线的情况。导致无法稳定持久的让Android设备对外提供服务。

例如:

Android设备A(以下简称设备A)原本以WIFI形式连接到局域网中,并且监听8082端口等待局域网内的其他设备访问并提供HTTP服务。但是设备AWIFI模块不稳定。那么可以通过adb forward + Rinetd使设备A通过USB的方式向外提供持久可靠的HTTP服务。

它是如何工作的

  • 设备A:监听A端口并等待连接。

  • adb forward:作为路由的功能,将计算机AA端口接收的数据以USB传输给设备AA端口

  • 计算机A:监听B端口并允许来自局域网的连接,将B端口上接收的数据转发给它自己的A端口

  • 通讯方式:

    1
    设备A <==设备A的A端口==> adb forward <==计算机A的A端口==> rinetd <==计算机A的B端口==> 局域网内的其他设备

要求

  • Rinetd:端口转发工具

部署

  • adb转发端口

假设设备A正在监听8082端口,那么就需要将计算机A18082端口接收来的数据转发到设备A8082端口。这里的端口都可以自定义的,不需要一定是808218082

1
adb -s 84B7N16620000115 forward tcp:18082 tcp:8082

也可以

1
adb -s 84B7N16620000115 forward tcp:0 tcp:8082

-s选项:可以指定设备序列号,在多个Android设备连接到同一台计算机时,这个选项是非常有用的。

tcp:18082 或 tcp:0:adb将在计算机A18082或任意一个可用的端口上开启监听。如果使用tcp:0,那么adb forwad成功后将输出成功开启监听的端口号。

tcp:8082:adb将计算机A18082端口或任意一个可用端口上接收到的数据转发给序列号为84B7N166200001158082端口去。

你需要确保计算机A18082端口是空闲的,否则adb会提示你端口被占用。

到这一步,你已经可以成功执行telnetcurl来测试adb的端口转发了:

1
2
telnet 127.0.0.1 18082
curl 127.0.0.1 18082

但是局域网内的其他计算机仍然不能通过局域网IP访问到计算机A18082端口,这是因为adb只监听回环IP,不允许来自局域网内的连接。

  • 安装并配置Rinetd

Rinetd端口转发工具允许来自局域网内的连接,所以还需要通过Rinetd计算机A18082端口做一次转发,以对局域网提供设备A的服务。

1
2
sudo apt-get install rinetd
sudo vim /etc/rinetd.conf

在该文件的最后一行添加以下内容并保存退出
0.0.0.0 10082 127.0.0.1 18082

该配置指出,监听计算机A10082端口并将接收到的数据转发给本机的18082端口;

  • 添加防火墙规则或关闭防火墙

关闭防火墙

至此,计算机A上开启了1808210082两个端口,并且局域网内的其他计算机可以通过局域网ip:10082访问设备A8082端口。并可以通过以下命令测试:

1
2
3
4
telnet 127.0.0.1 18082 // 测试本机18082端口是否能正常向手机的8082端口发送数据
telnet 127.0.0.1 10082 // 测试本机10082端口是否能正常向本机的18082端口发送数据
telnet 192.168.14.30 18082 // 该命令将失败,因为无法通过局域网访问adb转发的端口
telnet 192.168.14.30 10082 // 测试本机10082端口是否能正常向本机的18082端口发送数据

adb logcat中搜索指定进程的日志正则

1
7679\s+\d+\s+\w

打开Url Scheme协议链接

1
adb shell am start -a android.intent.action.VIEW -d "snssdk1128://user/profile/3733569708763603"

将用户证书修改为系统证书

1
2
3
4
5
6
7
8
adb shell
su
mount -o remount,rw /system
ls -al /data/misc/user/0/cacerts-added/
cp /data/misc/user/0/cacerts-added/* /etc/security/cacerts/*
rm /data/misc/user/0/cacerts-added/*
chmod 644 /etc/security/cacerts/*
chown root:root /etc/security/cacerts/*

查找端口占用情况

  • 通过端口号查找占用该端口的uid

例如需要查找8081端口,对应的16进制为:0x1f91

1
2
3
cat /proc/net/tcp6 | grep -i 1f91
# 或者
cat /proc/net/tcp | grep -i 1f91

结果如下:

1
53: 00000000000000000000000000000000:1F91 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 10080        0 300399 1 0000000000000000 99 0 0 10 -1
  • 通过uid查找该uid对应的进程号

其中10080uidUID(10080) - 10000 = 80 = u0_a80

1
adb shell su -c ps | grep u0_a80

结果如下:

结果有多个进程都属于u0_a80用户的,那么8081端口就在其中一个进程中

1
2
3
4
5
u0_a80    9732  530   1828844 114996 SyS_epoll_ 00f734acb8 S com.ss.android.ugc.aweme:push
u0_a80 9907 530 2520916 507228 SyS_epoll_ 00f734acb8 S com.ss.android.ugc.aweme
u0_a80 10029 530 1831376 118660 SyS_epoll_ 00f734acb8 S com.ss.android.ugc.aweme:pushservice
u0_a80 10956 530 1799376 102028 SyS_epoll_ 00f734acb8 S com.ss.android.ugc.aweme:downloader
u0_a80 10968 530 1989384 173844 SyS_epoll_ 00f734acb8 S com.ss.android.ugc.aweme:miniapp0
  • 根据进程id确定uid
1
adb shell su -c cat /proc/9907/cgroup

结果如下:

1
2
3
3:cpuset:/foreground
2:cpu:/
1:cpuacct:/uid_10080/pid_9907

查找顶级Activity

1
adb shell dumpsys activity activities > activity_activities.log

输出格式如下:其中每个Hist代表一个Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)

Display #0 (activities from top to bottom):

Stack #4:

Task id #144

* TaskRecord{e98d78a #144 A=com.tencent.karaoke U=0 sz=4}
...
* Hist #3: ActivityRecord{6da6fab u0 com.tencent.karaoke/.module.detail.ui.GiftBillboardActivity t144}
...

* Hist #2: ActivityRecord{cea57ec u0 com.tencent.karaoke/.module.live.ui.LiveActivity t144}
...

* Hist #1: ActivityRecord{840f95 u0 com.tencent.karaoke/.module.webview.ui.WebViewContainerActivity t144}
...

* Hist #0: ActivityRecord{ea80b18 u0 com.tencent.karaoke/.module.main.ui.MainTabActivity t144}
...

更改adbd的监听端口

1
2
3
setprop service.adb.tcp.port 5555
stop adbd
start adbd

启用/关闭开发者选项 - USB debugging

启用:setprop persist.sys.usb.config mtp,adb

关闭:setprop persist.sys.usb.config mtp
相关代码:

https://developer.android.com/reference/android/provider/Settings.Global.html#ADB_ENABLED

https://android.googlesource.com/platform/frameworks/base/+/android-4.4_r1.2/services/java/com/android/server/usb/UsbDeviceManager.java

调试启动APK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
:: Example:
:: run_dbg.bat org.github.testsignal .MainActivity
@ECHO OFF
CALL :DeQuote %1
SET PACKAGE_NAME=%return%

CALL :DeQuote %2
SET ACTIVITY_NAME=%return%

adb shell am start -D %PACKAGE_NAME%/%ACTIVITY_NAME%
adb shell ps | FINDSTR %PACKAGE_NAME%
ECHO please input process id:
SET /P PID=
adb forward tcp:12346 jdwp:%PID%
jdb -connect com.sun.jdi.SocketAttach:port=12346

PAUSE
GOTO :EOF

:DeQuote
SET return=%~1
GOTO :EOF

TWRP模式下挂载指定分区

1
2
3
adb shell make /test
adb shell ls -la /dev/block/platform/soc.0/f9824900.sdhci/by-name/boot
adb shell mount /dev/block/mmcblk0p43 /test

Ubuntu 上使用 Android-SDK

  • 安装platforms时需要注意引号

    1
    2
    root@github:/opt/android_sdk# ./tools/bin/sdkmanager --install "platforms;android-23"
    [=======================================] 100% Unzipping... android-6.0/source.p

logcat

android的Log.d系列日志是写在/dev/log_xxx文件中的;而/dev是挂载在tmpfs文件系统上,所以重启之后日志就消失了。参考:system/core/liblog/logd_write.csystem/core/liblog/logd_write_kern.c

1
2
# adb shell su -c mount | grep /dev
tmpfs /dev tmpfs rw,seclabel,nosuid,relatime,size=1424720k,nr_inodes=356180,mode=755 0 0

Hide all methods with CMAKE

在 CMAKE 中设置隐藏所有方法(不显示他们的符号);

Hide all methods without add “__attribute__(visibility(“default”))” for everyone of them:

1
2
set_target_properties(YOUR_TARGET_NAME PROPERTIES CXX_VISIBILITY_PRESET hidden)
set_target_properties(YOUR_TARGET_NAME PROPERTIES C_VISIBILITY_PRESET hidden)

Fucking knack of use ollvm edition clang to compile so on Android Studio

在 Android Studio 中使用 ollvm 版本的 clang 编译 so;

​ As you know, if you just overwrite the compiler executable file with ollvm edition, then you will get “‘xxx.h’ file not found” error, actually I am not understand this error explicitly, because the file exactly is there, and it will perform like you want when execute that compile command on shell, so here is my approach to avoid that:

​ Open “YOUT_PROJECT_PATH\app.externalNativeBuild\cmake\debug\TARGET_ABI\rules.ninja”, find the line of “rule C_COMPILER__TARGET”(TARGET mean the target name you specified by “add_library” on “CMakeLists.txt”), and you will find the path of clang executable file under it, modify it with your ollvm edition clang, then build your project as normal, you will get the ollvm compiled file.

​ 如果简单的使用 ollvm 版本的 clang.exe 等可执行文件替换掉原版 ndk toolchain 中的 exe,那么将会报一些头文件查找不到的错误,网上说的原因似乎是不同版本的 clang 将会使用的头文件有差异,然而如果在控制台中直接使用 ollvm 版本 clang 去手动执行编译命令,是可以正常编译成功得到 .o 文件的,以下是我避免该坑的方法:

​ 打开 “YOUT_PROJECT_PATH\app.externalNativeBuild\cmake\debug\TARGET_ABI\rules.ninja”,找到 “rule C_COMPILER__TARGET” 这一行(TARGET 指你在 CMakeLists.txt 中使用 add_library 指定的库名),然后你会在下面几行找到编译使用的 clang 路径,把它替换为你 ollvm 版本 clang 的路径,然后正常编译即可得到你想要的 so。

项目简介

Gnirehtet是一个非常优秀的项目。该项目为Android设备提供了通过adb方式的反向代理。它允许Android设备通过USB使用所接入计算机的Internet网络,并且计算机和Android设备都不需要任何root权限。它的服务器可以运行在GNU/LinuxWindowsMac OS上,客户端需要运行在Android Lollipop API 21 及以上。

Gnirehtet的当前版本(v2.4)支持通过IPv4传输TCPUDP协议的数据,但不支持IPv6

它是如何工作的

客户端(Client):android设备视为客户端。注册VPN服务,以拦截整个设备的网络流量。

服务器(Relay Server):计算机(WindowsGNU/LinuxMac OS)视为服务器。也称作中继服务器

客户端仅建立与服务器之间的TCP连接;并通过该TCP连接以字节数组的形式交换原生IPv4数据包

客户端和服务器之间的TCP连接在开始反向端口重定向后由adb建立,反向端口重定向命令如下:

1
adb reverse localabstract:gnirehtet tcp:31416

这意味着服务器必须监听31416端口,并且客户端的所有的sockets连接都将由adb重定向到服务器的31416端口上。所以务必确保服务器的31416端口未被其他程序占用,务必确保服务器和客户端之间的USB连接是正常且稳定的。

服务器从连接的客户端上接收IPv4数据包并且根据数据包与对应的目标IP建立sockets连接,然后开始双向中继传输数据。

这就需要服务器在OSI model上以Level 3(客户端一边)Level 5(外网一边)之间传输数据包;

获取更多详情请点我

为什么选择它

当Android设备的WIFI不够稳定时,或想获得更高的下载速度,或其他一些原因;

要求

  • Android Lollipop API 21 及以上;

  • Android设备需要启动adb debugging

  • Java 8的运行时环境,在Debian-based发行版上,需要openjdk-8-jre

  • adb 1.0.36及以上,因为需要adb reverse支持;

  • 服务器的31416端口未被占用且网络正常;

下载

根据需要下载对应的版本,建议下载最新版本:Last Release

Rust 版本

  • Linux: gnirehtet-rust-linux64-XXX.zip
  • Windows: gnirehtet-rust-win64-XXX.zip
  • Mac OS: gnirehtet-rust-macos64-XXX.zip

LinuxMac OS zip文件解压后包含以下文件:

  • gnirehtet.apk:安装在客户端上。
  • gnirehtet:安装在服务器上。

Windows zip文件解压后包含以下文件:

  • gnirehtet.apk:安装在客户端上。
  • gnirehtet.exe:安装在Windows服务器上。
  • gnirehtet-run.cmd:快速启动gnirehtet的批处理文件。

Java 版本

  • 全平台: gnirehtet-java-XXX.zip

解压后包含以下文件:

  • gnirehtet.apk:安装在客户端上。
  • gnirehtet.jar:部署在服务器上
  • gnirehtet:部署在服务器上
  • gnirehtet.cmd:部署在Windows服务器上
  • gnirehtet-run.cmd:快速启动gnirehtet的批处理文件。

运行

在服务器上启动服务,该服务不提供用户界面,以控制台终端的形式呈现:

1
./gnirehtet relay

Ubuntu上使Gnirehtet不占用命令行终端在后台运行:

1
sudo nohup ./gnirehtet relay &

在客户端上安装APK

1
adb install -r gnirehtet.apk

设置反向端口重定向并启动APP,该APP不提供用户界面,以Android Service的方式运行在系统后台:

1
2
adb reverse localabstract:gnirehtet tcp:31416
adb shell am start -a com.genymobile.gnirehtet.START -n com.genymobile.gnirehtet/.GnirehtetActivity

停止客户端:

1
adb shell am start -a com.genymobile.gnirehtet.STOP -n com.genymobile.gnirehtet/.GnirehtetActivity

停止服务器:

1
在gnirehtet的命令行终端上按下Ctrl + C组合键