1.了解hook抓包与混淆对抗
2.了解底层网络自吐
3.了解ebpf抓包
4.简单实战加解密协议
1.教程Demo
2.r0capture&ecapture
3.Reqable
4.wireshark
Hook 抓包是一种截取应用程序数据包的方法,通过 Hook 应用或系统函数来获取数据流。在应用层 Hook 时,通过查找触发请求的函数来抓包,优点是不受防抓包手段影响,缺点是抓包数据不便于我们分析和筛选。
常见安卓网络开发框架
参考项目:
OkHttpLogger-Frida
源码解析:
定位OkHttpClient关键点
拦截器加载关键点
使用操作:
1.将 okhttpfind.dex
拷贝到 /data/local/tmp/
目录下(顺带设置一下777权限)
2.执行命令启动frida -U wuaipojie -l okhttp_poker.js
可追加 -o [output filepath]
保存到文件
3.执行find()和hold()方法看看效果
问题:如果app不是用okhttp开发的呢?或者混淆定位不到?
[原创]android抓包学习的整理和归纳
r0capture开源地址
Hook实现
通过拦截 Java 中的 socketWrite0
和 socketRead0
方法,在数据发送和接收时收集相关信息并发送给指定的接收方,以便进行监控或调试
Hook实现
拦截了 SSLOutputStream
和 SSLInputStream
类的 write
和 read
方法,在进行数据读写时获取当前的调用栈信息
拦截 sendto
和 recvfrom
函数,捕获发送和接收的数据包。onEnter
钩子函数用于在函数调用前处理参数,获取文件描述符和缓冲区地址,调用 hexdump
打印缓冲区内容以便查看实际发送或接收的数据
Hook实现
r0capture简介
wireshark下载地址
what-is-ebpf
eBPF是一个运行在 Linux 内核里面的虚拟机组件,它可以在无需改变内核代码或者加载内核模块的情况下,安全而又高效地拓展内核的功能。
ecapture
官方案例
eCapture主要利用了eBPF和HOOK技术:
eCapture 的工作原理涉及到用户态和内核态。用户态就是运行应用程序的地方,比如各种 App。在这个区域中,eCapture 通过一个共享的模块(Shared Object)获取应用程序的网络数据。然后,它将这些数据传递给内核态的 eBPF 程序进行分析和处理。
在内核空间,eCapture 通过 eBPF 插件捕捉网络层的数据流,比如数据包是从哪里来的、发到了哪里去。这一过程不需要修改应用程序本身,所以对系统性能影响很小。
安卓设备的内核版本只有在5.10版本上才可以进行无任何修改的开箱抓包操作(如果你的设备是安卓13,应该可以正常使用ecapture。低于13的安卓设备,如果内核是5.10,理论也是可行的。 因为安卓使用的linux内核的ebpf环境受内核版本号的影响,而工作良好的ebpf接口是在内核5.5版本时才全部使能。)
可通过adb命令查看自己的设备的内核版本
下载地址
使用说明
服务端代码:
协议实现:
百度云
阿里云
哔哩哔哩
教程开源地址
PS:解压密码都是52pj,阿里云由于不能分享压缩包,所以下载exe文件,双击自解压
炒冷饭汇总抓包姿势-上
安卓 App 逆向课程之四 frida 注入 Okhttp 抓包中篇
OkHttpClient client =
new
OkHttpClient.Builder()
.addNetworkInterceptor(
new
LoggingInterceptor())
.build();
Request request =
new
Request.Builder()
.url(
"https://www.52pojie.cn/"
)
.header(
"User-Agent"
,
"OkHttp Example"
)
.build();
Response response = client.newCall(request).execute();
response.body().close();
OkHttpClient client =
new
OkHttpClient.Builder()
.addNetworkInterceptor(
new
LoggingInterceptor())
.build();
Request request =
new
Request.Builder()
.url(
"https://www.52pojie.cn/"
)
.header(
"User-Agent"
,
"OkHttp Example"
)
.build();
Response response = client.newCall(request).execute();
response.body().close();
/**
* 查找并配置OkHttpClient的Client和Builder类。
* 该方法通过反射扫描指定类的字段和方法来确定其是否符合OkHttpClient的结构特征。
* 如果找到符合的类,则会进一步配置和注入相关拦截器。
*
* @param classes 当前扫描的类
* @param className 类名,用于查找和调试
*/
private
void
findClientAndBuilderAndBuildAnd(Class classes, String className) {
try
{
if
(Modifier.isFinal(classes.getModifiers())
&& Modifier.isStatic(classes.getModifiers())) {
int
listCount =
0
;
int
finalListCount =
0
;
int
listInterfaceCount =
0
;
Field[] fields = classes.getDeclaredFields();
Field.setAccessible(fields,
true
);
for
(Field field : fields) {
String type = field.getType().getName();
if
(type.contains(List.
class
.getName())) {
listCount++;
Class genericClass = getGenericClass(field);
if
(
null
!= genericClass && genericClass.isInterface()) {
listInterfaceCount++;
}
}
if
(type.contains(List.
class
.getName()) && Modifier.isFinal(field.getModifiers())) {
finalListCount++;
}
}
if
(listCount ==
4
&& finalListCount ==
2
&& listInterfaceCount ==
2
) {
Class OkHttpClientClazz = classes.getEnclosingClass();
if
(Cloneable.
class
.isAssignableFrom(OkHttpClientClazz)) {
OkCompat.Cls_OkHttpClient = OkHttpClientClazz.getName();
if
(
null
!= classes &&
null
!= classes.getPackage()) {
Compat_PackageName = classes.getPackage().getName();
}
Class builderClazz = classes;
find_interceptor(builderClazz);
findClientAbout(OkHttpClientClazz);
findTag1 =
true
;
}
}
}
}
catch
(Throwable th) {
}
}
/**
* 查找并注入Interceptor拦截器到Builder类中。
* 此方法会扫描Builder类的字段,找到符合拦截器的字段并进行配置。
*
* @param builderClazz 需要查找的Builder类
*/
private
void
find_interceptor(Class builderClazz) {
if
(!checkPackage(builderClazz))
return
;
Field[] declaredFields = builderClazz.getDeclaredFields();
Field.setAccessible(declaredFields,
true
);
int
index =
0
;
for
(Field field : declaredFields) {
if
(List.
class
.isAssignableFrom(field.getType()) && Modifier.isFinal(field.getModifiers())
&& getGenericClass(field).isInterface()) {
if
(index ==
0
) {
findInterceptor(field);
index++;
}
}
}
}
/**
* 查找并配置OkHttpClient的Client和Builder类。
* 该方法通过反射扫描指定类的字段和方法来确定其是否符合OkHttpClient的结构特征。
* 如果找到符合的类,则会进一步配置和注入相关拦截器。
*
* @param classes 当前扫描的类
* @param className 类名,用于查找和调试
*/
private
void
findClientAndBuilderAndBuildAnd(Class classes, String className) {
try
{
if
(Modifier.isFinal(classes.getModifiers())
&& Modifier.isStatic(classes.getModifiers())) {
int
listCount =
0
;
int
finalListCount =
0
;
int
listInterfaceCount =
0
;
Field[] fields = classes.getDeclaredFields();
Field.setAccessible(fields,
true
);
for
(Field field : fields) {
String type = field.getType().getName();
if
(type.contains(List.
class
.getName())) {
listCount++;
Class genericClass = getGenericClass(field);
if
(
null
!= genericClass && genericClass.isInterface()) {
listInterfaceCount++;
}
}
if
(type.contains(List.
class
.getName()) && Modifier.isFinal(field.getModifiers())) {
finalListCount++;
}
}
if
(listCount ==
4
&& finalListCount ==
2
&& listInterfaceCount ==
2
) {
Class OkHttpClientClazz = classes.getEnclosingClass();
if
(Cloneable.
class
.isAssignableFrom(OkHttpClientClazz)) {
OkCompat.Cls_OkHttpClient = OkHttpClientClazz.getName();
if
(
null
!= classes &&
null
!= classes.getPackage()) {
Compat_PackageName = classes.getPackage().getName();
}
Class builderClazz = classes;
find_interceptor(builderClazz);
findClientAbout(OkHttpClientClazz);
findTag1 =
true
;
}
}
}
}
catch
(Throwable th) {
}
}
/**
* 查找并注入Interceptor拦截器到Builder类中。
* 此方法会扫描Builder类的字段,找到符合拦截器的字段并进行配置。
*
* @param builderClazz 需要查找的Builder类
*/
private
void
find_interceptor(Class builderClazz) {
if
(!checkPackage(builderClazz))
return
;
Field[] declaredFields = builderClazz.getDeclaredFields();
Field.setAccessible(declaredFields,
true
);
int
index =
0
;
for
(Field field : declaredFields) {
if
(List.
class
.isAssignableFrom(field.getType()) && Modifier.isFinal(field.getModifiers())
&& getGenericClass(field).isInterface()) {
if
(index ==
0
) {
findInterceptor(field);
index++;
}
}
}
}
/**
* hookRealCall - 拦截 OkHttp 的 RealCall 类的网络请求。
* 该方法通过拦截 RealCall 类的 `enqueue`(异步请求)和 `execute`(同步请求)方法,
* 实现对网络请求和响应的捕获和处理。
*
* @param {string} realCallClassName - OkHttp RealCall 类的完整类名。
*/
function hookRealCall(realCallClassName) {
Java.perform(function () {
console.log(
" ........... hookRealCall : "
+ realCallClassName)
var RealCall = Java.use(realCallClassName)
if
(
""
!= Cls_CallBack) {
RealCall[M_Call_enqueue].overload(Cls_CallBack).implementation = function (callback) {
var realCallBack = Java.use(callback.$className)
realCallBack[M_CallBack_onResponse].overload(Cls_Call, Cls_Response).implementation = function(call, response) {
var newResponse = buildNewResponse(response)
this
[M_CallBack_onResponse](call, newResponse)
}
this
[M_Call_enqueue](callback)
realCallBack.$dispose
}
}
RealCall[M_Call_execute].overload().implementation = function () {
var response =
this
[M_Call_execute]()
var newResponse = buildNewResponse(response)
return
newResponse;
}
})
}
/**
* hookRealCall - 拦截 OkHttp 的 RealCall 类的网络请求。
* 该方法通过拦截 RealCall 类的 `enqueue`(异步请求)和 `execute`(同步请求)方法,
* 实现对网络请求和响应的捕获和处理。
*
* @param {string} realCallClassName - OkHttp RealCall 类的完整类名。
*/
function hookRealCall(realCallClassName) {
Java.perform(function () {
console.log(
" ........... hookRealCall : "
+ realCallClassName)
var RealCall = Java.use(realCallClassName)
if
(
""
!= Cls_CallBack) {
RealCall[M_Call_enqueue].overload(Cls_CallBack).implementation = function (callback) {
var realCallBack = Java.use(callback.$className)
realCallBack[M_CallBack_onResponse].overload(Cls_Call, Cls_Response).implementation = function(call, response) {
var newResponse = buildNewResponse(response)
this
[M_CallBack_onResponse](call, newResponse)
}
this
[M_Call_enqueue](callback)
realCallBack.$dispose
}
}
RealCall[M_Call_execute].overload().implementation = function () {
var response =
this
[M_Call_execute]()
var newResponse = buildNewResponse(response)
return
newResponse;
}
})
}
D:\Program Files\WORKON_HOME\frida16\frida
-
agent
-
example>frida
-
U wuaipojie
-
l okhttp_poker.js
____
/
_ | Frida
16.1
.
3
-
A world
-
class
dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/
_
/
|_|
help
-
> Displays the
help
system
. . . .
object
?
-
> Display information about
'object'
. . . . exit
/
quit
-
> Exit
. . . .
. . . . More info at https:
/
/
frida.re
/
docs
/
home
/
. . . .
. . . . Connected to Redmi K30 (
id
=
30d9b4bf
)
Attaching...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
OkHttp Poker by SingleMan [V.
20201130
]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
API:
>>> find() 检查是否使用了Okhttp & 是否可能被混淆 & 寻找okhttp3关键类及函数
>>> switchLoader(
"okhttp3.OkHttpClient"
) 参数:静态分析到的okhttpclient类名
>>> hold() 开启HOOK拦截
>>> history() 打印可重新发送的请求
>>> resend(index) 重新发送请求
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
[Redmi K30::wuaipojie ]
-
> find()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 未 混 淆 (仅参考)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
likelyClazzList size :
352
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Start Find~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Find Result~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var Cls_Call
=
"okhttp3.Call"
;
var Cls_CallBack
=
"okhttp3.Callback"
;
var Cls_OkHttpClient
=
"okhttp3.OkHttpClient"
;
var M_rsp$builder_build
=
"build"
;
var M_rsp_newBuilder
=
"newBuilder"
;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Find Complete~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Redmi K30::wuaipojie ]
-
> hold()
[Redmi K30::wuaipojie ]
-
> ........... hookRealCall : okhttp3.RealCall
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
| URL: http:
/
/
192.168
.
124.21
:
5000
/
get_user_data
|
| Method: GET
|
| Request Headers:
0
| no headers
|
|
-
-
> END
|
| URL: http:
/
/
192.168
.
124.21
:
5000
/
get_user_data
|
| Status Code:
200
/
OK
|
| Response Headers:
5
| ┌─Server: Werkzeug
/
2.3
.
3
Python
/
3.10
.
11
| ┌─Date: Sun,
27
Oct
2024
04
:
27
:
52
GMT
| ┌─Content
-
Type
: application
/
json
| ┌─Content
-
Length:
104
| └─Connection: close
|
| Response Body:
| {
"user_data"
:
"{\"user_id\": \"zj2595\", \"is_vip\": true, \"vip_level\": \"5\", \"coin_amount\": 115}"
}
|
|<
-
-
END HTTP
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
D:\Program Files\WORKON_HOME\frida16\frida
-
agent
-
example>frida
-
U wuaipojie
-
l okhttp_poker.js
____
/
_ | Frida
16.1
.
3
-
A world
-
class
dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/
_
/
|_|
help
-
> Displays the
help
system
. . . .
object
?
-
> Display information about
'object'
. . . . exit
/
quit
-
> Exit
. . . .
. . . . More info at https:
/
/
frida.re
/
docs
/
home
/
. . . .
. . . . Connected to Redmi K30 (
id
=
30d9b4bf
)
Attaching...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
OkHttp Poker by SingleMan [V.
20201130
]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
API:
>>> find() 检查是否使用了Okhttp & 是否可能被混淆 & 寻找okhttp3关键类及函数
>>> switchLoader(
"okhttp3.OkHttpClient"
) 参数:静态分析到的okhttpclient类名
>>> hold() 开启HOOK拦截
>>> history() 打印可重新发送的请求
>>> resend(index) 重新发送请求
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
[Redmi K30::wuaipojie ]
-
> find()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 未 混 淆 (仅参考)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
likelyClazzList size :
352
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Start Find~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Find Result~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var Cls_Call
=
"okhttp3.Call"
;
var Cls_CallBack
=
"okhttp3.Callback"
;
var Cls_OkHttpClient
=
"okhttp3.OkHttpClient"
;
var M_rsp$builder_build
=
"build"
;
var M_rsp_newBuilder
=
"newBuilder"
;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Find Complete~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Redmi K30::wuaipojie ]
-
> hold()
[Redmi K30::wuaipojie ]
-
> ........... hookRealCall : okhttp3.RealCall
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
| URL: http:
/
/
192.168
.
124.21
:
5000
/
get_user_data
|
| Method: GET
|
| Request Headers:
0
| no headers
|
|
-
-
> END
|
| URL: http:
/
/
192.168
.
124.21
:
5000
/
get_user_data
|
| Status Code:
200
/
OK
|
| Response Headers:
5
| ┌─Server: Werkzeug
/
2.3
.
3
Python
/
3.10
.
11
| ┌─Date: Sun,
27
Oct
2024
04
:
27
:
52
GMT
| ┌─Content
-
Type
: application
/
json
| ┌─Content
-
Length:
104
| └─Connection: close
|
| Response Body:
| {
"user_data"
:
"{\"user_id\": \"zj2595\", \"is_vip\": true, \"vip_level\": \"5\", \"coin_amount\": 115}"
}
|
|<
-
-
END HTTP
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Java.use(
"java.net.SocketOutputStream"
).socketWrite0.overload(
'java.io.FileDescriptor'
,
'[B'
,
'int'
,
'int'
).implementation =
function
(fd, bytearry, offset, byteCount) {
var
result =
this
.socketWrite0(fd, bytearry, offset, byteCount);
var
message = {};
message[
"function"
] =
"HTTP_send"
;
message[
"ssl_session_id"
] =
""
;
message[
"src_addr"
] = ntohl(ipToNumber((
this
.socket.value.getLocalAddress().toString().split(
":"
)[0]).split(
"/"
).pop()));
message[
"src_port"
] = parseInt(
this
.socket.value.getLocalPort().toString());
message[
"dst_addr"
] = ntohl(ipToNumber((
this
.socket.value.getRemoteSocketAddress().toString().split(
":"
)[0]).split(
"/"
).pop()));
message[
"dst_port"
] = parseInt(
this
.socket.value.getRemoteSocketAddress().toString().split(
":"
).pop());
message[
"stack"
] = Java.use(
"android.util.Log"
).getStackTraceString(Java.use(
"java.lang.Throwable"
).$
new
()).toString();
var
ptr = Memory.alloc(byteCount);
for
(
var
i = 0; i < byteCount; ++i)
Memory.writeS8(ptr.add(i), bytearry[offset + i]);
send(message, Memory.readByteArray(ptr, byteCount));
return
result;
}
Java.use(
"java.net.SocketInputStream"
).socketRead0.overload(
'java.io.FileDescriptor'
,
'[B'
,
'int'
,
'int'
,
'int'
).implementation =
function
(fd, bytearry, offset, byteCount, timeout) {
var
result =
this
.socketRead0(fd, bytearry, offset, byteCount, timeout);
var
message = {};
message[
"function"
] =
"HTTP_recv"
;
message[
"ssl_session_id"
] =
""
;
message[
"src_addr"
] = ntohl(ipToNumber((
this
.socket.value.getRemoteSocketAddress().toString().split(
":"
)[0]).split(
"/"
).pop()));
message[
"src_port"
] = parseInt(
this
.socket.value.getRemoteSocketAddress().toString().split(
":"
).pop());
message[
"dst_addr"
] = ntohl(ipToNumber((
this
.socket.value.getLocalAddress().toString().split(
":"
)[0]).split(
"/"
).pop()));
message[
"dst_port"
] = parseInt(
this
.socket.value.getLocalPort());
message[
"stack"
] = Java.use(
"android.util.Log"
).getStackTraceString(Java.use(
"java.lang.Throwable"
).$
new
()).toString();
if
(result > 0) {
var
ptr = Memory.alloc(result);
for
(
var
i = 0; i < result; ++i)
Memory.writeS8(ptr.add(i), bytearry[offset + i]);
send(message, Memory.readByteArray(ptr, result));
}
return
result;
}
Java.use(
"java.net.SocketOutputStream"
).socketWrite0.overload(
'java.io.FileDescriptor'
,
'[B'
,
'int'
,
'int'
).implementation =
function
(fd, bytearry, offset, byteCount) {
var
result =
this
.socketWrite0(fd, bytearry, offset, byteCount);
var
message = {};
message[
"function"
] =
"HTTP_send"
;
message[
"ssl_session_id"
] =
""
;
message[
"src_addr"
] = ntohl(ipToNumber((
this
.socket.value.getLocalAddress().toString().split(
":"
)[0]).split(
"/"
).pop()));
message[
"src_port"
] = parseInt(
this
.socket.value.getLocalPort().toString());
message[
"dst_addr"
] = ntohl(ipToNumber((
this
.socket.value.getRemoteSocketAddress().toString().split(
":"
)[0]).split(
"/"
).pop()));
message[
"dst_port"
] = parseInt(
this
.socket.value.getRemoteSocketAddress().toString().split(
":"
).pop());
message[
"stack"
] = Java.use(
"android.util.Log"
).getStackTraceString(Java.use(
"java.lang.Throwable"
).$
new
()).toString();
var
ptr = Memory.alloc(byteCount);
for
(
var
i = 0; i < byteCount; ++i)
Memory.writeS8(ptr.add(i), bytearry[offset + i]);
send(message, Memory.readByteArray(ptr, byteCount));
return
result;
}
Java.use(
"java.net.SocketInputStream"
).socketRead0.overload(
'java.io.FileDescriptor'
,
'[B'
,
'int'
,
'int'
,
'int'
).implementation =
function
(fd, bytearry, offset, byteCount, timeout) {
var
result =
this
.socketRead0(fd, bytearry, offset, byteCount, timeout);
var
message = {};
message[
"function"
] =
"HTTP_recv"
;
message[
"ssl_session_id"
] =
""
;
message[
"src_addr"
] = ntohl(ipToNumber((
this
.socket.value.getRemoteSocketAddress().toString().split(
":"
)[0]).split(
"/"
).pop()));
message[
"src_port"
] = parseInt(
this
.socket.value.getRemoteSocketAddress().toString().split(
":"
).pop());
message[
"dst_addr"
] = ntohl(ipToNumber((
this
.socket.value.getLocalAddress().toString().split(
":"
)[0]).split(
"/"
).pop()));
message[
"dst_port"
] = parseInt(
this
.socket.value.getLocalPort());
message[
"stack"
] = Java.use(
"android.util.Log"
).getStackTraceString(Java.use(
"java.lang.Throwable"
).$
new
()).toString();
if
(result > 0) {
var
ptr = Memory.alloc(result);
for
(
var
i = 0; i < result; ++i)
Memory.writeS8(ptr.add(i), bytearry[offset + i]);
send(message, Memory.readByteArray(ptr, result));
}
return
result;
}
Java.use(
"com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream"
).write.overload(
'[B'
,
'int'
,
'int'
).implementation =
function
(bytearry, int1, int2) {
var
result =
this
.write(bytearry, int1, int2);
SSLstackwrite = Java.use(
"android.util.Log"
).getStackTraceString(Java.use(
"java.lang.Throwable"
).$
new
()).toString();
return
result;
}
Java.use(
"com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream"
).read.overload(
'[B'
,
'int'
,
'int'
).implementation =
function
(bytearry, int1, int2) {
var
result =
this
.read(bytearry, int1, int2);
SSLstackread = Java.use(
"android.util.Log"
).getStackTraceString(Java.use(
"java.lang.Throwable"
).$
new
()).toString();
return
result;
}
Java.use(
"com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream"
).write.overload(
'[B'
,
'int'
,
'int'
).implementation =
function
(bytearry, int1, int2) {
var
result =
this
.write(bytearry, int1, int2);
SSLstackwrite = Java.use(
"android.util.Log"
).getStackTraceString(Java.use(
"java.lang.Throwable"
).$
new
()).toString();
return
result;
}
Java.use(
"com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream"
).read.overload(
'[B'
,
'int'
,
'int'
).implementation =
function
(bytearry, int1, int2) {
var
result =
this
.read(bytearry, int1, int2);
SSLstackread = Java.use(
"android.util.Log"
).getStackTraceString(Java.use(
"java.lang.Throwable"
).$
new
()).toString();
return
result;
}
函数名称 |
描述 |
native.socketWrite0 |
这是一个 native 方法,负责从 Java 层向底层网络接口写入数据。 |
libopenjdk.so.NET_Send |
这是 libopenjdk.so 中的一个函数,调用底层的 sendto 方法,用于发送数据。 |
libc.so.sendto |
这是一个底层系统调用函数,将数据发送到指定的网络地址。 |
native.socketRead0 |
这是一个 native 方法,用于从底层网络接口读取数据。 |
libopenjdk.so.NET_Read |
这是 libopenjdk.so 中的一个函数,调用底层的 recvfrom 方法,负责接收数据。 |
libopenjdk.so.recvfrom |
这是一个底层系统调用函数,用于从网络接口接收数据包。 |
Hook实现 |
|
var
sendtoPtr = Module.getExportByName(
"libc.so"
,
"sendto"
);
var
recvfromPtr = Module.getExportByName(
"libc.so"
,
"recvfrom"
);
console.log(
"sendto:"
, sendtoPtr,
", recvfrom:"
, recvfromPtr);
Interceptor.attach(sendtoPtr, {
onEnter:
function
(args) {
var
fd = args[0];
var
buff = args[1];
var
size = args[2];
var
sockdata = getSocketData(fd.toInt32());
console.log(sockdata);
console.log(hexdump(buff, { length: size.toInt32() }));
},
onLeave:
function
(retval) {
}
});
Interceptor.attach(recvfromPtr, {
onEnter:
function
(args) {
this
.fd = args[0];
this
.buff = args[1];
this
.size = args[2];
},
onLeave:
function
(retval) {
var
sockdata = getSocketData(
this
.fd.toInt32());
console.log(sockdata);
console.log(hexdump(
this
.buff, { length:
this
.size.toInt32() }));
}
});
var
sendtoPtr = Module.getExportByName(
"libc.so"
,
"sendto"
);
var
recvfromPtr = Module.getExportByName(
"libc.so"
,
"recvfrom"
);
console.log(
"sendto:"
, sendtoPtr,
", recvfrom:"
, recvfromPtr);
Interceptor.attach(sendtoPtr, {
onEnter:
function
(args) {
var
fd = args[0];
var
buff = args[1];
var
size = args[2];
var
sockdata = getSocketData(fd.toInt32());
console.log(sockdata);
console.log(hexdump(buff, { length: size.toInt32() }));
},
onLeave:
function
(retval) {
}
});
Interceptor.attach(recvfromPtr, {
onEnter:
function
(args) {
this
.fd = args[0];
this
.buff = args[1];
this
.size = args[2];
},
onLeave:
function
(retval) {
最后于 5小时前
被正己编辑
,原因: