3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Frida Android hook

發布時間:2024/7/23 Android 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Frida Android hook 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

From:https://eternalsakura13.com/2020/07/04/frida/

目錄

1、r0ysue 大佬

2、Frida 環境

2.1 pyenv

2.2 frida 安裝

2.3 安裝 objection

2.4 frida 使用

frida 幫助 和 frida-server 幫助

2.5 frida 開發環境搭建

3、FRIDA 基礎

3.1 frida 查看當前存在的進程

3.2 frida 打印參數和修改返回值

3.3 frida 尋找 instance,主動調用。

3.4 frida rpc

3.5 frida 動態修改

3.6 API List

4、Frida 動靜態結合分析

4.1 Objection

objection 之 啟動并注入內存

objection 之 memory 命令

memory list modules ( 查看加載的 so 庫?)

memory list exports ( 查看 so 庫的導出函數表?)

memory dump(dump 內存空間)? ? ? ?

memory search(搜索 內存空間)

objection 之 android 命令

android heap search instances 類名

android heap execute 實例ID 實例方法

android hooking list activities/services

android intent launch_activity/launch_service activity/服務

android hooking list classes

android hooking search classes display

android hooking list class_methods 類名

android hooking search methods display

hook 類的方法(hook 類里的所有方法 / 具體某個方法)

grep trick 和 文件保存( objection log )

4.2 案例學習

案例學習 1:《仿VX數據庫原型取證逆向分析》

案例學習 2:主動調用爆破密碼

5、Frida hook 基礎(一)

5.1 Frida hook : 打印參數、返回值 / 設置返回值 / 主動調用

5.2 Frida hook : 主動調用靜態/非靜態函數 以及 設置靜態/非靜態成員變量的值

5.3 Frida hook : 內部類,枚舉類的方法?并 hook,trace原型1

5.4 Frida hook : hook 動態加載的 dex,與查找 interface,

5.5 Frida hook : 枚舉 class,trace原型2

frida rpc 枚舉 實現 接口的類

5.6 Frida hook : 搜索 interface 的具體實現類

6、Frida hook 基礎(二)

6.1 spawn / attach

6.2 Frida hook : hook構造函數/打印棧回溯

6.3 Frida hook : 打印棧回溯

6.4 Frida hook : 手動加載 dex 并調用

7、Frida 打印 與 參數構造

gson 打印 Java 對象的內容

char[] / [Object Object]

byte[]

java array 構造

類的多態:轉型 / Java.cast

interface / Java.registerClass

成員內部類 / 匿名內部類

hook enum

打印 hash map

打印 non-ascii

8、Frida native hook : NDK 開發入門

9、Frida native hook : JNIEnv 和 反射

9.1 以 jni字符串 來掌握基本的 JNIEnv用法

9.2 Java 反射

10、Frida 反調試 與 反反調試

11、Frida native hook : 符號 hook JNI、art&libc

11.1 Native函數的Java Hook及主動調用

11.2 jni.h 頭文件導入

11.3 JNI 函數符號 hook

11.4 JNI 函數參數、返回值打印和替換

12、Frida native hook : JNI_Onload / 動態注冊 / inline_hook / native層調用棧打印

12.1 JNI_Onload / 動態注冊原理

12.2 Frida hook RegisterNative

12.3 native 層調用棧打印

12.4 主動調用去進行方法參數替換

12.5 inline hook ( so庫里面的函數?)

13、Frida native hook : Frida hook native app 實戰

14、Frida trace 四件套

14.1 jni trace : trace jni

14.2 strace : trace syscall

14.3 frida-trace : trace libc(or more)

art trace

14.4 hook_artmethod : trace java 函數調用

14.5 修改AOSP源碼打印

15、Frida native hook : init_array 開發和自動化逆向

15.1 init_array原理 (?so 加載、啟動、執行 )

15.2 IDA靜態分析 init_array

15.3 IDA 動態調試 so

15.4 init_array && JNI_Onload "自吐"

JNI_Onload

init_array

15.5 native層未導出函數主動調用(任意符號和地址)

16、C/C++ hook

16.1 Native/JNI層參數打印和主動調用參數構造

16.2 C/C++編成 so 并引入 Frida 調用其中的函數


1、r0ysue 大佬

這篇文章完全來源于 r0ysue 的知識星球,推薦下大佬的星球

2、Frida 環境

github 地址:https://github.com/frida/frida

2.1 pyenv

python 全版本隨機切換,這里提供?macOS上的配置方法

brew update brew install pyenv echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bash_profile下載一個3.8.2,下載真的很慢,要慢慢等 pyenv install 3.8.2pyenv versions sakura@sakuradeMacBook-Pro:~$ pyenv versionssystem * 3.8.2 (set by /Users/sakura/.python-version) 切換到我們裝的 pyenv local 3.8.2 python -V pip -V 原本系統自帶的 python local system python -V

另外當你需要臨時禁用 pyenv 的時候

把這個注釋了然后另開終端就好了。關于卸載某個 python 版本

Uninstalling Python Versions As time goes on, you will accumulate Python versions in your $(pyenv root)/versions directory.To remove old Python versions, pyenv uninstall command to automate the removal process.Alternatively, simply rm -rf the directory of the version you want to remove. You can find the directory of a particular Python version with the pyenv prefix command, e.g. pyenv prefix 2.6.8.

2.2 frida 安裝

如果直接按下述安裝則會直接安裝 frida 和 frida-tools 的最新版本。

pip install frida pip install frida-tools frida --version frida-ps --version

也可以通過 版本號 安裝舊版本的 frida,例如 12.8.0

pyenv install 3.7.7 pyenv local 3.7.7 pip install frida==12.8.0 pip install frida-tools==5.3.0

老版本 frida 和 對應關系,對應關系很好找:

2.3 安裝 objection

安裝命令:

pyenv local 3.8.2 pip install objection objection -hpyenv local 3.7.7 pip install objection==1.8.4 objection -h

2.4 frida 使用

下載 frida-server 并解壓,在這里下載 frida-server :https://github.com/frida/frida/releases

先 adb shell,然后切換到 root 權限,把之前 push 進來的 frida server 改個名字叫 fs,然后運行 frida

adb push /tmp/frida-server-12.8.0-android-arm64 /data/local/tmp mv frida-server-12.8.0-android-arm64 fs chmod 777 fs ./fs

如果要監聽端口,就

./fs -l 0.0.0.0:8888

frida 幫助 和 frida-server 幫助

frida --help

frida-server --help

2.5 frida 開發環境搭建

  • 安裝
    ? ? ? ? git clone https://github.com/oleavr/frida-agent-example.git
    ? ? ? ? cd frida-agent-example/
    ? ? ? ? npm install
  • 使用 vscode 打開此工程,在 agent 文件夾下編寫 js,會有智能提示。
  • npm run watch?會監控代碼修改自動編譯生成 js 文件
  • python 腳本或者 cli 加載 _agent.js 命令:frida -U -f com.example.android --no-pause -l _agent.js
  • 下面是測試腳本

    s1.js

    function main() {Java.perform(function x() {console.log("sakura")}) } setImmediate(main)

    loader.py

    import time import fridadevice8 = frida.get_device_manager().add_remote_device("192.168.0.9:8888") pid = device8.spawn("com.android.settings") device8.resume(pid) time.sleep(1) session = device8.attach(pid) with open("si.js") as f:script = session.create_script(f.read()) script.load() input() #等待輸入

    解釋一下:這個腳本就是先通過 frida.get_device_manager().add_remote_device 來找到 device,然后以 spawn 方式啟動 settings,然后 attach 到上面,并執行 frida 腳本。

    當代碼里面沒有指定端口時,需要手動轉發端口:adb forward tcp:27042 tcp:27042

    import sys import time import fridajs_code = ''' function main() {Java.perform(function x() {console.log("sakura")}) } setImmediate(main); '''def on_message(msg, data):if msg['type'] == 'send':print(f'[*] {msg["payload"]}')else:print(msg)if __name__ == '__main__':select = 1if 1 == select:# ########################### 會自動重啟 app ############################ 會自動重啟 appdevice = frida.get_remote_device()pid = device.spawn(["com.android.settings"])device.resume(pid)time.sleep(1)process = device.attach("com.android.settings")script = process.create_script(js_code)script.load()input('按任意鍵繼續') # 等待輸入elif 2 == select:# ############ 需要先手動啟動 app , 然后才能執行腳本進行 hook ############## get_remote_device 獲取遠程設備 (get_usb_device)  attach 附加進程process = frida.get_remote_device().attach('com.android.settings')script = process.create_script(js_code)script.on('message', on_message) # 綁定 js 回調script.load()sys.stdin.read()pass

    運行結果:

    3、FRIDA 基礎

    3.1 frida 查看當前存在的進程

    frida-ps 命令:

    frida-ps -U?查看通過 usb 連接的 android 手機上的進程。可以通過 grep 過濾就可以找到我們想要的包名。

    sakura@sakuradeMacBook-Pro:~$ frida-ps -UPID Name ----- ---------------------------------------------------3640 ATFWD-daemon707 adbd728 adsprpcd 26041 android.hardware.audio@2.0-service741 android.hardware.biometrics.fingerprint@

    3.2 frida 打印參數和修改返回值

    package myapplication.example.com.frida_demo;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log;public class MainActivity extends AppCompatActivity {private String total = "@@@###@@@";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}fun(50,30);Log.d("sakura.string" , fun("LoWeRcAsE Me!!!!!!!!!"));}}void fun(int x , int y ){Log.d("sakura.Sum" , String.valueOf(x+y));}String fun(String x){total +=x;return x.toLowerCase();}String secret(){return total;} }

    注入的 js 代碼:

    function main() {console.log("Enter the Script!");Java.perform(function x() {console.log("Inside Java perform");var MainActivity = Java.use("myapplication.example.com.frida_demo.MainActivity");// 重載找到指定的函數MainActivity.fun.overload('java.lang.String').implementation = function (str) {//打印參數console.log("original call : str:" + str);//修改結果var ret_value = "sakura";return ret_value;};}) } setImmediate(main);

    查看設備。(?-f 是通過 spawn,也就是重啟 apk 注入 js

    sakura@sakura:~$ frida-ps -U | grep frida 8738 frida-helper-32 8897 myapplication.example.com.frida_demo// -f 是通過 spawn,也就是重啟 apk 注入 js sakura@sakura:~$ frida -U -f myapplication.example.com.frida_demo -l frida_demo.js ... original call : str:LoWeRcAsE Me!!!!!!!!! 12-21 04:46:49.875 9594-9594/myapplication.example.com.frida_demo D/sakura.string: sakura

    3.3 frida 尋找 instance,主動調用。

    function main() {console.log("Enter the Script!");Java.perform(function x() {console.log("Inside Java perform");var MainActivity = Java.use("myapplication.example.com.frida_demo.MainActivity");// overload 選擇被重載的對象MainActivity.fun.overload('java.lang.String').implementation = function (str) {//打印參數console.log("original call : str:" + str);//修改結果var ret_value = "sakura";return ret_value;};// 尋找類型為 classname 的實例Java.choose("myapplication.example.com.frida_demo.MainActivity", {onMatch: function (x) {console.log("find instance :" + x);console.log("result of secret func:" + x.secret());},onComplete: function () {console.log("end");}});}); } setImmediate(main);

    3.4 frida rpc

    function callFun() {Java.perform(function fn() {console.log("begin");Java.choose("myapplication.example.com.frida_demo.MainActivity", {onMatch: function (x) {console.log("find instance :" + x);console.log("result of fun(string) func:" + x.fun(Java.use("java.lang.String").$new("sakura")));},onComplete: function () {console.log("end");}})}) } rpc.exports = {callfun: callFun };

    Python 調用:

    import time import fridadevice = frida.get_usb_device() pid = device.spawn(["myapplication.example.com.frida_demo"]) device.resume(pid) time.sleep(1) session = device.attach(pid) with open("frida_demo_rpc_call.js") as f:script = session.create_script(f.read())def my_message_handler(message, payload):print(message)print(payload)script.on("message", my_message_handler) script.load()script.exports.callfun()

    執行:

    sakura@sakura:~/frida-agent-example/agent$ python frida_demo_rpc_loader.py begin find instance :myapplication.example.com.frida_demo.MainActivity@1d4b09d result of fun(string):sakura end

    3.5 frida 動態修改

    即將手機上的 app 的內容發送到 PC 上的 frida python 程序,然后處理后返回給 app,然后 app 再做后續的流程,核心是理解?send/recv?函數。

    <TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="please input username and password"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /><EditTextandroid:id="@+id/editText"android:layout_width="fill_parent"android:layout_height="40dp"android:hint="username"android:maxLength="20"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="1.0"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_bias="0.095" /><EditTextandroid:id="@+id/editText2"android:layout_width="fill_parent"android:layout_height="40dp"android:hint="password"android:maxLength="20"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_bias="0.239" /><Buttonandroid:id="@+id/button"android:layout_width="100dp"android:layout_height="35dp"android:layout_gravity="right|center_horizontal"android:text="提交"android:visibility="visible"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_bias="0.745" /> public class MainActivity extends AppCompatActivity {EditText username_et;EditText password_et;TextView message_tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);password_et = (EditText) this.findViewById(R.id.editText2);username_et = (EditText) this.findViewById(R.id.editText);message_tv = ((TextView) findViewById(R.id.textView));this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (username_et.getText().toString().compareTo("admin") == 0) {message_tv.setText("You cannot login as admin");return;}//hook targetmessage_tv.setText("Sending to the server :" + Base64.encodeToString((username_et.getText().toString() + ":" + password_et.getText().toString()).getBytes(), Base64.DEFAULT));}});} }

    先分析問題,我的最終目標是讓 message_tv.setText 可以”發送”username為admin的base64字符串。
    那肯定是 hook TextView.setText 這個函數。

    console.log("Script loaded successfully "); Java.perform(function () {var tv_class = Java.use("android.widget.TextView");tv_class.setText.overload("java.lang.CharSequence").implementation = function (x) {var string_to_send = x.toString();var string_to_recv;send(string_to_send); // send data to python coderecv(function (received_json_object) {string_to_recv = received_json_object.my_dataconsole.log("string_to_recv: " + string_to_recv);}).wait(); //block execution till the message is receivedvar my_string = Java.use("java.lang.String").$new(string_to_recv);this.setText(my_string);} });

    Python 腳本:

    import time import frida import base64def my_message_handler(message, payload):print(message)print(payload)if message["type"] == "send":print(message["payload"])data = message["payload"].split(":")[1].strip()print( 'message:', message)#data = data.decode("base64")#data = datadata = str(base64.b64decode(data))print( 'data:',data)user, pw = data.split(":")print( 'pw:',pw)#data = ("admin" + ":" + pw).encode("base64")data = str(base64.b64encode(("admin" + ":" + pw).encode()))print( "encoded data:", data)script.post({"my_data": data}) # send JSON objectprint( "Modified data sent")device = frida.get_usb_device() pid = device.spawn(["myapplication.example.com.frida_demo"]) device.resume(pid) time.sleep(1) session = device.attach(pid) with open("frida_demo2.js") as f:script = session.create_script(f.read()) script.on("message", my_message_handler) script.load() input()

    執行和輸出:

    sakura@sakuradeMacBook-Pro:~/gitsource/frida-agent-example/agent$ python frida_demo_rpc_loader2.py Script loaded successfully {'type': 'send', 'payload': 'Sending to the server :c2FrdXJhOjEyMzQ1Ng==\n'} None Sending to the server :c2FrdXJhOjEyMzQ1Ng==message: {'type': 'send', 'payload': 'Sending to the server :c2FrdXJhOjEyMzQ1Ng==\n'} data: b'sakura:123456' pw: 123456' encoded data: b'YWRtaW46MTIzNDU2Jw==' Modified data sent string_to_recv: b'YWRtaW46MTIzNDU2Jw=='

    參考鏈接:https://github.com/Mind0xP/Frida-Python-Binding

    3.6 API List

    • Java.choose(className: string, callbacks: Java.ChooseCallbacks): void
      通過掃描 Java VM 的堆來枚舉 className類 的 live instance。

    • Java.use(className: string): Java.Wrapper<{}>
      動態為 className 生成 JavaScript Wrappe r,可以通過調用$new()來調用構造函數來實例化對象。
      在實例上調用?$dispose()?以對其進行顯式清理,或者等待JavaScript對象被gc。

    • Java.perform(fn: () => void): void
      Function to run while attached to the VM.
      Ensures that the current thread is attached to the VM and calls fn. (This isn’t necessary in callbacks from Java.)
      Will defer calling fn if the app’s class loader is not available yet. Use Java.performNow() if access to the app’s classes is not needed.

    • send(message: any, data?: ArrayBuffer | number[]): void
      任何JSON可序列化的值。
      將JSON序列化后的message發送到您的基于Frida的應用程序,并包含(可選)一些原始二進制數據。
      The latter is useful if you e.g. dumped some memory using NativePointer#readByteArray().

    • recv(callback: MessageCallback): MessageRecvOperation
      Requests callback to be called on the next message received from your Frida-based application.
      This will only give you one message, so you need to call recv() again to receive the next one.

    • wait(): void
      堵塞,直到message已經receive并且callback已經執行完畢并返回

    4、Frida 動靜態結合分析

    4.1 Objection

    • 參考這篇文章:實用FRIDA進階:內存漫游、hook anywhere、抓包https://www.anquanke.com/post/id/197657
    • objection:https://pypi.org/project/objection/

    objection 之 啟動并注入內存

    ?命令:objection -d -g package_name exploresakura@sakura:~$ objection -d -g com.android.settings explore [debug] Agent path is: /Users/sakura/.pyenv/versions/3.7.7/lib/python3.7/site-packages/objection/agent.js [debug] Injecting agent... Using USB device `Google Pixel` [debug] Attempting to attach to process: `com.android.settings` [debug] Process attached! Agent injected and responds ok!_ _ _ ____| |_|_|___ ___| |_|_|___ ___ | . | . | | -_| _| _| | . | | |___|___| |___|___|_| |_|___|_|_||___|(object)inject(ion) v1.8.4Runtime Mobile Explorationby: @leonjza from @sensepost[tab] for command suggestions com.android.settings on (google: 8.1.0) [usb] #

    objection 之 memory 命令

    memory list modules ( 查看加載的 so 庫?)

    modules 就是指的 so 庫

    查看內存中加載的 module,命令:memory list modulescom.android.settings on (google: 8.1.0) [usb] # memory list modules Save the output by adding `--json modules.json` to this command Name Base Size Path ----------------------- ------------ -------------------- ------------------------------------ app_process64 0x64ce143000 32768 (32.0 KiB) /system/bin/app_process64 libandroid_runtime.so 0x7a90bc3000 1990656 (1.9 MiB) /system/lib64/libandroid_runtime.so libbinder.so 0x7a9379f000 557056 (544.0 KiB) /system/lib64/libbinder.so

    memory list exports ( 查看 so 庫的導出函數表?)

    查看庫的導出函數:memory list exports libssl.socom.android.settings on (google: 8.1.0) [usb] # memory list exports libssl.so Save the output by adding `--json exports.json` to this command Type Name Address -------- ----------------------------------------------------- ------------ function SSL_use_certificate_ASN1 0x7c8ff006f8 function SSL_CTX_set_dos_protection_cb 0x7c8ff077b8 function SSL_SESSION_set_ex_data 0x7c8ff098f4 function SSL_CTX_set_session_psk_dhe_timeout 0x7c8ff0a754 function SSL_CTX_sess_accept 0x7c8ff063b8 function SSL_select_next_proto 0x7c8ff06a74

    memory dump(dump 內存空間? ? ? ?

    memory dump all 文件名 memory dump from_base 起始地址 字節數 文件

    memory search(搜索 內存空間

    用法:memory search "<pattern eg: 41 41 41 ?? 41>" (--string) (--offsets-only)

    objection 之 android 命令

    android heap search instances 類名

    在內存堆上搜索類的實例 ,命令:android heap search instances 類名

    sakura@sakura:~$ objection -g myapplication.example.com.frida_demo explore Using USB device `Google Pixel` Agent injected and responds ok![usb] # android heap search instances myapplication.example.com.frida_demo .MainActivity Class instance enumeration complete for myapplication.example.com.frida_demo.MainActivity Handle Class toString() -------- ------------------------------------------------- --------------------------------------------------------- 0x2102 myapplication.example.com.frida_demo.MainActivity myapplication.example.com.frida_demo.MainActivity@5b1b0af

    android heap execute 實例ID 實例方法

    調用實例的方法, 命令:android heap execute 實例ID 實例方法

    android hooking list activities/services

    查看當前可用的 activity 或者 service 命令:android hooking list activities/servicescom.android.settings on (google: 8.1.0) [usb] # android hooking list services com.android.settings.SettingsDumpService com.android.settings.TetherService com.android.settings.bluetooth.BluetoothPairingService

    android intent launch_activity/launch_service activity/服務

    直接啟動 activity 或者服務 命令:android intent launch_activity/launch_service activity/服務示例:這個命令比較有趣的是用在如果有些設計的不好,可能就直接繞過了密碼鎖屏等直接進去。 android intent launch_activity com.android.settings.DisplaySettings

    android hooking list classes

    列出內存中所有的類 :android hooking list classes

    android hooking search classes display

    在內存中所有已加載的類中搜索包含特定關鍵詞的類 命令:android hooking search classes display //搜索類中包含 display 的類com.android.settings on (google: 8.1.0) [usb] # android hooking search classes display [Landroid.icu.text.DisplayContext$Type; [Landroid.icu.text.DisplayContext; [Landroid.view.Display$Mode; android.hardware.display.DisplayManager android.hardware.display.DisplayManager$DisplayListener android.hardware.display.DisplayManagerGlobal

    android hooking list class_methods 類名

    內存中搜索指定類的所有方法 命令:android hooking list class_methods 類名com.android.settings on (google: 8.1.0) [usb] # android hooking list class_methods java.nio.charset.Charset private static java.nio.charset.Charset java.nio.charset.Charset.lookup(java.lang.String) private static java.nio.charset.Charset java.nio.charset.Charset.lookup2(java.lang.String) private static java.nio.charset.Charset java.nio.charset.Charset.lookupViaProviders(java.lang.String)

    android hooking search methods display

    在內存中所有已加載的類的方法中搜索包含特定關鍵詞的方法

    命令:?android hooking search methods display

    com.android.settings on (google: 8.1.0) [usb] # android hooking search methods display Warning, searching all classes may take some time and in some cases, crash the target application. Continue? [y/N]: y Found 5529 classes, searching methods (this may take some time)... android.app.ActionBar.getDisplayOptions android.app.ActionBar.setDefaultDisplayHomeAsUpEnabled android.app.ActionBar.setDisplayHomeAsUpEnabled

    hook 類的方法(hook 類里的所有方法 / 具體某個方法)

    • android hooking watch class 類名
      ? ? 這樣就可以 hook 這個類里面的所有方法,每次調用都會被 log 出來。
    • android hooking watch class 類名 --dump-args --dump-backtrace --dump-return
      ? ? 在上面的基礎上,額外 dump 參數,棧回溯,返回值
      ? ? 示例:android hooking watch class xxx.MainActivity --dump-args --dump-backtrace --dump-return
    • android hooking watch class_method 方法名
      ? ? ? ? // 可以直接 hook 到所有重載
      ? ? ? ? android hooking watch class_method xxx.MainActivity.fun --dump-args --dump-backtrace --dump-return

    grep trick 和 文件保存( objection log )

    objection log 默認是不能用 grep 過濾的,但是可以通過 objection run xxx | grep yyy 的方式,從終端通過管道來過濾。用法如下

    sakura@sakura:~$ objection -g com.android.settings run memory list modules | grep libc Warning: Output is not to a terminal (fd=1). libcutils.so 0x7a94a1c000 81920 (80.0 KiB) /system/lib64/libcutils.so libc++.so 0x7a9114e000 983040 (960.0 KiB) /system/lib64/libc++.so libc.so 0x7a9249d000 892928 (872.0 KiB) /system/lib64/libc.so libcrypto.so 0x7a92283000 1155072 (1.1 MiB) /system/lib64/libcrypto.so

    有的命令后面可以通過?--json logfile?來直接保存結果到文件里。

    有的可以通過查看 .objection (位置:C:\Users\用戶名\.objection )文件里的輸出 log 來查看結果。

    sakura@sakurade:~/.objection$ cat *log | grep -i display android.hardware.display.DisplayManager android.hardware.display.DisplayManager$DisplayListener android.hardware.display.DisplayManagerGlobal

    4.2 案例學習

    案例學習 1:《仿VX數據庫原型取證逆向分析》

    案例學習case1:《仿VX數據庫原型取證逆向分析》

    附件鏈接?:https://www.52pojie.cn/forum.php?mod=viewthread&tid=1082706

    android-backup-extractor工具鏈接:https://github.com/nelenkov/android-backup-extractor

    sakura@sakurade:~/Desktop/frida_learn$ java -version java version "1.8.0_141"sakura@sakuradeMacBook-Pro:~/Desktop/frida_learn$ java -jar abe-all.jar unpack 1.ab 1.tar 0% 1% 2% 3% 4% 5% 6% 7% 8% 9% 10% 11% 12% 13% 14% 15% 16% 17% 18% 19% 20% 21% 22% 23% 24% 25% 26% 27% 28% 29% 30% 31% 32% 33% 34% 35% 36% 37% 38% 39% 40% 41% 42% 43% 44% 45% 46% 47% 48% 49% 50% 51% 52% 53% 54% 55% 56% 57% 58% 59% 60% 61% 62% 63% 64% 65% 66% 67% 68% 69% 70% 71% 72% 73% 74% 75% 76% 77% 78% 79% 80% 81% 82% 83% 84% 85% 86% 87% 88% 89% 90% 91% 92% 93% 94% 95% 96% 97% 98% 99% 100% 9097216 bytes written to 1.tar.... sakura@sakurade:~/Desktop/frida_learn/apps/com.example.yaphetshan.tencentwelcome$ ls Encryto.db _manifest a db

    裝個夜神模擬器玩

    sakura@sakura:/Applications/NoxAppPlayer.app/Contents/MacOS$ ./adb connect 127.0.0.1:62001 * daemon not running. starting it now on port 5037 * adb E 5139 141210 usb_osx.cpp:138] Unable to create an interface plug-in (e00002be) * daemon started successfully * connected to 127.0.0.1:62001 sakura@sakuradeMacBook-Pro:/Applications/NoxAppPlayer.app/Contents/MacOS$ ./adb shell dream2qltechn:/ # whoami root dream2qltechn:/ # uname -a Linux localhost 4.0.9+ #222 SMP PREEMPT Sat Mar 14 18:24:36 HKT 2020 i686

    肯定還是先定位目標字符串?Wait a Minute,What was happend?

    jadx 搜索字符串

    重點在 a() 代碼里,其實是根據明文的 name 和 password,然后?aVar.a(a2 + aVar.b(a2, contentValues.getAsString("password"))).substring(0, 7)?再做一遍復雜的計算并截取7位當做密碼,傳入 getWritableDatabase 去解密 demo.db 數據庫。

    所以我們 hook一下 getWritableDatabase 即可。

    // 首先查看要注入的進程 frida-ps -U ... 5662 com.example.yaphetshan.tencentwelcome ...// 使用 objection 注入 objection -d -g com.example.yaphetshan.tencentwelcome explore

    看一下源碼

    package net.sqlcipher.database; ... public abstract class SQLiteOpenHelper {...public synchronized SQLiteDatabase getWritableDatabase(char[] cArr) {

    也可以 objection search 一下這個 method

    (samsung: 7.1.2) [usb] # android hooking search methods getWritableDatabase Warning, searching all classes may take some time and in some cases, crash the target application. Continue? [y/N]: y Found 4650 classes, searching methods (this may take some time)...android.database.sqlite.SQLiteOpenHelper.getWritableDatabase ... net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase

    hook 一下這個 method

    [usb] # android hooking watch class_method net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase --dump-args --dump-backtrace --dump-return - [incoming message] ------------------ {"payload": "Attempting to watch class \u001b[32mnet.sqlcipher.database.SQLiteOpenHelper\u001b[39m and method \u001b[32mgetWritableDatabase\u001b[39m.","type": "send" } - [./incoming message] ---------------- (agent) Attempting to watch class net.sqlcipher.database.SQLiteOpenHelper and method getWritableDatabase. - [incoming message] ------------------ {"payload": "Hooking \u001b[32mnet.sqlcipher.database.SQLiteOpenHelper\u001b[39m.\u001b[92mgetWritableDatabase\u001b[39m(\u001b[31mjava.lang.String\u001b[39m)","type": "send" } - [./incoming message] ---------------- (agent) Hooking net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(java.lang.String) - [incoming message] ------------------ {"payload": "Hooking \u001b[32mnet.sqlcipher.database.SQLiteOpenHelper\u001b[39m.\u001b[92mgetWritableDatabase\u001b[39m(\u001b[31m[C\u001b[39m)","type": "send" } - [./incoming message] ---------------- (agent) Hooking net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase([C) - [incoming message] ------------------ {"payload": "Registering job \u001b[94mjytq1qeyllq\u001b[39m. Type: \u001b[92mwatch-method for: net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase\u001b[39m","type": "send" } - [./incoming message] ---------------- (agent) Registering job jytq1qeyllq. Type: watch-method for: net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase ...mple.yaphetshan.tencentwelcome on (samsung: 7.1.2) [usb] #

    hook 好之后再打開這個 apk

    (agent) [1v488x28gcs] Called net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(java.lang.String) ... (agent) [1v488x28gcs] Backtrace:net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(Native Method)com.example.yaphetshan.tencentwelcome.MainActivity.a(MainActivity.java:55)com.example.yaphetshan.tencentwelcome.MainActivity.onCreate(MainActivity.java:42)android.app.Activity.performCreate(Activity.java:6692) ... (agent) [1v488x28gcs] Arguments net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(ae56f99)... ...mple.yaphetshan.tencentwelcome on (samsung: 7.1.2) [usb] # jobs list Job ID Hooks Type ----------- ------- ----------------------------------------------------------------------------- 1v488x28gcs 2 watch-method for: net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase

    找到參數?ae56f99

    剩下的就是用這個密碼去打開加密的 db。

    然后base64解密一下就好了。

    還有一種策略是主動調用,即自己去調用 a 函數以觸發 getWritableDatabase 的數據庫解密。先尋找 a 所在類的實例,然后 hook getWritableDatabase,最終主動調用 a。這里幸運的是 a 沒有什么奇奇怪怪的參數需要我們傳入。

    [usb] # android heap search instances com.example.yaphetshan.tencentwelcome.MainActivity Class instance enumeration complete for com.example.yaphetshan.tencentwelcome.MainActivity Handle Class toString() -------- -------------------------------------------------- ---------------------------------------------------------- 0x20078a com.example.yaphetshan.tencentwelcome.MainActivity com.example.yaphetshan.tencentwelcome.MainActivity@1528f80[usb] # android hooking watch class_method net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase --dump-args --dump-backtrace --dump-return [usb] # android heap execute 0x20078a a (agent) [taupgwkum4h] Arguments net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(ae56f99)

    案例學習 2:主動調用爆破密碼

    附件鏈接:https://bbs.pediy.com/thread-257745.htm

    因為直接找?Unfortunately,note the right PIN :(找不到,可能是把字符串藏在什么資源文件里了。
    review 代碼之后找到校驗的核心函數,邏輯就是將 input 編碼一下之后和密碼比較,這肯定是什么不可逆的加密。

    public static boolean verifyPassword(Context context, String input) {if (input.length() != 4) {return false;}byte[] v = encodePassword(input);byte[] p = "09042ec2c2c08c4cbece042681caf1d13984f24a".getBytes();if (v.length != p.length) {return false;}for (int i = 0; i < v.length; i++) {if (v[i] != p[i]) {return false;}}return true; }

    這里就爆破一下密碼。

    // 查看 app 進程 frida-ps -U | grep qualification 7660 org.teamsik.ahe17.qualification.easy// frida 命令執行 js 進行 hook frida -U -f org.teamsik.ahe17.qualification.easy -l force.js# 上面命令執行成功后,會進入 frida,再輸入 %resume 然后回車,即可讓程序繼續執行

    或者使用 -F 大寫F 參數,frida -U -F?org.teamsik.ahe17.qualification.easy -l force.js

    js 腳本:

    function main() {Java.perform(function x() {console.log("In Java perform")var verify = Java.use("org.teamsik.ahe17.qualification.Verifier")var stringClass = Java.use("java.lang.String")var p = stringClass.$new("09042ec2c2c08c4cbece042681caf1d13984f24a")var pSign = p.getBytes()// var pStr = stringClass.$new(pSign)// console.log(parseInt(pStr))for (var i = 999; i < 10000; i++){var v = stringClass.$new(String(i))var vSign = verify.encodePassword(v)if (parseInt(stringClass.$new(pSign)) == parseInt(stringClass.$new(vSign))) {console.log("yes: " + v)break}console.log("not :" + v)}}) } setImmediate(main)

    ?

    ?...
    not :9080
    not :9081
    not :9082
    yes: 9083

    這里注意 parseInt

    5、Frida hook 基礎(一)

    • 調用 靜態函數非靜態函數
    • 設置 (同名)成員變量
    • 內部類,枚舉類的函數并hook,trace原型1
    • 查找接口,hook動態加載dex
    • 枚舉class,trace原型2
    • objection 不能切換 classloader

    5.1 Frida hook : 打印參數、返回值 / 設置返回值 / 主動調用

    demo 就不貼了,還是先定位登錄失敗點,然后搜索字符串。

    public class LoginActivity extends AppCompatActivity {/* access modifiers changed from: private */public Context mContext;public void onCreate(Bundle bundle) {super.onCreate(bundle);this.mContext = this;setContentView((int) R.layout.activity_login);final EditText editText = (EditText) findViewById(R.id.username);final EditText editText2 = (EditText) findViewById(R.id.password);((Button) findViewById(R.id.login)).setOnClickListener(new View.OnClickListener() {public void onClick(View view) {String obj = editText.getText().toString();String obj2 = editText2.getText().toString();if (TextUtils.isEmpty(obj) || TextUtils.isEmpty(obj2)) {Toast.makeText(LoginActivity.this.mContext, "username or password is empty.", 1).show();} else if (LoginActivity.a(obj, obj).equals(obj2)) {LoginActivity.this.startActivity(new Intent(LoginActivity.this.mContext, FridaActivity1.class));LoginActivity.this.finishActivity(0);} else {Toast.makeText(LoginActivity.this.mContext, "Login failed.", 1).show();}}});}

    LoginActivity.a(obj, obj).equals(obj2)?分析之后可得 obj2 來自 password,由從 username 得來的 obj,經過 a 函數運算之后得到一個值,這兩個值相等則登錄成功。所以這里關鍵是 hook a 函數的參數,最簡腳本如下。

    //打印參數、返回值 function Login(){Java.perform(function(){Java.use("com.example.androiddemo.Activity.LoginActivity").a.overload('java.lang.String', 'java.lang.String').implementation = function (str, str2){var result = this.a(str, str2);console.log("args0:" + str + " args1:" + str2 + " result:" + result);return result;}}) } setImmediate(Login)

    觀察輸入和輸出,這里也可以直接主動調用。

    function login() {Java.perform(function () {console.log("start")var login = Java.use("com.example.androiddemo.Activity.LoginActivity")var result = login.a("1234","1234")console.log(result)}) } setImmediate(login)

    輸出:

    ... start 4e4feaea959d426155a480dc07ef92f4754ee93edbe56d993d74f131497e66fb 然后 adb shell input text "4e4feaea959d426155a480dc07ef92f4754ee93edbe56d993d74f131497e66fb"

    接下來是第一關

    public abstract class BaseFridaActivity extends AppCompatActivity implements View.OnClickListener {public Button mNextCheck;public void CheckSuccess() {}public abstract String getNextCheckTitle();public abstract void onCheck();/* access modifiers changed from: protected */public void onCreate(Bundle bundle) {super.onCreate(bundle);setContentView((int) R.layout.activity_frida);this.mNextCheck = (Button) findViewById(R.id.next_check);this.mNextCheck.setOnClickListener(this);Button button = this.mNextCheck;button.setText(getNextCheckTitle() + ",點擊進入下一關");}public void onClick(View view) {onCheck();}public void CheckFailed() {Toast.makeText(this, "Check Failed!", 1).show();} } ...public class FridaActivity1 extends BaseFridaActivity {private static final char[] table = {'L', 'K', 'N', 'M', 'O', 'Q', 'P', 'R', 'S', 'A', 'T', 'B', 'C', 'E', 'D', 'F', 'G', 'H', 'I', 'J', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'o', 'd', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'e', 'f', 'g', 'h', 'j', 'i', 'k', 'l', 'm', 'n', 'y', 'z', '0', '1', '2', '3', '4', '6', '5', '7', '8', '9', '+', '/'};public String getNextCheckTitle() {return "當前第1關";}public void onCheck() {try {if (a(b("請輸入密碼:")).equals("R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=")) {CheckSuccess();startActivity(new Intent(this, FridaActivity2.class));finishActivity(0);return;}super.CheckFailed();} catch (Exception e) {e.printStackTrace();}}public static String a(byte[] bArr) throws Exception {StringBuilder sb = new StringBuilder();for (int i = 0; i <= bArr.length - 1; i += 3) {byte[] bArr2 = new byte[4];byte b = 0;for (int i2 = 0; i2 <= 2; i2++) {int i3 = i + i2;if (i3 <= bArr.length - 1) {bArr2[i2] = (byte) (b | ((bArr[i3] & 255) >>> ((i2 * 2) + 2)));b = (byte) ((((bArr[i3] & 255) << (((2 - i2) * 2) + 2)) & 255) >>> 2);} else {bArr2[i2] = b;b = 64;}}bArr2[3] = b;for (int i4 = 0; i4 <= 3; i4++) {if (bArr2[i4] <= 63) {sb.append(table[bArr2[i4]]);} else {sb.append('=');}}}return sb.toString();}public static byte[] b(String str) {try {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();GZIPOutputStream gZIPOutputStream = new GZIPOutputStream(byteArrayOutputStream);gZIPOutputStream.write(str.getBytes());gZIPOutputStream.finish();gZIPOutputStream.close();byte[] byteArray = byteArrayOutputStream.toByteArray();try {byteArrayOutputStream.close();return byteArray;} catch (Exception e) {e.printStackTrace();return byteArray;}} catch (Exception unused) {return null;}} }

    關鍵函數在??a(b("請輸入密碼:")).equals("R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=")

    這里應該直接 hook a,讓其返回值為?R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=就可以進入下一關了。

    function ch1() {Java.perform(function () {console.log("start")Java.use("com.example.androiddemo.Activity.FridaActivity1").a.implementation = function (x) {return "R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL="}}) }

    上面的代碼 hook 了 類中的靜態函數。在寫 hook 的 js 代碼時,靜態 非靜態 區別:

    • hook 靜態函數時候,不需要 overload
    • hook 類的成員函數時,需要 overload

    上面代碼是 hook 并 實現函數,然后調用,

    下面代碼是?hook 但 不實現函數,只調用

    5.2 Frida hook : 主動調用靜態/非靜態函數 以及 設置靜態/非靜態成員變量的值

    總結:

    • 靜態函數直接 use class 然后調用方法,非靜態函數需要先 choose 實例然后調用
    • 設置成員變量的值,寫法是?xx.value = yy,其他方面和函數一樣。
    • 如果有一個成員變量和成員函數的名字相同,則在其前面加一個_,如?_xx.value = yy

    然后是第二關

    public class FridaActivity2 extends BaseFridaActivity {private static boolean static_bool_var = false;private boolean bool_var = false;public String getNextCheckTitle() {return "當前第2關";}private static void setStatic_bool_var() {static_bool_var = true;}private void setBool_var() {this.bool_var = true;}public void onCheck() {if (!static_bool_var || !this.bool_var) {super.CheckFailed();return;}CheckSuccess();startActivity(new Intent(this, FridaActivity3.class));finishActivity(0);} }

    這一關的關鍵在于下面的 if 判斷要為 false,則?static_bool_var?和?this.bool_var?都要為 true。

    if (!static_bool_var || !this.bool_var) {super.CheckFailed();return; }

    這樣就要調用?setBool_var?和?setStatic_bool_var?兩個函數了。

    function ch2() {Java.perform(function () {console.log("start")var FridaActivity2 = Java.use("com.example.androiddemo.Activity.FridaActivity2")// hook 靜態函數 直接調用FridaActivity2.setStatic_bool_var()// hook 動態函數,找到 instance 實例,從 實例中 調用函數方法Java.choose("com.example.androiddemo.Activity.FridaActivity2", {onMatch: function (instance) {instance.setBool_var()},onComplete: function () {console.log("end")}})}) } setImmediate(ch2)

    接下來是第三關

    public class FridaActivity3 extends BaseFridaActivity {private static boolean static_bool_var = false;private boolean bool_var = false;private boolean same_name_bool_var = false;public String getNextCheckTitle() {return "當前第3關";}private void same_name_bool_var() {Log.d("Frida", static_bool_var + " " + this.bool_var + " " + this.same_name_bool_var);}public void onCheck() {if (!static_bool_var || !this.bool_var || !this.same_name_bool_var) {super.CheckFailed();return;}CheckSuccess();startActivity(new Intent(this, FridaActivity4.class));finishActivity(0);} }

    關鍵是讓?if (!static_bool_var || !this.bool_var || !this.same_name_bool_var)為 false,則三個變量都要為 true

    function ch3() {Java.perform(function () {console.log("start")var FridaActivity3 = Java.use("com.example.androiddemo.Activity.FridaActivity3")FridaActivity3.static_bool_var.value = trueJava.choose("com.example.androiddemo.Activity.FridaActivity3", {onMatch: function (instance) {instance.bool_var.value = trueinstance._same_name_bool_var.value = true},onComplete: function () {console.log("end")}})}) }

    注意:類里有一個 成員函數成員變量 都叫做??same_name_bool_var?,這種時候在成員變量前加一個?_,修改值的形式為??xx.value = yy

    5.3 Frida hook : 內部類,枚舉類的方法?并 hook,trace原型1

    總結:

    • 對于內部類,通過?類名$內部類名?去 use 或者 choose
    • 對 use 得到的 clazz 應用反射,如?clazz.class.getDeclaredMethods()?可以得到 類里面聲明的所有方法,即 可以枚舉類里面的所有函數

    接下來是第四關

    public class FridaActivity4 extends BaseFridaActivity {public String getNextCheckTitle() {return "當前第4關";}private static class InnerClasses {public static boolean check1() { return false;}public static boolean check2() { return false;}public static boolean check3() { return false;}public static boolean check4() { return false;}public static boolean check5() { return false;}public static boolean check6() { return false;}private InnerClasses() {}}public void onCheck() {if (!InnerClasses.check1() || !InnerClasses.check2() || !InnerClasses.check3() || !InnerClasses.check4() || !InnerClasses.check5() || !InnerClasses.check6()){super.CheckFailed();return;}CheckSuccess();startActivity(new Intent(this, FridaActivity5.class));finishActivity(0);} }

    這一關的關鍵是讓?if (!InnerClasses.check1() || !InnerClasses.check2() || !InnerClasses.check3() || !InnerClasses.check4() || !InnerClasses.check5() || !InnerClasses.check6())?中的所有 check 全部返回 true。

    其實這里唯一的問題就是尋找內部類?InnerClasses,對于內部類的 hook,通過 類名$內部類名 去 use。

    function ch4() {Java.perform(function () {var InnerClasses = Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses")console.log("start")InnerClasses.check1.implementation = function () { return true }InnerClasses.check2.implementation = function () { return true }InnerClasses.check3.implementation = function () { return true }InnerClasses.check4.implementation = function () { return true }InnerClasses.check5.implementation = function () { return true }InnerClasses.check6.implementation = function () { return true }}) }

    利用反射,獲取類中的所有 method 聲明,然后字符串拼接去獲取到方法名,例如下面的 check1,然后就可以批量 hook,而不用像我上面那樣一個一個寫。

    var inner_classes = Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses") var all_methods = inner_classes.class.getDeclaredMethods();... public static boolean com.example.androiddemo.Activity.FridaActivity4$InnerClasses.check1(), public static boolean com.example.androiddemo.Activity.FridaActivity4$InnerClasses.check2(), public static boolean com.example.androiddemo.Activity.FridaActivity4$InnerClasses.check3(), public static boolean com.example.androiddemo.Activity.FridaActivity4$InnerClasses.check4(), public static boolean com.example.androiddemo.Activity.FridaActivity4$InnerClasses.check5(), public static boolean com.example.androiddemo.Activity.FridaActivity4$InnerClasses.check6()

    hook 類方法 的 所有 重載

    方法 1:

    //目標類 var hook = Java.use(targetClass); //重載次數 var overloadCount = hook[targetMethod].overloads.length; //打印日志:追蹤的方法有多少個重載 console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]"); //每個重載都進入一次 for (var i = 0; i < overloadCount; i++) { //hook每一個重載hook[targetMethod].overloads[i].implementation = function() {console.warn("\n*** entered " + targetClassMethod);//可以打印每個重載的調用棧,對調試有巨大的幫助,當然,信息也很多,盡量不要打印,除非分析陷入僵局Java.perform(function() {var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());console.log("\nBacktrace:\n" + bt);}); // 打印參數if (arguments.length) console.log();for (var j = 0; j < arguments.length; j++) {console.log("arg[" + j + "]: " + arguments[j]);}//打印返回值var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?)console.log("\nretval: " + retval);console.warn("\n*** exiting " + targetClassMethod);return retval;} }

    方法 2:

    function hookOneClassAllMethod(clsName) {console.log("開始 hook 一個類的所有方法");// var NetContent = Java.use("com.xbiao.utils.net.NetContent");var clazz = Java.use(clsName); // 得到 classvar all_method = clazz.class.getDeclaredMethods(); // 得到類的所有方法all_method.forEach(function (mth) { // 遍歷類的所有方法var mthName = mth.getName(); // 得到 方法名var all_overload = clazz[mthName].overloads;all_overload.forEach(function (olad) {// hook 重載 argumentTypesolad.implementation = function () {console.log("\r")// printStack()for (var i = 0; i < arguments.length; i++) {var arg_type = olad.argumentTypes[i].className;var arg_val = arguments[i];var arg_fmt = JSON.stringify(arg_val);var msg = mthName + " ---> " + "arg[" + i + ":"+ arg_type +"]:" + arg_fmt;console.log(msg);}var retVal = this[mthName].apply(this, arguments);console.log(mthName + " ---> 返回值:" + retVal);return retVal;}})}) } function main() {Java.perform(() => {Java.enumeratteClassLoaders({onMatch: function(loader){console.log("ClassLoader start");try {if(loader.findClass("com.xbiao.utils.AESdedUtil")){console.log("Successfully found loader")console.log(loader);Java.classFactory.loader = loader ;hookOneClassAllMethod("com.xbiao.utils.net.NetContent")}}catch(error){console.log("find error:" + error)}},onComplete: function (){console.log("ClassLoader end");}});}); } setImmediate(main)

    執行結果:?

    5.4 Frida hook : hook 動態加載的 dex,與查找 interface,

    總結:

    • 通過?enumerateClassLoaders?來枚舉加載進內存的 classloader
    • 再?loader.findClass(xxx)?尋找是否包括我們想要的 interface 的實現類,
    • 最后通過?Java.classFactory.loader = loader?來切換 classloader,從而加載該實現類。

    第五關比較有趣,它的 check 函數是動態加載進來的。

    java 里有 interface 的概念,是指一系列抽象的接口,需要類來實現。

    package com.example.androiddemo.Dynamic;public interface CheckInterface { boolean check(); } ...public class DynamicCheck implements CheckInterface {public boolean check() { return false; } } ... public class FridaActivity5 extends BaseFridaActivity {private CheckInterface DynamicDexCheck = null;...public CheckInterface getDynamicDexCheck() {if (this.DynamicDexCheck == null) {loaddex();}return this.DynamicDexCheck;}/* access modifiers changed from: protected */public void onCreate(Bundle bundle) {super.onCreate(bundle);loaddex();// this.DynamicDexCheck = (CheckInterface) new DexClassLoader(// str, filesDir.getAbsolutePath(), (String) null, getClassLoader()// ).loadClass("com.example.androiddemo.Dynamic.DynamicCheck").newInstance();}public void onCheck() {if (getDynamicDexCheck() == null) {Toast.makeText(this, "onClick loaddex Failed!", 1).show();} else if (getDynamicDexCheck().check()) {CheckSuccess();startActivity(new Intent(this, FridaActivity6.class));finishActivity(0);} else {super.CheckFailed();}} }

    這里有個 loaddex 其實就是先從資源文件加載 classloader 到內存里,再 loadClass DynamicCheck,創建出一個實例,最終調用這個實例的 check。

    所以現在我們就要先枚舉 class loader,找到能實例化我們要的 class 的那個 class loader,然后把它設置成 Java 的默認 class factory 的 loader。

    現在就可以用這個 class loader 來使用 .use 去 import 一個給定的類。

    function ch5() {Java.perform(function () {// Java.choose("com.example.androiddemo.Activity.FridaActivity5",{// onMatch:function(x){// console.log(x.getDynamicDexCheck().$className)// },onComplete:function(){}// })console.log("start")Java.enumerateClassLoaders({onMatch: function (loader) {try {if(loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")){console.log("Successfully found loader")console.log(loader);Java.classFactory.loader = loader ;}}catch(error){console.log("find error:" + error)}},onComplete: function () {console.log("end1")}})Java.use("com.example.androiddemo.Dynamic.DynamicCheck").check.implementation = function () {return true}console.log("end2")}) } setImmediate(ch5)

    todo有一個疑問:https://github.com/frida/frida/issues/1049

    5.5 Frida hook : 枚舉 class,trace原型2

    總結: 通過?Java.enumerateLoadedClasses?來 枚舉類,然后?name.indexOf(str)?過濾一下并 hook。

    接下來是第六關

    import com.example.androiddemo.Activity.Frida6.Frida6Class0; import com.example.androiddemo.Activity.Frida6.Frida6Class1; import com.example.androiddemo.Activity.Frida6.Frida6Class2;public class FridaActivity6 extends BaseFridaActivity {public String getNextCheckTitle() {return "當前第6關";}public void onCheck() {if (!Frida6Class0.check() || !Frida6Class1.check() || !Frida6Class2.check()) {super.CheckFailed();return;}CheckSuccess();startActivity(new Intent(this, FridaActivity7.class));finishActivity(0);} }

    這關是 import 了一些類,然后 調用類里的靜態方法,所以我們枚舉所有的類,然后過濾一下,并把過濾出來的結果 hook 上,改掉其返回值。

    function ch6() {Java.perform(function () {Java.enumerateLoadedClasses({onMatch: function (class_name, handle){if (class_name.indexOf("com.example.androiddemo.Activity.Frida6") != -1) {console.log("class_name:" + class_name + " handle:" + handle)Java.use(class_name).check.implementation = function () {return true}}},onComplete: function () {console.log("end")}})}) }

    frida rpc 枚舉 實現 接口的類

    import sys import frida''' frida rpc 枚舉類 '''def on_message(message, data):if message['type'] == 'send':print("[*] {message['payload']}")else:print(message)hook = """ Java.perform(function(){Java.enumerateLoadedClasses({"onMatch" : function(classname){if(classname.indexOf("com.csair.mbp") < 0){return;}// 實現類 implementstry{var hookCls = Java.use(classname)var interFaces = hookCls.class.getInterfaces();if (interFaces.length > 0) {console.log(classname)for (var i in interFaces) {// 接口類 interFacesconsole.log("\t", interFaces[i].toString())}} }catch(e){console.log(e)}},"onComplete" : function(){}}) }) """process = frida.get_usb_device().attach('com.csair.mbp') script = process.create_script(hook) script.on('message', on_message) print('[*] Running CTF') script.load() sys.stdin.read()

    5.6 Frida hook : 搜索 interface 的具體實現類

    利用反射得到類里面實現的 interface 數組,并打印出來。

    function more() {Java.perform(function () {Java.enumerateLoadedClasses({onMatch: function (class_name){if (class_name.indexOf("com.example.androiddemo") < 0) {return}else {var hook_cls = Java.use(class_name)var interfaces = hook_cls.class.getInterfaces()if (interfaces.length > 0) {console.log(class_name + ": ")for (var i in interfaces) {console.log("\t", interfaces[i].toString())}}}},onComplete: function () {console.log("end")}})}) }

    6、Frida hook 基礎(二)

    • spawn / attach
    • 各種主動調用
    • hook函數 和 hook構造函數
    • 調用棧? /簡單腳本
    • 動態加載自己的 dex

    題目下載地址:https://github.com/tlamb96/kgb_messenger

    6.1 spawn / attach

    firda 的 -f 參數代表 span 啟動:frida -U -f com.tlamb96.spetsnazmessenger -l frida_russian.js --no-pause

    上面命令執行完后,會進入 frida ,然后在輸入 %resume 恢復程序運行

    /* access modifiers changed from: protected */public void onCreate(Bundle bundle) {super.onCreate(bundle);setContentView((int) R.layout.activity_main);String property = System.getProperty("user.home");String str = System.getenv("USER");if (property == null || property.isEmpty() || !property.equals("Russia")) {a("Integrity Error", "This app can only run on Russian devices.");} else if (str == null || str.isEmpty() || !str.equals(getResources().getString(R.string.User))) {a("Integrity Error", "Must be on the user whitelist.");} else {a.a(this);startActivity(new Intent(this, LoginActivity.class));}} }

    這個題目比較簡單,但是因為這個 check 是在?onCreate?里,所以 app 剛啟動就自動檢查,所以這里需要用 spawn 的方式去啟動 frida 腳本 hook,而不是 attach。

    這里有兩個檢查,一個是檢查 property 的值,一個是檢查 str 的值。分別從?System.getProperty?和?System.getenv?里獲取,hook 住這兩個函數就行。

    這里要注意從資源文件里找到 User 的值。

    frida_russian.js?

    function main() {Java.perform(function () {Java.use("java.lang.System").getProperty.overload('java.lang.String').implementation = function (str) {return "Russia";}Java.use("java.lang.System").getenv.overload('java.lang.String').implementation = function(str){return "RkxBR3s1N0VSTDFOR180UkNIM1J9Cg==";}}) } setImmediate(main)

    運行結果截圖:

    接下來進入到 login 功能

    public void onLogin(View view) {EditText editText = (EditText) findViewById(R.id.login_username);EditText editText2 = (EditText) findViewById(R.id.login_password);this.n = editText.getText().toString();this.o = editText2.getText().toString();if (this.n != null && this.o != null && !this.n.isEmpty() && !this.o.isEmpty()) {if (!this.n.equals(getResources().getString(R.string.username))) {Toast.makeText(this, "User not recognized.", 0).show();editText.setText("");editText2.setText("");} else if (!j()) {Toast.makeText(this, "Incorrect password.", 0).show();editText.setText("");editText2.setText("");} else {i();startActivity(new Intent(this, MessengerActivity.class));}}} ...private boolean j() {String str = "";for (byte b : this.m.digest(this.o.getBytes())) {str = str + String.format("%x", new Object[]{Byte.valueOf(b)});}return str.equals(getResources().getString(R.string.password));} ...private void i() {char[] cArr = {'(', 'W', 'D', ')', 'T', 'P', ':', '#', '?', 'T'};cArr[0] = (char) (cArr[0] ^ this.n.charAt(1));cArr[1] = (char) (cArr[1] ^ this.o.charAt(0));cArr[2] = (char) (cArr[2] ^ this.o.charAt(4));cArr[3] = (char) (cArr[3] ^ this.n.charAt(4));cArr[4] = (char) (cArr[4] ^ this.n.charAt(7));cArr[5] = (char) (cArr[5] ^ this.n.charAt(0));cArr[6] = (char) (cArr[6] ^ this.o.charAt(2));cArr[7] = (char) (cArr[7] ^ this.o.charAt(3));cArr[8] = (char) (cArr[8] ^ this.n.charAt(6));cArr[9] = (char) (cArr[9] ^ this.n.charAt(8));Toast.makeText(this, "FLAG{" + new String(cArr) + "}", 1).show();}

    從資源文件里找到 username,密碼則是要算一個 j() 函數,要讓它返回 true,順便打印一下 i 函數 toast 到界面的 flag。

    ( github 代碼中 不是 j() 函數,而是?checkPassword() 函數?)

    var clazz = Java.use("com.tlamb96.kgbmessenger.LoginActivity") clazz.j.implementation = function (){return true} ...var clazz = Java.use("android.widget.Toast") clazz.makeText.overload('android.content.Context', 'java.lang.CharSequence', 'int').implementation = function (x, y, z) {var flag = Java.use("java.lang.String").$new(y)console.log(flag) } ... [Google Pixel::com.tlamb96.spetsnazmessenger]-> FLAG{G&qG13 R0}

    代碼:

    Java.perform(function () {Java.use("com.tlamb96.kgbmessenger.LoginActivity").checkPassword.implementation = function () {return true};Java.use("android.widget.Toast").makeText.overload('android.content.Context', 'java.lang.CharSequence', 'int').implementation = function (x, y, z) {var flag = Java.use("java.lang.String").$new(y);console.log(flag);return this.makeText(x, y, z);} })

    執行結果:

    6.2 Frida hook : hook構造函數/打印棧回溯

    總結:hook 構造函數實現 通過use取得類,然后clazz.$init.implementation = callback?hook 構造函數。

    我們先學習一下怎么 hook 構造函數。

    add(new com.tlamb96.kgbmessenger.b.a(R.string.katya, "Archer, you up?", "2:20 am", true)); ... package com.tlamb96.kgbmessenger.b; public class a { ...public a(int i, String str, String str2, boolean z) {this.f448a = i;this.b = str;this.c = str2;this.d = z;} ... }

    用?$init?來 hook 構造函數

    function printstack() {console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())); }Java.use("com.tlamb96.kgbmessenger.b.a").$init.implementation = function (i, str1, str2, z) {this.$init(i, str1, str2, z)console.log(i, str1, str2, z)printStack("com.tlamb96.kgbmessenger.b.a") }

    打印堆棧:

    function printstack() {console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())); }

    6.3 Frida hook : 打印棧回溯

    打印棧回溯

    function printStack(name) {Java.perform(function () {var Exception = Java.use("java.lang.Exception");var instanceTemp = Exception.$new("Exception");var straces = instanceTemp.getStackTrace();if (straces != undefined && straces != null) {var strace = straces.toString();var replaceStr = strace.replace(/,/g, "\\n");console.log("=============================" + name + " Stack strat=======================");console.log(replaceStr);console.log("=============================" + name + " Stack end=======================\r\n");Exception.$dispose();}}); }

    輸出就是這樣

    [Google Pixel::com.tlamb96.spetsnazmessenger]-> 2131558449 111 02:27 下午 false =============================com.tlamb96.kgbmessenger.b.a Stack strat======================= com.tlamb96.kgbmessenger.b.a.<init>(Native Method) com.tlamb96.kgbmessenger.MessengerActivity.onSendMessage(Unknown Source:40) java.lang.reflect.Method.invoke(Native Method) android.support.v7.app.m$a.onClick(Unknown Source:25) android.view.View.performClick(View.java:6294) android.view.View$PerformClick.run(View.java:24770) android.os.Handler.handleCallback(Handler.java:790) android.os.Handler.dispatchMessage(Handler.java:99) android.os.Looper.loop(Looper.java:164) android.app.ActivityThread.main(ActivityThread.java:6494) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) =============================com.tlamb96.kgbmessenger.b.a Stack end=======================

    6.4 Frida hook : 手動加載 dex 并調用

    總結:編譯出 dex 后,通過 Java.openClassFile("xxx.dex").load() 加載,就可以正常通過 Java.use 調用里面的方法了。

    現在我們來繼續解決這個問題。

    public void onSendMessage(View view) {EditText editText = (EditText) findViewById(R.id.edittext_chatbox);String obj = editText.getText().toString();if (!TextUtils.isEmpty(obj)) {this.o.add(new com.tlamb96.kgbmessenger.b.a(R.string.user, obj, j(), false));this.n.c();if (a(obj.toString()).equals(this.p)) {Log.d("MessengerActivity", "Successfully asked Boris for the password.");this.q = obj.toString();this.o.add(new com.tlamb96.kgbmessenger.b.a(R.string.boris, "Only if you ask nicely", j(), true));this.n.c();}if (b(obj.toString()).equals(this.r)) {Log.d("MessengerActivity", "Successfully asked Boris nicely for the password.");this.s = obj.toString();this.o.add(new com.tlamb96.kgbmessenger.b.a(R.string.boris, "Wow, no one has ever been so nice to me! Here you go friend: FLAG{" + i() + "}", j(), true));this.n.c();}this.m.b(this.m.getAdapter().a() - 1);editText.setText("");} }

    新的一關是一個聊天框。分析一下代碼可知,obj 是我們輸入的內容,輸入完了之后,加到一個 this.o 的 ArrayList 里。關鍵的 if 判斷就是 if (a(obj.toString()).equals(this.p)) 和 if (b(obj.toString()).equals(this.r)),所以 hook a函數b函數,讓它們的返回值等于下面的字符串即可。

    private String p = "V@]EAASB\u0012WZF\u0012e,a$7(&am2(3.\u0003"; private String q; private String r = "\u0000dslp}oQ\u0000 dks$|M\u0000h +AYQg\u0000P*!M$gQ\u0000"; private String s;

    但實際上這題比我想象中的還要麻煩,這題的邏輯上是如果通過了 a 和 b 這兩個函數的計算,等于對應的值之后,會把用來計算的 obj 的值賦值給 q 和 s,然后根據這個 q 和 s 來計算出最終的 flag。
    所以如果不逆向算法,通過 hook 的方式通過了 a和b 的計算,obj 的值還是錯誤的,也計算不出正確的 flag。

    這樣就逆向一下算法好了,先自己寫一個 apk,用 java 去實現注冊機。

    可以直接把 class 文件轉成 dex,不復述,我比較懶,所以我直接解壓 apk 找到?classes.dex,并 push 到手機上。
    然后用 frida 加載這個 dex,并調用里面的方法。

    var dex = Java.openClassFile("/data/local/tmp/classes.dex").load(); console.log("decode_P:"+Java.use("myapplication.example.com.reversea.reverseA").decode_P()); console.log("r_to_hex:"+Java.use("myapplication.example.com.reversea.reverseA").r_to_hex()); ... ... decode_P:Boris, give me the password r_to_hex:0064736c707d6f510020646b73247c4d0068202b4159516700502a214d24675100

    7、Frida 打印 與 參數構造

    • 數組 / (字符串)對象數組 / gson / Java.array
    • 對象 / 多態、強轉Java.cast / 接口Java.register
    • 泛型、List、Map、Set、迭代打印

    打印 [object object]

    • 方法 1:先確認 object 是什么類型,比如要打印 p,先 console.log(p.$className) 查看 p 是什么數據類型,然后用 Java.cast 把 p 強制轉為對應類型,強制轉換之后,在調用轉換后類型的輸出方法,通常為 toString()
    • 方法 2:使用 js 里面的 json 類,嘗試 console.log(JSON.stringify(p)),可能打印不出來字符串,一般能打印出 p 的字節數組
    • 方法 3:使用 objection 插件 wallbreak

    $className 參看官方文檔說明:

    gson 打印 Java 對象的內容

    Gson 是谷歌官方推出的支持?JSON 和 Java Object?相互轉換的 Java?序列化/反序列化?庫。

    gson?基本用法:https://blog.csdn.net/chenrenxiang/article/details/80291224? ??https://www.cnblogs.com/baiqiantao/p/7512336.html

    Android Gson使用詳解:https://www.jianshu.com/p/0444693c2639

    Frida?打印 [object] 解決 'gson'?包重名的問題:https://www.52pojie.cn/thread-1167397-1-1.html

    使用 Frida 時,想要打印 Java 對象的內容,可以使用谷歌的 gson包,可以非常優秀的將 Java 對象的內容,以 json 的格式打印出來。

    Java.openClassFile("/data/local/tmp/r0gson.dex").load(); const gson = Java.use('com.r0ysue.gson.Gson'); console.log(gson.$new().toJson(xxx));

    char[] / [Object Object]

    Log.d("SimpleArray", "onCreate: SImpleArray"); char arr[][] = new char[4][]; // 創建一個4行的二維數組 arr[0] = new char[] { '春', '眠', '不', '覺', '曉' }; // 為每一行賦值 arr[1] = new char[] { '處', '處', '聞', '啼', '鳥' }; arr[2] = new char[] { '夜', '來', '風', '雨', '聲' }; arr[3] = new char[] { '花', '落', '知', '多', '少' }; Log.d("SimpleArray", "-----橫版-----"); for (int i = 0; i < 4; i++) { // 循環4行Log.d("SimpleArraysToString", Arrays.toString(arr[i]));Log.d("SimpleStringBytes", Arrays.toString(Arrays.toString(arr[i]).getBytes()));for (int j = 0; j < 5; j++) { // 循環5列Log.d("SimpleArray", Character.toString(arr[i][j])); // 輸出數組中的元素}if (i % 2 == 0) {Log.d("SimpleArray", ",");// 如果是一、三句,輸出逗號} else {Log.d("SimpleArray", "。");// 如果是二、四句,輸出句號} }

    新建一個 Android 項目,把上面代碼放到 onCreate 函數中,再導入缺失的包

    import android.util.Log; import java.util.Arrays;

    ?點擊菜單欄上的 build ---> 生成 apk,成功生成 apk 后,手機安裝 apk,在啟動 frida-server 和端口轉發

    ?執行命令:frida-ps -Ua 查看 apk 的包名

    main.js?

    function main() {Java.perform(function x() {Java.openClassFile("/data/local/tmp/r0gson.dex").load();const gson = Java.use('com.r0ysue.gson.Gson');Java.use("java.lang.Character").toString.overload('char').implementation = function (char) {var result = this.toString(char);console.log("char,result", char, result);return result;}Java.use("java.util.Arrays").toString.overload('[C').implementation = function (charArray) {var result = this.toString(charArray);console.log("charArray,result:", charArray, result)console.log("charArray Object Object:", gson.$new().toJson(charArray));return result;}}) }setImmediate(main)

    ?在執行命令:frida -U -f com.example.myapplication -l .\main.js --no-pause?

    這里的?[C?是 JNI 函數簽名

    byte[]

    function main() {Java.perform(function x() {Java.openClassFile("/data/local/tmp/r0gson.dex").load();const gson = Java.use('com.r0ysue.gson.Gson');Java.use("java.util.Arrays").toString.overload('[B').implementation = function (byteArray) {var result = this.toString(byteArray);console.log("byteArray,result):", byteArray, result)console.log("byteArray Object Object:", gson.$new().toJson(byteArray));return result;}}) }setImmediate(main)

    ?// byte[] bArray = "123abc".getBytes() // java 代碼
    var strTemp = Java.use("java.lang.String").$new(bArray);
    console.log(strTemp)

    java array 構造

    如果不只是想打印出結果,而是要替換原本的參數,就要先自己構造出一個charArray,使用?Java.array 這個API

    /*** Creates a Java array with elements of the specified `type`, from a* JavaScript array `elements`. The resulting Java array behaves like* a JS array, but can be passed by reference to Java APIs in order to* allow them to modify its contents.** @param type Type name of elements.* @param elements Array of JavaScript values to use for constructing the* Java array.*/ function array(type: string, elements: any[]): any[]; Java.use("java.util.Arrays").toString.overload('[C').implementation = function(charArray){var newCharArray = Java.array('char', [ '一','去','二','三','里' ]);var result = this.toString(newCharArray);console.log("newCharArray,result:",newCharArray,result)console.log("newCharArray Object Object:",gson.$new().toJson(newCharArray));var newResult = Java.use('java.lang.String').$new(Java.array('char', [ '煙','村','四','五','家']))return newResult; }

    可以用來構造參數重發包,用在爬蟲上。

    類的多態:轉型 / Java.cast

    可以通過?getClass().getName().toString()來查看當前實例的類型。

    找到一個 instance,通過?Java.cast?來強制轉換對象的類型。

    /*** Creates a JavaScript wrapper given the existing instance at `handle` of* given class `klass` as returned from `Java.use()`.** @param handle An existing wrapper or a JNI handle.* @param klass Class wrapper for type to cast to.*/ function cast(handle: Wrapper | NativePointerValue, klass: Wrapper): Wrapper;

    java 示例代碼( 定義一個 water 類 和 一個 Juice 類,同時 Juice 繼承 water ):

    public class Water { // 水 類public static String flow(Water W) { // 水 的方法// SomeSentenceLog.d("2Object", "water flow: I`m flowing");return "water flow: I`m flowing";}public String still(Water W) { // 水 的方法// SomeSentenceLog.d("2Object", "water still: still water runs deep!");return "water still: still water runs deep!";} } ... public class Juice extends Water { // 果汁 類 繼承了水類public String fillEnergy(){Log.d("2Object", "Juice: i`m fillingEnergy!");return "Juice: i`m fillingEnergy!";}

    js 示例代碼:

    var JuiceHandle = null ; Java.choose("com.r0ysue.a0526printout.Juice",{onMatch:function(instance){console.log("found juice instance",instance);console.log("juice instance call fill",instance.fillEnergy());JuiceHandle = instance;},onComplete:function(){console.log("juice handle search completed!")} }) console.log("Saved juice handle :",JuiceHandle); var WaterHandle = Java.cast(JuiceHandle,Java.use("com.r0ysue.a0526printout.Water")) console.log("call Waterhandle still method:",WaterHandle.still(WaterHandle));

    示例:

    function printHashMap(param_hm){
    ? ? var HashMap = Java.use('java.util.HashMap');
    ? ? var args_map = Java.cast(param_hm, HashMap)
    ? ? send('args_map:' + args_map.toString());
    }

    interface / Java.registerClass

    public interface liquid {public String flow(); }

    frida 提供能力去創建一個新的 java class

    /*** Creates a new Java class.** @param spec Object describing the class to be created.*/ function registerClass(spec: ClassSpec): Wrapper;

    首先獲取要實現的 interface,然后調用 registerClass 來實現 interface。

    function main() {Java.perform(function(){var liquid = Java.use("com.r0ysue.a0526printout.liquid");var beer = Java.registerClass({name: 'com.r0ysue.a0526printout.beer',implements: [liquid],methods: {flow: function () {console.log("look, beer is flowing!")return "look, beer is flowing!";}}});console.log("beer.bubble:",beer.$new().flow()) }) } setImmediate(main)

    成員內部類 / 匿名內部類

    看 smali 或者 枚舉出來的類。

    hook enum

    關于 java 枚舉,從這篇文章了解:https://www.cnblogs.com/jingmoxukong/p/6098351.html

    enum Signal {GREEN, YELLOW, RED } public class TrafficLight {public static Signal color = Signal.RED;public static void main() {Log.d("4enum", "enum "+ color.getClass().getName().toString());switch (color) {case RED:color = Signal.GREEN;break;case YELLOW:color = Signal.RED;break;case GREEN:color = Signal.YELLOW;break;}} } Java.perform(function(){Java.choose("com.r0ysue.a0526printout.Signal",{onMatch:function(instance){console.log("instance.name:",instance.name());console.log("instance.getDeclaringClass:",instance.getDeclaringClass()); },onComplete:function(){console.log("search completed!")}})})

    打印 hash map

    【深入Java基礎】HashMap 的基本用法:https://blog.csdn.net/wxgxgp/article/details/79194360

    Java集合之HashMap的用法:https://blog.csdn.net/weixin_43263961/article/details/86427533

    frida 打印 map

    Java.perform(function(){Java.choose("java.util.HashMap",{onMatch:function(instance){if(instance.toString().indexOf("ISBN")!= -1){console.log("instance.toString:",instance.toString());}},onComplete:function(){console.log("search complete!")}})})

    frida 復雜類型參數打印、參數轉換、調用棧打印:https://blog.csdn.net/weixin_35762183/article/details/106802647

    示例:

    # -*- coding: UTF-8 -*- import frida, sysjsCode = """ Java.perform(function () {/*var clazz = Java.use("xxx");clazz.b.overload('java.util.Map').implementation = function (args1) {var result = "";var keyset = args1.keySet();var it = keyset.iterator();while (it.hasNext()) {var keystr = it.next().toString();var valuestr = args1.get(keystr).toString();console.log(keystr)console.log(valuestr)result += valuestr;}var args = this.b(args1)console.log("出參--", args)return args}*/var HashMap = Java.use('java.util.HashMap');var ShufferMap = Java.use('com.xiaojianbang.app.ShufferMap');ShufferMap.show.implementation = function (map) {var hm = HashMap.$new();hm.put("user","dajianbang");hm.put("pass","87654321");hm.put("code","123456");return this.show(hm);} }); """;def message(message, data):if message["type"] == 'send':print(u"[*] {0}".format(message['payload']))else:print(message)process = frida.get_remote_device().attach("com.xiaojianbang.app") script= process.create_script(jsCode) script.on("message", message) script.load() sys.stdin.read()

    js_code:

    js_code = ''' Java.perform(function() {var clazz = Java.use('com.xxx.xxx');clazz.signUrl.overload('java.lang.String', 'java.util.Map').implementation = function(arg_str, arg_map) { console.log('arg_str:', arg_str);console.log('arg_map:', arg_map); var result = "";var key_set = arg_map.keySet();var key_set_it = key_set.iterator();while(key_set_it.hasNext()){var key_str = key_set_it.next().toString();var value_str = arg_map.get(key_str).toString();console.log(key_str) console.log(value_str) } return this.signUrl(arg_str, arg_map)} }); '''

    js_code?( hashmap 有個 toString 函數,可以直接打印?)

    function printHashMap(param_hm){var HashMap = Java.use('java.util.HashMap');var args_map = Java.cast(param_hm, HashMap)send('args_map:' + args_map.toString()); }

    打印 non-ascii

    https://api-caller.com/2019/03/30/frida-note/#non-ascii

    類名非 ASCII 字符串時,先編碼打印出來,?再用編碼后的字符串去 hook。

    //場景 hook cls.forName尋找目標類的 classloader。 cls.forName.overload('java.lang.String', 'boolean', 'java.lang.ClassLoader').implementation = function (arg1, arg2, arg3) {var clsName = cls.forName(arg1, arg2, arg3);console.log('oriClassName:' + arg1)var base64Name = encodeURIComponent(arg1)console.log('encodeName:' + base64Name);//通過日志確認base64后的非ascii字符串,下面對比并打印classloader//clsName為特殊字符o.?é?if ('o.%CE%99%C9%AB' == base64Name) {//打印classloaderconsole.log(arg3);}return clsName; }

    8、Frida native hook : NDK 開發入門

    https://www.jianshu.com/p/87ce6f565d37

    • Android JNI(一)——NDK與JNI基礎
    • Android JNI學習(二)——實戰JNI之“hello world”
    • Android JNI學習(三)——Java與Native相互調用
    • Android JNI學習(四)——JNI的常用方法的中文API
    • Android JNI學習(五)——Demo演示

    extern "C"?與 名稱修飾 (name mangling)

    • 通過 C++ filt 工具可以直接還原得到原來的函數名
    • https://zh.wikipedia.org/zh-hans/名字修飾
    • 通過 extern "C" 導出的 JNI 函數不會被 name mangling
    • JNI參數基本類型
    • 第一個 NDK程序

    • JNI log

    #define TAG "sakura1328" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)extern "C" JNIEXPORT jstring JNICALL Java_myapplication_example_com_ndk_1demo_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C++";LOGD("sakura1328");return env->NewStringUTF(hello.c_str()); } ... public class MainActivity extends AppCompatActivity {private static final String TAG = "sakura";// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Example of a call to a native methodTextView tv = (TextView) findViewById(R.id.sample_text);tv.setText(stringFromJNI());Log.d(TAG, stringFromJNI());}/*** A native method that is implemented by the 'native-lib' native library,* which is packaged with this application.*/public native String stringFromJNI(); }

    9、Frida native hook : JNIEnv反射

    9.1 以 jni字符串 來掌握基本的 JNIEnv用法

    public native String stringWithJNI(String context); ...extern "C" JNIEXPORT jstring JNICALL Java_myapplication_example_com_ndk_1demo_MainActivity_stringWithJNI(JNIEnv *env, jobject instance, jstring context_) {const char *context = env->GetStringUTFChars(context_, 0);int context_size = env->GetStringUTFLength(context_);if (context_size > 0) {LOGD("%s\n", context);}env->ReleaseStringUTFChars(context_, context);return env->NewStringUTF("sakura1328"); }12-26 22:30:00.548 15764-15764/myapplication.example.com.ndk_demo D/sakura1328: sakura

    9.2 Java 反射

    總結:多去讀一下 Java 的反射 API。

    ?Java高級特性 -----?反射?:https://www.jianshu.com/p/9be58ee20dee

    • 查找調用各種 API 接口、JNI、frida/xposed原理的一部分
    • 反射基本 API
    • 反射修改訪問控制、修改屬性值
    • JNI so調用反射進入java世界
    • xposed/Frida hook原理

    這里其實有一個伏筆,就是為什么我們要 trace artmethod,hook artmethod ?????

    是因為有些 so 混淆得非常厲害,然后也就很難靜態分析看出 so 里面調用了哪些 java 函數,也不是通過類似 JNI 的 GetMethodID 這樣來調用的。

    而是通過類似 findclass 這種方法先得到類,然后再反射調用 app 里面的某個 java 函數。

    所以去 hook 它執行的位置,每一個 java 函數對于 Android 源碼而言都是一個 artmethod 結構體,然后 hook 拿到 artmethod 實例后,再去調用類函數,打印這個函數的名稱

    public class MainActivity extends AppCompatActivity {private static final String TAG = "sakura";// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Example of a call to a native methodTextView tv = (TextView) findViewById(R.id.sample_text);tv.setText(stringWithJNI("sakura")); // Log.d(TAG, stringFromJNI()); // Log.d(TAG, stringWithJNI("sakura"));try {testClass();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}public void testClass() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Test sakuraTest = new Test();// 獲得Class的方法(三種)Class testClazz = MainActivity.class.getClassLoader().loadClass("myapplication.example.com.ndk_demo.Test");Class testClazz2 = Class.forName("myapplication.example.com.ndk_demo.Test");Class testClazz3 = Test.class;Log.i(TAG, "Classloader.loadClass->" + testClazz);Log.i(TAG, "Classloader.loadClass->" + testClazz2);Log.i(TAG, "Classloader.loadClass->" + testClazz3.getName());// 獲得類中屬性相關的方法Field publicStaticField = testClazz3.getDeclaredField("publicStaticField");Log.i(TAG, "testClazz3.getDeclaredField->" + publicStaticField);Field publicField = testClazz3.getDeclaredField("publicField");Log.i(TAG, "testClazz3.getDeclaredField->" + publicField);//對于Field的get方法,如果是static,則傳入null即可;如果不是,則需要傳入一個類的實例String valueStaticPublic = (String) publicStaticField.get(null);Log.i(TAG, "publicStaticField.get->" + valueStaticPublic);String valuePublic = (String) publicField.get(sakuraTest);Log.i(TAG, "publicField.get->" + valuePublic);//對于private屬性,需要設置AccessibleField privateStaticField = testClazz3.getDeclaredField("privateStaticField");privateStaticField.setAccessible(true);String valuePrivte = (String) privateStaticField.get(null);Log.i(TAG, "modified before privateStaticField.get->" + valuePrivte);privateStaticField.set(null, "modified");valuePrivte = (String) privateStaticField.get(null);Log.i(TAG, "modified after privateStaticField.get->" + valuePrivte);Field[] fields = testClazz3.getDeclaredFields();for (Field i : fields) {Log.i(TAG, "testClazz3.getDeclaredFields->" + i);}// 獲得類中method相關的方法Method publicStaticMethod = testClazz3.getDeclaredMethod("publicStaticFunc");Log.i(TAG, "testClazz3.getDeclaredMethod->" + publicStaticMethod);publicStaticMethod.invoke(null);Method publicMethod = testClazz3.getDeclaredMethod("publicFunc", java.lang.String.class);Log.i(TAG, "testClazz3.getDeclaredMethod->" + publicMethod);publicMethod.invoke(sakuraTest, " sakura");}/*** A native method that is implemented by the 'native-lib' native library,* which is packaged with this application.*/public native String stringFromJNI();public native String stringWithJNI(String context); } ... public class Test {private static final String TAG = "sakura_test";public static String publicStaticField = "i am a publicStaticField";public String publicField = "i am a publicField";private static String privateStaticField = "i am a privateStaticField";private String privateField = "i am a privateField";public static void publicStaticFunc() {Log.d(TAG, "I`m from publicStaticFunc");}public void publicFunc(String str) {Log.d(TAG, "I`m from publicFunc" + str);}private static void privateStaticFunc() {Log.i(TAG, "I`m from privateFunc");}private void privateFunc() {Log.i(TAG, "I`m from privateFunc");} } ... ... 12-26 23:57:11.784 17682-17682/myapplication.example.com.ndk_demo I/sakura: Classloader.loadClass->class myapplication.example.com.ndk_demo.Test 12-26 23:57:11.784 17682-17682/myapplication.example.com.ndk_demo I/sakura: Classloader.loadClass->class myapplication.example.com.ndk_demo.Test 12-26 23:57:11.784 17682-17682/myapplication.example.com.ndk_demo I/sakura: Classloader.loadClass->myapplication.example.com.ndk_demo.Test 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredField->public static java.lang.String myapplication.example.com.ndk_demo.Test.publicStaticField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredField->public java.lang.String myapplication.example.com.ndk_demo.Test.publicField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: publicStaticField.get->i am a publicStaticField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: publicField.get->i am a publicField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: modified before privateStaticField.get->i am a privateStaticField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: modified after privateStaticField.get->modified 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredFields->private java.lang.String myapplication.example.com.ndk_demo.Test.privateField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredFields->public java.lang.String myapplication.example.com.ndk_demo.Test.publicField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredFields->private static final java.lang.String myapplication.example.com.ndk_demo.Test.TAG 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredFields->private static java.lang.String myapplication.example.com.ndk_demo.Test.privateStaticField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredFields->public static java.lang.String myapplication.example.com.ndk_demo.Test.publicStaticField 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredMethod->public static void myapplication.example.com.ndk_demo.Test.publicStaticFunc() 12-26 23:57:11.785 17682-17682/myapplication.example.com.ndk_demo D/sakura_test: I`m from publicStaticFunc 12-26 23:57:11.786 17682-17682/myapplication.example.com.ndk_demo I/sakura: testClazz3.getDeclaredMethod->public void myapplication.example.com.ndk_demo.Test.publicFunc(java.lang.String) 12-26 23:57:11.786 17682-17682/myapplication.example.com.ndk_demo D/sakura_test: I`m from publicFunc sakura

    memory list modules

    流出加載的 so 庫

    10、Frida 反調試反反調試

    這一節的主要內容就是關于反調試的原理和如何破解反調試,重要內容還是看文章理解即可。
    因為我并不需要做反調試相關的工作,所以部分內容略過。

    Frida 反調試反反調試 基本思路
    (Java層API、Native層API、Syscall)

    • AntiFrida:https://github.com/qtfreet00/AntiFrida
    • frida-detection-demo:https://github.com/b-mueller/frida-detection-demo
    • 多種特征檢測Frida:https://bbs.pediy.com/thread-217482.htm
    • 來自高維的對抗 - 逆向TinyTool自制:https://yq.aliyun.com/articles/71120
    • Unicorn 在 Android 的應用:https://bbs.pediy.com/thread-253868.htm

    11、Frida native hook : 符號 hook JNI、art&libc

    11.1 Native函數的Java Hook及主動調用

    對 native 函數的 java 層 hook 和主動調用和普通 java 函數完全一致,略過。

    11.2 jni.h 頭文件導入

    導入 jni.h,先 search 一下這個文件在哪。

    Error /Users/sakura/Library/Android/sdk/ndk-bundle/sysroot/usr/include/jni.h,27: Can't open include file 'stdarg.h' Total 1 errors Caching 'Exports'... ok

    報錯,所以拷貝一份 jni.h 出來,將這兩個頭文件導入刪掉

    導入成功

    現在就能識別_JNIEnv了,如圖

    11.3 JNI 函數符號 hook

    先查看一下導出了哪些函數。

    extern "C" JNIEXPORT jstring JNICALL Java_myapplication_example_com_ndk_1demo_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C++";LOGD("sakura1328");return env->NewStringUTF(hello.c_str()); } extern "C" JNIEXPORT jstring JNICALL Java_myapplication_example_com_ndk_1demo_MainActivity_stringWithJNI(JNIEnv *env, jobject instance,jstring context_) {const char *context = env->GetStringUTFChars(context_, 0);int context_size = env->GetStringUTFLength(context_);if (context_size > 0) {LOGD("%s\n", context);}env->ReleaseStringUTFChars(context_, context);return env->NewStringUTF("sakura1328"); }

    這里有幾個需要的 API。

    • 首先是找到是否 so 被加載,通過?Process.enumerateModules(),這個API可以枚舉被加載到內存的 modules。
    • 然后通過Module.findBaseAddress(module name)來查找要hook的函數所在的so的基地址,如果找不到就返回null。
    • 然后可以通過findExportByName(moduleName: string, exportName: string): NativePointer來查找導出函數的絕對地址。如果不知道moduleName是什么,可以傳入一個null進入,但是會花費一些時間遍歷所有的module。如果找不到就返回null。
    • 找到地址之后,就可以攔截function/instruction的執行。通過Interceptor.attach。使用方法見下代碼。
    • 另外為了將jstring的值打印出來,可以使用jenv的函數getStringUtfChars,就像正常的寫native程序一樣。
      Java.vm.getEnv().getStringUtfChars(args[2], null).readCString()

    這里是循環調用的 string_with_jni,如果不循環調用,就要主動調用一下這個函數,或者 hook dlopen。

    hook dlopen 的方法(?https://github.com/lasting-yang/frida_dump/blob/master/dump_dex.js )可以參考。

    function hook_native() {// console.log(JSON.stringify(Process.enumerateModules()));var libnative_addr = Module.findBaseAddress("libnative-lib.so")console.log("libnative_addr is: " + libnative_addr)if (libnative_addr) {var string_with_jni_addr = Module.findExportByName("libnative-lib.so", "Java_myapplication_example_com_ndk_1demo_MainActivity_stringWithJNI")console.log("string_with_jni_addr is: " + string_with_jni_addr)}Interceptor.attach(string_with_jni_addr, {onEnter: function (args) {console.log("string_with_jni args: " + args[0], args[1], args[2])console.log(Java.vm.getEnv().getStringUtfChars(args[2], null).readCString())},onLeave: function (retval) {console.log("retval:", retval)console.log(Java.vm.getEnv().getStringUtfChars(retval, null).readCString())var newRetval = Java.vm.getEnv().newStringUtf("new retval from hook_native");retval.replace(ptr(newRetval));}}) } libnative_addr is: 0x7a0842f000 string_with_jni_addr is: 0x7a08436194 [Google Pixel::myapplication.example.com.ndk_demo]-> string_with_jni args: 0x7a106cc1c0 0x7ff0b71da4 0x7ff0b71da8 sakura retval: 0x75 sakura1328

    這里還寫了一個 hook env 里的 GetStringUTFChars 的代碼,和上面一樣,不贅述了。

    function hook_art(){var addr_GetStringUTFChars = null;//console.log( JSON.stringify(Process.enumerateModules()));var symbols = Process.findModuleByName("libart.so").enumerateSymbols();for(var i = 0;i<symbols.length;i++){var symbol = symbols[i].name;if((symbol.indexOf("CheckJNI")==-1)&&(symbol.indexOf("JNI")>=0)){if(symbol.indexOf("GetStringUTFChars")>=0){console.log(symbols[i].name);console.log(symbols[i].address);addr_GetStringUTFChars = symbols[i].address;}}}console.log("addr_GetStringUTFChars:", addr_GetStringUTFChars);Java.perform(function (){Interceptor.attach(addr_GetStringUTFChars, {onEnter: function (args) {console.log("addr_GetStringUTFChars OnEnter args[0],args[1]",args[0],args[1]);//console.log(hexdump(args[0].readPointer()));//console.log(Java.vm.tryGetEnv().getStringUtfChars(args[0]).readCString()); }, onLeave: function (retval) {console.log("addr_GetStringUTFChars OnLeave",ptr(retval).readCString());}})}) }

    11.4 JNI 函數參數、返回值打印和替換

    • libc 函數符號 hook
    • libc 函數參數、返回值打印和替換
      hook libc 的也和上面的完全一樣,也不贅述了。
      所以看到這里,究其本質就是找到導出符號和它所在的so基地址了。
    function hook_libc(){var pthread_create_addr = null;var symbols = Process.findModuleByName("libc.so").enumerateSymbols();for(var i = 0;i<symbols.length;i++){var symbol = symbols[i].name;if(symbol.indexOf("pthread_create")>=0){//console.log(symbols[i].name);//console.log(symbols[i].address);pthread_create_addr = symbols[i].address;}}console.log("pthread_create_addr,",pthread_create_addr);Interceptor.attach(pthread_create_addr,{onEnter:function(args){console.log("pthread_create_addr args[0],args[1],args[2],args[3]:",args[0],args[1],args[2],args[3]);},onLeave:function(retval){console.log("retval is:",retval)}}) }

    12、Frida native hook : JNI_Onload / 動態注冊 / inline_hook / native層調用棧打印

    https://github.com/android/ndk-samples

    12.1 JNI_Onload / 動態注冊原理

    JNI_Onload / 動態注冊 / Frida hook RegisterNative

    • JNI與動態注冊:https://zhuanlan.kanxue.com/article-4482.htm
    • native 方法的動態注冊:https://eternalsakura13.com/2018/02/08/jni2/
    • Frida hook art:https://github.com/lasting-yang/frida_hook_libart

    詳細的內容參見我寫的文章,這里只給出例子。

    Log.d(TAG,stringFromJNI2()); public native String stringFromJNI2(); JNIEXPORT jstring JNICALL stringFromJNI2(JNIEnv *env,jclass clazz) {jclass testClass = env->FindClass("myapplication/example/com/ndk_demo/Test");jfieldID publicStaticField = env->GetStaticFieldID(testClass, "publicStaticField","Ljava/lang/String;");jstring publicStaticFieldValue = (jstring) env->GetStaticObjectField(testClass,publicStaticField);const char *value_ptr = env->GetStringUTFChars(publicStaticFieldValue, NULL);LOGD("now content is %s", value_ptr);std::string hello = "Hello from C++ stringFromJNI2";return env->NewStringUTF(hello.c_str()); } ... JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {JNIEnv *env;vm->GetEnv((void **) &env, JNI_VERSION_1_6);JNINativeMethod methods[] = {{"stringFromJNI2", "()Ljava/lang/String;", (void *) stringFromJNI2},};env->RegisterNatives(env->FindClass("myapplication/example/com/ndk_demo/MainActivity"), methods,1);return JNI_VERSION_1_6; }

    12.2 Frida hook RegisterNative

    使用下面這個腳本來打印出 RegisterNatives 的參數,這里需要注意的是使用了enumerateSymbolsSync,它是 enumerateSymbols 的同步版本。
    另外和我們之前通過?Java.vm.tryGetEnv().getStringUtfChars來調用env里的方法不同。
    這里則是通過將之前找到的getStringUtfChars函數地址和參數信息封裝起來,直接調用,具體的原理我沒有深入分析,先記住用法。
    原理其實是一樣的,都是?根據符號找到地址,然后hook符號地址,然后打印參數

    declare const NativeFunction: NativeFunctionConstructor;interface NativeFunctionConstructor {new(address: NativePointerValue, retType: NativeType, argTypes: NativeType[], abiOrOptions?: NativeABI | NativeFunctionOptions): NativeFunction;readonly prototype: NativeFunction; } ... var funcGetStringUTFChars = new NativeFunction(addrGetStringUTFChars, "pointer", ["pointer", "pointer", "pointer"]); var ishook_libart = false;function hook_libart() {if (ishook_libart === true) {return;}var symbols = Module.enumerateSymbolsSync("libart.so");var addrGetStringUTFChars = null;var addrNewStringUTF = null;var addrFindClass = null;var addrGetMethodID = null;var addrGetStaticMethodID = null;var addrGetFieldID = null;var addrGetStaticFieldID = null;var addrRegisterNatives = null;var addrAllocObject = null;var addrCallObjectMethod = null;var addrGetObjectClass = null;var addrReleaseStringUTFChars = null;for (var i = 0; i < symbols.length; i++) {var symbol = symbols[i];if (symbol.name == "_ZN3art3JNI17GetStringUTFCharsEP7_JNIEnvP8_jstringPh") {addrGetStringUTFChars = symbol.address;console.log("GetStringUTFChars is at ", symbol.address, symbol.name);} else if (symbol.name == "_ZN3art3JNI12NewStringUTFEP7_JNIEnvPKc") {addrNewStringUTF = symbol.address;console.log("NewStringUTF is at ", symbol.address, symbol.name);} else if (symbol.name == "_ZN3art3JNI9FindClassEP7_JNIEnvPKc") {addrFindClass = symbol.address;console.log("FindClass is at ", symbol.address, symbol.name);} else if (symbol.name == "_ZN3art3JNI11GetMethodIDEP7_JNIEnvP7_jclassPKcS6_") {addrGetMethodID = symbol.address;console.log("GetMethodID is at ", symbol.address, symbol.name);} else if (symbol.name == "_ZN3art3JNI17GetStaticMethodIDEP7_JNIEnvP7_jclassPKcS6_") {addrGetStaticMethodID = symbol.address;console.log("GetStaticMethodID is at ", symbol.address, symbol.name);} else if (symbol.name == "_ZN3art3JNI10GetFieldIDEP7_JNIEnvP7_jclassPKcS6_") {addrGetFieldID = symbol.address;console.log("GetFieldID is at ", symbol.address, symbol.name);} else if (symbol.name == "_ZN3art3JNI16GetStaticFieldIDEP7_JNIEnvP7_jclassPKcS6_") {addrGetStaticFieldID = symbol.address;console.log("GetStaticFieldID is at ", symbol.address, symbol.name);} else if (symbol.name == "_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi") {addrRegisterNatives = symbol.address;console.log("RegisterNatives is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("_ZN3art3JNI11AllocObjectEP7_JNIEnvP7_jclass") >= 0) {addrAllocObject = symbol.address;console.log("AllocObject is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("_ZN3art3JNI16CallObjectMethodEP7_JNIEnvP8_jobjectP10_jmethodIDz") >= 0) {addrCallObjectMethod = symbol.address;console.log("CallObjectMethod is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("_ZN3art3JNI14GetObjectClassEP7_JNIEnvP8_jobject") >= 0) {addrGetObjectClass = symbol.address;console.log("GetObjectClass is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("_ZN3art3JNI21ReleaseStringUTFCharsEP7_JNIEnvP8_jstringPKc") >= 0) {addrReleaseStringUTFChars = symbol.address;console.log("ReleaseStringUTFChars is at ", symbol.address, symbol.name);}}if (addrRegisterNatives != null) {Interceptor.attach(addrRegisterNatives, {onEnter: function (args) {console.log("[RegisterNatives] method_count:", args[3]);var env = args[0];var java_class = args[1];var funcAllocObject = new NativeFunction(addrAllocObject, "pointer", ["pointer", "pointer"]);var funcGetMethodID = new NativeFunction(addrGetMethodID, "pointer", ["pointer", "pointer", "pointer", "pointer"]);var funcCallObjectMethod = new NativeFunction(addrCallObjectMethod, "pointer", ["pointer", "pointer", "pointer"]);var funcGetObjectClass = new NativeFunction(addrGetObjectClass, "pointer", ["pointer", "pointer"]);var funcGetStringUTFChars = new NativeFunction(addrGetStringUTFChars, "pointer", ["pointer", "pointer", "pointer"]);var funcReleaseStringUTFChars = new NativeFunction(addrReleaseStringUTFChars, "void", ["pointer", "pointer", "pointer"]);var clz_obj = funcAllocObject(env, java_class);var mid_getClass = funcGetMethodID(env, java_class, Memory.allocUtf8String("getClass"), Memory.allocUtf8String("()Ljava/lang/Class;"));var clz_obj2 = funcCallObjectMethod(env, clz_obj, mid_getClass);var cls = funcGetObjectClass(env, clz_obj2);var mid_getName = funcGetMethodID(env, cls, Memory.allocUtf8String("getName"), Memory.allocUtf8String("()Ljava/lang/String;"));var name_jstring = funcCallObjectMethod(env, clz_obj2, mid_getName);var name_pchar = funcGetStringUTFChars(env, name_jstring, ptr(0));var class_name = ptr(name_pchar).readCString();funcReleaseStringUTFChars(env, name_jstring, name_pchar);//console.log(class_name);var methods_ptr = ptr(args[2]);var method_count = parseInt(args[3]);for (var i = 0; i < method_count; i++) {var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));var name = Memory.readCString(name_ptr);var sig = Memory.readCString(sig_ptr);var find_module = Process.findModuleByAddress(fnPtr_ptr);console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base));}},onLeave: function (retval) { }});}ishook_libart = true; }hook_libart();

    結果很明顯的打印了出來,包括動態注冊的函數的名字,函數簽名,加載地址和在so里的偏移量,

    [RegisterNatives] java_class: myapplication.example.com.ndk_demo.MainActivity name: stringFromJNI2 sig: ()Ljava/lang/String; fnPtr: 0x79f8698484 module_name: libnative-lib.so module_base: 0x79f8691000 offset: 0x7484

    最后測試一下 yang 開源的一個hook art的腳本,很有意思,trace 出了非常多的需要的信息。

    frida -U --no-pause -f package_name -l hook_art.js ... [FindClass] name:myapplication/example/com/ndk_demo/Test [GetStaticFieldID] name:publicStaticField, sig:Ljava/lang/String; [GetStringUTFChars] result:i am a publicStaticField [NewStringUTF] bytes:Hello from C++ stringFromJNI2 [GetStringUTFChars] result:sakura

    12.3 native 層調用棧打印

    直接使用 frida 提供的接口打印棧回溯。

    Interceptor.attach(f, {onEnter: function (args) {console.log('RegisterNatives called from:\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');} });

    效果如下,我加到了 hook registerNative 的地方。

    [Google Pixel::myapplication.example.com.ndk_demo]-> RegisterNatives called from: 0x7a100be03c libart.so!0xe103c 0x7a100be038 libart.so!0xe1038 0x79f85699a0 libnative-lib.so!_ZN7_JNIEnv15RegisterNativesEP7_jclassPK15JNINativeMethodi+0x44 0x79f85698e0 libnative-lib.so!JNI_OnLoad+0x90 0x7a102b9fd4 libart.so!_ZN3art9JavaVMExt17LoadNativeLibraryEP7_JNIEnvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEP8_jobjectP8_jstringPS9_+0x638 0x7a08e3820c libopenjdkjvm.so!JVM_NativeLoad+0x110 0x70b921c4 boot.oat!oatexec+0xa81c4

    12.4 主動調用去進行方法參數替換

    使用?Interceptor.replace,不贅述。主要目的還是為了改掉函數原本的執行行為,而不是僅僅打印一些信息。

    12.5 inline hook ( so庫里面的函數?)

    inline hook 簡單理解就是:不是 hook 函數開始執行的地方,而是 hook 函數中間執行的指令
    整體來說沒什么區別,就是把找函數符號地址改成從so里找到偏移,然后加到so基地址上就行,注意一下它的 attach 的 callback。

    /*** Callback to invoke when an instruction is about to be executed.*/ type InstructionProbeCallback = (this: InvocationContext, args: InvocationArguments) => void; type InvocationContext = PortableInvocationContext | WindowsInvocationContext | UnixInvocationContext;interface PortableInvocationContext {/*** Return address.*/returnAddress: NativePointer;/*** CPU registers. You may also update register values by assigning to these keys.*/context: CpuContext;/*** OS thread ID.*/threadId: ThreadId;/*** Call depth of relative to other invocations.*/depth: number;/*** User-defined invocation data. Useful if you want to read an argument in `onEnter` and act on it in `onLeave`.*/[x: string]: any; } ... ... interface Arm64CpuContext extends PortableCpuContext {x0: NativePointer;x1: NativePointer;x2: NativePointer;x3: NativePointer;x4: NativePointer;x5: NativePointer;x6: NativePointer;x7: NativePointer;x8: NativePointer;x9: NativePointer;x10: NativePointer;x11: NativePointer;x12: NativePointer;x13: NativePointer;x14: NativePointer;x15: NativePointer;x16: NativePointer;x17: NativePointer;x18: NativePointer;x19: NativePointer;x20: NativePointer;x21: NativePointer;x22: NativePointer;x23: NativePointer;x24: NativePointer;x25: NativePointer;x26: NativePointer;x27: NativePointer;x28: NativePointer;fp: NativePointer;lr: NativePointer; }

    我的 so 是自己編譯的,具體的匯編代碼如下,總之這里很明顯在 775C 時,x0 里保存的是一個指向 "sakura"?這個字符串的指針。(其實我也不是很看得懂 arm64 了已經,就隨便 hook 了一下)
    所以 hook 這個指令,然后?Memory.readCString(this.context.x0);打印出來,結果如下

    .text:000000000000772C ; __unwind { .text:000000000000772C SUB SP, SP, #0x40 .text:0000000000007730 STP X29, X30, [SP,#0x30+var_s0] .text:0000000000007734 ADD X29, SP, #0x30 .text:0000000000007738 ; 6: v6 = a1; .text:0000000000007738 MOV X8, XZR .text:000000000000773C STUR X0, [X29,#var_8] .text:0000000000007740 ; 7: v5 = a3; .text:0000000000007740 STUR X1, [X29,#var_10] .text:0000000000007744 STR X2, [SP,#0x30+var_18] .text:0000000000007748 ; 8: v4 = (const char *)_JNIEnv::GetStringUTFChars(a1, a3, 0LL); .text:0000000000007748 LDUR X0, [X29,#var_8] .text:000000000000774C LDR X1, [SP,#0x30+var_18] .text:0000000000007750 MOV X2, X8 .text:0000000000007754 BL ._ZN7_JNIEnv17GetStringUTFCharsEP8_jstringPh ; _JNIEnv::GetStringUTFChars(_jstring *,uchar *) .text:0000000000007758 STR X0, [SP,#0x30+var_20] .text:000000000000775C ; 9: if ( (signed int)_JNIEnv::GetStringUTFLength(v6, v5) > 0 ) .text:000000000000775C LDUR X0, [X29,#var_8] .text:0000000000007760 LDR X1, [SP,#0x30+var_18] function inline_hook() {var libnative_lib_addr = Module.findBaseAddress("libnative-lib.so");if (libnative_lib_addr) {console.log("libnative_lib_addr:", libnative_lib_addr);var addr_775C = libnative_lib_addr.add(0x775C);console.log("addr_775C:", addr_775C);Java.perform(function () {Interceptor.attach(addr_775C, {onEnter: function (args) {var name = this.context.x0.readCString()console.log("addr_775C OnEnter :", this.returnAddress, name);},onLeave: function (retval) {console.log("retval is :", retval) }})})} } setImmediate(inline_hook()) Attaching... libnative_lib_addr: 0x79fabe0000 addr_775C: 0x79fabe775c TypeError: cannot read property 'apply' of undefinedat [anon] (../../../frida-gum/bindings/gumjs/duktape.c:56618)at frida/runtime/core.js:55 [Google Pixel::myapplication.example.com.ndk_demo]-> addr_775C OnEnter : 0x79fabe7758 sakura addr_775C OnEnter : 0x79fabe7758 sakura

    到這里已經可以總結一下我目前的學習了,需要補充一些 frida api 的學習,比如 NativePointr 里居然有個 readCString,這些 API 是需要再看看的。

    13、Frida native hook : Frida hook native app 實戰

    • 破解 Frida 全端口檢測的 native層反調試
      • hook libc 的 pthread_create 函數
    • 破解 TracePid 的 native 反調試
      • target:Android反調試技術整理與實踐:https://gtoad.github.io/2017/06/25/Android-Anti-Debug/
      • solve : hook libc的fgets函數
    • native 層修改參數、返回值
    • 靜態分析 JNI_Onload
    • 動態 trace 主動注冊 & IDA溯源
    • 動態trace JNI、libc函數 & IDA溯源
    • native層主動調用、打調用棧
    • 主動調用 libc 讀寫文件

    首先看下 logcat

    n/u0a128 for activity com.gdufs.xman/.MainActivity 12-28 05:53:26.898 26615 26615 V com.gdufs.xman: JNI_OnLoad() 12-28 05:53:26.898 26615 26615 V com.gdufs.xman: RegisterNatives() --> nativeMethod() ok 12-28 05:53:26.898 26615 26615 D com.gdufs.xman m=: 0 12-28 05:53:26.980 26615 26615 D com.gdufs.xman m=: Xman

    sakura@sakuradeMacBook-Pro:~/gitsource/frida-agent-example/agent$ frida -U --no-pause -f com.gdufs.xman -l hook_reg.js ... [Google Pixel::com.gdufs.xman]-> [RegisterNatives] method_count: 0x3 [RegisterNatives] java_class: com.gdufs.xman.MyApp name: initSN sig: ()V fnPtr: 0xd4ddf3b1 module_name: libmyjni.so module_base: 0xd4dde000 offset: 0x13b1 [RegisterNatives] java_class: com.gdufs.xman.MyApp name: saveSN sig: (Ljava/lang/String;)V fnPtr: 0xd4ddf1f9 module_name: libmyjni.so module_base: 0xd4dde000 offset: 0x11f9 [RegisterNatives] java_class: com.gdufs.xman.MyApp name: work sig: ()V fnPtr: 0xd4ddf4cd module_name: libmyjni.so module_base: 0xd4dde000 offset: 0x14cd

    initSN

    感覺意思應該是從?/sdcard/reg.dat?里讀一個值,然后和?EoPAoY62@ElRD?進行比較。
    最后setValue,從導出函數看一下,最后推測第一個參數應該是JNIEnv *env,然后就看到了給字段m賦值。

    aveSN

    這個看上去就是根據str的值,去變換”W3_arE_whO_we_ARE”字符串,然后寫入到/sdcard/reg.dat里

    結合一下看,只要initSN檢查到/sdcard/reg.dat里是EoPAoY62@ElRD,應該就會給m設置成1。
    只要m的值是1,就能走到work()函數的邏輯。

    參考:?frida 的 file api:https://frida.re/docs/javascript-api/#file

    function main() {var file = new File("/sdcard/reg.dat",'w')file.write("EoPAoY62@ElRD")file.flush()file.close() } setImmediate(main())

    這樣我們繼續看 work 的邏輯

    v2 是從 getValue 得到的,看上去就是 m字段的值,此時應該是1,一會 hook 一下看看。

    [NewStringUTF] bytes:輸入即是flag,格式為xman{……}!

    callWork 里又調用了 work 函數,死循環了。

    那看來看去最后還是回到了initSN,那其實我們看的順序似乎錯了。
    理一下邏輯,n2執行完保存到文件,然后n1 check一下,所以最后還是要逆n2的算法,pass。

    14、Frida trace 四件套

    14.1 jni trace : trace jni

    https://github.com/chame1eon/jnitrace

    pip install jnitraceRequirement already satisfied: frida>=12.5.0 in /Users/sakura/.pyenv/versions/3.7.7/lib/python3.7/site-packages (from jnitrace) (12.8.0) Requirement already satisfied: colorama in /Users/sakura/.pyenv/versions/3.7.7/lib/python3.7/site-packages (from jnitrace) (0.4.3) Collecting hexdump (from jnitrace)Downloading https://files.pythonhosted.org/packages/55/b3/279b1d57fa3681725d0db8820405cdcb4e62a9239c205e4ceac4391c78e4/hexdump-3.3.zip Installing collected packages: hexdump, jnitraceRunning setup.py install for hexdump ... doneRunning setup.py install for jnitrace ... done Successfully installed hexdump-3.3 jnitrace-3.0.8

    usage:?jnitrace [options] -l libname target
    默認應該是 spawn 運行的,

    • -m?來指定是?spawn?還是?attach
    • -b?指定是?fuzzy?還是?accurate
    • -i <regex>?指定一個正則表達式來過濾出方法名,例如?-i Get -i RegisterNatives?就會只打印出名字里包含 Get 或者 RegisterNatives 的 JNI methods。
    • -e <regex>?和?-i?相反,同樣通過正則表達式來過濾,但這次會將指定的內容忽略掉。
    • -I <string>?trace 導出的方法,jnitrace 認為導出的函數應該是從 Java 端能夠直接調用的函數,所以可以包括使用 RegisterNatives 來注冊的函數,例如?-I stringFromJNI -I nativeMethod([B)V,就包括導出名里有 stringFromJNI,以及使用 RegisterNames 來注冊,并帶有 nativeMethod([B)V 簽名的函數。
    • -o path/output.json,導出輸出到文件里。
    • -p path/to/script.js,用于在加載 jnitrace 腳本之前將指定路徑的 Frida 腳本加載到目標進程中,這可以用于在 jnitrace 啟動之前對抗反調試。
    • -a path/to/script.js,用于在加載 jnitrace 腳本之后將指定路徑的 Frida 腳本加載到目標進程中
    • --ignore-env,不打印所有的 JNIEnv 函數
    • --ignore-vm,不打印所有的 JavaVM 函數
    sakura@sakura:~/Desktop/frida_learn/lib/armeabi-v7a$ jnitrace -l libmyjni.so com.gdufs.xman Tracing. Press any key to quit... Traced library "libmyjni.so" loaded from path "/data/app/com.gdufs.xman-X0HkzLhbptSc0tjGZ3yQ2g==/lib/arm"./* TID 28890 */355 ms [+] JavaVM->GetEnv355 ms |- JavaVM* : 0xefe99140355 ms |- void** : 0xda13e028355 ms |: 0xeff312a0355 ms |- jint : 65542355 ms |= jint : 0355 ms ------------------------Backtrace------------------------355 ms |-> 0xda13a51b: JNI_OnLoad+0x12 (libmyjni.so:0xda139000)/* TID 28890 */529 ms [+] JNIEnv->FindClass529 ms |- JNIEnv* : 0xeff312a0529 ms |- char* : 0xda13bdef529 ms |: com/gdufs/xman/MyApp529 ms |= jclass : 0x81 { com/gdufs/xman/MyApp }529 ms ------------------------Backtrace------------------------529 ms |-> 0xda13a539: JNI_OnLoad+0x30 (libmyjni.so:0xda139000)/* TID 28890 */584 ms [+] JNIEnv->RegisterNatives584 ms |- JNIEnv* : 0xeff312a0584 ms |- jclass : 0x81 { com/gdufs/xman/MyApp }584 ms |- JNINativeMethod* : 0xda13e004584 ms |: 0xda13a3b1 - initSN()V584 ms |: 0xda13a1f9 - saveSN(Ljava/lang/String;)V584 ms |: 0xda13a4cd - work()V584 ms |- jint : 3584 ms |= jint : 0584 ms ------------------------Backtrace------------------------584 ms |-> 0xda13a553: JNI_OnLoad+0x4a (libmyjni.so:0xda139000)/* TID 28890 */638 ms [+] JNIEnv->FindClass638 ms |- JNIEnv* : 0xeff312a0638 ms |- char* : 0xda13bdef638 ms |: com/gdufs/xman/MyApp638 ms |= jclass : 0x71 { com/gdufs/xman/MyApp }638 ms -----------------------Backtrace-----------------------638 ms |-> 0xda13a377: setValue+0x12 (libmyjni.so:0xda139000)/* TID 28890 */688 ms [+] JNIEnv->GetStaticFieldID688 ms |- JNIEnv* : 0xeff312a0688 ms |- jclass : 0x71 { com/gdufs/xman/MyApp }688 ms |- char* : 0xda13be04688 ms |: m688 ms |- char* : 0xda13be06688 ms |: I688 ms |= jfieldID : 0xf1165004 { m:I }688 ms -----------------------Backtrace-----------------------688 ms |-> 0xda13a38d: setValue+0x28 (libmyjni.so:0xda139000)

    14.2 strace : trace syscall

    strace 跟蹤進程中的系統調用:https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/strace.html

    14.3 frida-trace : trace libc(or more)

    ? ? ? ? frida-trace:https://frida.re/docs/frida-trace/

    ? ? ? ? Usage:frida-trace [options] target

    frida-trace -U -i "strcmp" -f com.gdufs.xman ...5634 ms strcmp(s1="fi", s2="es-US")5635 ms strcmp(s1="da", s2="es-US")5635 ms strcmp(s1="es", s2="es-US")5635 ms strcmp(s1="eu-ES", s2="es-US")5635 ms strcmp(s1="et-EE", s2="es-US")5635 ms strcmp(s1="et-EE", s2="es-US")

    art trace

    hook artmethod:https://github.com/lasting-yang/frida_hook_libart/blob/master/hook_artmethod.js

    14.4 hook_artmethod : trace java 函數調用

    https://github.com/lasting-yang/frida_hook_libart/blob/master/hook_artmethod.js

    14.5 修改AOSP源碼打印

    改 aosp 源碼 trace 信息:https://bbs.pediy.com/thread-255653-1.htm

    15、Frida native hook : init_array 開發和自動化逆向

    15.1 init_array原理 (?so 加載、啟動、執行 )

    常見的保護都會在 init_array 里面做,關于其原理,主要閱讀以下文章即可。

    • IDA 調試 android so 的 .init_array 數組:https://www.cnblogs.com/bingghost/p/6297325.html
    • Android NDK中.init段和.init_array段函數的定義方式:https://www.dllhook.com/post/213.html
    • Linker 學習筆記( so 加載、啟動、執行):https://wooyun.js.org/drops/Android Linker學習筆記.html

    15.2 IDA靜態分析 init_array

    // 編譯生成后在.init段 [名字不可更改] extern "C" void _init(void) {LOGD("Enter init......"); }// 編譯生成后在.init_array段 [名字可以更改] __attribute__((__constructor__)) static void sakura_init() {LOGD("Enter sakura_init......"); } ... ... 2016-12-29 16:51:23.017 5160-5160/com.example.ndk_demo D/sakura1328: Enter init...... 2016-12-29 16:51:23.017 5160-5160/com.example.ndk_demo D/sakura1328: Enter sakura_init......

    IDA快捷鍵shift+F7找到segment,然后就可以找到.init_array段,然后就可以找到里面保存的函數地址。

    15.3 IDA 動態調試 so

    • 打開要調試的 apk,找到入口

    sakura@sakura:~/.gradle/caches$ adb shell dumpsys activity top | grep TASK TASK com.android.systemui id=29 userId=0 TASK null id=26 userId=0 TASK com.example.ndk_demo id=161 userId=0
    • 啟動 apk,并讓設備將處于一個Waiting For Debugger的狀態
      ? ? ? ? adb shell am start -D -n com.example.ndk_demo/.MainActivity
    • 執行 android_server64
    sailfish:/data/local/tmp # ./android_server64 IDA Android 64-bit remote debug server(ST) v1.22. Hex-Rays (c) 2004-2017 Listening on 0.0.0.0:23946...
    • 新開一個窗口使用forward程序進行端口轉發:adb forward tcp:23946 tcp:23946

    adb forward tcp:<本地機器的網絡端口號> tcp:<模擬器或是真機的網絡端口號>

    例:adb [-d|-e|-s?] forward tcp:6100 tcp:7100 表示把本機的6100端口號與模擬器的7100端口建立起相關,當模擬器或真機向自己的7100端口發送了數據,那們我們可以在本機的6100端口讀取其發送的內容,這是一個很關鍵的命令,以后我們使用jdb調試apk之前,就要用它先把目標進程和本地端口建立起關聯

    • 打開IDA,選擇菜單Debugger -> Attach -> Remote ARM Linux/Android debugger

    • 打開IDA,選擇菜單Debugger -> Process options, 填好,然后選擇進程去attach。

    • 查看待調試的進程?adb jdwp
    sakura@sakuradeMacBook-Pro:~$ adb jdwp 10436
    • 轉發端口adb forward tcp:8700 jdwp:10436,將該進程的調試端口和本機的8700綁定。

    • jdb連接調試端口,從而讓程序繼續運行?jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

    • 找到斷點并斷下。

    打開 module

    找到 linker64

    找到 call array 函數

    下斷,并按 F9 斷下

    最終我確實可以調試到?.init_array?的初始化,具體的代碼分析見?Linker學習筆記?這里。

    15.4 init_array && JNI_Onload "自吐"

    JNI_Onload

    目標是找到動態注冊的函數的地址,因為這種函數沒有導出。

    JNINativeMethod methods[] = {{"stringFromJNI2", "()Ljava/lang/String;", (void *) stringFromJNI2}, }; env->RegisterNatives(env->FindClass("com/example/ndk_demo/MainActivity"), methods, 1);

    首先:jnitrace -m spawn -i "RegisterNatives" -l libnative-lib.so com.example.ndk_demo

    525 ms [+] JNIEnv->RegisterNatives 525 ms |- JNIEnv* : 0x7a106cc1c0 525 ms |- jclass : 0x89 { com/example/ndk_demo/MainActivity } 525 ms |- JNINativeMethod* : 0x7ff0b71120 525 ms |: 0x79f00d36b0 - stringFromJNI2()Ljava/lang/String;

    然后:objection -d -g com.example.ndk_demo run memory list modules explore | grep demo

    sakura@sakuradeMacBook-Pro:~$ objection -d -g com.example.ndk_demo run memory list modules explore | grep demo [debug] Attempting to attach to process: `com.example.ndk_demo` Warning: Output is not to a terminal (fd=1). base.odex 0x79f0249000 106496 (104.0 KiB) /data/app/com.example.ndk_demo-HGAFhnKyKCSIpzn227pwXw==/oat/arm64/base.odex libnative-lib.so 0x79f00c4000 221184 (216.0 KiB) /data/app/com.example.ndk_demo-HGAFhnKyKCSIpzn227pwXw==/lib/arm64/libnative...

    offset = 0x79f00d36b0 - 0x79f00c4000 = 0xf6b0

    這樣就找到了

    init_array

    沒有支持 arm64,可以在安裝 app 的時候?adb install --abi armeabi-v7a?強制讓 app 運行在32位模式

    這個腳本整體來說就是 hook callfunction,然后打印出 init_array 里面的函數地址和參數等。

    從源碼看,關鍵就是 call_array 這里調用的 call_function,第一個參數代表這是注冊的 init_array 里面的 function,第二個參數則是 init_array 里存儲的函數的地址。

    template <typename F> static void call_array(const char* array_name __unused,F* functions,size_t count,bool reverse,const char* realpath) {if (functions == nullptr) {return;}TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, realpath);int begin = reverse ? (count - 1) : 0;int end = reverse ? -1 : count;int step = reverse ? -1 : 1;for (int i = begin; i != end; i += step) {TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);call_function("function", functions[i], realpath);}TRACE("[ Done calling %s for '%s' ]", array_name, realpath); } function LogPrint(log) {var theDate = new Date();var hour = theDate.getHours();var minute = theDate.getMinutes();var second = theDate.getSeconds();var mSecond = theDate.getMilliseconds()hour < 10 ? hour = "0" + hour : hour;minute < 10 ? minute = "0" + minute : minute;second < 10 ? second = "0" + second : second;mSecond < 10 ? mSecond = "00" + mSecond : mSecond < 100 ? mSecond = "0" + mSecond : mSecond;var time = hour + ":" + minute + ":" + second + ":" + mSecond;var threadid = Process.getCurrentThreadId();console.log("[" + time + "]" + "->threadid:" + threadid + "--" + log);}function hooklinker() {var linkername = "linker";var call_function_addr = null;var arch = Process.arch;LogPrint("Process run in:" + arch);if (arch.endsWith("arm")) {linkername = "linker";} else {linkername = "linker64";LogPrint("arm64 is not supported yet!");}var symbols = Module.enumerateSymbolsSync(linkername);for (var i = 0; i < symbols.length; i++) {var symbol = symbols[i];//LogPrint(linkername + "->" + symbol.name + "---" + symbol.address);if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) {call_function_addr = symbol.address;LogPrint("linker->" + symbol.name + "---" + symbol.address)}}if (call_function_addr != null) {var func_call_function = new NativeFunction(call_function_addr, 'void', ['pointer', 'pointer', 'pointer']);Interceptor.replace(new NativeFunction(call_function_addr,'void', ['pointer', 'pointer', 'pointer']), new NativeCallback(function (arg0, arg1, arg2) {var functiontype = null;var functionaddr = null;var sopath = null;if (arg0 != null) {functiontype = Memory.readCString(arg0);}if (arg1 != null) {functionaddr = arg1;}if (arg2 != null) {sopath = Memory.readCString(arg2);}var modulebaseaddr = Module.findBaseAddress(sopath);LogPrint("after load:" + sopath + "--start call_function,type:" + functiontype + "--addr:" + functionaddr + "---baseaddr:" + modulebaseaddr);if (sopath.indexOf('libnative-lib.so') >= 0 && functiontype == "DT_INIT") {LogPrint("after load:" + sopath + "--ignore call_function,type:" + functiontype + "--addr:" + functionaddr + "---baseaddr:" + modulebaseaddr);} else {func_call_function(arg0, arg1, arg2);LogPrint("after load:" + sopath + "--end call_function,type:" + functiontype + "--addr:" + functionaddr + "---baseaddr:" + modulebaseaddr);}}, 'void', ['pointer', 'pointer', 'pointer']));} }setImmediate(hooklinker)

    我調試了一下 linker64,因為沒有導出 call_function 的地址,所以不能直接 hook 符號名,而是要根據偏移去 hook,以后再說。
    其實要看?init_array,直接 shift+F7 去 segment 里面找?.init_array?段就可以了,這里主要是為了反反調試,因為可能反調試會加在 init_array 里,hook call_function 就可以讓它不加載反調試程序。

    15.5 native層未導出函數主動調用(任意符號和地址)

    現在我想要主動調用 sakura_add 來打印值,可以 ida 打開找符號,或者根據偏移,總之最終用這個 NativePointer 指針來初始化一個 NativeFunction 來調用。

    extern "C" JNIEXPORT jint JNICALL Java_com_example_ndk_1demo_MainActivity_sakuraWithInt(JNIEnv *env, jobject thiz, jint a, jint b) {// TODO: implement sakuraWithInt()return sakura_add(a,b); } ... int sakura_add(int a, int b){int sum = a+b;LOGD("sakura add a+b:",sum);return sum; }

    function main() {var libnative_lib_addr = Module.findBaseAddress("libnative-lib.so");console.log("libnative_lib_addr is :", libnative_lib_addr);if (libnative_lib_addr) {var sakura_add_addr1 = Module.findExportByName("libnative-lib.so", "_Z10sakura_addii");var sakura_add_addr2 = libnative_lib_addr.add(0x0F56C) ;console.log("sakura_add_addr1 ", sakura_add_addr1);console.log("sakura_add_addr2 ", sakura_add_addr2)}var sakura_add1 = new NativeFunction(sakura_add_addr1, "int", ["int", "int"]);var sakura_add2 = new NativeFunction(sakura_add_addr2, "int", ["int", "int"]);console.log("sakura_add1 result is :", sakura_add1(200, 33));console.log("sakura_add2 result is :", sakura_add2(100, 133)); } setImmediate(main()) ... ... libnative_lib_addr is : 0x79fa1c5000 sakura_add_addr1 0x79fa1d456c sakura_add_addr2 0x79fa1d456c sakura_add1 result is : 233 sakura_add2 result is : 233

    16、C/C++ hook

    //todo

    16.1 Native/JNI層參數打印和主動調用參數構造

    jni的基本類型要通過調用jni相關的api轉化成c++對象,才能打印和調用。
    jni主動調用的時候,參數構造有兩種方式,一種是Java.vm.getenv,另一種是hook獲取env之后來調用jni相關的api構造參數。

    16.2 C/C++編成 so 并引入 Frida 調用其中的函數

    總結

    以上是生活随笔為你收集整理的Frida Android hook的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    亚洲欧美国产精品久久 | 久久精品99久久香蕉国产色戒 | 久久aⅴ免费观看 | 狠狠色丁香久久婷婷综合五月 | 亚欧洲精品在线视频免费观看 | 无码毛片视频一区二区本码 | 国产精品高潮呻吟av久久 | 男女爱爱好爽视频免费看 | 图片小说视频一区二区 | 理论片87福利理论电影 | 东京一本一道一二三区 | 欧美日韩精品 | 亚洲精品一区三区三区在线观看 | 男女性色大片免费网站 | 精品一区二区三区无码免费视频 | 亚洲欧美精品aaaaaa片 | 免费中文字幕日韩欧美 | 亚洲精品中文字幕乱码 | 国产av无码专区亚洲a∨毛片 | 中文字幕无码日韩专区 | 性色欲网站人妻丰满中文久久不卡 | 青青草原综合久久大伊人精品 | 奇米影视888欧美在线观看 | 在线成人www免费观看视频 | 国色天香社区在线视频 | 亚洲热妇无码av在线播放 | 国产疯狂伦交大片 | 亚洲成av人片在线观看无码不卡 | 动漫av网站免费观看 | 免费中文字幕日韩欧美 | 国产超级va在线观看视频 | 成熟人妻av无码专区 | 国产人妻久久精品二区三区老狼 | 国产 浪潮av性色四虎 | 无码免费一区二区三区 | 18无码粉嫩小泬无套在线观看 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 亚洲国产精品久久久久久 | 少妇邻居内射在线 | 国产精品久久久一区二区三区 | 亚洲国产高清在线观看视频 | 亚洲乱码日产精品bd | 天天躁夜夜躁狠狠是什么心态 | 午夜男女很黄的视频 | 无码人妻精品一区二区三区下载 | 精品无人区无码乱码毛片国产 | 国产精品久久久久久亚洲影视内衣 | 中文字幕 人妻熟女 | 亚洲欧美综合区丁香五月小说 | 国产一区二区三区日韩精品 | 性生交大片免费看女人按摩摩 | 国产 精品 自在自线 | 国产成人精品久久亚洲高清不卡 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 国产乱子伦视频在线播放 | 久久久久免费精品国产 | 97se亚洲精品一区 | 成人免费无码大片a毛片 | 国产福利视频一区二区 | 无码人妻黑人中文字幕 | 国产在线精品一区二区三区直播 | 国产超碰人人爽人人做人人添 | 丝袜美腿亚洲一区二区 | 荫蒂被男人添的好舒服爽免费视频 | 国产精品国产自线拍免费软件 | 成人片黄网站色大片免费观看 | 成人片黄网站色大片免费观看 | 欧美日韩在线亚洲综合国产人 | 无码成人精品区在线观看 | 色婷婷综合激情综在线播放 | 99久久精品国产一区二区蜜芽 | 99久久精品午夜一区二区 | 国产av一区二区精品久久凹凸 | 人人爽人人澡人人高潮 | 99精品久久毛片a片 | 免费观看的无遮挡av | 熟妇激情内射com | 性生交片免费无码看人 | 日韩视频 中文字幕 视频一区 | 精品国产av色一区二区深夜久久 | 亚洲最大成人网站 | 亚洲色成人中文字幕网站 | 日韩视频 中文字幕 视频一区 | 狠狠色欧美亚洲狠狠色www | 久久国内精品自在自线 | 亚洲s色大片在线观看 | 国产一区二区三区四区五区加勒比 | 草草网站影院白丝内射 | 中文字幕日韩精品一区二区三区 | 午夜福利电影 | 亚洲一区二区三区香蕉 | 欧美精品在线观看 | 免费中文字幕日韩欧美 | 午夜福利电影 | 国产激情无码一区二区app | 九九热爱视频精品 | 亚欧洲精品在线视频免费观看 | 啦啦啦www在线观看免费视频 | 国产精品久久久久久久影院 | 成人精品一区二区三区中文字幕 | 久久综合给久久狠狠97色 | 四十如虎的丰满熟妇啪啪 | 特大黑人娇小亚洲女 | 国产精品久久福利网站 | 人人爽人人爽人人片av亚洲 | 99久久久无码国产aaa精品 | 久久五月精品中文字幕 | 九一九色国产 | 宝宝好涨水快流出来免费视频 | 在线播放免费人成毛片乱码 | 伊人久久婷婷五月综合97色 | 国产亚洲人成a在线v网站 | 骚片av蜜桃精品一区 | 99久久精品国产一区二区蜜芽 | 无码人妻精品一区二区三区不卡 | 一本一道久久综合久久 | 人妻无码αv中文字幕久久琪琪布 | 荫蒂被男人添的好舒服爽免费视频 | 夜夜影院未满十八勿进 | 久久精品一区二区三区四区 | 午夜时刻免费入口 | 一本色道久久综合狠狠躁 | 欧美放荡的少妇 | 人人妻人人澡人人爽精品欧美 | 三上悠亚人妻中文字幕在线 | 国产精品怡红院永久免费 | 国产亚洲人成在线播放 | 婷婷色婷婷开心五月四房播播 | 日本欧美一区二区三区乱码 | √天堂中文官网8在线 | 久久这里只有精品视频9 | 老熟妇仑乱视频一区二区 | 精品国产青草久久久久福利 | 亚洲色在线无码国产精品不卡 | 天堂久久天堂av色综合 | 国产精品香蕉在线观看 | 久久久久免费精品国产 | 特黄特色大片免费播放器图片 | 麻豆精品国产精华精华液好用吗 | 67194成是人免费无码 | 国产精品高潮呻吟av久久4虎 | 日产精品高潮呻吟av久久 | 婷婷五月综合缴情在线视频 | 人妻尝试又大又粗久久 | 国产精品美女久久久久av爽李琼 | 乱人伦人妻中文字幕无码 | 丰满诱人的人妻3 | 国色天香社区在线视频 | 中文无码伦av中文字幕 | 国产手机在线αⅴ片无码观看 | 六十路熟妇乱子伦 | 精品一区二区三区波多野结衣 | 国产精品无套呻吟在线 | 亚洲人成无码网www | 亚洲色大成网站www | 免费人成在线视频无码 | 综合激情五月综合激情五月激情1 | 日本va欧美va欧美va精品 | 久久伊人色av天堂九九小黄鸭 | 久久午夜无码鲁丝片秋霞 | 亚洲国产午夜精品理论片 | 国产精品亚洲а∨无码播放麻豆 | 国产午夜亚洲精品不卡下载 | 对白脏话肉麻粗话av | 欧美老人巨大xxxx做受 | 3d动漫精品啪啪一区二区中 | 国产偷抇久久精品a片69 | 久久亚洲日韩精品一区二区三区 | 免费无码一区二区三区蜜桃大 | 樱花草在线播放免费中文 | 精品一区二区三区波多野结衣 | 国产精品久久福利网站 | 动漫av网站免费观看 | 丰满人妻精品国产99aⅴ | 日本熟妇乱子伦xxxx | 欧美亚洲国产一区二区三区 | 亚洲人成人无码网www国产 | 精品久久久中文字幕人妻 | 小泽玛莉亚一区二区视频在线 | 久久 国产 尿 小便 嘘嘘 | 国内少妇偷人精品视频 | 黄网在线观看免费网站 | 国语自产偷拍精品视频偷 | 午夜男女很黄的视频 | 少妇人妻av毛片在线看 | 日韩精品无码一区二区中文字幕 | 国内精品九九久久久精品 | 国产在线精品一区二区三区直播 | 日日橹狠狠爱欧美视频 | 国产亚洲美女精品久久久2020 | 妺妺窝人体色www在线小说 | 高潮毛片无遮挡高清免费 | 青青久在线视频免费观看 | 玩弄人妻少妇500系列视频 | 亚洲乱亚洲乱妇50p | av小次郎收藏 | 色欲久久久天天天综合网精品 | 欧美自拍另类欧美综合图片区 | 久久久久99精品国产片 | 性欧美牲交xxxxx视频 | 内射后入在线观看一区 | 国产精品毛多多水多 | 大色综合色综合网站 | 婷婷六月久久综合丁香 | 亚洲性无码av中文字幕 | 成人无码影片精品久久久 | 国产人妻精品一区二区三区不卡 | 亚洲一区二区三区国产精华液 | 无码人妻出轨黑人中文字幕 | 日本一卡二卡不卡视频查询 | 亚洲国产精品成人久久蜜臀 | 300部国产真实乱 | 亚洲精品一区二区三区大桥未久 | 亚洲精品中文字幕 | 宝宝好涨水快流出来免费视频 | 色老头在线一区二区三区 | 国产成人精品视频ⅴa片软件竹菊 | av无码久久久久不卡免费网站 | 国产熟女一区二区三区四区五区 | 欧美丰满老熟妇xxxxx性 | 99久久精品日本一区二区免费 | 日本欧美一区二区三区乱码 | 亚洲中文字幕无码一久久区 | 99久久99久久免费精品蜜桃 | 人妻天天爽夜夜爽一区二区 | 蜜桃无码一区二区三区 | 久久久精品人妻久久影视 | 蜜桃无码一区二区三区 | 成人试看120秒体验区 | 久久天天躁夜夜躁狠狠 | 无码人妻av免费一区二区三区 | 人妻少妇精品无码专区二区 | 国产精品久久国产三级国 | 内射白嫩少妇超碰 | 久久午夜无码鲁丝片午夜精品 | 无码中文字幕色专区 | 精品国产国产综合精品 | 在线 国产 欧美 亚洲 天堂 | 九九在线中文字幕无码 | 国产精品亚洲а∨无码播放麻豆 | 亚洲国产精品久久久天堂 | 欧美熟妇另类久久久久久多毛 | 2019午夜福利不卡片在线 | 亚洲日韩av片在线观看 | 天天躁夜夜躁狠狠是什么心态 | 超碰97人人射妻 | 夜夜躁日日躁狠狠久久av | 久热国产vs视频在线观看 | 午夜成人1000部免费视频 | 强辱丰满人妻hd中文字幕 | 国产无遮挡吃胸膜奶免费看 | www国产精品内射老师 | 中文字幕乱妇无码av在线 | 久久人人爽人人爽人人片av高清 | 亚洲热妇无码av在线播放 | 欧美自拍另类欧美综合图片区 | 久久国产精品二国产精品 | 久久综合狠狠综合久久综合88 | 无码国模国产在线观看 | 无码中文字幕色专区 | 午夜精品一区二区三区在线观看 | 色老头在线一区二区三区 | 亚洲成a人一区二区三区 | 又大又黄又粗又爽的免费视频 | 免费网站看v片在线18禁无码 | 51国偷自产一区二区三区 | 最新国产乱人伦偷精品免费网站 | 国产真实夫妇视频 | 老熟女乱子伦 | 国产黑色丝袜在线播放 | 欧美兽交xxxx×视频 | 国产精品资源一区二区 | 欧美高清在线精品一区 | 无码精品人妻一区二区三区av | 国产偷自视频区视频 | 亚洲精品综合一区二区三区在线 | 好爽又高潮了毛片免费下载 | 国产无套内射久久久国产 | 2020久久超碰国产精品最新 | 97色伦图片97综合影院 | 无码国产色欲xxxxx视频 | 国产手机在线αⅴ片无码观看 | 国产99久久精品一区二区 | 帮老师解开蕾丝奶罩吸乳网站 | 无码一区二区三区在线 | 曰韩少妇内射免费播放 | 久久无码专区国产精品s | 精品国产福利一区二区 | 野外少妇愉情中文字幕 | 精品偷拍一区二区三区在线看 | 日日碰狠狠丁香久燥 | 国内精品九九久久久精品 | 精品偷自拍另类在线观看 | 日本一区二区三区免费高清 | 无码国内精品人妻少妇 | 久久国产劲爆∧v内射 | 精品国产精品久久一区免费式 | 人妻少妇精品久久 | 亚洲国产精品久久久久久 | 性生交片免费无码看人 | 久久国内精品自在自线 | 99视频精品全部免费免费观看 | 国产亚洲人成a在线v网站 | 久久熟妇人妻午夜寂寞影院 | 久久精品成人欧美大片 | 免费看少妇作爱视频 | 亚洲人成影院在线无码按摩店 | а√天堂www在线天堂小说 | 午夜理论片yy44880影院 | 纯爱无遮挡h肉动漫在线播放 | 免费观看又污又黄的网站 | 国产免费观看黄av片 | 国产成人精品久久亚洲高清不卡 | 麻豆果冻传媒2021精品传媒一区下载 | 荫蒂被男人添的好舒服爽免费视频 | 久久精品中文字幕一区 | 日本大乳高潮视频在线观看 | 日本大乳高潮视频在线观看 | 国产精品欧美成人 | 亚洲人交乣女bbw | 精品夜夜澡人妻无码av蜜桃 | 国产熟妇高潮叫床视频播放 | 色狠狠av一区二区三区 | 欧美性猛交xxxx富婆 | 67194成是人免费无码 | 7777奇米四色成人眼影 | 国产av人人夜夜澡人人爽麻豆 | 亚洲成av人片天堂网无码】 | 狠狠综合久久久久综合网 | 无码人妻丰满熟妇区毛片18 | 最近免费中文字幕中文高清百度 | 国产精品鲁鲁鲁 | 300部国产真实乱 | 无码播放一区二区三区 | aⅴ在线视频男人的天堂 | 国产精品多人p群无码 | 欧美性猛交内射兽交老熟妇 | 动漫av一区二区在线观看 | 四虎国产精品一区二区 | 亚洲经典千人经典日产 | 国产97在线 | 亚洲 | 亚洲中文字幕乱码av波多ji | 欧美一区二区三区视频在线观看 | 国产偷国产偷精品高清尤物 | 东京无码熟妇人妻av在线网址 | 大胆欧美熟妇xx | 亚洲人成影院在线无码按摩店 | 欧美性生交xxxxx久久久 | 久久精品国产日本波多野结衣 | 蜜桃视频插满18在线观看 | 狠狠色噜噜狠狠狠狠7777米奇 | 一个人免费观看的www视频 | 成 人 网 站国产免费观看 | 欧洲vodafone精品性 | 狠狠色色综合网站 | 高潮毛片无遮挡高清免费视频 | 午夜肉伦伦影院 | 国产偷国产偷精品高清尤物 | 欧美人与禽猛交狂配 | 国产一区二区三区四区五区加勒比 | 正在播放东北夫妻内射 | 成人无码精品1区2区3区免费看 | 亚洲国产av精品一区二区蜜芽 | 日欧一片内射va在线影院 | 97色伦图片97综合影院 | 男人的天堂2018无码 | 亚洲精品鲁一鲁一区二区三区 | 小sao货水好多真紧h无码视频 | 午夜免费福利小电影 | 国产亚洲tv在线观看 | 麻豆国产人妻欲求不满谁演的 | 欧美性生交xxxxx久久久 | 1000部夫妻午夜免费 | 丰满人妻被黑人猛烈进入 | 国产成人无码av片在线观看不卡 | 国产农村妇女高潮大叫 | 伊人色综合久久天天小片 | 人妻互换免费中文字幕 | 女人色极品影院 | 国产成人无码区免费内射一片色欲 | 男人的天堂2018无码 | 国产成人综合美国十次 | 中文字幕无码日韩欧毛 | 亚洲综合无码久久精品综合 | 中文字幕av伊人av无码av | 特级做a爰片毛片免费69 | 日本精品少妇一区二区三区 | 欧美激情综合亚洲一二区 | 久久99久久99精品中文字幕 | 国产欧美精品一区二区三区 | 国产一区二区不卡老阿姨 | 精品无人区无码乱码毛片国产 | 亚洲精品综合五月久久小说 | 中文字幕 亚洲精品 第1页 | 亚洲精品久久久久久一区二区 | 又粗又大又硬又长又爽 | 亚洲中文字幕乱码av波多ji | 国产亚洲精品久久久久久久 | 亚洲欧美综合区丁香五月小说 | 国产av人人夜夜澡人人爽麻豆 | 野外少妇愉情中文字幕 | 精品aⅴ一区二区三区 | 国产无遮挡又黄又爽免费视频 | 久9re热视频这里只有精品 | 欧美老妇交乱视频在线观看 | www国产精品内射老师 | 捆绑白丝粉色jk震动捧喷白浆 | 3d动漫精品啪啪一区二区中 | 久久精品中文字幕一区 | 国产亚洲精品久久久久久久久动漫 | 噜噜噜亚洲色成人网站 | 欧美变态另类xxxx | 九一九色国产 | 97夜夜澡人人双人人人喊 | 免费国产黄网站在线观看 | 久久久国产一区二区三区 | 国精品人妻无码一区二区三区蜜柚 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 精品国产精品久久一区免费式 | 久久久精品人妻久久影视 | 久久久精品欧美一区二区免费 | av人摸人人人澡人人超碰下载 | 97se亚洲精品一区 | 高潮毛片无遮挡高清免费视频 | 中文字幕乱妇无码av在线 | 亚洲精品国产品国语在线观看 | 久久99久久99精品中文字幕 | 日本熟妇大屁股人妻 | 老熟女重囗味hdxx69 | 中文字幕av日韩精品一区二区 | 久久婷婷五月综合色国产香蕉 | 婷婷丁香六月激情综合啪 | 久久久久久久久888 | 国产一区二区不卡老阿姨 | 午夜丰满少妇性开放视频 | 国产性生交xxxxx无码 | 无码帝国www无码专区色综合 | 人人妻人人藻人人爽欧美一区 | 人妻熟女一区 | 无码人妻丰满熟妇区五十路百度 | 日韩精品无码一本二本三本色 | 色婷婷欧美在线播放内射 | 日韩av无码中文无码电影 | 精品成人av一区二区三区 | 日日噜噜噜噜夜夜爽亚洲精品 | 2020久久香蕉国产线看观看 | 欧美人与动性行为视频 | 黑人大群体交免费视频 | 欧美激情一区二区三区成人 | 国产av人人夜夜澡人人爽麻豆 | 日韩少妇内射免费播放 | 国产绳艺sm调教室论坛 | 国产乱人伦av在线无码 | 无码人妻精品一区二区三区不卡 | 在线播放无码字幕亚洲 | 自拍偷自拍亚洲精品10p | 亚洲乱亚洲乱妇50p | 国产熟妇高潮叫床视频播放 | 日本乱人伦片中文三区 | 无码人妻久久一区二区三区不卡 | 日本丰满熟妇videos | 中文字幕乱码中文乱码51精品 | 亚洲国产成人a精品不卡在线 | 国产福利视频一区二区 | 伊人色综合久久天天小片 | 亚洲综合无码久久精品综合 | 亚洲中文字幕久久无码 | 粗大的内捧猛烈进出视频 | 老子影院午夜精品无码 | 亚洲日韩av一区二区三区中文 | 国产无遮挡吃胸膜奶免费看 | 精品无码一区二区三区的天堂 | 国产精品怡红院永久免费 | 国产精品无码永久免费888 | 欧美激情一区二区三区成人 | 国产情侣作爱视频免费观看 | 人人妻人人澡人人爽欧美一区九九 | 日本精品久久久久中文字幕 | 色狠狠av一区二区三区 | 天天摸天天透天天添 | 亚洲人成人无码网www国产 | 国产精品.xx视频.xxtv | 性色欲网站人妻丰满中文久久不卡 | 性欧美牲交xxxxx视频 | 国产真实夫妇视频 | 欧美老妇交乱视频在线观看 | 国产三级精品三级男人的天堂 | 熟妇人妻中文av无码 | 波多野结衣av在线观看 | 蜜臀aⅴ国产精品久久久国产老师 | 97精品人妻一区二区三区香蕉 | 国产精品久久久久久亚洲毛片 | 18黄暴禁片在线观看 | 小鲜肉自慰网站xnxx | 亚洲欧美综合区丁香五月小说 | 国产熟女一区二区三区四区五区 | 国产猛烈高潮尖叫视频免费 | 亚洲国产精品无码一区二区三区 | 精品国偷自产在线视频 | 久久99国产综合精品 | 亚洲 高清 成人 动漫 | 帮老师解开蕾丝奶罩吸乳网站 | 国产精品亚洲а∨无码播放麻豆 | 性色欲情网站iwww九文堂 | 国产精品人人爽人人做我的可爱 | 欧美成人午夜精品久久久 | 成人片黄网站色大片免费观看 | 中文字幕亚洲情99在线 | 午夜成人1000部免费视频 | 国产精品嫩草久久久久 | 欧美老人巨大xxxx做受 | 亚洲色偷偷偷综合网 | 免费人成网站视频在线观看 | 久久亚洲精品成人无码 | 国产成人精品三级麻豆 | 免费观看又污又黄的网站 | 国产av一区二区三区最新精品 | 久久99精品国产.久久久久 | 一区二区三区乱码在线 | 欧洲 | 精品国精品国产自在久国产87 | 日本丰满护士爆乳xxxx | www一区二区www免费 | 日韩精品无码一区二区中文字幕 | 精品无码国产自产拍在线观看蜜 | 牲欲强的熟妇农村老妇女 | 久久国产精品精品国产色婷婷 | 亚洲中文字幕成人无码 | 午夜性刺激在线视频免费 | 日本丰满熟妇videos | 欧美激情综合亚洲一二区 | 一本久久a久久精品vr综合 | 男人的天堂2018无码 | 久久国产自偷自偷免费一区调 | 中文字幕精品av一区二区五区 | 午夜成人1000部免费视频 | 亚洲色无码一区二区三区 | 国产成人人人97超碰超爽8 | 国产精品永久免费视频 | 粉嫩少妇内射浓精videos | 啦啦啦www在线观看免费视频 | 久久人人爽人人爽人人片av高清 | 大肉大捧一进一出好爽视频 | 狠狠综合久久久久综合网 | 亚洲精品中文字幕 | 中文字幕中文有码在线 | 宝宝好涨水快流出来免费视频 | 久久 国产 尿 小便 嘘嘘 | 性生交大片免费看女人按摩摩 | 国产xxx69麻豆国语对白 | 亚洲国产成人a精品不卡在线 | 青青青爽视频在线观看 | 99久久亚洲精品无码毛片 | 一本久久a久久精品亚洲 | 女人色极品影院 | 国产精品久久久久9999小说 | 欧美人与善在线com | 免费播放一区二区三区 | 76少妇精品导航 | 国产成人亚洲综合无码 | 人人妻人人澡人人爽人人精品浪潮 | 亚洲爆乳精品无码一区二区三区 | 亚洲阿v天堂在线 | 亚洲熟妇色xxxxx欧美老妇 | 在线天堂新版最新版在线8 | 狠狠噜狠狠狠狠丁香五月 | 玩弄人妻少妇500系列视频 | 日本丰满熟妇videos | 无码成人精品区在线观看 | 免费国产成人高清在线观看网站 | 男女性色大片免费网站 | 成人无码视频免费播放 | 国产成人综合在线女婷五月99播放 | 久久视频在线观看精品 | 2019nv天堂香蕉在线观看 | 天堂а√在线地址中文在线 | 午夜精品久久久久久久久 | 亚洲の无码国产の无码步美 | 少妇人妻av毛片在线看 | 男女猛烈xx00免费视频试看 | 成人动漫在线观看 | 午夜免费福利小电影 | 国产激情精品一区二区三区 | 日韩欧美中文字幕在线三区 | 欧美野外疯狂做受xxxx高潮 | 国产麻豆精品一区二区三区v视界 | 精品人妻中文字幕有码在线 | 美女毛片一区二区三区四区 | 国产成人无码一二三区视频 | 色爱情人网站 | 久久久www成人免费毛片 | 成人一在线视频日韩国产 | 国产精品久久久久影院嫩草 | 无码av最新清无码专区吞精 | 久久成人a毛片免费观看网站 | 亚洲熟妇色xxxxx亚洲 | 欧美日本免费一区二区三区 | 亚洲成熟女人毛毛耸耸多 | 国产成人精品视频ⅴa片软件竹菊 | 国产suv精品一区二区五 | 超碰97人人做人人爱少妇 | 日日摸夜夜摸狠狠摸婷婷 | 高清国产亚洲精品自在久久 | 性色欲网站人妻丰满中文久久不卡 | 国产97人人超碰caoprom | 亚洲综合伊人久久大杳蕉 | 99riav国产精品视频 | 久久人人97超碰a片精品 | 亚洲欧美综合区丁香五月小说 | 欧美人与禽zoz0性伦交 | 欧洲精品码一区二区三区免费看 | 一本久久a久久精品亚洲 | 日本www一道久久久免费榴莲 | а天堂中文在线官网 | 中文毛片无遮挡高清免费 | 国产麻豆精品一区二区三区v视界 | 久久综合九色综合欧美狠狠 | 国产免费无码一区二区视频 | 少妇被黑人到高潮喷出白浆 | 东京热男人av天堂 | 一二三四社区在线中文视频 | 小鲜肉自慰网站xnxx | 美女毛片一区二区三区四区 | 亚洲精品久久久久中文第一幕 | 国产精品国产自线拍免费软件 | 色综合视频一区二区三区 | 亚洲色大成网站www国产 | 亚洲欧美日韩国产精品一区二区 | 国产精品久久久久无码av色戒 | 中文毛片无遮挡高清免费 | 亚洲色欲色欲欲www在线 | 亚洲成av人综合在线观看 | 精品国产麻豆免费人成网站 | 色一情一乱一伦一视频免费看 | 97久久超碰中文字幕 | 亚拍精品一区二区三区探花 | 日日碰狠狠躁久久躁蜜桃 | 麻豆国产97在线 | 欧洲 | 久久这里只有精品视频9 | 高中生自慰www网站 | 粉嫩少妇内射浓精videos | 中文无码精品a∨在线观看不卡 | 一本大道久久东京热无码av | 思思久久99热只有频精品66 | 亚洲日韩一区二区三区 | 久久国语露脸国产精品电影 | 综合人妻久久一区二区精品 | 色妞www精品免费视频 | 一个人免费观看的www视频 | 日本在线高清不卡免费播放 | 国产做国产爱免费视频 | 亚洲a无码综合a国产av中文 | 美女黄网站人色视频免费国产 | 亚洲国产综合无码一区 | 在线欧美精品一区二区三区 | 久久视频在线观看精品 | 国产成人人人97超碰超爽8 | 嫩b人妻精品一区二区三区 | 又黄又爽又色的视频 | 久久精品人人做人人综合试看 | 两性色午夜免费视频 | 国产av剧情md精品麻豆 | 最新国产乱人伦偷精品免费网站 | 亚洲 激情 小说 另类 欧美 | 国产精品igao视频网 | 51国偷自产一区二区三区 | 国产一区二区三区四区五区加勒比 | 午夜福利不卡在线视频 | 日本爽爽爽爽爽爽在线观看免 | 巨爆乳无码视频在线观看 | 免费无码一区二区三区蜜桃大 | 久久成人a毛片免费观看网站 | 中国大陆精品视频xxxx | 国产午夜视频在线观看 | 亚洲欧美国产精品专区久久 | 亚洲精品午夜无码电影网 | 无码中文字幕色专区 | 欧美精品国产综合久久 | 亚洲国产精品一区二区第一页 | 色妞www精品免费视频 | 熟女体下毛毛黑森林 | 99久久久无码国产精品免费 | 成年美女黄网站色大免费全看 | 国产成人精品一区二区在线小狼 | 天天综合网天天综合色 | 亚洲国产精品无码一区二区三区 | 乱码av麻豆丝袜熟女系列 | 无码精品国产va在线观看dvd | 国产香蕉尹人综合在线观看 | 特级做a爰片毛片免费69 | 精品少妇爆乳无码av无码专区 | 欧美变态另类xxxx | 2020久久超碰国产精品最新 | 亚洲国产精华液网站w | 国产成人精品一区二区在线小狼 | 爱做久久久久久 | 国产色视频一区二区三区 | 激情内射日本一区二区三区 | 1000部啪啪未满十八勿入下载 | 狠狠色噜噜狠狠狠狠7777米奇 | 色一情一乱一伦一视频免费看 | 国产精品va在线播放 | 国产精品对白交换视频 | 熟女俱乐部五十路六十路av | 国产激情无码一区二区 | 精品无码av一区二区三区 | 青青草原综合久久大伊人精品 | 成人无码视频免费播放 | 老子影院午夜精品无码 | 国产精华av午夜在线观看 | 国产精品亚洲综合色区韩国 | 国产亚洲精品久久久久久大师 | 99精品久久毛片a片 | 亚洲精品国偷拍自产在线麻豆 | 久久99热只有频精品8 | 国产成人精品一区二区在线小狼 | 国产内射老熟女aaaa | 久久精品女人天堂av免费观看 | 亚洲国产一区二区三区在线观看 | 亚洲熟妇色xxxxx欧美老妇 | 国产色在线 | 国产 | 在线成人www免费观看视频 | 国产97人人超碰caoprom | 亚洲国产高清在线观看视频 | 成 人 免费观看网站 | 中文字幕精品av一区二区五区 | 樱花草在线播放免费中文 | 亚洲国产精品一区二区第一页 | 国产高清av在线播放 | 午夜精品久久久久久久久 | 日本熟妇浓毛 | 午夜丰满少妇性开放视频 | 激情亚洲一区国产精品 | 纯爱无遮挡h肉动漫在线播放 | 欧美黑人巨大xxxxx | 欧洲熟妇色 欧美 | 好屌草这里只有精品 | 在线视频网站www色 | 国产成人无码av在线影院 | 国产免费久久精品国产传媒 | 久久久久久a亚洲欧洲av冫 | 欧美三级a做爰在线观看 | 亚洲综合色区中文字幕 | 亚洲一区二区三区国产精华液 | 国产精品亚洲专区无码不卡 | 久久久久亚洲精品中文字幕 | 久久人人爽人人人人片 | 天海翼激烈高潮到腰振不止 | 精品欧美一区二区三区久久久 | 国产精品视频免费播放 | 超碰97人人射妻 | 正在播放老肥熟妇露脸 | 男女爱爱好爽视频免费看 | 国产乱人偷精品人妻a片 | 少妇性l交大片欧洲热妇乱xxx | 99精品国产综合久久久久五月天 | 国内揄拍国内精品少妇国语 | 日韩少妇内射免费播放 | 人妻少妇精品无码专区动漫 | 青草青草久热国产精品 | 久久久久亚洲精品男人的天堂 | 红桃av一区二区三区在线无码av | 漂亮人妻洗澡被公强 日日躁 | 成人无码影片精品久久久 | 福利一区二区三区视频在线观看 | 九月婷婷人人澡人人添人人爽 | 精品人人妻人人澡人人爽人人 | 亚洲乱码国产乱码精品精 | 中文字幕无码乱人伦 | 欧美成人家庭影院 | 丝袜美腿亚洲一区二区 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 熟妇女人妻丰满少妇中文字幕 | 在教室伦流澡到高潮hnp视频 | 少妇无码av无码专区在线观看 | 国产精品亚洲lv粉色 | 日韩视频 中文字幕 视频一区 | 中文字幕无码av波多野吉衣 | 久久综合香蕉国产蜜臀av | 久久久精品欧美一区二区免费 | av人摸人人人澡人人超碰下载 | 四虎影视成人永久免费观看视频 | 国产另类ts人妖一区二区 | 亚洲啪av永久无码精品放毛片 | 激情亚洲一区国产精品 | 任你躁国产自任一区二区三区 | 中文字幕色婷婷在线视频 | 久久久成人毛片无码 | 久久aⅴ免费观看 | 国内精品人妻无码久久久影院蜜桃 | 性做久久久久久久免费看 | 粗大的内捧猛烈进出视频 | 性欧美牲交在线视频 | 综合人妻久久一区二区精品 | yw尤物av无码国产在线观看 | 天海翼激烈高潮到腰振不止 | 成人一区二区免费视频 | 久久精品中文字幕一区 | 国产亚洲欧美在线专区 | 国产九九九九九九九a片 | 亚洲日本va午夜在线电影 | 亚洲成色在线综合网站 | 18黄暴禁片在线观看 | 欧美日本免费一区二区三区 | 免费中文字幕日韩欧美 | 成熟人妻av无码专区 | 亚洲色大成网站www国产 | 国产亚洲精品久久久闺蜜 | 伊人久久大香线焦av综合影院 | 国产精品99爱免费视频 | 亚洲熟悉妇女xxx妇女av | 丰满少妇女裸体bbw | 水蜜桃亚洲一二三四在线 | 色爱情人网站 | 97se亚洲精品一区 | 亚洲中文字幕久久无码 | 日韩无套无码精品 | 国产人妻精品一区二区三区 | 2020最新国产自产精品 | 乱中年女人伦av三区 | 无码国产乱人伦偷精品视频 | 丰满少妇熟乱xxxxx视频 | 久久精品无码一区二区三区 | 女高中生第一次破苞av | 曰韩无码二三区中文字幕 | 在线a亚洲视频播放在线观看 | 欧美放荡的少妇 | 亚洲成av人片天堂网无码】 | 成人欧美一区二区三区 | 欧美日韩一区二区综合 | 亚洲男人av香蕉爽爽爽爽 | 国产精品无码一区二区桃花视频 | 久久99久久99精品中文字幕 | 国产在线一区二区三区四区五区 | 中文字幕色婷婷在线视频 | 久久国产精品二国产精品 | 狠狠色色综合网站 | 亚洲国产精品无码久久久久高潮 | 青青久在线视频免费观看 | 久久99精品久久久久久动态图 | 人妻尝试又大又粗久久 | 久久www免费人成人片 | 草草网站影院白丝内射 | 2020久久超碰国产精品最新 | 夜精品a片一区二区三区无码白浆 | 网友自拍区视频精品 | 亚洲国产精华液网站w | 高清国产亚洲精品自在久久 | 99久久久国产精品无码免费 | 熟女俱乐部五十路六十路av | 午夜嘿嘿嘿影院 | 国产亚洲视频中文字幕97精品 | 亚洲欧美国产精品久久 | 中文字幕无码日韩欧毛 | 中文字幕日韩精品一区二区三区 | 欧美日韩人成综合在线播放 | 午夜成人1000部免费视频 | 无码一区二区三区在线 | 国产精品亚洲lv粉色 | 任你躁在线精品免费 | 亚拍精品一区二区三区探花 | 午夜精品久久久久久久久 | 少妇人妻大乳在线视频 | 熟女少妇人妻中文字幕 | 男人和女人高潮免费网站 | 久久久久99精品国产片 | 无码国产色欲xxxxx视频 | 伊人久久婷婷五月综合97色 | 无码吃奶揉捏奶头高潮视频 | 国产特级毛片aaaaaa高潮流水 | 亚洲欧美日韩国产精品一区二区 | 亚洲爆乳大丰满无码专区 | 午夜理论片yy44880影院 | 爱做久久久久久 | 国产特级毛片aaaaaaa高清 | 精品乱子伦一区二区三区 | 国产黄在线观看免费观看不卡 | 日韩av无码中文无码电影 | 无码乱肉视频免费大全合集 | 高潮毛片无遮挡高清免费 | 鲁大师影院在线观看 | 无码人妻久久一区二区三区不卡 | 无码人妻黑人中文字幕 | 精品国产一区二区三区四区在线看 | 久久久久国色av免费观看性色 | 老头边吃奶边弄进去呻吟 | 两性色午夜视频免费播放 | 少妇一晚三次一区二区三区 | 亚洲人交乣女bbw | 噜噜噜亚洲色成人网站 | 久久久久免费精品国产 | 四虎国产精品一区二区 | 少妇无码av无码专区在线观看 | 国产两女互慰高潮视频在线观看 | 99久久久国产精品无码免费 | 久久久久久a亚洲欧洲av冫 | 久久国产自偷自偷免费一区调 | 狂野欧美性猛交免费视频 | 中文字幕日产无线码一区 | 欧美成人家庭影院 | 中文字幕人成乱码熟女app | 高清不卡一区二区三区 | 成 人影片 免费观看 | 成人aaa片一区国产精品 | 成人aaa片一区国产精品 | 国产精品美女久久久网av | 日韩精品乱码av一区二区 | 精品国偷自产在线视频 | 国产免费久久精品国产传媒 | 国产真实伦对白全集 | 国产麻豆精品精东影业av网站 | 久久精品国产大片免费观看 | 国产又粗又硬又大爽黄老大爷视 | 欧美高清在线精品一区 | 精品久久8x国产免费观看 | 国产成人精品久久亚洲高清不卡 | 亚洲乱码中文字幕在线 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 无码av中文字幕免费放 | 极品嫩模高潮叫床 | 免费人成在线观看网站 | 人妻与老人中文字幕 | 99精品无人区乱码1区2区3区 | 午夜熟女插插xx免费视频 | 亚洲欧美日韩综合久久久 | 中文字幕无码视频专区 | 2020最新国产自产精品 | 18无码粉嫩小泬无套在线观看 | 亚洲の无码国产の无码步美 | 欧美三级a做爰在线观看 | 性欧美疯狂xxxxbbbb | 亚洲aⅴ无码成人网站国产app | 天天躁日日躁狠狠躁免费麻豆 | 国产黄在线观看免费观看不卡 | 人妻无码αv中文字幕久久琪琪布 | 青青青手机频在线观看 | 免费观看的无遮挡av | 日产国产精品亚洲系列 | 精品亚洲成av人在线观看 | 亚洲中文字幕av在天堂 | 欧美丰满少妇xxxx性 | 亚洲日韩av一区二区三区四区 | 未满小14洗澡无码视频网站 | 无码精品人妻一区二区三区av | 精品夜夜澡人妻无码av蜜桃 | 少女韩国电视剧在线观看完整 | 荫蒂添的好舒服视频囗交 | 无码乱肉视频免费大全合集 | 色综合久久中文娱乐网 | 小鲜肉自慰网站xnxx | 成年美女黄网站色大免费全看 | 日欧一片内射va在线影院 | 97精品国产97久久久久久免费 | 免费无码av一区二区 | 亚洲国产精品一区二区美利坚 | 亚洲狠狠色丁香婷婷综合 | 丰满护士巨好爽好大乳 | 麻花豆传媒剧国产免费mv在线 | 欧美老妇交乱视频在线观看 | 丰满肥臀大屁股熟妇激情视频 | 国产黄在线观看免费观看不卡 | 国产亚洲精品久久久久久久 | 国产午夜福利亚洲第一 | 精品国产av色一区二区深夜久久 | 国产美女极度色诱视频www | 久久伊人色av天堂九九小黄鸭 | 婷婷丁香五月天综合东京热 | 日韩av无码一区二区三区不卡 | 一本大道伊人av久久综合 | 久久精品女人天堂av免费观看 | 国产极品视觉盛宴 | 蜜臀aⅴ国产精品久久久国产老师 | 99国产精品白浆在线观看免费 | 久久久久久亚洲精品a片成人 | 无遮无挡爽爽免费视频 | 狠狠躁日日躁夜夜躁2020 | 亚洲国产精品无码一区二区三区 | 国产精品国产三级国产专播 | 久久国产精品_国产精品 | 久久久久99精品成人片 | 妺妺窝人体色www在线小说 | 成在人线av无码免观看麻豆 | 国产精品久久福利网站 | 草草网站影院白丝内射 | 欧美丰满熟妇xxxx性ppx人交 | 日日橹狠狠爱欧美视频 | 无码播放一区二区三区 | 国产精品第一国产精品 | 久久精品99久久香蕉国产色戒 | 久久久久久久人妻无码中文字幕爆 | 国产绳艺sm调教室论坛 | 成人片黄网站色大片免费观看 | 一区二区传媒有限公司 | 黑人巨大精品欧美一区二区 | a在线观看免费网站大全 | 亚洲 日韩 欧美 成人 在线观看 | 久久综合网欧美色妞网 | а天堂中文在线官网 | 亚洲欧美中文字幕5发布 | 色欲av亚洲一区无码少妇 | 免费观看的无遮挡av | 东京热男人av天堂 | 狂野欧美性猛xxxx乱大交 | 伊人久久大香线焦av综合影院 | 国产精品久久久久久久9999 | 亚洲综合久久一区二区 | 蜜桃无码一区二区三区 | 久久无码专区国产精品s | 亚洲男人av天堂午夜在 | 中国大陆精品视频xxxx | 无人区乱码一区二区三区 | 秋霞成人午夜鲁丝一区二区三区 | 久久久久久久人妻无码中文字幕爆 | 国产香蕉尹人视频在线 | 精品成在人线av无码免费看 | 欧美日韩视频无码一区二区三 | 亚洲精品国产a久久久久久 | 牲交欧美兽交欧美 | 成人免费视频在线观看 | 日本一区二区三区免费高清 | 欧美日韩人成综合在线播放 | 亚洲乱码中文字幕在线 | 日本精品少妇一区二区三区 | 性欧美大战久久久久久久 | 色狠狠av一区二区三区 | 东北女人啪啪对白 | 亚洲中文字幕无码中字 | 国产舌乚八伦偷品w中 | 狠狠亚洲超碰狼人久久 | 欧美zoozzooz性欧美 | 欧美黑人性暴力猛交喷水 | 在线精品亚洲一区二区 | 日韩少妇白浆无码系列 | 中文字幕无码视频专区 | 久久久亚洲欧洲日产国码αv | 99久久婷婷国产综合精品青草免费 | 久久国产精品偷任你爽任你 | 青青青手机频在线观看 | 日本一卡二卡不卡视频查询 | 自拍偷自拍亚洲精品被多人伦好爽 | 麻豆成人精品国产免费 | 色综合久久中文娱乐网 | 麻豆人妻少妇精品无码专区 | 色一情一乱一伦一视频免费看 | 乱人伦人妻中文字幕无码 | 一本久道高清无码视频 | 中文精品久久久久人妻不卡 | 激情五月综合色婷婷一区二区 | 亚洲成a人片在线观看无码3d | 大色综合色综合网站 | 又黄又爽又色的视频 | 中文字幕av伊人av无码av | 欧美性猛交内射兽交老熟妇 | 久久亚洲a片com人成 | 日韩av无码一区二区三区 | 日韩欧美群交p片內射中文 | 国产成人无码av一区二区 | 日本成熟视频免费视频 | 久久99精品久久久久久动态图 | av无码久久久久不卡免费网站 | 亚洲精品一区三区三区在线观看 | 欧美熟妇另类久久久久久多毛 | 免费观看又污又黄的网站 | 久久午夜无码鲁丝片午夜精品 | 午夜时刻免费入口 | 亚洲毛片av日韩av无码 | 亚洲中文字幕无码一久久区 | 久久99热只有频精品8 | 国产精品自产拍在线观看 | 丰满少妇人妻久久久久久 | 亚洲乱亚洲乱妇50p | 永久黄网站色视频免费直播 | 久久99精品国产麻豆蜜芽 | 久久久国产一区二区三区 | 麻豆成人精品国产免费 | 亚洲欧美日韩成人高清在线一区 | 日韩精品久久久肉伦网站 | 99久久亚洲精品无码毛片 | 无码播放一区二区三区 | 国产综合色产在线精品 | 亚洲最大成人网站 | 人人超人人超碰超国产 | 内射老妇bbwx0c0ck | 免费人成在线视频无码 | 欧美 亚洲 国产 另类 | 亚洲区欧美区综合区自拍区 | 国产成人精品三级麻豆 | 无码人妻精品一区二区三区下载 | 帮老师解开蕾丝奶罩吸乳网站 | 久久久精品成人免费观看 | 少妇人妻av毛片在线看 | 日韩人妻系列无码专区 | 国产高清av在线播放 | 久久久久se色偷偷亚洲精品av | 天天躁日日躁狠狠躁免费麻豆 | 四虎永久在线精品免费网址 | 又粗又大又硬毛片免费看 | 99精品久久毛片a片 | 夜先锋av资源网站 | 人人妻人人藻人人爽欧美一区 | 欧美性黑人极品hd | 亚洲国产精品毛片av不卡在线 | 日韩少妇内射免费播放 | 欧美性生交活xxxxxdddd | 亚洲综合无码一区二区三区 | 中文字幕人妻无码一夲道 | 日本一区二区更新不卡 | 国产suv精品一区二区五 | 免费观看激色视频网站 | 日日天干夜夜狠狠爱 | 少妇愉情理伦片bd | 丝袜 中出 制服 人妻 美腿 | 永久黄网站色视频免费直播 | 精品一二三区久久aaa片 | 天天做天天爱天天爽综合网 | 极品尤物被啪到呻吟喷水 | 国产精品怡红院永久免费 | 欧美国产亚洲日韩在线二区 | 影音先锋中文字幕无码 | 牲交欧美兽交欧美 | 久久99精品国产.久久久久 | 免费无码午夜福利片69 | 亚洲人成影院在线观看 | 伊人久久大香线蕉av一区二区 | 一个人看的www免费视频在线观看 | 欧美性猛交xxxx富婆 | 亚洲综合伊人久久大杳蕉 | 黄网在线观看免费网站 | 在教室伦流澡到高潮hnp视频 | 亚洲大尺度无码无码专区 | 久激情内射婷内射蜜桃人妖 | 久久精品视频在线看15 | 亚洲啪av永久无码精品放毛片 | 黄网在线观看免费网站 | 精品厕所偷拍各类美女tp嘘嘘 | 爽爽影院免费观看 | 国产色视频一区二区三区 | 亚洲国产高清在线观看视频 | 97无码免费人妻超级碰碰夜夜 | 内射欧美老妇wbb | 免费国产黄网站在线观看 | 亚洲精品中文字幕 | 亚拍精品一区二区三区探花 | 亚洲欧美日韩国产精品一区二区 | 牲欲强的熟妇农村老妇女视频 | a片免费视频在线观看 | 国内丰满熟女出轨videos | 国产深夜福利视频在线 | 4hu四虎永久在线观看 | 日韩精品无码免费一区二区三区 | 国产97人人超碰caoprom | 鲁大师影院在线观看 | 玩弄少妇高潮ⅹxxxyw | 三级4级全黄60分钟 | 中文久久乱码一区二区 | 国产精品亚洲lv粉色 | 久久久久久久女国产乱让韩 | 奇米影视888欧美在线观看 | 亚洲精品无码人妻无码 | 亚洲成av人在线观看网址 | 纯爱无遮挡h肉动漫在线播放 | 国产精品久久久久影院嫩草 | a片免费视频在线观看 | а√资源新版在线天堂 | 特黄特色大片免费播放器图片 | 欧美日韩久久久精品a片 | 亚洲色欲色欲天天天www | 亚洲国产精品无码一区二区三区 | 亚洲欧美综合区丁香五月小说 | 午夜男女很黄的视频 | 女人被男人爽到呻吟的视频 | 奇米影视7777久久精品人人爽 | 亚洲区小说区激情区图片区 | 俺去俺来也www色官网 | 久久精品视频在线看15 | 四虎国产精品免费久久 | 精品久久久无码人妻字幂 | 色婷婷欧美在线播放内射 | 国产精品无套呻吟在线 | 国产三级精品三级男人的天堂 | 精品亚洲成av人在线观看 | 一本精品99久久精品77 | 内射白嫩少妇超碰 | 欧美第一黄网免费网站 | 特大黑人娇小亚洲女 | 亚洲中文字幕无码中字 | 中文字幕av日韩精品一区二区 | 欧美日韩色另类综合 | 亚洲成av人片在线观看无码不卡 | 领导边摸边吃奶边做爽在线观看 | 亚洲精品一区二区三区婷婷月 | 正在播放老肥熟妇露脸 | 国产 精品 自在自线 | 精品熟女少妇av免费观看 | 丰满少妇弄高潮了www | 久久成人a毛片免费观看网站 | 青春草在线视频免费观看 | 免费视频欧美无人区码 | 久久久久av无码免费网 | 特级做a爰片毛片免费69 | 免费国产黄网站在线观看 | 免费人成在线视频无码 | 久久国产自偷自偷免费一区调 | 天堂无码人妻精品一区二区三区 | 国产精品内射视频免费 | 双乳奶水饱满少妇呻吟 | 国产精品18久久久久久麻辣 | 白嫩日本少妇做爰 | 日本一区二区三区免费高清 | 乱人伦人妻中文字幕无码久久网 | 国产精品毛多多水多 | 亚洲国产av精品一区二区蜜芽 | 丰满妇女强制高潮18xxxx | 欧美日韩一区二区三区自拍 | 中文字幕乱妇无码av在线 | 国模大胆一区二区三区 | 无码任你躁久久久久久久 | 国产在线精品一区二区三区直播 | 国产偷国产偷精品高清尤物 | 国产一区二区三区四区五区加勒比 | 午夜理论片yy44880影院 | 无码人妻丰满熟妇区五十路百度 | 少妇性l交大片欧洲热妇乱xxx | 一本一道久久综合久久 | 波多野结衣乳巨码无在线观看 | 牲交欧美兽交欧美 | 精品无码成人片一区二区98 | 成人片黄网站色大片免费观看 | 在线播放无码字幕亚洲 | 55夜色66夜色国产精品视频 | 国产亚洲日韩欧美另类第八页 | 性史性农村dvd毛片 | 伊人久久大香线蕉av一区二区 | 撕开奶罩揉吮奶头视频 | 国产在热线精品视频 | 国产精品久久久久久亚洲影视内衣 | 精品国产精品久久一区免费式 | 亚洲综合伊人久久大杳蕉 | 性欧美videos高清精品 | yw尤物av无码国产在线观看 | 人妻少妇精品视频专区 | 理论片87福利理论电影 | 欧美丰满老熟妇xxxxx性 | 伊人久久大香线蕉午夜 | 天天摸天天透天天添 | 少妇无码av无码专区在线观看 | 少妇高潮一区二区三区99 | 亚洲精品鲁一鲁一区二区三区 | 亚洲精品中文字幕 | 国产精品久久久午夜夜伦鲁鲁 | 国产在线无码精品电影网 | 亚洲色偷偷男人的天堂 | 欧美丰满老熟妇xxxxx性 | 国产网红无码精品视频 | 久久久国产精品无码免费专区 | 国产成人综合在线女婷五月99播放 | 性开放的女人aaa片 | 欧美日韩视频无码一区二区三 | 无遮无挡爽爽免费视频 | 久久午夜无码鲁丝片秋霞 | 国产精品久久久久久久影院 | 欧洲熟妇精品视频 | 国产偷自视频区视频 | 青青草原综合久久大伊人精品 | 成人欧美一区二区三区黑人 | 中文毛片无遮挡高清免费 | 天堂无码人妻精品一区二区三区 | 亚无码乱人伦一区二区 | 久久人人爽人人爽人人片av高清 | 亚洲区小说区激情区图片区 | 精品熟女少妇av免费观看 | 少妇性l交大片 | 欧美性猛交内射兽交老熟妇 | 国产舌乚八伦偷品w中 | 国产精品欧美成人 | 国产精品久久久久久亚洲影视内衣 | 日本欧美一区二区三区乱码 | 一本精品99久久精品77 | 亚洲自偷自拍另类第1页 | 国产午夜福利100集发布 | 久久精品人妻少妇一区二区三区 | 亚洲成熟女人毛毛耸耸多 | 中文字幕 人妻熟女 | аⅴ资源天堂资源库在线 | av在线亚洲欧洲日产一区二区 | 亚洲欧美日韩国产精品一区二区 | 精品国产一区二区三区av 性色 | 爽爽影院免费观看 | 日韩欧美中文字幕在线三区 | 成熟女人特级毛片www免费 | 日韩欧美中文字幕在线三区 | 欧美阿v高清资源不卡在线播放 | 亚洲日韩一区二区 | 老太婆性杂交欧美肥老太 | 日韩人妻系列无码专区 | 色狠狠av一区二区三区 | 无码国产激情在线观看 | 欧美一区二区三区 | 国产精品无码一区二区桃花视频 | 嫩b人妻精品一区二区三区 | 中文字幕无码日韩欧毛 | 亚洲自偷自偷在线制服 | 久久精品国产大片免费观看 | 亚洲精品久久久久久一区二区 | 天堂亚洲2017在线观看 | 午夜嘿嘿嘿影院 | 双乳奶水饱满少妇呻吟 | 鲁鲁鲁爽爽爽在线视频观看 | 无码av免费一区二区三区试看 | 在线看片无码永久免费视频 | 曰本女人与公拘交酡免费视频 | 亚洲中文字幕久久无码 | 久久99精品国产麻豆 | 东京一本一道一二三区 | 色婷婷综合中文久久一本 | 午夜精品一区二区三区的区别 | 成人一在线视频日韩国产 | 国产精品国产三级国产专播 | 日韩欧美群交p片內射中文 | 国产成人精品无码播放 | 青春草在线视频免费观看 | 亚洲精品国产品国语在线观看 | 国产精品无码成人午夜电影 | 国产真实伦对白全集 | 国产午夜视频在线观看 | 性色欲网站人妻丰满中文久久不卡 | 欧美日韩一区二区免费视频 | 国精产品一品二品国精品69xx | 国产手机在线αⅴ片无码观看 | 成人av无码一区二区三区 | 亚洲欧美中文字幕5发布 | 蜜桃臀无码内射一区二区三区 | 国产激情一区二区三区 | 青草青草久热国产精品 | 欧美三级a做爰在线观看 | 在线а√天堂中文官网 | 又大又硬又爽免费视频 | 免费观看又污又黄的网站 | 久久久精品成人免费观看 | 97精品国产97久久久久久免费 | 色噜噜亚洲男人的天堂 | 中文字幕无码免费久久9一区9 | 久久午夜夜伦鲁鲁片无码免费 | 亚洲爆乳精品无码一区二区三区 | 牛和人交xxxx欧美 | 日本va欧美va欧美va精品 | 国模大胆一区二区三区 | 人人爽人人澡人人人妻 | 国产综合色产在线精品 | 天天摸天天碰天天添 | 国产热a欧美热a在线视频 | 免费无码肉片在线观看 | 免费人成网站视频在线观看 | 中国女人内谢69xxxx | 欧美一区二区三区 | 天干天干啦夜天干天2017 | 高潮喷水的毛片 | 美女极度色诱视频国产 | 波多野结衣乳巨码无在线观看 | 377p欧洲日本亚洲大胆 | 最近中文2019字幕第二页 | 人妻少妇精品视频专区 | 天堂一区人妻无码 | 欧美一区二区三区视频在线观看 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 妺妺窝人体色www在线小说 | 好男人www社区 | 51国偷自产一区二区三区 | 在线精品亚洲一区二区 | 久久久久久a亚洲欧洲av冫 | 精品一区二区三区波多野结衣 | 日本精品少妇一区二区三区 | 无人区乱码一区二区三区 | 大肉大捧一进一出好爽视频 | 男女爱爱好爽视频免费看 | av无码电影一区二区三区 | 无码播放一区二区三区 | 人妻少妇精品久久 | 日韩精品a片一区二区三区妖精 | 性色欲网站人妻丰满中文久久不卡 | 亚洲区欧美区综合区自拍区 | 99久久精品无码一区二区毛片 | 天下第一社区视频www日本 | 2020最新国产自产精品 | 无码av最新清无码专区吞精 | 中文字幕无码人妻少妇免费 | 欧美日韩一区二区免费视频 | 性欧美牲交在线视频 | 乱人伦人妻中文字幕无码 | 亚洲春色在线视频 | 亚洲熟妇色xxxxx欧美老妇 | 国产舌乚八伦偷品w中 | 无码人妻av免费一区二区三区 | 成熟妇人a片免费看网站 | 国产色xx群视频射精 | 亚洲gv猛男gv无码男同 | 对白脏话肉麻粗话av | 国产综合在线观看 | 久久久久人妻一区精品色欧美 | 亚洲精品综合一区二区三区在线 | 精品国产国产综合精品 | 欧美日韩色另类综合 | 天海翼激烈高潮到腰振不止 | 高清不卡一区二区三区 | 中文字幕无线码免费人妻 | 一本久道久久综合婷婷五月 | 久久国产精品萌白酱免费 | 无码成人精品区在线观看 | 亚洲国精产品一二二线 | 欧美三级a做爰在线观看 | 少妇无套内谢久久久久 | 成年美女黄网站色大免费视频 | 狂野欧美性猛交免费视频 | 成人无码影片精品久久久 | 国产精品18久久久久久麻辣 | 丰满少妇人妻久久久久久 | 乌克兰少妇xxxx做受 | 国产精品毛片一区二区 | 午夜福利一区二区三区在线观看 | 亚洲成av人综合在线观看 | 国产网红无码精品视频 | 草草网站影院白丝内射 | 亚洲成色在线综合网站 | 免费视频欧美无人区码 | 中文字幕乱码亚洲无线三区 | 亚洲中文字幕va福利 | 国产成人精品无码播放 | 日本饥渴人妻欲求不满 | 无码午夜成人1000部免费视频 | 丰腴饱满的极品熟妇 | 国产午夜精品一区二区三区嫩草 | 日韩少妇内射免费播放 | 欧美肥老太牲交大战 | 久久国产自偷自偷免费一区调 | 亚洲人成网站色7799 | 精品国产一区二区三区四区 | 久久国产自偷自偷免费一区调 | 国产精品内射视频免费 | 成人无码精品1区2区3区免费看 | 亚洲精品欧美二区三区中文字幕 | 国产av人人夜夜澡人人爽麻豆 | 久久精品国产大片免费观看 | 国产网红无码精品视频 | 精品无码成人片一区二区98 | 动漫av一区二区在线观看 | 欧美激情内射喷水高潮 | 久久久久免费看成人影片 | 国产美女极度色诱视频www | 女人被男人躁得好爽免费视频 | 国产精品美女久久久 | 夜夜夜高潮夜夜爽夜夜爰爰 | 好男人www社区 | 麻豆果冻传媒2021精品传媒一区下载 | 国内精品一区二区三区不卡 | 一本久道高清无码视频 | 麻豆成人精品国产免费 | 久久精品人妻少妇一区二区三区 | 久久午夜无码鲁丝片午夜精品 | 日本又色又爽又黄的a片18禁 | 水蜜桃色314在线观看 | 国产精品久久久久7777 | 婷婷丁香六月激情综合啪 | 内射老妇bbwx0c0ck | 亚洲 a v无 码免 费 成 人 a v | 亚洲综合久久一区二区 | 国产综合久久久久鬼色 | 无码帝国www无码专区色综合 | 久久精品国产99久久6动漫 | 18黄暴禁片在线观看 | 国产精品久久国产精品99 | 久久国产精品_国产精品 | 精品厕所偷拍各类美女tp嘘嘘 | 老子影院午夜伦不卡 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产超碰人人爽人人做人人添 | 精品亚洲成av人在线观看 | 午夜无码区在线观看 | 欧美一区二区三区视频在线观看 | 一区二区传媒有限公司 | 欧美丰满少妇xxxx性 | 人妻无码αv中文字幕久久琪琪布 | 亚洲一区二区三区四区 | 妺妺窝人体色www在线小说 | 免费观看又污又黄的网站 | 亚洲精品一区二区三区大桥未久 | 麻豆国产丝袜白领秘书在线观看 | 在线播放免费人成毛片乱码 | 人妻尝试又大又粗久久 | 99视频精品全部免费免费观看 | 人人爽人人澡人人人妻 | 俄罗斯老熟妇色xxxx | 亚洲熟悉妇女xxx妇女av | 日本熟妇大屁股人妻 | 日本xxxx色视频在线观看免费 | 无码人妻精品一区二区三区下载 | 一个人看的www免费视频在线观看 | 亚洲天堂2017无码中文 | 成熟人妻av无码专区 | 亚洲欧美色中文字幕在线 | 麻豆人妻少妇精品无码专区 | 日日干夜夜干 | 国产成人久久精品流白浆 | 国内精品人妻无码久久久影院 | 中文字幕无码热在线视频 | 在线观看欧美一区二区三区 | 激情人妻另类人妻伦 | 女人高潮内射99精品 | 精品欧美一区二区三区久久久 | 国产精品第一区揄拍无码 | 特级做a爰片毛片免费69 | 国产精品毛片一区二区 | 国产两女互慰高潮视频在线观看 | 老子影院午夜精品无码 | 国产乱人无码伦av在线a | 台湾无码一区二区 | 999久久久国产精品消防器材 | 无遮挡啪啪摇乳动态图 | 国产人成高清在线视频99最全资源 | 精品久久久久久人妻无码中文字幕 | 亚洲一区二区三区偷拍女厕 | 国产午夜精品一区二区三区嫩草 | 午夜时刻免费入口 | 欧美性生交活xxxxxdddd | 精品一区二区三区无码免费视频 | 99久久人妻精品免费一区 | 中文字幕乱码人妻二区三区 | 欧美亚洲日韩国产人成在线播放 | 亚洲啪av永久无码精品放毛片 | 国产色精品久久人妻 | 香蕉久久久久久av成人 | 国产激情一区二区三区 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 日韩欧美中文字幕公布 | 国产av一区二区精品久久凹凸 | 伊人久久婷婷五月综合97色 | 无遮无挡爽爽免费视频 | 在线欧美精品一区二区三区 | 欧洲熟妇精品视频 | 国产肉丝袜在线观看 | 日韩精品无码一本二本三本色 | 成人一区二区免费视频 | 全球成人中文在线 | 久久无码专区国产精品s | 亚洲人成网站色7799 | 欧美成人家庭影院 | 日韩欧美群交p片內射中文 | 图片小说视频一区二区 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | a片在线免费观看 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 日本高清一区免费中文视频 | 亚洲 a v无 码免 费 成 人 a v | 自拍偷自拍亚洲精品10p | 亚洲人亚洲人成电影网站色 | 久久www免费人成人片 | 骚片av蜜桃精品一区 | 国产精品久久久久久无码 | 色 综合 欧美 亚洲 国产 | 亚洲精品一区国产 | 自拍偷自拍亚洲精品被多人伦好爽 | 国产热a欧美热a在线视频 | 精品久久久久久亚洲精品 | 国产亚洲人成a在线v网站 | 久久午夜无码鲁丝片午夜精品 | 亚洲日本va中文字幕 | 老司机亚洲精品影院 | 免费国产成人高清在线观看网站 | 午夜无码人妻av大片色欲 | 国产亚洲精品精品国产亚洲综合 | 内射欧美老妇wbb | 亚洲综合另类小说色区 | 日本熟妇人妻xxxxx人hd | 日韩亚洲欧美精品综合 | 玩弄人妻少妇500系列视频 | 国产精品亚洲五月天高清 | 日韩少妇内射免费播放 | 一本色道婷婷久久欧美 | 激情国产av做激情国产爱 | 亚洲成a人片在线观看无码3d | 日产精品99久久久久久 | 俺去俺来也www色官网 | 国产精品高潮呻吟av久久4虎 | 丁香花在线影院观看在线播放 | 天堂久久天堂av色综合 | 国产一区二区三区精品视频 | 人妻少妇精品无码专区二区 | av人摸人人人澡人人超碰下载 | 亚洲国产精品无码一区二区三区 | 亚洲日韩av一区二区三区四区 | 成人免费无码大片a毛片 | 亚洲 另类 在线 欧美 制服 | 性色av无码免费一区二区三区 | 给我免费的视频在线观看 | 亚洲の无码国产の无码步美 | 亚洲国产日韩a在线播放 | 少妇无套内谢久久久久 | 免费人成在线观看网站 | 日韩精品无码一本二本三本色 | 亚洲精品国产精品乱码不卡 | 丝袜 中出 制服 人妻 美腿 | 久久人人爽人人爽人人片av高清 | 夜先锋av资源网站 | 国产超级va在线观看视频 | 亚洲色大成网站www国产 | 免费中文字幕日韩欧美 | 亚洲色偷偷偷综合网 | 欧美自拍另类欧美综合图片区 | 久青草影院在线观看国产 | 精品一区二区不卡无码av | 露脸叫床粗话东北少妇 | 精品国精品国产自在久国产87 | 国色天香社区在线视频 | 久久精品人人做人人综合 | 日韩少妇白浆无码系列 | 国产无套内射久久久国产 | 麻豆国产97在线 | 欧洲 | 国产亚洲日韩欧美另类第八页 | 久久人人97超碰a片精品 | 未满成年国产在线观看 | 亚洲第一网站男人都懂 | 初尝人妻少妇中文字幕 | 一本大道久久东京热无码av | 无码人妻av免费一区二区三区 | 国产97色在线 | 免 | 婷婷丁香五月天综合东京热 | 国产精品无套呻吟在线 | 骚片av蜜桃精品一区 | 亚洲熟女一区二区三区 | 精品aⅴ一区二区三区 | 影音先锋中文字幕无码 | 国产激情综合五月久久 | 又大又硬又黄的免费视频 | 精品亚洲韩国一区二区三区 | 色婷婷香蕉在线一区二区 | 捆绑白丝粉色jk震动捧喷白浆 | 日韩精品久久久肉伦网站 | 国产激情艳情在线看视频 | 76少妇精品导航 | 色综合久久中文娱乐网 | 亚洲精品久久久久久一区二区 | 中文字幕人妻丝袜二区 | 欧洲熟妇精品视频 | 亚洲男女内射在线播放 | 日韩欧美中文字幕在线三区 | 欧洲熟妇色 欧美 | 久久久久久久女国产乱让韩 | 国产色xx群视频射精 | 中文字幕亚洲情99在线 | 亚洲成av人影院在线观看 | 国产精品igao视频网 | 久久精品女人天堂av免费观看 | 色偷偷人人澡人人爽人人模 | 亚洲精品成人福利网站 | 久久久国产精品无码免费专区 | 日韩精品成人一区二区三区 | 国产精品内射视频免费 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 波多野结衣一区二区三区av免费 | 欧洲美熟女乱又伦 | 强奷人妻日本中文字幕 | 丰满少妇熟乱xxxxx视频 | 久激情内射婷内射蜜桃人妖 | 国产免费久久久久久无码 | 未满小14洗澡无码视频网站 | 午夜无码人妻av大片色欲 | 国产亚洲精品久久久久久久久动漫 | 久久无码中文字幕免费影院蜜桃 | 国内揄拍国内精品少妇国语 | 九九热爱视频精品 | 99久久久无码国产精品免费 | 一区二区三区乱码在线 | 欧洲 | 大肉大捧一进一出好爽视频 | 免费男性肉肉影院 | 日本丰满熟妇videos | 亚洲熟妇色xxxxx欧美老妇y | 网友自拍区视频精品 | 免费国产黄网站在线观看 |