文章总结: 本文档详细分析Frida框架中ObjC和Java模块的JavaScriptAPI与底层C/C++实现的五层映射架构,涵盖接口定义、GumJS绑定、平台实现、工厂模式和核心集成层。关键发现包括两类模块的函数映射表、内存布局、执行流程和跨平台差异,提供移动应用动态分析、安全测试和逆向工程的实际应用场景。文档强调通过理解JS-C++映射关系可提升移动平台Hook、SSLPinning绕过等实战能力,并给出性能优化与错误处理的最佳实践。 综合评分: 85 文章分类: 移动安全,逆向分析,WEB安全,红队,渗透测试
frida各模块js与cpp函数分析对照(六)
原创
haidragon haidragon
安全狗的自我修养
2026年4月5日 11:40 湖南
-
官网:http://securitytech.cc
ObjC和Java模块 JavaScript与底层C++函数映射关系分析
文档概述
本文档详细分析Frida中ObjC和Java模块的JavaScript API与其底层C/C++实现之间的映射关系,涵盖完整的五层架构模型分析。
五层架构模型分析
1. 接口定义层 (JavaScript API Layer)
ObjC模块主要接口:
Java模块主要接口:
2. 基础结构层 (GumJS Binding Layer)
在
subprojects/frida-gum/bindings/gumjs目录中,ObjC和Java模块的绑定实现在相关文件中。关键数据结构
### 3. 具体实现层 (Platform-specific Implementation)
#### ObjC实现 ( gumobjc*.c)
关键函数:
#### Java实现 ( gumjava*.c)
关键函数:
### 4. 工厂模式层 (Backend Factory)
#### ObjC工厂
#### Java工厂
### 5. 应用集成层 (Integration with Frida Core)
ObjC和Java模块通过frida-core与上层应用集成,提供统一的API接口,并与JNI(Java)和Objective-C Runtime深度集成。
## 详细函数映射关系表
### ObjC模块映射表
| JavaScript Function | C Function | File Location | Description |
| — | — | — | — |
| ObjC.classes.ClassName | gum_objc_api_resolver_get_class() | gumobjcapiresolver.c | 获取Objective-C类 |
| ObjC.Object.choose() | gum_objc_object_choose() | gumobjcobject.c | 枚举指定类的所有实例 |
| ObjC.selectorAsString() | gum_objc_selector_to_string() | gumobjcmessage.c | 将选择器转换为字符串 |
| ObjC.schedule() | gum_objc_schedule_on_queue() | gumobjcdispatch.c | 在指定队列上调度任务 |
### Java模块映射表
| JavaScript Function | C Function | File Location | Description |
| — | — | — | — |
| Java.use() | gum_java_use() | gumjavaapiresolver.c | 获取Java类包装器 |
| Java.choose() | gum_java_choose() | gumjavaobject.c | 枚举指定类的所有实例 |
| Java.cast() | gum_java_cast() | gumjavaobject.c | 转换Java对象类型 |
| Java.perform() | gum_java_perform() | gumjavavm.c | 在Java VM线程上执行代码 |
| Java.enumerateLoadedClasses() | gum_java_enumerate_loaded_classes() | gumjavavm.c | 枚举已加载的Java类 |
## 内存布局与数据结构可视化
### GumObjCObject结构体内存布局
### GumJavaObject结构体内存布局
### GumJavaClassWrapper结构体内存布局
## 系统调用级执行流程追踪
### ObjC.classes.ClassName执行流程
### Java.use()执行流程
### Java.perform()执行流程
### ObjC.Object.choose()执行流程
## 跨平台差异与抽象机制
### 平台特定实现
### 内存管理差异
### 线程模型差异
### 抽象层设计
## 调试命令与安全实践
### GDB调试示例
### 性能优化建议
### 安全考虑
## 错误处理与边界情况
### 常见错误场景
### 最佳实践
## 攻击检测场景映射
### 可用于检测的场景
### 防御绕过技术
## 性能分析与优化
### 时间复杂度分析
### 内存使用分析
## 扩展功能与自定义实现
### 自定义ObjC工具
### 自定义Java工具
### 底层扩展点
## 版本兼容性与演进
### API变更历史
### 向后兼容性保证
## 实战案例分析
### 案例1: iOS应用Hook
### 案例2: Android SSL Pinning Bypass
### 案例3: 动态类分析
### 案例4: ObjC内存分析
## 总结与最佳实践
ObjC和Java模块是Frida在移动平台上的核心功能,提供了对高级语言运行时的深度访问能力。理解其JS与C++的映射关系有助于:
通过本文档的五层架构分析,开发者可以全面掌握ObjC和Java模块的工作原理和使用技巧,为移动平台的动态分析任务提供坚实的基础。
-
核心API保持稳定
-
新功能通过扩展方式添加
-
废弃的API会标记并提供迁移路径
-
Frida早期版本: 基本的ObjC支持
-
Frida 6.x: 添加Java支持
-
Frida 8.x: 完善跨平台支持和性能优化
-
Frida 10.x: 添加更多的高级语言特性支持
-
Frida 12.x: 优化内存使用和错误处理
-
Frida 14.x: 改进Android版本兼容性和稳定性
-
可以通过修改
gumobjcapiresolver.c添加新的Objective-C特性支持 -
通过修改
gumjavaapiresolver.c添加新的Java API支持 -
扩展对象包装器支持更多的属性和方法访问模式
-
ObjC包装器: 每个对象和类包装器占用固定内存
-
Java包装器: 需要维护JNI引用和JavaScript包装器
-
优化建议:
-
及时释放不再使用的对象引用
-
重用类包装器避免重复查找
-
使用weak引用避免内存泄漏
-
ObjC类查找: O(1)(缓存后),O(n)(首次查找,n为类数量)
-
Java类查找: O(m)(m为类路径搜索时间)
-
对象创建: O(1)(简单包装),O(k)(k为构造函数复杂度)
-
方法调用: O(1)(直接调用),O(p)(p为参数转换开销)
-
直接调用: 绕过高级语言API直接调用底层函数
-
动态加载: 运行时动态加载和解析类
-
混淆技术: 使用混淆技术隐藏类和方法名
-
多线程规避: 在未被监控的线程中执行敏感操作
-
ObjC Hook检测: 监控关键Objective-C方法的调用
-
Java Hook检测: 监控敏感Java API的使用
-
反调试检测: 检测ObjC和Java运行时的存在
-
行为分析: 基于高级语言API调用进行行为分析
-
ObjC错误:
-
类不存在:返回undefined
-
方法不存在:调用时抛出异常
-
内存不足:对象创建失败
-
Java错误:
-
Java VM不可用:Java.available为false
-
类未找到:Java.use()抛出异常
-
JNI异常:需要正确处理和清除
-
线程错误:在非Java线程上执行JNI调用
-
ObjC安全:
-
避免调用可能导致崩溃的私有方法
-
注意内存管理避免循环引用
-
处理nil对象和异常情况
-
Java安全:
-
正确处理JNI异常
-
避免在错误的线程上下文中操作
-
注意Android版本兼容性
-
ObjC优化:
-
缓存常用的类和方法引用
-
避免频繁的对象创建和销毁
-
使用批处理减少消息发送开销
-
Java优化:
-
重用Java.use()返回的类对象
-
减少Java.perform()调用次数
-
使用局部变量避免重复字段访问
-
ObjC:
-
可以在任何线程上调用Objective-C方法
-
Grand Central Dispatch(GCD)支持
-
主队列和自定义队列调度
-
Java:
-
必须在附加到Java VM的线程上执行JNI调用
-
主线程通常已经附加,其他线程需要显式附加
-
Android主线程有特殊限制
-
ObjC内存管理:
-
自动引用计数(ARC)或手动引用计数(MRC)
-
使用
retain/release管理对象生命周期 -
JavaScript包装器持有强引用
-
Java内存管理:
-
Java垃圾回收自动管理
-
JNI局部引用和全局引用管理
-
需要显式释放全局引用避免内存泄漏
-
ObjC: 仅在Apple平台(macOS、iOS)可用
-
依赖Objective-C Runtime API
-
使用
objc_msgSend()进行消息发送 -
支持ARC和MRC内存管理
-
Java: 主要在Android平台可用
-
依赖JNI(Java Native Interface)
-
需要处理Java VM线程附加/分离
-
支持不同的Android版本和Java VM实现
-
分离线程 (
DetachCurrentThread()) -
附加线程到Java VM (
AttachCurrentThread()) -
调用
FindClass()JNI函数 -
处理类加载器上下文
-
gum_java_api_resolver_new() -
gum_java_perform() -
gum_java_use() -
gum_java_choose() -
gum_java_cast() -
核心实现:
gumjavaapiresolver.c– Java API解析器 -
VM交互:
gumjavavm.c– Java VM交互层 -
对象管理:
gumjavaobject.c– Java对象包装 -
类加载:
gumjavaclassloader.c– 类加载器管理 -
gum_objc_api_resolver_new() -
gum_objc_api_resolver_query_method() -
gum_objc_object_new() -
gum_objc_send_message() -
核心实现:
gumobjcapiresolver.c– Objective-C API解析器 -
对象管理:
gumobjcobject.c– Objective-C对象包装 -
消息发送:
gumobjcmessage.c– 消息发送机制 -
类枚举:
gumobjcmodule.c– 类和方法枚举 -
Java.available -
Java.androidVersion -
Java.enumerateLoadedClasses(callbacks) -
Java.enumerateClassLoaders(callbacks) -
Java.use(className) -
Java.choose(className,callbacks) -
Java.cast(handle,klass) -
Java.array(className,elements) -
Java.registerClass(spec) -
Java.scheduleOnMainThread(fn) -
Java.perform(fn) -
Java.performNow(fn) -
Java.vm -
Java.classFactory -
ObjC.available -
ObjC.classes -
ObjC.Object -
ObjC.Object.choose() -
ObjC.selectorAsString(sel) -
ObjC.schedule(queue,work) -
ObjC.mainQueue -
ObjC.deepUnwrap(obj) -
ObjC.deepWrap(value)
-
移动应用分析: 对iOS和Android应用进行深入的动态分析
-
安全测试: 绕过各种安全机制进行渗透测试
-
逆向工程: 辅助复杂的移动应用逆向工程任务
-
自动化测试: 构建基于高级语言API的自动化测试框架
-
// 分析iOS应用内存中的对象 -
if(ObjC.available){ -
// 枚举特定类的所有实例 -
constNSString=ObjC.classes.NSString; -
ObjC.Object.choose(NSString,{ -
onMatch:function(instance){ -
try{ -
const stringContent = instance.UTF8String().readUtf8String(); -
if(stringContent && stringContent.includes('password')){ -
console.log('Password-related string found:', stringContent); -
} -
}catch(e){ -
// 忽略无效对象 -
} -
}, -
onComplete:function(){ -
console.log('NSString enumeration completed'); -
} -
}); -
// 监控对象创建 -
constNSObject=ObjC.classes.NSObject; -
Interceptor.attach(NSObject['- init'].implementation,{ -
onLeave:function(retval){ -
const obj =newObjC.Object(retval); -
console.log('New object created:', obj.$className); -
} -
}); -
} -
// 动态分析Android应用类 -
if(Java.available){ -
Java.perform(function(){ -
// 枚举所有加载的类 -
Java.enumerateLoadedClasses({ -
onMatch:function(className){ -
if(className.startsWith('com.targetapp.')){ -
console.log('Target class found:', className); -
try{ -
const klass =Java.use(className); -
// 分析类的方法 -
const methods = klass.class.getDeclaredMethods(); -
methods.forEach(method =>{ -
const methodName = method.getName(); -
if(methodName.includes('encrypt')|| methodName.includes('decrypt')){ -
console.log(Sensitive method found: ${className}.${methodName}); -
// Hook敏感方法 -
klass[methodName].implementation =function(){ -
console.log(Called sensitive method: ${className}.${methodName}); -
returnthis[methodName].apply(this, arguments); -
}; -
} -
}); -
}catch(e){ -
console.error(Failed to analyze class ${className}:, e); -
} -
} -
}, -
onComplete:function(){ -
console.log('Class enumeration completed'); -
} -
}); -
}); -
} -
// 绕过Android SSL证书锁定 -
if(Java.available){ -
Java.perform(function(){ -
constCertificateFactory=Java.use('java.security.cert.CertificateFactory'); -
constFileInputStream=Java.use('java.io.FileInputStream'); -
constBufferedInputStream=Java.use('java.io.BufferedInputStream'); -
const X509Certificate =Java.use('java.security.cert.X509Certificate'); -
constKeyStore=Java.use('java.security.KeyStore'); -
constTrustManagerFactory=Java.use('javax.net.ssl.TrustManagerFactory'); -
// Hook X509TrustManager的checkServerTrusted方法 -
const X509TrustManager =Java.use('javax.net.ssl.X509TrustManager'); -
X509TrustManager.checkServerTrusted.implementation =function(chain, authType){ -
console.log('Bypassing SSL certificate check'); -
// 不执行任何验证,直接通过 -
}; -
// Hook OkHttp的CertificatePinner -
constCertificatePinner=Java.use('okhttp3.CertificatePinner'); -
CertificatePinner.check.overload('java.lang.String','java.util.List').implementation =function(hostname, certificates){ -
console.log('Bypassing OkHttp certificate pinning for:', hostname); -
// 不执行任何检查,直接通过 -
}; -
}); -
} -
// Hook iOS UIApplication delegate -
if(ObjC.available){ -
constUIApplication=ObjC.classes.UIApplication; -
const appDelegate =UIApplication.sharedApplication().delegate(); -
console.log('App delegate:', appDelegate.$className); -
// Hook特定方法 -
constViewController=ObjC.classes.ViewController; -
if(ViewController!==undefined){ -
Interceptor.attach(ViewController['- viewDidLoad'].implementation,{ -
onEnter:function(args){ -
console.log('View controller loaded'); -
const self =newObjC.Object(args[0]); -
console.log('Self:', self.$className); -
} -
}); -
} -
} -
// 扩展Java模块功能 -
Java.dumpClass =function(className){ -
const klass =Java.use(className); -
console.log(Class: ${className}); -
console.log('Methods:'); -
// 获取所有方法 -
const methods = klass.class.getDeclaredMethods(); -
methods.forEach(method =>{ -
console.log(${method.toString()}); -
}); -
console.log('Fields:'); -
const fields = klass.class.getDeclaredFields(); -
fields.forEach(field =>{ -
console.log(${field.toString()}); -
}); -
}; -
// Java对象属性访问简化 -
Java.getObjectProperty =function(obj, propertyName){ -
try{ -
const getterName ='get'+ propertyName.charAt(0).toUpperCase()+ propertyName.slice(1); -
if(obj[getterName]){ -
return obj[getterName](); -
} -
const fieldName = propertyName.charAt(0).toLowerCase()+ propertyName.slice(1); -
if(obj[fieldName]){ -
return obj[fieldName].value; -
} -
}catch(e){ -
console.error('Failed to get property:', e); -
} -
returnnull; -
}; -
// 扩展ObjC模块功能 -
ObjC.dumpClass =function(className){ -
const klass =ObjC.classes[className]; -
if(!klass){ -
console.log(Class ${className} not found); -
return; -
} -
console.log(Class: ${className}); -
console.log('Methods:'); -
// 获取所有实例方法 -
const methods = klass.$ownMethods; -
methods.forEach(method =>{ -
console.log(-${method}); -
}); -
// 获取所有类方法 -
const classMethods = klass.$ownClassMethods; -
classMethods.forEach(method =>{ -
console.log(+${method}); -
}); -
}; -
// 安全的ObjC使用 -
function safeUseObjCClass(className){ -
if(!ObjC.available){ -
console.warn('Objective-C runtime not available'); -
returnnull; -
} -
try{ -
const klass =ObjC.classes[className]; -
if(klass ===undefined){ -
console.warn(Class ${className} not found); -
returnnull; -
} -
return klass; -
}catch(e){ -
console.error(Failed to use ObjCclass ${className}:, e); -
returnnull; -
} -
} -
// 安全的Java使用 -
function safeUseJavaClass(className){ -
if(!Java.available){ -
console.warn('Java runtime not available'); -
returnnull; -
} -
try{ -
returnJava.use(className); -
}catch(e){ -
console.error(Failed to use Javaclass ${className}:, e); -
returnnull; -
} -
} -
// 安全的Java执行 -
function safeJavaPerform(fn){ -
if(!Java.available){ -
console.warn('Java runtime not available'); -
returnnull; -
} -
try{ -
returnJava.perform(fn); -
}catch(e){ -
console.error('Java perform failed:', e); -
returnnull; -
} -
} -
# 在ObjC类查找处设置断点 -
(gdb)break gum_objc_api_resolver_get_class -
# 查看类查找过程 -
(gdb) info args -
(gdb) print (char*)$rsi # 查看类名 -
(gdb) print/x $rax # 查看返回的类指针 -
# 在Java类使用处设置断点 -
(gdb)break gum_java_use -
(gdb) info registers -
(gdb) x/s $rdi # 查看类名字符串 -
// 语言API解析器抽象 -
struct_GumLanguageApiResolver -
{ -
GObject parent; -
gpointer (* get_class)(GumLanguageApiResolver* self,const gchar * name); -
gpointer (* create_instance)(GumLanguageApiResolver* self, gpointer klass,...); -
gpointer (* invoke_method)(GumLanguageApiResolver* self, gpointer object,const gchar * method_name,...); -
// ... 其他方法 -
}; -
// 对象包装器抽象 -
struct_GumScriptObjectWrapper -
{ -
JSObjectRef wrapper; -
gpointer handle; -
GumScriptClassWrapper* klass; -
GumScript* script; -
void(* dispose)(GumScriptObjectWrapper* self); -
gpointer (* get_property)(GumScriptObjectWrapper* self,const gchar * name); -
void(* set_property)(GumScriptObjectWrapper* self,const gchar * name,JSValueRef value); -
}; -
JavaScript调用
ObjC.Object.choose(klass,callbacks)→ GumJS绑定层 -
调用
gum_objc_object_choose(klass,callbacks) -
使用Objective-C Runtime的
objc_getClassList()获取所有类 -
对每个类实例进行内存扫描
-
验证实例类型匹配
-
对每个匹配实例调用onMatch回调
-
完成后调用onComplete回调
-
返回执行结果
-
执行传入的JavaScript函数
-
如果线程是临时附加的:
-
JavaScript调用
Java.perform(fn)→ GumJS绑定层 -
调用
gum_java_perform(fn) -
获取当前线程的JNIEnv
-
如果当前线程不是Java线程:
-
创建GumJavaClassWrapper包装器
-
缓存方法和字段信息
-
返回JavaScript类对象
-
JavaScript调用
Java.use("com.example.ClassName")→ GumJS绑定层 -
调用
gum_java_use("com.example.ClassName") -
验证Java VM可用性
-
在Java VM线程上执行类查找:
-
JavaScript访问
ObjC.classes.ClassName→ GumJS绑定层 -
调用
gum_objc_api_resolver_get_class("ClassName") -
查询Objective-C Runtime的类注册表
-
如果类存在,创建GumScriptClassWrapper包装器
-
缓存类包装器以供后续使用
-
返回JavaScript类对象
-
+------------------+ -
| wrapper (JSObjectRef)|->JavaScript类包装器 -
+------------------+ -
| handle (jclass)|-> JNI类引用 -
+------------------+ -
| name (char*)|->类名字符串 -
+------------------+ -
| methods (GHashTable*)|->方法缓存表 -
+------------------+ -
| fields (GHashTable*)|->字段缓存表 -
+------------------+ -
+------------------+ -
| wrapper (JSObjectRef)|->JavaScript对象包装器 -
+------------------+ -
| handle (jobject)|-> JNI局部/全局引用 -
+------------------+ -
| klass (GumScriptClassWrapper*)|->类包装器引用 -
+------------------+ -
| script (GumScript*)|->脚本上下文引用 -
+------------------+ -
| is_global_ref (gboolean)|->是否为全局引用 -
+------------------+ -
+------------------+ -
| wrapper (JSObjectRef)|->JavaScript对象包装器 -
+------------------+ -
| handle (gpointer)|->Objective-C对象指针 -
+------------------+ -
| klass (GumScriptClassWrapper*)|->类包装器引用 -
+------------------+ -
| script (GumScript*)|->脚本上下文引用 -
+------------------+ -
| ref_count (gint)|->引用计数 -
+------------------+ -
// GumJavaApiResolver工厂 -
GumJavaApiResolver* -
gum_java_api_resolver_new (void); -
// GumJavaObject工厂 -
GumJavaObject* -
gum_java_object_new (jobject handle,GumScript* script); -
// 类工厂 -
GumJavaClassFactory* -
gum_java_class_factory_new (void); -
// GumObjCApiResolver工厂 -
GumObjCApiResolver* -
gum_objc_api_resolver_new (void); -
// GumObjCObject工厂 -
GumObjCObject* -
gum_objc_object_new (gpointer handle,GumScript* script); -
// ObjC相关的结构 -
typedefstruct_GumObjCApi{ -
gboolean (* is_available)(void); -
gpointer (* get_class)(const gchar * name); -
gpointer (* alloc_object)(gpointer klass); -
gpointer (* send_message)(gpointer object,const gchar * selector,...); -
// ... 其他函数指针 -
}GumObjCApi; -
// Java相关的结构 -
typedefstruct_GumJavaApi{ -
gboolean (* is_available)(void); -
void(* perform)(GumScriptCallback callback, gpointer data); -
gboolean (* use)(const gchar * class_name,GError** error); -
gboolean (* choose)(const gchar * class_name,GumScriptCallback on_match,GumScriptCallback on_complete, gpointer user_data); -
// ... 其他函数指针 -
}GumJavaApi; -
// 类包装器结构 -
typedefstruct_GumScriptClassWrapper{ -
JSObjectRef wrapper; -
gpointer handle; -
gchar * name; -
GumScript* script; -
}GumScriptClassWrapper; -
// 对象包装器结构 -
typedefstruct_GumScriptObjectWrapper{ -
JSObjectRef wrapper; -
gpointer handle; -
GumScriptClassWrapper* klass; -
GumScript* script; -
}GumScriptObjectWrapper;
- 公众号:安全狗的自我修养
- vx:2207344074
- http://gitee.com/haidragon
- http://github.com/haidragon
- bilibili:haidragonx
#
#
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:安全狗的自我修养 haidragon haidragon《frida各模块js与cpp函数分析对照(六)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论