Frida是個so級別的hook框架,它能夠幫助開發、安全人員對指定的進程的so模塊進行分析。它主要提供了功能簡單的Python接口和功能豐富的JS接口,使得hook函數和修改so能夠編程化,接口中包含了主控端與目標進程的交互接口。javascript
目標進程的交互接口分爲:php
Frida功能較多,暫時沒有需求要每一個都掌握,我如今的需求就是在程序運行的時候修改函數傳參值、獲得函數的返回值這種簡單操做,下面經過JS配合Python腳本方式對這兩個功能進行探討。html
adb shell dumpsys activity top
,獲取當前 Android 系統中與用戶交互(頂層) Activity 的詳細信息本身寫的一個Android Demo,下面有代碼。
java
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
這個是本身寫的android代碼,沒有混淆。若是你用反編譯的方式打開別人的代碼,大機率是混淆過的,不過也同樣用,無非是將類名、函數名、變量名變成a、b、c...,只是增長看代碼的難度而已,可是調用流程仍是同樣的。python
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 "我是默認的返回值⊙_⊙"; } }
import frida import sys jscode = """ /* 這個字段標記Java虛擬機(例如: Dalvik 或者 ART)是否已加載, 操做Java任何東西的以前,要確認這個值是否爲true */ if(Java.available){ /* 1十一、22二、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()
調用說明:
linux
腳本注入說明:android
代碼運行結果:
shell
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編程