####
模擬器的安裝和使用
1,本來是想在mac上使用mumu模擬器,但是安裝Xposed一直失敗,
2,我嘗試使用真機來進行脫殼,但是Xposed可以安裝,
電腦adb連接真機的方法:
首先真機打開開發者模式,進入設置,打開關於手機,找到版本號,一直點擊版本號,在點擊過程中會提示“還有×次,直到打開“開發人員選項”。並且打開usb調試開關,這樣adb就能看到設備了
然后使用adb命令,在真機安裝fdex2,命令,adb install fdex2.apk
然后進入真機的Xposed,這個app里面--進入模塊,-點擊fdex2,激活一下,
但是fdex2不支持安卓8,氣人!我又不想對這個真機刷機,
3,我嘗試在mac上面安裝一個虛擬機,運行win10系統,在上面裝一個雷電或者夜神模擬器,但是安裝上之后非常的慢,根本無法使用,
4,我最后使用了genymotion
這個模擬器,適合開發者使用的一款比較快的Android模擬器,這個比那些夜神模擬器,要好,因為那些模擬器開發出來主要是為了玩游戲的,
第一步,VirtualBox的安裝,Genymotion的運行需要依賴獄VirtualBox,所以需要先安裝VirtualBox。
第二步,Genymotion的安裝,到官網下載https://www.genymotion.com/download/,這個模擬器能再Linux-Ubuntu,mac,還有Windows,都可以安裝使用,很強大,
第三步,創建Android模擬器,點擊上面的加號Add,彈出一個創建模擬器的窗口。 按下圖中的步驟創建一個GoogleNexus5 -6.0.0-API123模擬器。安裝速度可能會有點稍慢。耐心等待下就好。
下載安裝完成后就會在Genymotion主界面看到剛創建好的Android模擬器。點擊start就可以運行這個模擬器了,
我下載的是Google nexus6p手機,安卓6.0版本,
5,當然如果有app開發能力,最好使用Android studio 自帶的模擬器,更好
#####
Xposed的安裝和脫殼使用
1,在genymotion安裝了Xposed,
2,安裝了fdex2,使用這個工具要先安裝Xposed,這兩個都是apk,
3,進入Xposed,這個app里面--點擊左上角,進入模塊,-點擊fdex2,激活一下,

打鈎說明這個fdex2,激活了,
4,使用fdex2,這個工具脫殼,
點擊這個fdex2,進入這個apk里面,里面會列出你安裝的所有app,

然后點擊其中一個你要脫殼的app,提示了dex的輸出目錄,還有就是需要再次打開app,

5,再次打開app,使用adb,進入dex輸出目錄,看看是否是脫殼出來了,
adb devices,查看一下模擬器目錄,如果沒有看到嘗試adb kill-server ,adb start-server,重新啟動一下adb,
adb shell,進入這個模擬器里面,
cd /data/user/0/com.iCitySuzhou.suzhou001,進入這個目錄就可以看到dex文件,如果沒有就卸載app,安裝app,但是不要打開這個app,再重新脫殼一次試試,
adb pull /data/user/0/com.iCitySuzhou.suzhou001 /Users/liqian/Desktop 把這個從模擬器里面pull出來到電腦桌面,
把apk脫殼之后,就會有導出的dex文件,會有好幾個dex文件,
然后使用jadx,打開就是源代碼了,怎么確定是哪一個dex文件,每一個都打開,搜索MyApplication,看看有沒有這個文件, 有就對了

因為這個myapplication是不能被混淆的,要用這個名字做事情的,
大部分都可以使用這個工具脫殼,
使用,jadx-gui,打開這個jadx工具,打開脫殼的dex文件, 看到源碼,
至此,整個的脫殼就完成了,
下一步就是開始分析這個脫殼之后的源碼了,我們可以看到代碼是被混淆的,下一步更重要的是看懂代碼,
是不是很簡單,那意義在哪里?方法雖然簡單,但是你要知道這種方法並不是100%能把一個app脫殼出來,還需要其他更高級的脫殼手段,
這個工具還是要掌握的,因為這個工具可以把大部分的app都脫殼,
#####
實戰:我們把引力播app,里面的新聞抓取下來,
安卓逆向第一步:app抓包
首先是要抓包,
使用Charles,進行app抓包,具體的抓包設置網絡上都有,
主要的一步是在手機的wifi上面進行設置代理ip和端口,https://www.cnblogs.com/andy0816/p/15146008.html

抓包之后,我們可以發現這個接口里面有一個signature是變化的,
這個字段就是訪問api的加密字段,
有的app,接口調用的時候,有一個參數sign,要攜帶上請求接口才行,這個是變動的,你不知道,所以就不能調用通接口,
可以通過重放來確定這個參數是不是動態的,
下一步就是找到這個signature,然后看他怎么加密的,然后攜帶上這個signature,才可以請求這個api,
安卓逆向第二步:找到接口參數加密的地方,逆向出來
我們多抓幾次包,就會發現這個signature是每次變化的,另外就是每一個接口都有這個signature,
所以我們判斷這個是一個公共的部分定義了這個signature,
怎么辦?
你需要找到app里面哪里生成的這個sign,是怎么生成的,然后你自己用python寫出來,然后攜帶請求接口就行了,
怎么着這個生成的地方?
我們發現每一個接口都有這個signature,所以應該是一個功能的地方生成的,
第一步,先用jadx打開dex文件,先搜索試試
在源代碼里面搜索這個關鍵詞signature,找到對應的代碼,可能會有很多的結果,耐心找找

這里面有很多,需要你去分辨,左右是對應的,可以打開文件看,
每一個都看一下,就會給你更多的啟發,

這一行就會給我們啟發,因為我們請求接口的時候,也有這個字段,

我們雙擊進入,看就是這個文件,

找到之后可能是混淆過的,可以用工具做反混淆,使用的是jadx-工具里面的一個反混淆,

這樣反混淆之后再去查看源代碼,這個反混淆不是徹底的,只是把一個名字變成唯一的, 否則你搜索一個a,b,c,會有幾千個出來,

找到一個方法實現的地方,可以右鍵

###
你找到了加密生成的代碼之后,你還需要看懂,所以你還是需要java的功底的

這就是生成signature的地方,
但是你看不懂怎么辦,可以打包成為一個java文件,讓python調用,具體怎么實現呢?
####
安卓逆向第三步:怎么把java代碼打包,讓python調用?

第一點,你要安裝java環境,
第二點,制作java文件,
這個是java加密參數的源碼:

####
網上有在線的java執行工具,可以把這段java代碼拿出來,然后去執行一下,方便調試java代碼,https://tool.lu/coderunner/
import java.security.MessageDigest; /* renamed from: com.hualong.framework.b.a */ public class MySig { /* renamed from: a */ public static String get_sig(String str) { if (str == null) { return null; } StringBuffer stringBuffer = new StringBuffer(); try { MessageDigest instance = MessageDigest.getInstance("MD5"); instance.update(str.getBytes()); byte[] digest = instance.digest(); for (byte b : digest) { stringBuffer.append(Integer.toString((b >>> 4) & 15, 16)).append(Integer.toString(b & 15, 16)); } } catch (Exception e) { } return stringBuffer.toString(); } // public static void main(String args[]){ // System.out.println("hello world"); // } }
把文件編譯成為class文件,通過命令,javac xxx.java,
###
第三步,把class文件打包成jar包,通過命令,jar cvf xxx.jar
第四步,通過jpype 這個python的第三方庫,調用這個jar,就可以實現python調java了,
這個jpype需要安裝一下這個包,pip install jpype1,

###
import jpype import requests import time uuid = "IMEI867686023834169-IMSI460NNNNNNNNNNNN" time = str(int(time.time())) ori_sig = uuid + "&&" + time + "&&" + "f1190aca-d08e-4041-8666-29931cd89dde" # ①、使用jpype開啟虛擬機(在開啟jvm之前要加載類路徑) # 加載剛才打包的jar文件 jarpath = "/Users/liqian/PycharmProjects/spider/java/MySig.jar" # 獲取jvm.dll 的文件路徑 jvmPath = jpype.getDefaultJVMPath() # 開啟jvm jpype.startJVM(jvmPath, "-ea", "-Djava.class.path=%s" % (jarpath)) # ②、加載java類(參數是java的長類名) javaClass = jpype.JClass("MySig") # 實例化java對象 javaInstance = javaClass() encry_sig = javaInstance.get_sig(ori_sig) # java.lang.System.out.println(encry_sig) print(encry_sig) # ③、調用java方法,由於我寫的是靜態方法,直接使用類名就可以調用方法 # javaClass.show() # ④、關閉jvm jpype.shutdownJVM()
###
從jvmpath就是jpype庫的用法了,
startJVM 是開啟一個Java虛擬機,
JClass("MySig"),這是調用一個java方法,
我們可以看到是要傳遞一個字符串進入,這個字符串的格式就是uuid設備id,時間戳,還有一串固定字符串,三部分通過&&組成的,

最終python代碼:
import jpype import requests import time import urllib3 urllib3.disable_warnings() udid = "IMEI867686023834169-IMSI460NNNNNNNNNNNN" time = str(int(time.time())) ori_sig = udid + "&&" + time + "&&" + "f1190aca-d08e-4041-8666-29931cd89dde" # ①、使用jpype開啟虛擬機(在開啟jvm之前要加載類路徑) # 加載剛才打包的jar文件 jarpath = "/Users/liqian/PycharmProjects/spider/java/MySig.jar" # 獲取jvm.dll 的文件路徑 jvmPath = jpype.getDefaultJVMPath() # 開啟jvm jpype.startJVM(jvmPath, "-ea", "-Djava.class.path=%s" % (jarpath)) # ②、加載java類(參數是java的長類名) javaClass = jpype.JClass("MySig") # 實例化java對象 javaInstance = javaClass() encry_sig = javaInstance.get_sig(ori_sig) # java.lang.System.out.println(encry_sig) print(encry_sig) # ③、調用java方法,由於我寫的是靜態方法,直接使用類名就可以調用方法 # javaClass.show() url = "https://app.suzhou-news.cn/api/v1/appNews/getBannerNewsList7?page=1&bannerID=11" headers = { "sys": "Android", "sysversion": "8.1.0", "appversion": "8.2", "appversioncode": "54", "udid": udid, "clienttype": "android", "timestamp": "1632747791", "signature": "850196b383f11879ebb2c232d04d3b47", "accept-encoding": "gzip", "user-agent": "okhttp/3.9.0", "Accept": "*/*", "Postman-Token": "3c95da01-208f-4d15-895d-3a3230654863", "Host": "app.suzhou-news.cn", "Connection": "keep-alive", } # resp = requests.get(url, verify=False) # {"code":3,"message":"請求失敗,缺少必要參數"} resp = requests.get(url, headers=headers,verify=False) print(resp.text) # ④、關閉jvm jpype.shutdownJVM()
這樣用這個python代碼,就可以成功通過接口獲取到數據了,
###
但是這種把java拿過來直接python調用的方法,
不是任何時候都適用的,
因為有時候,這段java代碼可能是有很多的依賴的包,你運行的時候,就會缺少很多的包,
這樣就很麻煩,所以用python調用java的情況,這段代碼最好不要有太多的依賴,
如果加密的程序,依賴別的文件比較少,可以使用這種方法,但是如果太復雜,依賴比較多,這個還是需要自己使用python實現,這個就是比較難的地方,
###
####
