tmf.js Hook Shark框架相关疑问归纳总结报告

一、问题背景

在使用tmf.js脚本Hook目标APP的Shark框架(主要用于拦截、修改sendShark请求及响应)过程中,通过反编译目标APP源码,发现Shark框架核心类SharkHttpEntity的params字段类型为Protocol.MTMFShark.SashimiHeader,但tmf.js脚本中却定义了两个不同包路径的SashimiHeader类,且实际Hook过程中,无论使用哪个包路径的类定义,脚本均能正常执行、抓取请求,由此产生一系列关于类定义、类引用、动态解析及字段作用的疑问,结合实操测试逐步排查,现将核心问题及解析归纳如下。

二、核心疑问及详细解析

(一)类定义相关疑问

疑问1:tmf.js中为何定义两个SashimiHeader类?是否均被使用?

脚本中初始定义了两个SashimiHeader类,分别为:

  • var PClass = Java.use('Protocol.MShark.SashimiHeader')

  • var PPClass = Java.use('Protocol.MTMFShark.SashimiHeader')

经排查发现,两个类均未被实际引用(变量显示灰色,无任何调用场景),属于冗余代码。结合反编译源码可知,目标APP中确实存在这两个包路径的SashimiHeader类,且二者结构、字段完全一致------根据源码显示,Protocol.MShark.SashimiHeader类实际继承自Protocol.MTMFShark.SashimiHeader类,源码如下:

java 复制代码
package Protocol.MShark;

/* loaded from: classes.dex */
public class SashimiHeader extends Protocol.MTMFShark.SashimiHeader {
}

因继承关系,Protocol.MShark.SashimiHeader完全复用了父类(Protocol.MTMFShark.SashimiHeader)的所有字段(均包含apiName、header、cookies、query等核心字段),无额外新增或修改,推测脚本开发时,为兼容不同模块可能存在的不同类路径,提前定义了两个类作为备用,但后续解析参数时采用了动态类获取方式,导致这两个预定义类未被使用。

疑问2:反编译源码中SharkHttpEntity仅导入Protocol.MTMFShark.SashimiHeader,为何脚本中用Protocol.MShark.SashimiHeader也能正常执行?

核心原因:结合源码可知,Protocol.MShark.SashimiHeader是Protocol.MTMFShark.SashimiHeader的子类(二者为继承关系),子类完全复用父类的所有结构和字段,无任何差异。Frida动态Hook环境中,只要类的字段匹配,即使包路径不同、存在继承关系,也能正常对字段进行赋值、解析,因此无论使用哪个包路径的类定义,均不会影响脚本执行。但结合SharkHttpEntity源码可知,其params字段的实际类型为Protocol.MTMFShark.SashimiHeader(父类),Protocol.MShark.SashimiHeader(子类)属于非实际业务使用的类,仅为兼容导致的"错误定义可正常执行"场景。

(二)类解析与引用相关疑问

疑问3:脚本中实际通过何种方式解析SharkHttpEntity的params字段?

脚本中未使用预定义的PClass、PPClass,而是通过 动态获取类名 的方式解析params字段,关键代码为:

javascript 复制代码
var params = Java.cast(sharkHttpEnt.params.value, Java.use(sharkHttpEnt.params.value.$className))

解析:sharkHttpEnt.params.value.$className 会动态获取params对象的实际类名(即源码中正确的Protocol.MTMFShark.SashimiHeader),再通过Java.use动态获取该类,最后通过Java.cast进行类型转换,实现params字段的解析。

疑问4:打印类名时,为何显示的类名与预定义的SashimiHeader类路径一致?如何获取原始实际类名?

  1. 显示类名与预定义一致的原因:Frida中,通过Java.use定义类后,会将该类与变量绑定,打印params.value.$className时,会受预定义类的影响,显示预定义的类路径,而非原始实际类路径,导致打印结果无参考意义。

  2. 获取原始实际类名的方法:可通过类加载器强制加载目标类,代码示例:

  3. 获取原始实际类名的方法:可通过类加载器强制加载目标类,代码示例(规范代码块格式):

javascript 复制代码
var classLoader = Java.use('java.lang.ClassLoader').getSystemClassLoader();
var realClass = classLoader.loadClass('Protocol.MTMFShark.SashimiHeader');
console.log('原始实际类名:' + realClass.getName());

补充说明:加载结果并非返回true/false判断,而是通过"是否抛出异常"来判断加载是否正确------

① 若类加载正确:loadClass方法会成功返回该类的Class对象(即realClass有值),不会抛出异常,后续打印realClass.getName()会输出完整类名(Protocol.MTMFShark.SashimiHeader),说明加载正常;

② 若类加载失败(比如类路径写错、类未被加载到虚拟机):loadClass方法会直接抛出ClassNotFoundException异常(不会返回false),脚本会中断执行,由此可判断类未加载正确。

疑问5:Java.use()既能处理类,也能处理接口吗?二者获取的对象有何区别?

是的,Java.use()既能通过全类名获取Java类的Class对象,也能获取接口的Class对象,本质是通过类/接口的全路径获取其对应的Class对象,但二者存在核心区别:

  • 获取类的Class对象:可通过.new()创建该类的实例(如SashimiHeader.new()创建该类的实例(如SashimiHeader.new()创建该类的实例(如SashimiHeader.new()),用于操作类的字段、方法。

  • 获取接口的Class对象:无法通过.$new()创建实例(接口不能直接实例化),仅能用于Hook接口的实现类方法,或获取接口的相关定义。

(三)字段与实例相关疑问

疑问6:SashimiHeader类的作用是什么?其data字段是否存储请求和响应数据?

  1. SashimiHeader类作用:并非仅存储请求头,而是Shark框架中 统一封装 请求 、响应 元数据的容器类,其作用覆盖请求和响应场景------请求场景中,用于封装请求相关元数据;响应场景中,作为回调方法的响应体载体,核心字段及作用如下:
  • apiName:接口名称

  • header:HTTP请求头信息

  • cookies:请求携带的Cookie信息

  • query:URL查询参数

  1. data字段及响应存储相关:SashimiHeader类中 无data字段,data字段属于SharkHttpEntity类,仅用于存储请求体数据;而响应数据并非由专门的响应类处理,而是同样通过SashimiHeader类存储------结合sendShark方法的第三个入参ISharkCallback2(推测你提及的ISharkCallBack2为该接口),其onFinish回调方法中,响应体的类型正是SashimiHeader,即响应相关的元数据(如响应头、响应状态关联信息等),会封装到SashimiHeader实例中返回,因此SashimiHeader类同时承担请求元数据封装和响应元数据承载的作用,并非仅存储请求数据。

疑问7:Frida中访问对象字段为何需要加.value?创建实例后如何获取其所属类名?

  1. 加.value的原因:Frida中,通过Java.use获取的类、对象,其字段均为"字段描述符",并非直接的字段值,需通过.value才能获取到字段的实际值(如sharkHttpEnt.params.value 才能获取到params字段对应的SashimiHeader实例)。

  2. 获取实例所属类名的方法:通过实例.$className即可获取完整类名(包路径+类名),示例:

var newParams = Java.use('Protocol.MTMFShark.SashimiHeader').$new();

console.log('实例所属类名:' + newParams.$className);

(四)其他实操相关疑问

疑问8:Java.cast()的作用是什么?在脚本中如何体现?

Java.cast()的作用是 类型转换,即将一个对象转换成指定的类类型,确保后续能正常操作该类的字段、方法。脚本中核心应用场景为解析params字段:

var params = Java.cast(sharkHttpEnt.params.value, Java.use(sharkHttpEnt.params.value.$className));

此处将sharkHttpEnt.params.value(Object类型对象),转换成其实际对应的SashimiHeader类型,后续才能正常获取apiName、header等字段的值。

疑问9:脚本中创建new_params实例时,为何用预定义的SashimiHeader也能正常赋值?

脚本中创建新参数实例的代码为:var new_params = SashimiHeader.$new()(SashimiHeader为预定义的类变量),之所以能正常赋值,是因为无论预定义的类路径是否正确,其字段与实际SashimiHeader类的字段完全匹配,Frida动态环境会自动匹配字段进行赋值,因此不影响新参数的构建及请求的发送。

三、结论

(一)核心结论

  1. tmf.js中两个SashimiHeader类定义均为冗余代码,未被实际引用,脚本核心通过"动态获取类名+类型转换"解析params字段,确保请求正常抓取。

  2. 两个包路径的SashimiHeader类结构、字段完全一致,二者为继承关系(Protocol.MShark.SashimiHeader继承自Protocol.MTMFShark.SashimiHeader),子类复用父类所有字段,这是"错误类定义仍能正常执行"的核心原因,Frida动态环境对类路径的匹配要求较低,仅需字段匹配即可正常解析。

  3. SharkHttpEntity的params字段实际类型为Protocol.MTMFShark.SashimiHeader,SashimiHeader类是统一的请求/响应元数据容器,既存储请求相关元数据,也会作为sendShark方法回调(ISharkCallback2的onFinish方法)中响应体的类型,承载响应相关元数据,并非仅存储请求数据。

  4. 脚本中预定义类未被使用,动态类获取(Java.use(sharkHttpEnt.params.value.$className))是解析参数的核心方式,覆盖了预定义类的作用。

(二)现存问题

  1. 脚本存在冗余代码(PClass、PPClass定义),虽不影响执行,但降低代码可读性。

  2. 类定义与源码实际使用的类路径不一致(脚本初始用Protocol.MShark.SashimiHeader,源码用Protocol.MTMFShark.SashimiHeader),虽不影响功能,但存在潜在兼容性风险。

四、优化建议

  1. 删除冗余代码:移除PClass、PPClass的定义,仅保留与源码一致的Protocol.MTMFShark.SashimiHeader类定义,提升代码可读性。

  2. 统一类路径:将脚本中所有SashimiHeader类的定义,统一改为Protocol.MTMFShark.SashimiHeader,与SharkHttpEntity源码保持一致,避免潜在的兼容性问题。

  3. 添加日志打印:在params解析、实例创建的关键位置,添加类名打印日志,确保能直观看到实际使用的类路径,便于后续问题排查,示例代码:

五、总结

本次遇到的所有疑问,核心源于Frida动态Hook环境的特性(字段匹配即可正常执行)、脚本开发时的冗余定义,以及对SashimiHeader类作用、动态类解析方式的不了解。通过反编译源码对比、实操测试(修改类路径、添加日志、删除冗余代码),已明确所有疑问的核心原因,且确认当前脚本无功能性问题。优化后,脚本将更简洁、规范,与目标APP源码的一致性更高,后续Hook过程中可减少类路径相关的排查成本。

(注:文档部分内容可能由 AI 生成)

相关推荐
武帝为此1 小时前
【Shell 变量作用域详解】
前端·chrome
琢磨先生David2 小时前
Java算法每日一题
java·开发语言·算法
重生之后端学习2 小时前
114. 二叉树展开为链表
java·数据结构·算法·链表·职场和发展·深度优先
henry1010102 小时前
Deepseek辅助生成的HTML5网页版抄经典《弟子规》
前端·javascript·css·html·html5
csdn2015_2 小时前
mybatisplus自动生成id
java·mybatis
时艰.2 小时前
电商订单系统设计与实现
java
sheji34162 小时前
【开题答辩全过程】以 基于Java的网上书店销售系统的设计与实现为例,包含答辩的问题和答案
java·开发语言
少云清2 小时前
【UI自动化测试】2_web自动化测试 _Selenium环境搭建(重点)
前端·selenium·测试工具·web自动化测试
石去皿2 小时前
数据结构与算法面试核心考点精要
java·算法·面试