前言-Preface
最近在学习Frida,在网络上也看了不少相关的文章,几乎没有一个讲如何访问指针类型类的成员。昨天在拦截抖音的“getUserInfo”方法时,就遇到了无法使用普通方式直接访问其对象成员的数据。
Recently, I've been learning about Frida and have read quite a few articles online, but hardly any of them discuss how to access members of pointer-type classes. Yesterday, when I tried to intercept the "getUserInfo" method in DouYin(like TikTok, operating only in China), I encountered issues with accessing the data of object members using normal methods.
正文-Main Content
分析-Analysis
使用jadx工具对抖音的APK文件进行反编译,通过搜索直播评论JSON数据中的某个字段(通过抓包获取)最终定位到获取用户信息的方法:getUserInfo,该方法位于X.0kjE
包中,其部分代码如下:
Using the jadx tool, I decompiled DouYin's APK file and located the method for retrieving user information:
getUserInfo
, by searching for a specific field in the JSON data of live comments (obtained through packet capture). This method is found in theX.0kjE
package, and the snippet of code is as follows:
@Override // X.InterfaceC1337650kqh
public User getUserInfo() {
return this.userInfo;
}
通过jadx的”查找声明“找到User的定义文件,其部分代码如下:
By using the "Find Declaration" feature in jadx tool, I located the definition file for User. The snippet of code in this file is as follows:
public class User extends FlexModelBase<IBaseUser> implements IBaseUser, InterfaceC1917210zvT {
@SerializedName("nickname")
public String nickName;
@SerializedName("member_entrance_info")
public AnchorCommonVip anchorCommonVip;
@IgnoreProtoFieldCheck
@SerializedName("anchor_info")
public C1916470zuH anchorInfo;
@IgnoreProtoFieldCheck
@SerializedName("webcast_anchor_level")
public C1917260zvY anchorLevel;
@IgnoreProtoFieldCheck
@SerializedName("author_stats")
public C1917200zvS authorInfo;
里面包含了很多用户的相关信息,其中就有一个nickName(用户昵称)。所以只要我们Hook了getUserInfo
方法,就可以获取到用户的信息数据。因此使用如下的Frida脚本来HookgetUserInfo
方法。
The code above contains user-related information, including nickname. Therefore, by hooking the
getUserInfo
method, we can retrieve user information data. To do this, the following Frida script can be used to hook thegetUserInfo
method.
Java.perform(() => {
let C1333020kjE = Java.use("X.0kjE");
C1333020kjE["getUserInfo"].overload().implementation = function () {
let result = this["getUserInfo"]();
console.log(result.nickName.value);
return result;
};
});
这个时候如果你直接使用result.nickName.value
是会提示undefined的。
At this point, if you directly use
result.nickName.value
, you will get an 'undefined' error.
解决-Solution
遇事不决,倒头睡觉。经过一觉之后,我突然想到是否是和指针相关呢,于是马上询问ChatGPT(现在已经是面向ChatGPT编程了),提示词:How to access a pointer that points to a class in Frida?(如何在Frida中访问一个指向类的指针),ChatGPT给出了一个答案:
Go to sleep if you encounter any hard thing. After a good night's sleep, I suddenly wondered if it might be related to pointers. So, I immediately asked ChatGPT (I'm now a ChatGPT-oriented programming developer), the prompt is: How to access a pointer that points to a class in Frida? The ChatGPT gave me the answer as below:
Java.perform(function () {
var instance = Java.cast(ptr("0x12345678"), Java.use("com.example.ClassName"));
console.log("Method result: " + instance.methodName());
});
于是,按照ChatGPT给出的答案改造了一下我的代码:
So, I modified my code according to the answer provided by ChatGPT:
Java.perform(() => {
let C1333020kjE = Java.use("X.0kjE");
let User = Java.use("com.bytedance.android.live.base.model.user.User");
C1333020kjE["getUserInfo"].overload().implementation = function () {
let result = this["getUserInfo"]();
// 核心代码: 将result指针转换为User对象
// Core code: Convert the result pointer to a User object.
let userinfo = Java.cast(result, User)
console.log(userinfo.nickName.value);
return result;
};
});
上面的代码完美的解决了获取User对象成员的问题。
The above code perfectly solved the problem of accessing the members of the User object.
下图则是某个直播间用户发言时获取到的用户昵称数据(为什么有重复的昵称呢,因为getUserInfo
方法有多处调用)。
The image below shows the users' nickname data obtained when users comment in a live broadcast room (The reason why there are duplicate nicknames is because the
getUserInfo
method is called multiple times).