android 使用socket完成進程間通信

近來反編譯看一些android應用,特別是涉及到底層的功能性的應用,比如遊戲加速,修改內存,掛機腳本神馬的,發現裏面的通信機制無一例外的都是使用的socket,基本上已經成爲這類應用的一種標配了。


因爲這類應用有以下的幾個共同點:


1 需要android 手機的root權限,畢竟要修改一些比較底層的東西,沒有root權限有時候木有辦法修改啊


2 有自己的so,同時比較重要的或者比較吃力的活都編譯成一個可執行的elf文件,然後讓apk應用給這個elf文件給啓動起來。關於這個elf文件放置的位置也有幾種選擇。


情況1:直接放在應用包下面的lib目錄下,然後給這個可執行文件賦予一個可執行的權限。

情況2:放在assets文件夾下面,在程序啓動的時候拷貝到files文件夾下面,賦予可執行的權限後,然後執行

情況3:也是放在assets文件夾下面,只不過安全性高一點,一般會做一個簡單的異或或者移位加密,然後修改以下擴展名,拷貝過去的時候減密一下。再執行,有時候執行了以後會把真正的elf文件再給刪除了。



3 可執行的so文件和java應用程序之間的通信使用socket,因爲畢竟可執行的so纔是真正幹活的主力,而java應用程序要給so發送指令,而so也要給java應用程序反饋一些有用的數據供上層顯示給用戶。關於socket通信的方式也有下面的幾種情況


情況1: 可執行的so作爲server端,java應用程序給其發送指令的時候主動去鏈接可執行so,發送數據,有時候so也會返回一些數據,一般這種情況so就直接把活給幹了,比如遊戲加減速。

情況2:可執行的so文件作爲客戶端,同時使用長鏈接的方式,這種情況就需要java應用程序作爲server端了,這裏的稍微巧妙一點的是不採用固定的socket的端口號,而是java應用程序在創建socket的時候使用系統自動分配的端口號。不過需要通過java應用程序在啓動可執行so的時候將端口號傳遞給so文件。



原理基本上就這麼多了,下面的是一個例子,這個例子涉及到的編程技術主要是java應用程序自己創建socket的客戶端和服務器端,然後進行通信,同時也啓動了一個so的可執行文件,通過進程之間的數據流,向可執行的so發送數據,可執行的so將接收到的數據通過log給打印出來。




進入demo例子,


點擊啓動 socket server



這個時候log會打印出來


11-04 15:56:28.341:V/cheatecore-server(5774): server port = 44034

這樣的數據,

由於serverSocket = new ServerSocket(m_port);

其中 m_port 0,所以端口號是系統臨時分配的。


然後socketserver 就開始等待有客戶端的socket 來鏈接

m_socket = serverSocket.accept();

其中 accept 是阻塞函數,會將這個線程阻塞掉的。這個時候


通過 adb shell 進入android手機,使用 netstat –an | busybox grep 44034 查看,發現是這樣的現象


spacer.gif162506902.jpg


顯然這個端口是 listen 狀態



然後點擊設置客戶端socket端口號和啓動客戶端socket


11-04 16:03:11.067: V/cheatecore(5774): 獲取服務器端的端口號:44034

11-04 16:03:15.575:V/cheatecore-client(5774): client socket begin

11-04 16:03:15.575:V/cheatecore-server(5774): a client socket come here!!!


這個時候出現了a client socket comehere!!!

這條log再次執行剛纔的

netstat –an | busybox grep 44034

發現已經變成如下的結果了

162556762.png


已經有隨機分配的客戶端端口號跟server端建立了鏈接了


然後再點擊獲取數據流


reader = new BufferedReader(inputreader);

serveroutwriter = new PrintWriter(newBufferedWriter(new OutputStreamWriter(sk.getOutputStream())),true);


主要獲取socket的輸入流和輸出流,也就是客戶端和服務端的tcp鏈接已經建立起來了,剩下的就是通過流來接收和發送數據了


接着點擊

啓動服務器socket 接收數據線程


String sReader = reader.readLine();

這條語句就在等着客戶端的socket數據過來呢,其中readLine是一個阻塞函數,熟悉c語言的同學,其實這個就是socket 中的 recv函數,阻塞調用了。


因爲tcp是全雙工的,並且當前狀態是長鏈接,所以服務端可以向客戶端發送數據,客戶端也可以向服務端發送數據,下一個按鈕


服務器端socket發送數據


11-04 16:11:19.810: V/cheatecore-client(5774):客戶端接收到服務端的數據:server data

11-04 16:11:19.810:V/cheatecore-server(5774): 服務端接收到客戶端的數據:clientdata


這個時候出現的log,客戶端在收到服務器的數據以後,也會向服務器端再返回數據,這樣就完成了一次交互,但是其實這個時候socket並沒有斷掉,因爲是長鏈接,可以進行多次發送


最後結束socket


關閉了socket,這個時候再用 netstat –an | busybox grep 44034

這個指令來進行查詢,發現如下圖:

162636442.png


剛纔建立的socket已經釋放了,再過一會查詢wait超時後也會將端口釋放掉了



測試向啓動的進程發送數據


11-04 16:15:11.278: E/cheatecore(6163):input target main function!!!!

11-04 16:15:11.278: E/cheatecore(6163):scanf input content is 44034



主要過程是首先啓動


/data/data/com.example.sockettest/files/target

這個程序


testprocee =Runtime.getRuntime().exec(cmd);

     PrintWriterpoutwriter = newPrintWriter(newBufferedWriter(newOutputStreamWriter(testprocee.getOutputStream())),true);      

     poutwriter.println(test);


然後發送數據,完成了這次進程間數據的交互,其實這也是進程之間通信的一種方式,和利用socket完成進程之間的通信並列的。


例子見下面


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章