Frida接口功能介绍

Frida是个so级别的hook框架,它可以帮助开发、安全人员对指定的进程的so模块进行分析。它主要提供了功能简单的Python接口和功能丰富的JS接口,使得hook函数和修改so可以编程化,接口中包含了主控端与目标进程的交互接口。

目标进程的交互接口分为:

  • JS接口

    功能包括但不限于进程操作、模块操作、内存操作、函数操作、线程操作、网络通信、数据流操作、文件操作、数据库操作、寄存器操作。
  • Python接口

    提供的功能较少,基本都是用来获取进程、模块、函数操作。

Frida功能较多,暂时没有需求要每个都掌握,我现在的需求就是在程序运行的时候修改函数传参值、得到函数的返回值这种简单操作,下面通过JS配合Python脚本方式对这两个功能进行探讨。

注入Android系统的使用流程

  1. 打开一个APP应用,并跳转到有你想注入的页面
  2. 通过adb shell dumpsys activity top,获取当前 Android 系统中与用户交互(顶层) Activity 的详细信息
  3. 反编译APK文件,根据上一步提供的信息,进行代码查看,然后定位到想hook的函数,查看的该函数的传参和返回值
  4. 编写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()

调用说明:

脚本注入说明:

  1. 打开你想注入的界面
  2. 运行上面步骤4的代码
  3. Android回退到系统主界面,再次进入一次,主要是为了触发函数
  4. 查看运行结果

代码运行结果:

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

最新文章

  1. 免费领取百度云盘2048G永久空间,永久离线下载特权
  2. 通过DIV+span方式模拟进度条的实现方法
  3. emoji和utf8mb4字符集
  4. [BZOJ2502]清理雪道
  5. sql Server 使某一列的值等于行号
  6. Part 53 to 55 Talking about Reflection in C#
  7. Mysql 中bitwise对效率的影响??
  8. cocos2dx addchild坐标问题
  9. How to Use Custom TTF Font on iOS
  10. 航道水下地形DEM构建方法比较
  11. 为什么python适合写爬虫?(python到底有啥好的?!)
  12. 201521123060 《Java程序设计》第7周学习总结
  13. Python创建微信机器人
  14. Django中session的基础了解
  15. 搭建智能合约开发环境Remix IDE及使用
  16. Effective Objective-C 笔记之熟悉OC
  17. LINUX系统下CIFS文件系统
  18. Web框架Django
  19. pca主成份分析方法
  20. 基于Mybatis的Dao层开发

热门文章

  1. Netty启动流程剖析
  2. DOM增删改替换
  3. Unicode字符串和非Unicode字符串
  4. 演示vsftpd服务匿名访问模式、本地用户模式的配置
  5. 映客直播软开校招岗(go语言)
  6. jquery.eraser制作擦涂效果
  7. MD5 加盐加密
  8. django_4:数据库0——配置数据库
  9. libdispatch.dylib中dispatch_group的实现
  10. thinking in JAVA 编译记录