(轉)MitmProxy+APPnium安裝使用


MitmProxy+APPnium安裝使用

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接: https://blog.csdn.net/jiageibuuuyi/article/details/99716357

MitmProxy+APPnium安裝使用指導手冊

1、環境搭建

1.1、環境准備

Windows 10版本 64位系統

  1. jdk1.6.0 (64位)
  2. android-sdk_r24.3.4-windows
  3. Node.js
  4. appium
  5. .net framework
  6. Appium-Python-Client
  7. mitmproxy

1.2、jdk安裝

  1. 下載jdk包,根據自己的系統選擇對應版本,jdk版本8.0比較合適。
  2. 一路傻瓜式安裝,注意安裝路徑不要有空格,不要有中文。jdk和jre不要放在一個文件夾下
  3. 設置三個環境變量,我的電腦>選擇“屬性”->“高級”->“環境變量”->“系統變量”->“新建”

JAVA_HOME----D:\Java\jdk1.6.0” (根據自己安裝路徑填寫)

img

CLASSPATH— .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar;

img

PATH-----;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

在path路徑下加上面那兩個

​ 4.打開cmd驗證是否安裝成功,輸入java -version,然后輸入javac

能顯示版本號和下面的幫助信息說明安裝成功

img


 

1.3、android-sdk下載安裝

1.3.1、Android SDK簡介

Android SDK(Software Development Kit,軟件開發工具包)被軟件開發工程師用於為特定的軟件包、軟件框架、硬件平台、操作系統等建立應用軟件的開發工具的集合。它提供了 Android API 庫和開發工具構建,測試和調試應用程序。簡單來講,Android SDK 可以看做用於開發和運行 Android 應用的一個軟件。

1.3.2、下載SDK

1.目前官網上已經沒有單獨的SDK下載安裝包了。目前官網推薦的是下載包含有Android SDK的Android Studio。官網下載傳送門

Android Studio 的一個功能非常強大的用來做安卓開發試調的官方出品的工具。Ps:官網下載,需科學(翻)上(牆)網

**2.由於這個Android Studio 的安裝包過大且官網下載需要翻牆,而咱們在用Appium 的時候實際上只需要用到SDK 工具而已。所以推薦大家去另外一個國內的Android 工具的下載網站下載。傳送門**

進入頁面后點擊【Android SDK 工具】按鈕,然后在彈出的選擇框內點擊【SDK Tools】按鈕,然后界面會自動跳轉到SDK 的下載界面,選擇適合自己的版本進行下載

img

將下載后的安裝包解壓到相應的目錄下,如下圖:

img

1.3.3、安裝Android 版本

進入SDK的解壓目錄下,雙擊“SDK Manager.exe”打開SDK管理器

img

在使用這個管理器的時候,需要使用科學,才能進行下載安裝;或者你也可以在上面推薦的那個下載SDK的國內安卓工具網站上下載適合你的版本的Android SDK 鏡像,網站傳送門(可根據夜神模擬器使用的安卓版本下載)

img

1.3.4、下載aapt

​ 1.在android-sdk里面雙擊SDK-manager,下載buidl-tools

img

​ 2.勾選build-tools,隨便選一個版本

img

1.3.4、SDK環境配置

在解壓完成后,就可以開始配置環境變量了。方法和設置JAVA JDK的環境變量的方法類似。

“右鍵 我的電腦”—“屬性”—“高級系統設置”—“環境變量”—“系統變量”—“新建”

SDK 需要對環境變量做如下更改(win 10):
1 創建ANDROID_HOME,值是你的剛剛SDK的解壓目錄,比如     E:\Android\android-sdk-windows
  • 1
  • 2

img

在新建完ANDROID_HOME之后,找到Path變量,然后雙擊打開Path 變量

將SDK的platform-tools和tool的路徑添加到Path 變量內(這兩個目錄在你通過SDK Manager安裝更新Android SDK Tools和Android SDK Platform-tools之后就會有了)
1 新建 %ANDROID_HOME%\platform-tools
2 新建 %ANDROID_HOME%\tools
3 新建 %ANDROID_HOME%\build—tools\28.0.0
  • 1
  • 2
  • 3
  • 4

img

在cmd輸入adb可以查看對應版本號

img

輸入aapt出現如下界面,說明環境OK了

img

1.3.5、adb連接夜神模擬器

  1. 輸入adb version命令,查看adb版本,我電腦的adb版本為1.0.39

    夜神模擬器怎么連接adb

  2. 輸入nox_adb version 命令,查看模擬器的adb版本,發現模擬器的版本是1.0.36與android-sdk的adb版本不一致

    夜神模擬器怎么連接adb

  3. 首先進入android-sdk的platform-tools目錄下復制adb.exe

    夜神模擬器怎么連接adb

  4. 進入模擬器的安裝目錄下,修改nox_adb.exe的名字為nox_adb.exe.bak

    夜神模擬器怎么連接adb

  5. 把android-sdk的adb.exe文件復制到桌面一份,修改adb.exe的名稱為nox_adb.exe,再把桌面修改完名稱的nox_adb.exe復制到模擬器的Nox\bin目錄下

    夜神模擬器怎么連接adb

  6. 再次在cmd窗口中輸入命令nox_adb version ,發現替換完文件后的版本變為1.0.39了,版本一致了

    夜神模擬器怎么連接adb

  7. 打開模擬器

    夜神模擬器怎么連接adb

  8. 在cmd中輸入 adb devices,可以發現模擬器設備了,已經連接上了,大功告成

    夜神模擬器怎么連接adb


1.4、安裝node.js

下載官網地址:https://nodejs.org/en/download/23

img

下載后一路傻瓜式安裝,安裝完成后,運行cmd,輸入node –v查看版本號,然后輸入npm

img

出現如上圖信息,表示node.js安裝成功。npm是一個node包管理和分發工具,有了npm,后面就可以輸入指令在線安裝appium(打開 cmd輸入:npm install –g appium但是一般不推薦這種,下載比較慢,所以用下面這種客戶端安裝)


1.5、安裝appium

下載安裝地址:https://bitbucket.org/appium/appium.app/downloads/16

img

直接雙擊appium-installer.exe文件安裝就好,桌面會生成一個appium的圖標,啟動后界面顯示如下

img


1.6、安裝.net framework

Appium是用.net開發的,所以需要安裝.net framework4.5,下載地址:https://www.microsoft.com/zh-cn/download/details.aspx?id=3065332

img


1.7、appium-doctor

  1. appium安裝好后,找到這個文件目錄D:\appium\Appium\node_modules.bin
  2. 將上面的地址添加到環境變量path下
  3. 打卡cmd,輸入appium-doctor,檢查環境是否OK,出現如下圖所示,說明環境OK

img

1.8、安裝Appium-Python-Client

安裝python庫:pip install Appium-Python-Client
img


1.9、安裝mitmproxy

安裝 python 的 mitmproxy 包除了會得到 mitmproxy 工具外,還會得到開發定制腳本所需要的包依賴,其安裝過程並不復雜。

首先需要安裝好 python,版本需要不低於 3.6,且安裝了附帶的包管理工具 pip。不同操作系統安裝 python 3 的方式不一,參考 python 的下載頁,這里不做展開,假設你已經准備好這樣的環境了。

安裝開始。

在 linux 中:

sudo pip3 install mitmproxy
  • 1

在 windows 中,以管理員身份運行 cmd 或 power shell:

pip3 install mitmproxy
  • 1

安裝結束。

完成后,系統將擁有 mitmproxymitmdumpmitmweb 三個命令,由於 mitmproxy 命令不支持在 windows 系統中運行(這沒關系,不用擔心),我們可以拿 mitmdump 測試一下安裝是否成功,執行:

mitmdump --version
  • 1

應當可以看到類似於這樣的輸出:

Mitmproxy: 4.0.1
Python:    3.6.5
OpenSSL:   OpenSSL 1.1.0h  27 Mar 2018
Platform:  Windows-10-10.0.16299-SP0
  • 1
  • 2
  • 3
  • 4

1.10、證書安裝

手機抓包大家都知道要安裝證書就是相當於一個護照有了它你才可以出國旅游,在你安裝好mitmdump (我們這里用win系統作為例子因為win只可以用mitmdump和mitmweb)

首先我們要把手機和電腦鏈接在同一個網絡下比如我的電腦和Wifi都在連接在shangwang這個wifi下面

img

填寫上你的正確的ip地址和抓包開啟的端口號默認8080端口也可使用其他端口

img

img

我這里是192.168.1.105所以服務器輸入192.168.1.105端口號使用默認端口號8080就可以了如果大家想使用其他端口號也可以使用

mitmdump -p ****
  • 1

進行端口指定,防止8080端口被其他的軟件所占用。

手機配置好以后我們就開始使用了首先是訪問mitm.it網站安裝證書

img

選擇你的手機機型,我這里是蘋果機型所以選擇第一個下載安裝好證書以后就可訪問網站了,如果你沒有安裝好證書就訪問其他網頁其他網頁是阻止訪問的,注意:蘋果機型是需要設置證書信任的11.x版本都是在設置->通用->關於本機->證書信任里面設置信任證書。

2、操作指導

  1. mitmproxy操作
  2. appnium操作

2.1、mitmproxy

mitmproxy 就是用於 MITM 的 proxy,MITM 即中間人攻擊(Man-in-the-middle attack)。用於中間人攻擊的代理首先會向正常的代理一樣轉發請求,保障服務端與客戶端的通信,其次,會適時的查、記錄其截獲的數據,或篡改數據,引發服務端或客戶端特定的行為。

不同於 fiddler 或 wireshark 等抓包工具,mitmproxy 不僅可以截獲請求幫助開發者查看、分析,更可以通過自定義腳本進行二次開發。舉例來說,利用 fiddler 可以過濾出瀏覽器對某個特定 url 的請求,並查看、分析其數據,但實現不了高度定制化的需求,類似於:“截獲對瀏覽器對該 url 的請求,將返回內容置空,並將真實的返回內容存到某個數據庫,出現異常時發出郵件通知”。而對於 mitmproxy,這樣的需求可以通過載入自定義 python 腳本輕松實現。

但 mitmproxy 並不會真的對無辜的人發起中間人攻擊,由於 mitmproxy 工作在 HTTP 層,而當前 HTTPS 的普及讓客戶端擁有了檢測並規避中間人攻擊的能力,所以要讓 mitmproxy 能夠正常工作,必須要讓客戶端(APP 或瀏覽器)主動信任 mitmproxy 的 SSL 證書,或忽略證書異常,這也就意味着 APP 或瀏覽器是屬於開發者本人的——顯而易見,這不是在做黑產,而是在做開發或測試。

那這樣的工具有什么實際意義呢?據我所知目前比較廣泛的應用是做仿真爬蟲,即利用手機模擬器、無頭瀏覽器來爬取 APP 或網站的數據,mitmpproxy 作為代理可以攔截、存儲爬蟲獲取到的數據,或修改數據調整爬蟲的行為。

事實上,以上說的僅是 mitmproxy 以正向代理模式工作的情況,通過調整配置,mitmproxy 還可以作為透明代理、反向代理、上游代理、SOCKS 代理等,但這些工作模式針對 mitmproxy 來說似乎不大常用,故本文僅討論正向代理模式。

“安裝 mitmproxy”這句話是有歧義的,既可以指“安裝 mitmproxy 工具”,也可以指“安裝 python 的 mitmproxy 包”,注意后者是包含前者的。

如果只是拿 mitmproxy 做一個替代 fiddler 的工具,沒有什么定制化的需求,那完全只需要“安裝 mitmproxy 工具”即可,去 mitmproxy 官網 上下載一個 installer 便可開箱即用,不需要提前准備好 python 開發環境。但顯然,這不是這里要討論的,我們需要的是“安裝 python 的 mitmproxy 包”。

2.1.1、啟動

要啟動 mitmproxy 用 mitmproxymitmdumpmitmweb 這三個命令中的任意一個即可,這三個命令功能一致,且都可以加載自定義腳本,唯一的區別是交互界面的不同。

mitmproxy 命令啟動后,會提供一個命令行界面,用戶可以實時看到發生的請求,並通過命令過濾請求,查看請求數據。形如:

img

mitmweb 命令啟動后,會提供一個 web 界面,用戶可以實時看到發生的請求,並通過 GUI 交互來過濾請求,查看請求數據。形如:

img

mitmdump 命令啟動后——你應該猜到了,沒有界面,程序默默運行,所以 mitmdump 無法提供過濾請求、查看數據的功能,只能結合自定義腳本,默默工作。

由於 mitmproxy 命令的交互操作稍顯繁雜且不支持 windows 系統,而我們主要的使用方式又是載入自定義腳本,並不需要交互,所以原則上說只需要 mitmdump 即可,但考慮到有交互界面可以更方便排查錯誤,所以這里以 mitmweb 命令為例。實際使用中可以根據情況選擇任何一個命令。

啟動 mitmproxy:

mitmweb
  • 1

應當看到如下輸出:

Web server listening at http://127.0.0.1:8081/
Proxy server listening at http://*:8080

  • 1
  • 2
  • 3

mitmproxy 綁定了 *:8080 作為代理端口,並提供了一個 web 交互界面在 127.0.0.1:8081

現在可以測試一下代理,讓 Chrome 以 mitmproxy 為代理並忽略證書錯誤。為了不影響平時正常使用,我們不去改 Chrome 的配置,而是通過命令行帶參數起一個 Chrome。如果你不使用 Chrome 而是其他瀏覽器,也可以搜一下對應的啟動參數是什么,應該不會有什么坑。此外示例僅以 windows 系統為例,因為使用 linux 或 mac 開發的同學應該更熟悉命令行的使用才對,應當能自行推導出在各自環境中對應的操作。

由於 Chrome 要開始赴湯蹈火走代理了,為了方便繼續在 web 界面上與 mitmproxy 交互,我們委屈求全使用 Edge 或其他瀏覽器打開 127.0.0.1:8081。插一句,我用 Edge 實在是因為機器上沒其他瀏覽器了(IE 不算),Edge 有一個默認禁止訪問回環地址的狗屁設定,詳見解決方案

接下來關閉所有 Chrome 窗口,否則命令行啟動時的附加參數將失效。打開 cmd,執行:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --proxy-server=127.0.0.1:8080 --ignore-certificate-errors

  • 1
  • 2

前面那一長串是 Chrome 的的安裝路徑,應當根據系統實際情況修改,后面兩參數設置了代理地址並強制忽略掉證書錯誤。用 Chrome 打開一個網站,可以看到:

img

同時在 Edge 上可以看到:

img

2.1.2、腳本

完成了上述工作,我們已經具備了操作 mitmproxy 的基本能力 了。接下來開始開發自定義腳本,這才是 mitmproxy 真正強大的地方。

腳本的編寫需要遵循 mitmproxy 規定的套路,這樣的套路有兩個。

第一個是,編寫一個 py 文件供 mitmproxy 加載,文件中定義了若干函數,這些函數實現了某些 mitmproxy 提供的事件,mitmproxy 會在某個事件發生時調用對應的函數,形如:

import mitmproxy.http
from mitmproxy import ctx

num = 0


def request(flow: mitmproxy.http.HTTPFlow):
    global num
    num = num + 1
    ctx.log.info("We've seen %d flows" % num)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

第二個是,編寫一個 py 文件供 mitmproxy 加載,文件定義了變量 addons,addons 是個數組,每個元素是一個類實例,這些類有若干方法,這些方法實現了某些 mitmproxy 提供的事件,mitmproxy 會在某個事件發生時調用對應的方法。這些類,稱為一個個 addon,比如一個叫 Counter 的 addon:

import mitmproxy.http
from mitmproxy import ctx


class Counter:
    def __init__(self):
        self.num = 0

    def request(self, flow: mitmproxy.http.HTTPFlow):
        self.num = self.num + 1
        ctx.log.info("We've seen %d flows" % self.num)


addons = [
    Counter()
]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

這里強烈建議使用第二種套路,直覺上就會感覺第二種套路更為先進,使用會更方便也更容易管理和拓展。況且這也是官方內置的一些 addon 的實現方式。

我們將上面第二種套路的示例代碼存為 addons.py,再重新啟動 mitmproxy:

mitmweb -s addons.py

  • 1
  • 2

當瀏覽器使用代理進行訪問時,就應該能看到控制台里有類似這樣的日志:

Web server listening at http://127.0.0.1:8081/
Loading script addons.py
Proxy server listening at http://*:8080
We've seen 1 flows
……
……
We've seen 2 flows
……
We've seen 3 flows
……
We've seen 4 flows
……
……
We've seen 5 flows
……

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

這就說明自定義腳本生效了。

2.1.3、事件

上述的腳本估計不用我解釋相信大家也看明白了,就是當 request 發生時,計數器加一,並打印日志。這里對應的是 request 事件,那攏共有哪些事件呢?不多,也不少,這里詳細介紹一下。

事件針對不同生命周期分為 5 類。“生命周期”這里指在哪一個層面看待事件,舉例來說,同樣是一次 web 請求,我可以理解為“HTTP 請求 -> HTTP 響應”的過程,也可以理解為“TCP 連接 -> TCP 通信 -> TCP 斷開”的過程。那么,如果我想拒絕來個某個 IP 的客戶端請求,應當注冊函數到針對 TCP 生命周期 的 tcp_start 事件,又或者,我想阻斷對某個特定域名的請求時,則應當注冊函數到針對 HTTP 聲明周期的 http_connect 事件。其他情況同理。

下面一段估計會又臭又長,如果你沒有耐心看完,那至少看掉針對 HTTP 生命周期的事件,然后跳到示例

2.1.3.1、 針對 HTTP 生命周期
def http_connect(self, flow: mitmproxy.http.HTTPFlow): 
  • 1
  • 2

(Called when) 收到了來自客戶端的 HTTP CONNECT 請求。在 flow 上設置非 2xx 響應將返回該響應並斷開連接。CONNECT 不是常用的 HTTP 請求方法,目的是與服務器建立代理連接,僅是 client 與 proxy 的之間的交流,所以 CONNECT 請求不會觸發 request、response 等其他常規的 HTTP 事件。

def requestheaders(self, flow: mitmproxy.http.HTTPFlow): 
  • 1
  • 2

(Called when) 來自客戶端的 HTTP 請求的頭部被成功讀取。此時 flow 中的 request 的 body 是空的。

def request(self, flow: mitmproxy.http.HTTPFlow):

  • 1
  • 2

(Called when) 來自客戶端的 HTTP 請求被成功完整讀取。

def responseheaders(self, flow: mitmproxy.http.HTTPFlow):

  • 1
  • 2

(Called when) 來自服務端的 HTTP 響應的頭部被成功讀取。此時 flow 中的 response 的 body 是空的。

def response(self, flow: mitmproxy.http.HTTPFlow):

  • 1
  • 2

(Called when) 來自服務端端的 HTTP 響應被成功完整讀取。

def error(self, flow: mitmproxy.http.HTTPFlow):

  • 1
  • 2

(Called when) 發生了一個 HTTP 錯誤。比如無效的服務端響應、連接斷開等。注意與“有效的 HTTP 錯誤返回”不是一回事,后者是一個正確的服務端響應,只是 HTTP code 表示錯誤而已。

2.1.3.2、 針對 TCP 生命周期
def tcp_start(self, flow: mitmproxy.tcp.TCPFlow):

  • 1
  • 2

(Called when) 建立了一個 TCP 連接。

def tcp_message(self, flow: mitmproxy.tcp.TCPFlow):

  • 1
  • 2

(Called when) TCP 連接收到了一條消息,最近一條消息存於 flow.messages[-1]。消息是可修改的。

def tcp_error(self, flow: mitmproxy.tcp.TCPFlow):

  • 1
  • 2

(Called when) 發生了 TCP 錯誤。

def tcp_end(self, flow: mitmproxy.tcp.TCPFlow):

  • 1
  • 2

(Called when) TCP 連接關閉。

2.1.3.3、 針對 Websocket 生命周期
def websocket_handshake(self, flow: mitmproxy.http.HTTPFlow):

  • 1
  • 2

(Called when) 客戶端試圖建立一個 websocket 連接。可以通過控制 HTTP 頭部中針對 websocket 的條目來改變握手行為。flow 的 request 屬性保證是非空的的。

def websocket_start(self, flow: mitmproxy.websocket.WebSocketFlow):

  • 1
  • 2

(Called when) 建立了一個 websocket 連接。

def websocket_message(self, flow: mitmproxy.websocket.WebSocketFlow):

  • 1
  • 2

(Called when) 收到一條來自客戶端或服務端的 websocket 消息。最近一條消息存於 flow.messages[-1]。消息是可修改的。目前有兩種消息類型,對應 BINARY 類型的 frame 或 TEXT 類型的 frame。

def websocket_error(self, flow: mitmproxy.websocket.WebSocketFlow):

  • 1
  • 2

(Called when) 發生了 websocket 錯誤。

def websocket_end(self, flow: mitmproxy.websocket.WebSocketFlow):

  • 1
  • 2

(Called when) websocket 連接關閉。

2.1.3.4、 針對網絡連接生命周期
def clientconnect(self, layer: mitmproxy.proxy.protocol.Layer):

  • 1
  • 2

(Called when) 客戶端連接到了 mitmproxy。注意一條連接可能對應多個 HTTP 請求。

def clientdisconnect(self, layer: mitmproxy.proxy.protocol.Layer):

  • 1
  • 2

(Called when) 客戶端斷開了和 mitmproxy 的連接。

def serverconnect(self, conn: mitmproxy.connections.ServerConnection):

  • 1
  • 2

(Called when) mitmproxy 連接到了服務端。注意一條連接可能對應多個 HTTP 請求。

def serverdisconnect(self, conn: mitmproxy.connections.ServerConnection):

  • 1
  • 2

(Called when) mitmproxy 斷開了和服務端的連接。

def next_layer(self, layer: mitmproxy.proxy.protocol.Layer):

  • 1
  • 2

(Called when) 網絡 layer 發生切換。你可以通過返回一個新的 layer 對象來改變將被使用的 layer。詳見 layer 的定義

2.1.3.5、 通用生命周期
def configure(self, updated: typing.Set[str]):

  • 1
  • 2

(Called when) 配置發生變化。updated 參數是一個類似集合的對象,包含了所有變化了的選項。在 mitmproxy 啟動時,該事件也會觸發,且 updated 包含所有選項。

def done(self):

  • 1
  • 2

(Called when) addon 關閉或被移除,又或者 mitmproxy 本身關閉。由於會先等事件循環終止后再觸發該事件,所以這是一個 addon 可以看見的最后一個事件。由於此時 log 也已經關閉,所以此時調用 log 函數沒有任何輸出。

def load(self, entry: mitmproxy.addonmanager.Loader):

  • 1
  • 2

(Called when) addon 第一次加載時。entry 參數是一個 Loader 對象,包含有添加選項、命令的方法。這里是 addon 配置它自己的地方。

def log(self, entry: mitmproxy.log.LogEntry):

  • 1
  • 2

(Called when) 通過 mitmproxy.ctx.log 產生了一條新日志。小心不要在這個事件內打日志,否則會造成死循環。

def running(self):

  • 1
  • 2

(Called when) mitmproxy 完全啟動並開始運行。此時,mitmproxy 已經綁定了端口,所有的 addon 都被加載了。

def update(self, flows: typing.Sequence[mitmproxy.flow.Flow]):

  • 1
  • 2

(alled when) 一個或多個 flow 對象被修改了,通常是來自一個不同的 addon。

2.1.3.6、示例

估計看了那么多的事件你已經暈了,正常,鬼才會記得那么多事件。事實上考慮到 mitmproxy 的實際使用場景,大多數情況下我們只會用到針對 HTTP 生命周期的幾個事件。再精簡一點,甚至只需要用到 http_connectrequestresponse 三個事件就能完成大多數需求了。

這里以一個稍微有點黑色幽默的例子,覆蓋這三個事件,展示如果利用 mitmproxy 工作。

需求是這樣的:

  1. 因為百度搜索是不靠譜的,所有當客戶端發起百度搜索時,記錄下用戶的搜索詞,再修改請求,將搜索詞改為“360 搜索”;
  2. 因為 360 搜索還是不靠譜的,所有當客戶端訪問 360 搜索時,將頁面中所有“搜索”字樣改為“請使用谷歌”。
  3. 因為谷歌是個不存在的網站,所有就不要浪費時間去嘗試連接服務端了,所有當發現客戶端試圖訪問谷歌時,直接斷開連接。
  4. 將上述功能組裝成名為 Joker 的 addon,並保留之前展示名為 Counter 的 addon,都加載進 mitmproxy。

第一個需求需要篡改客戶端請求,所以實現一個 request 事件:

def request(self, flow: mitmproxy.http.HTTPFlow):
    # 忽略非百度搜索地址
    if flow.request.host != "www.baidu.com" or not flow.request.path.startswith("/s"):
        return

    # 確認請求參數中有搜索詞
    if "wd" not in flow.request.query.keys():
        ctx.log.warn("can not get search word from %s" % flow.request.pretty_url)
        return

    # 輸出原始的搜索詞
    ctx.log.info("catch search word: %s" % flow.request.query.get("wd"))
    # 替換搜索詞為“360搜索”
    flow.request.query.set_all("wd", ["360搜索"])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

第二個需求需要篡改服務端響應,所以實現一個 response 事件:

def response(self, flow: mitmproxy.http.HTTPFlow):
    # 忽略非 360 搜索地址
    if flow.request.host != "www.so.com":
        return

    # 將響應中所有“搜索”替換為“請使用谷歌”
    text = flow.response.get_text()
    text = text.replace("搜索", "請使用谷歌")
    flow.response.set_text(text) 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

第三個需求需要拒絕客戶端請求,所以實現一個 http_connect 事件:

def http_connect(self, flow: mitmproxy.http.HTTPFlow):
    # 確認客戶端是想訪問 www.google.com
    if flow.request.host == "www.google.com":
        # 返回一個非 2xx 響應斷開連接
        flow.response = http.HTTPResponse.make(404)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

為了實現第四個需求,我們需要將代碼整理一下,即易於管理也易於查看。

創建一個 joker.py 文件,內容為:

import mitmproxy.http
from mitmproxy import ctx, http


class Joker:
    def request(self, flow: mitmproxy.http.HTTPFlow):
        if flow.request.host != "www.baidu.com" or not flow.request.path.startswith("/s"):
            return

        if "wd" not in flow.request.query.keys():
            ctx.log.warn("can not get search word from %s" % flow.request.pretty_url)
            return

        ctx.log.info("catch search word: %s" % flow.request.query.get("wd"))
        flow.request.query.set_all("wd", ["360搜索"])

    def response(self, flow: mitmproxy.http.HTTPFlow):
        if flow.request.host != "www.so.com":
            return

        text = flow.response.get_text()
        text = text.replace("搜索", "請使用谷歌")
        flow.response.set_text(text)

    def http_connect(self, flow: mitmproxy.http.HTTPFlow):
        if flow.request.host == "www.google.com":
            flow.response = http.HTTPResponse.make(404)

  • 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

創建一個 counter.py 文件,內容為:

import mitmproxy.http
from mitmproxy import ctx


class Counter:
    def __init__(self):
        self.num = 0

    def request(self, flow: mitmproxy.http.HTTPFlow):
        self.num = self.num + 1
        ctx.log.info("We've seen %d flows" % self.num)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

創建一個 addons.py 文件,內容為:

import counter
import joker

addons = [
    counter.Counter(),
    joker.Joker(),
]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

將三個文件放在相同的文件夾,在該文件夾內啟動命令行,運行:

mitmweb -s addons.py

  • 1
  • 2

老規矩,關閉所有 Chrome 窗口,從命令行中啟動 Chrome 並指定代理且忽略證書錯誤。

測試一下運行效果:

img

img

img


2.2、Appnium

2.2.1、啟動APP

2.2.1.1、獲取apk包名

  1. 將准備測試的APK放到D盤某個目錄,如D:\test
  2. 打開cmd,輸入指令aapt dump badging D:\test\xxx.apk(APK的全名,如手機淘寶.apk)
  3. 以手機淘寶.apk為例,如下圖
  4. 這里就可以看到apk的包名:com.taobao.taobao

img

注:老司機可以直接把apk放在桌面上,輸入指令后拖到cmd框

2.2.1.2、獲取launcherActivity

​ 1.接着上一步操作,cmd屏幕拖到中間l找到auncherActivity

​ 2.這里可以看到,淘寶的launcherActivity值為com.taobao.tao.welcome.Welcome

img

2.2.1.3、寫腳本

  1. platformName:這里是android的apk
  2. deviceName:手機設備名稱,通過adb devices查看
  3. platformVersion:android系統的版本號
  4. appPackage:apk包名
  5. appActivity:apk的launcherActivity

img

2.2.1.4、運行appium

​ 1.啟動appium,右上角點三角形按鈕,變成正方形,就是啟動狀態。

img

​ 2.確認手機連上電腦

img

​ 3.在pycharm運行腳本,隨后在手機上會彈出安裝下面兩個軟件的提示,安裝后,桌面上多兩個圖標。那么恭喜你啟動成功!

img

​ 4.接着會看到淘寶app已經啟動啦,有木有小激動~~

2.2.1.5、代碼

# coding=utf-8 from appium import webdriver desired_caps = { 'platformName': 'Android', 'deviceName': '30d4e606', 'platformVersion': '5.0', # apk包名 'appPackage': 'com.taobao.taobao', # apk的launcherActivity 'appActivity': 'com.taobao.tao.welcome.Welcome' } driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

這個地址是怎么來的呢?

img

2.2.2、定位元素

uiautomatorviewer是android-sdk自帶的一個元素定位工具,非常簡單好用,使用uiautomatorviewer,你可以檢查一個應用的UI來查看應用的布局和組件以及相關的屬性。

2.2.2.1、啟動uiautomatorviewer.bat

​ 1.打開目錄D:\androidsdk\android-sdk-windows\tools

img

​ 2.雙擊啟動,啟動之后出現如下界面

img

​ 3如果不喜歡雙擊啟動的話,也可以在cmd里面通過指令啟動,先cd到tools目錄下,然后輸入uiautomatorviewer.bat回車后啟動服務

img

2.2.2.2、連接模擬器

​ 1.cmd打開輸入adb devices,確認模擬器已連上

​ 2.打開手機淘寶頁面,讓屏幕處於點亮狀態

​ 3.點左上角安卓機器人按鈕Devices Screenshot按鈕刷新頁面

img

2.2.2.3、定位元素

​ 1.移動鼠標到需要定位的元素上,如搜索輸入框

img

2.右下角可以看到元素對應的屬性

text:搭配新寵不能缺
resource-id:com.taobao.taobao:id/home_searchedit
class:android.widget.EditText

  • 1
  • 2
  • 3
  • 4

2.2.2.4、點搜索框

​ 1.前面一篇啟動app后,休眠五秒,等待頁面加載完成

​ 2.通過id來定位到搜索框,然后點擊

img

2.2.2.5、代碼

\

# coding=utf-8 from appium import webdriver import time desired_caps = { 'platformName': 'Android', 'deviceName': '30d4e606', 'platformVersion': '5.0', 'appPackage': 'com.taobao.taobao', 'appActivity': 'com.taobao.tao.welcome.Welcome', } driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) # 休眠五秒等待頁面加載完成 time.sleep(5) driver.find_element_by_id("com.taobao.taobao:id/home_searchedit").click() 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2.2.2.6、元素定位

​ appium的webdriver提供了11種元素定位方法,在selenium的基礎上擴展了三個,可以在pycharm里面輸入driver.find_element_by然后會自動匹配出來

img


3、Demo

抓取得到APP數據

首先通過Fiddler抓包分析想要的數據在說明url的請求中:

可以發現數據在請求https://entree.igetget.com/bauhinia/h5/college/course中

在這里插入圖片描述

記住該信息方便下面進行代碼編撰。

3.1、環境說明

本機IP:
在這里插入圖片描述

夜神模擬器代理配置:

在這里插入圖片描述

查看APK信息

在這里插入圖片描述

在這里插入圖片描述

確認模擬器連接電腦

3.2、代碼

joker.py

import json import mitmproxy.http class Joker: #針對響應動作抓包 def response(self, flow: mitmproxy.http.HTTPFlow): #過濾所有響應,只針對存在想要數據的url響應進行解析 if flow.request.url == 'https://entree.igetget.com/bauhinia/h5/college/course': # ctx.log.info(str(type(flow.request.data.content))) res = flow.response.text #獲取響應內容 parse(res) #調用解析函數 #解析函數 def parse(text): res = json.loads(text).get('c').get('list') for i in res: result = {} teacher_list = [] teacher_dict = {} result['name'] = i.get('name') teacher_dict['name'] = i.get('lecturer_name') teacher_dict['indtoduce'] = i.get('lecturer_title') teacher_list.append(teacher_dict) result['teacher'] = teacher_list result['introduce'] = i.get('highlight') result['price'] = str(int(i.get('price'))/100) result['period'] = i.get('phase_num') with open('test.json', 'a+', encoding='utf8') as f: json.dump(result, f, indent=4, ensure_ascii=False) f.write('\n\n') 
  • 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

addon.py

import joker addons = [ joker.Joker(), ] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

app_contorl.py

import time from appium import webdriver class AppConn: def __init__(self): self.desired_caps = { 'platformName': 'Android', #系統名 'deviceName': '127.0.0.1:62001', #設備名 通過adb devices查看 'platformVersion': '5.0', #android系統的版本號 'appPackage': 'com.luojilab.player', #apk包名 'appActivity': 'com.luojilab.business.welcome.SplashActivity' #apk的launcherActivity } self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', self.desired_caps) #點擊事件,選取指定的元素進行點擊 def click(self, college): time.sleep(5) self.driver.find_element_by_id('com.luojilab.player:id/classImageView').click() time.sleep(1) # a = self.driver.find_element_by_xpath('//android.widget.TextView[@text="%s"]'%college).click() # print(a) #滑動事件,滑動屏幕刷新儲更多的數據 def move(self, num): l = (self.driver.get_window_size()['width'], self.driver.get_window_size()['height']) x1 = int(l[0] * 0.5) # x坐標 y1 = int(l[1] * 0.25) # 起始y坐標 y2 = int(l[1] * 0.75) for i in range(num): self.driver.swipe(x1, y2, x1, y1, 1000) time.sleep(0.2) if __name__ == '__main__': test = AppConn() # college_list = ['商學院25', '能力學院60', '人文學院', '視野學院', '商學院'] test.click('商學院25') test.move(10) 
  • 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

3.3、啟動命令

  1. cmd啟動mimtproxy

在這里插入圖片描述

mitmweb --web-port 8889 -p 8888 -s addons.py

  • 1
  • 2
  1. 啟動Appnium

在這里插入圖片描述

  1. 執行app_control.py

  2. APPnium開始操作apk

在這里插入圖片描述

  1. 抓包處理數據並保存

在這里插入圖片描述

以上大部分內容皆整理於以下鏈接

參考鏈接

https://cnblogs.com/yoyoketang/p/6128725.html
https://www.cnblogs.com/yoyoketang/p/6128730.html
https://www.cnblogs.com/yoyoketang/p/6128735.html
https://www.cnblogs.com/yoyoketang/p/6128741.html
https://cnblogs.com/grandlulu/p/9525417.html
https://jingyan.baidu.com/article/cb5d6105a3365f005c2fe0f7.html
https://blog.csdn.net/weixin_36662706/article/details/81042352


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM