標籤:android busybox traceroute 非root 交叉編譯
作者 : 萬境絕塵
轉載請著名出處 : http://blog.csdn.net/shulianghan/article/details/36438365
範例程式碼下載 :
-- CSDN : http://download.csdn.net/detail/han1202012/7639253;
-- GitHub : https://github.com/han1202012/TracerouteAndBusybox ;
1. 原理思路
檔案許可權修改無法實現 : 如果 沒有 root 許可權, 就不能改變二進位檔案的檔案許可權;
-- 將busybox推送到Android系統中 : 使用 adb push 命令, 將 busybox 傳入到 sd 卡中, 注意, 上傳到記憶體中無法實現;
-- 上傳到sd卡成功 : 使用 adb push 檔案名稱 手機中的檔案全路徑名 命令;
[email protected]:~/csdn$ adb push busybox-armv7l /sdcard/octopus/busybox3256 KB/s (1109128 bytes in 0.332s)
--
上傳到記憶體失敗 : 使用 adb push 上傳到記憶體中失敗, 因為 adb 使用的是 system 使用者, 只有 root 使用者才有許可權向記憶體中寫入資料;
[email protected]:~/csdn$ adb push busybox-armv7l /data/busyboxfailed to copy ‘busybox-armv7l‘ to ‘/data/busybox‘: Permission denied
--
查看並修改busybox許可權失敗 : system 使用者沒有修改 sd 卡檔案模式的許可權;
[email protected]:/sdcard/octopus $ ll -rw-rw-r-- root sdcard_rw 1109128 2014-07-08 19:49 busybox[email protected]:/sdcard/octopus $ chmod 755 busybox Unable to chmod busybox: Operation not permitted
應用程式解決方案 :
-- 應用程式專屬使用者 : Android 作業系統會為每個應用程式設定一個使用者, 這個使用者對其安裝目錄(/data/data/包名/)下的檔案有完整的許可權;
-- 將可執行二進位檔案拷貝到安裝目錄中 : 將交叉編譯好的 busybox 放到 工程目錄下的 res/assets/ 目錄下;
2. 實現策略
檔案初始放置 : 將 交叉編譯好的 busybox 檔案放在 工程目錄的 /res/assets/ 目錄下;
檔案拷貝 : 將該 二進位檔案 拷貝到 app 的安裝目錄的 files 目錄下, 即 /data/data/包名/files/下;
修改檔案許可權 : 使用命令可以直接修改該目錄下的許可權, 注意這個操作是可以執行的;
執行busybox : 在代碼中執行 ./data/data/包名/files/busybox ;
擷取執行結果 :
3. 使用到的api解析
(1) 擷取 assets 目錄檔案的輸入資料流
InputStream is = context.getAssets().open(source);
--
擷取AssetsManager : 調用 Context 內容物件的 context.getAssets() 即可擷取 AssetsManager對象;
-- 擷取輸入資料流 : 調用 AssetsManager 的 open(String fileName) 即可擷取對應檔案名稱的輸入資料流;
(2) 檔案流相關操作
根據輸入資料流擷取檔案大小 : 調用輸入資料流的 inputStream.available() 方法;
int size = is.available();
將檔案讀取到緩衝區中 : 建立一個與檔案大小相同的位元組數組緩衝區, 輸入資料流將資料存放到緩衝區中;
byte[] buffer = new byte[size];is.read(buffer);is.close();
將檔案寫到記憶體中 : 調用內容物件的 openFileOutput(絕對路徑名, 許可權), 即可建立一個檔案的輸出資料流;
FileOutputStream output = context.openFileOutput(destination, Context.MODE_PRIVATE);output.write(buffer);output.close();
(3) 擷取檔案的絕對路徑
擷取app絕對安裝路徑 : 調用 內容物件的 getFilesDir().getAbsolutePath() 方法;
String filesPath = context.getFilesDir().getAbsolutePath();
(4) 執行二進位檔案
建立 Process 對象, 並使用該 process 執行shell指令碼命令 :
Runtime runtime = Runtime.getRuntime();process = runtime.exec(cmd);
擷取執行的命令列結果 :
InputStream is = process.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = null; while ((line = br.readLine()) != null) { processList.add(line); } br.close();
4. 程式碼範例
MainActivity 主程式碼 :
package cn.org.octopus.tracerouteandbusybox;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;import android.content.Context;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.View;import android.widget.EditText;import android.widget.TextView;/** 看不懂注釋我就吃半斤狗糧 :-) */public class MainActivity extends ActionBarActivity {private EditText et_cmd;private String app_path;private TextView tv_result;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.home_activity);/*初始化控制項*/et_cmd = (EditText) findViewById(R.id.et_cmd);tv_result = (TextView) findViewById(R.id.tv_result);/* 擷取app安裝路徑 */app_path = getApplicationContext().getFilesDir().getAbsolutePath();}/** 按鈕點擊事件 */public void onClick(View view) {int id = view.getId();switch (id) {case R.id.copy_busybox: /* 拷貝busybox可執行檔 */varifyFile(getApplicationContext(), "busybox");break;case R.id.copy_traceroute:/* 拷貝traceroute可執行檔 */varifyFile(getApplicationContext(), "traceroute");break;case R.id.exe_busybox:/* 將busybox命令添加到Editext中 */String cmd = "." + app_path + "/busybox";System.out.println(et_cmd);et_cmd.setText(cmd);break;case R.id.exe_traceroute:/* 將traceroute命令添加到Editext中 */cmd = "." + app_path + "/traceroute 8.8.8.8";et_cmd.setText(cmd);break;case R.id.exe: /* 執行Editext中的命令 */cmd = et_cmd.getText().toString();/* 執行指令碼命令 */List<String> results = exe(cmd);String result = "";/* 將結果轉換成字串, 輸出到 TextView中 */for(String line : results){result += line + "\n";}tv_result.setText(result);break;default:break;}}/** 驗證檔案是否存在, 如果不存在就拷貝 */private void varifyFile(Context context, String fileName) { try { /* 查看檔案是否存在, 如果不存在就會走異常中的代碼 */ context.openFileInput(fileName); } catch (FileNotFoundException notfoundE) { try { /* 拷貝檔案到app安裝目錄的files目錄下 */ copyFromAssets(context, fileName, fileName); /* 修改檔案許可權指令碼 */ String script = "chmod 700 " + app_path + "/" + fileName; /* 執行指令碼 */ exe(script); } catch (Exception e) { e.printStackTrace(); } } }/** 將檔案從assets目錄中拷貝到app安裝目錄的files目錄下 */private void copyFromAssets(Context context, String source,String destination) throws IOException {/* 擷取assets目錄下檔案的輸入資料流 */InputStream is = context.getAssets().open(source);/* 擷取檔案大小 */int size = is.available();/* 建立檔案的緩衝區 */byte[] buffer = new byte[size];/* 將檔案讀取到緩衝區中 */is.read(buffer);/* 關閉輸入資料流 */is.close();/* 開啟app安裝目錄檔案的輸出資料流 */FileOutputStream output = context.openFileOutput(destination,Context.MODE_PRIVATE);/* 將檔案從緩衝區中寫出到記憶體中 */output.write(buffer);/* 關閉輸出資料流 */output.close();}/** 執行 shell 指令碼命令 */private List<String> exe(String cmd) {/* 擷取執行工具 */Process process = null; /* 存放指令碼執行結果 */ List<String> list = new ArrayList<String>(); try { /* 擷取運行時環境 */ Runtime runtime = Runtime.getRuntime(); /* 執行指令碼 */ process = runtime.exec(cmd); /* 擷取指令碼結果的輸入資料流 */ InputStream is = process.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = null; /* 逐行讀取指令碼執行結果 */ while ((line = br.readLine()) != null) { list.add(line); } br.close(); } catch (IOException e) { e.printStackTrace(); } return list;}}
home_activity.xml 布局檔案代碼 :
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal" > <Button android:id="@+id/copy_busybox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="拷貝busybox" android:textSize="7dp" android:textStyle="bold" /> <Button android:id="@+id/copy_traceroute" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="拷貝traceroute" android:textSize="7dp" android:textStyle="bold" /> <Button android:id="@+id/exe_busybox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="執行busybox" android:textSize="7dp" android:textStyle="bold" /> <Button android:id="@+id/exe_traceroute" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="執行traceroute" android:textSize="7dp" android:textStyle="bold" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <EditText android:id="@+id/et_cmd" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="4" android:hint="輸入要執行的命令" android:textStyle="bold" /> <Button android:id="@+id/exe" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="onClick" android:text="執行" android:textSize="10dp" android:textStyle="bold" /> </LinearLayout> <TextView android:id="@+id/tv_result" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000000" android:textColor="#FFF" android:textSize="10dp" android:textStyle="bold" /></LinearLayout>
5. 執行結果
執行 busybox 程式 :
執行 traceroute 程式 :
範例程式碼下載 :
-- CSDN : http://download.csdn.net/detail/han1202012/7639253;
-- GitHub : https://github.com/han1202012/TracerouteAndBusybox ;
作者 : 萬境絕塵
轉載請著名出處 : http://blog.csdn.net/shulianghan/article/details/36438365