Frida用法之函数操作
Frida接口功能介绍
Frida是个so级别的hook框架,它可以帮助开发、安全人员对指定的进程的so模块进行分析。它主要提供了功能简单的Python接口和功能丰富的JS接口,使得hook函数和修改so可以编程化,接口中包含了主控端与目标进程的交互接口。
目标进程的交互接口分为:
- JS接口
功能包括但不限于进程操作、模块操作、内存操作、函数操作、线程操作、网络通信、数据流操作、文件操作、数据库操作、寄存器操作。 - Python接口
提供的功能较少,基本都是用来获取进程、模块、函数操作。
Frida功能较多,暂时没有需求要每个都掌握,我现在的需求就是在程序运行的时候修改函数传参值、得到函数的返回值这种简单操作,下面通过JS配合Python脚本方式对这两个功能进行探讨。
注入Android系统的使用流程
- 打开一个APP应用,并跳转到有你想注入的页面
- 通过
adb shell dumpsys activity top
,获取当前 Android 系统中与用户交互(顶层) Activity 的详细信息 - 反编译APK文件,根据上一步提供的信息,进行代码查看,然后定位到想hook的函数,查看的该函数的传参和返回值
- 编写js注入代码,运行脚本注入到函数中
步骤1演示 - 打开APP页面
自己写的一个Android Demo,下面有代码。
步骤2演示 - 获取顶层Activity信息
adb shell dumpsys activity top
TASK com.example.myapplication id=190
ACTIVITY com.example.myapplication/.MainActivity 6b2b7a5 pid=31745
Local Activity e71a071 State:
mResumed=false mStopped=true mFinished=false
mChangingConfigurations=false
mCurrentConfig={1.0 ?mcc?mnc zh_CN ldltr sw411dp w411dp h659dp 420dpi nrml port finger -keyb/v/h -nav/h s.4}
mLoadersStarted=true
Active Fragments in 6e3c2de:
#0: ReportFragment{a0dccbf #0 androidx.lifecycle.LifecycleDispatcher.report_fragment_tag}
mFragmentId=#0 mContainerId=#0 mTag=androidx.lifecycle.LifecycleDispatcher.report_fragment_tag
mState=3 mIndex=0 mWho=android:fragment:0 mBackStackNesting=0
mAdded=true mRemoving=false mResumed=false mFromLayout=false mInLayout=false
mHidden=false mDetached=false mMenuVisible=true mHasMenu=false
mRetainInstance=false mRetaining=false mUserVisibleHint=true
mFragmentManager=FragmentManager{6e3c2de in HostCallbacks{6fc8f8c}}
mHost=android.app.Activity$HostCallbacks@6fc8f8c
Child FragmentManager{f8df6d5 in ReportFragment{a0dccbf}}:
FragmentManager misc state:
mHost=android.app.Activity$HostCallbacks@6fc8f8c
mContainer=android.app.Fragment$1@e652eea
mParent=ReportFragment{a0dccbf #0 androidx.lifecycle.LifecycleDispatcher.report_fragment_tag}
mCurState=3 mStateSaved=true mDestroyed=false
Added Fragments:
#0: ReportFragment{a0dccbf #0 androidx.lifecycle.LifecycleDispatcher.report_fragment_tag}
FragmentManager misc state:
mHost=android.app.Activity$HostCallbacks@6fc8f8c
mContainer=android.app.Activity$HostCallbacks@6fc8f8c
mCurState=3 mStateSaved=true mDestroyed=false
ViewRoot:
mAdded=true mRemoved=false
mConsumeBatchedInputScheduled=false
mConsumeBatchedInputImmediatelyScheduled=false
mPendingInputEventCount=0
mProcessInputEventsScheduled=false
mTraversalScheduled=false mIsAmbientMode=false
android.view.ViewRootImpl$NativePreImeInputStage: mQueueLength=0
android.view.ViewRootImpl$ImeInputStage: mQueueLength=0
android.view.ViewRootImpl$NativePostImeInputStage: mQueueLength=0
Choreographer:
mFrameScheduled=false
mLastFrameTime=64637557 (5732266 ms ago)
View Hierarchy:
com.android.internal.policy.PhoneWindow$DecorView{85c75db V.E...... R....... 0,0-1080,1920}
android.widget.LinearLayout{da91878 V.E...... ........ 0,0-1080,1794}
android.view.ViewStub{b442b51 G.E...... ......I. 0,0-0,0 #10203b0 android:id/action_mode_bar_stub}
android.widget.FrameLayout{2df4fb6 V.E...... ........ 0,63-1080,1794}
androidx.appcompat.widget.ActionBarOverlayLayout{2294b7 V.E...... ........ 0,0-1080,1731 #7f070030 app:id/decor_content_parent}
androidx.appcompat.widget.ContentFrameLayout{4934424 V.E...... ........ 0,147-1080,1731 #1020002 android:id/content}
androidx.constraintlayout.widget.ConstraintLayout{94f2b8d V.E...... ........ 0,0-1080,1584}
androidx.appcompat.widget.AppCompatTextView{208b142 V.ED..... ........ 191,724-890,861 #7f07008d app:id/tv}
androidx.appcompat.widget.ActionBarContainer{ec1c553 V.ED..... ........ 0,0-1080,147 #7f070008 app:id/action_bar_container}
androidx.appcompat.widget.Toolbar{3d27e90 V.E...... ........ 0,0-1080,147 #7f070006 app:id/action_bar}
androidx.appcompat.widget.AppCompatTextView{68ff389 V.ED..... ........ 42,38-196,109}
androidx.appcompat.widget.ActionMenuView{c749f8e V.E...... ......ID 1080,0-1080,147}
androidx.appcompat.widget.ActionBarContextView{c1963af G.E...... ......I. 0,0-0,0 #7f07000e app:id/action_context_bar}
android.view.View{b88f3bc V.ED..... ........ 0,1794-1080,1920 #1020030 android:id/navigationBarBackground}
android.view.View{2fb3f45 V.ED..... ........ 0,0-1080,63 #102002f android:id/statusBarBackground}
Looper (main, tid 1) {69f269a}
(Total messages: 0, polling=false, quitting=false)
Local FragmentActivity e71a071 State:
mCreated=true mResumed=false mStopped=true FragmentManager misc state:
mHost=androidx.fragment.app.FragmentActivity$HostCallbacks@4a28bcb
mContainer=androidx.fragment.app.FragmentActivity$HostCallbacks@4a28bcb
mCurState=2 mStateSaved=true mStopped=true mDestroyed=false
步骤3演示 - 查看代码
这个是自己写的android代码,没有混淆。如果你用反编译的方式打开别人的代码,大概率是混淆过的,不过也一样用,无非是将类名、函数名、变量名变成a、b、c...,只是增加看代码的难度而已,但是调用流程还是一样的。
public class MainActivity extends AppCompatActivity {
private TextView testview;
private String returnvalule;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testview = findViewById(R.id.tv);
testview.setText("得分计次1:60 \n");
returnvalule = addnumber("60");
testview.append("addnumber()的返回值:" + returnvalule);
}
private String addnumber(String nubs){
testview.append("得分计次2:" + nubs + "\n");
return "我是默认的返回值⊙_⊙";
}
}
步骤4演示 - JS配合Python脚本注入
import frida
import sys
jscode = """
/* 这个字段标记Java虚拟机(例如: Dalvik 或者 ART)是否已加载, 操作Java任何东西的之前,要确认这个值是否为true */
if(Java.available){
/* 111、222、333 打这些log的目的是看流程走到哪里 */
console.log("111");
/* Java.perform(function(){ ... Javascript代码成功被附加到目标进程时调用,我们核心的代码要在里面写。是个固定格式 */
Java.perform(function(){
/* Java.use方法用于声明一个Java类,在用一个Java类之前首先得声明。比如声明一个String类,要指定完整的类名var StringClass=Java.use("java.lang.String"); */
var MainActivity = Java.use("com.example.myapplication.MainActivity");
console.log("222");
/* 类.函数.overload(参数类型).implementation = function(形参名称){ */
MainActivity.addnumber.overload("java.lang.String").implementation = function(nubs){
console.log("333");
/* 给addnumber函数传参、得到addnumber函数的返回值 */
console.log(this.addnumber("77"));
/* 修改addnumber函数的返回值 */
return "I am Mysticbinary!";
}
});
}
"""
def on_message(message, data):
if message['type'] == 'send':
print(" {0}".format(message['payload']))
else:
print(message)
# 查找USB设备并附加到目标进程
session = frida.get_usb_device().attach('com.example.myapplication')
# 在目标进程里创建脚本
script = session.create_script(jscode)
# 注册消息回调
script.on('message', on_message)
# 加载创建好的javascript脚本
script.load()
# 读取系统输入
sys.stdin.read()
调用说明:
脚本注入说明:
- 打开你想注入的界面
- 运行上面步骤4的代码
- Android回退到系统主界面,再次进入一次,主要是为了触发函数
- 查看运行结果
代码运行结果:
app注入结果:
最后总结一下,难点一是操作步骤多,难点二是要看懂要注入的函数的用法,Frida提供的API接口其实非常简单使用,最后感谢Frida作者开发出这么优秀的框架,让我们小白都能做注入。
参考文章
https://www.cnblogs.com/mysticbinary/p/12012935.html
https://frida.re/docs/javascript-api/
https://bbs.pediy.com/thread-226846.htm
https://www.52pojie.cn/forum.php?mod=viewthread&tid=931872
Frida用法之函数操作的更多相关文章
- makefile高级用法--使用函数
makefile高级用法--使用函数 分类: C/C++ 使用函数 ———— 在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能.make所支持的函数也不算很多, ...
- Python学习-字符串函数操作3
字符串函数操作 isprintable():判断一个字符串中所有字符是否都是可打印字符的. 与isspace()函数很相似 如果字符串中的所有字符都是可打印的字符或字符串为空返回 True,否则返回 ...
- day5_7.3 数据类型的各种函数操作
昨日补充: 1.在代码的编写中,总会有一些分支编写不出来,为了不影响整个系统的跑动,可以使用pass关键字进行跳过.如 count=0 while count<10: if count<5 ...
- 第33讲:List的一阶函数操作代码实战详解
今天来看一下关于List的一阶函数操作 让我们看下下面的代码 println(List(1,2,3,4):::List(4,5,6,7,8):::List(10,11))//列表连接 print ...
- SQL 语句日期用法及函数
SQL 语句日期用法及函数 --DAY().MONTH().YEAR()——返回指定日期的天数.月数.年数:select day(cl_s_time) as '日' from class --返回天 ...
- Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤
原文地址: Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤 - 网络资源是无限的 - 博客频道 - CSDN.NET http://blog.csdn.net/fen ...
- scala集合和高级函数操作
scala常用函数操作 reduceLeft 是将集合的元素从左向右进行所需要的相应操作,图以减法为例展示,表达的算法是 : 1-2-3-4-5 例: (1 to 5).reduceLeft(_ ...
- C语言对函数操作的结果声明
可以用来返回给调用者函数操作的状态值. /* 这是一份关于函数返回值定义的头文件. */ #ifndef _STATUS_H_ #define _STATUS_H_ #define STATUS in ...
- Trident中的解析包含的函数操作与投影操作
一:函数操作 1.介绍 Tuple本身是不可变的 Function只是在原有的基础上追加新的tuple 2.说明 如果原来的字段是log,flag 新增之后的tuple可以访问这些字段,log,fla ...
随机推荐
- 阿里巴巴开源项目: 基于mysql数据库binlog的增量订阅&消费
背景 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求.不过早期的数据库同步业务,主要是基于trigger的方式获取增量变更,不过从2010年开始,阿里系公司开始逐步的尝 ...
- 八、springboot 简单优雅的通过docker-compose 构建
前言 这个项目有一段时间没有更新了,不过我可没有偷懒哟,是偷偷准备了一个大招,现在是时候展示啦哈哈. 我们今天要做的,就是将我们的项目通过docker-compose 构建成镜像运行.为什么要这样做呢 ...
- NOIP模拟测试19考试反思
这次考试是存在很大问题的,(如果不是T1T2出乎意料地A了,鬼知道会发生什么) T2A是情理之中,考试的时候测的极限数据跑的很快(无论m什么范围),但是T1真的...... T3没有分配太多的时间+没 ...
- python——inspect模块
inspect模块常用功能 import inspect # 导入inspect模块 inspect.isfunction(fn) # 检测fn是不是函数 inspect.isgenerator((x ...
- php查询字符串的函数
/* 查找一个字符串在另一个字符串的第一次出现,并返回其余部分(strstr别名) */ var_dump(strchr("hello world hello", "wo ...
- Mybatis加入日志
*在mybatis-config.xml核心配置文件中加入如下设置,在configration中标签中加入 <!--打印日志,方便看输出SQL --> <settings> & ...
- nyoj 276-比较字母大小 (顺序比较, 逆序输出)
276-比较字母大小 内存限制:64MB 时间限制:3000ms 特判: No 通过数:13 提交数:15 难度:1 题目描述: 任意给出两个英文字母,比较它们的大小,规定26个英文字母A,B,C.. ...
- 100天搞定机器学习|Day56 随机森林工作原理及调参实战(信用卡欺诈预测)
本文是对100天搞定机器学习|Day33-34 随机森林的补充 前文对随机森林的概念.工作原理.使用方法做了简单介绍,并提供了分类和回归的实例. 本期我们重点讲一下: 1.集成学习.Bagging和随 ...
- 查找文件或目录(find、locate、whereis、which、whatis)
find命令:可以按文件名.文件的类型.用户等条件来递归查找文件或目录 find [路径] [匹配表达式] ,常用选项如下 -name filename 按文件名 -user username ...
- Pashmak and Parmida's problem(树状数组)
题目链接:http://codeforces.com/contest/459/problem/D 题意: 数列A, ai表示 i-th 的值, f(i,j, x) 表示[i,j]之间x的数目, 问:当 ...