天天看點

【Android 應用開發】Android 上實作非root的 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/busybox
3256 KB/s (1109128 bytes in 0.332s)
           

-- 上傳到記憶體失敗 : 使用 adb push 上傳到記憶體中失敗, 因為 adb 使用的是 system 使用者, 隻有 root 使用者才有權限向記憶體中寫入資料;

[email protected]:~/csdn$ adb push busybox-armv7l /data/busybox
failed 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;
	
	@Override
	protected 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 程式 : 

【Android 應用開發】Android 上實作非root的 Traceroute -- 非Root權限下移植可執行二進制檔案 腳本檔案

執行 traceroute 程式 : 

【Android 應用開發】Android 上實作非root的 Traceroute -- 非Root權限下移植可執行二進制檔案 腳本檔案

示例代碼下載下傳 :

-- CSDN : http://download.csdn.net/detail/han1202012/7639253;

-- GitHub : https://github.com/han1202012/TracerouteAndBusybox ;

作者 : 萬境絕塵

轉載請著名出處 : http://blog.csdn.net/shulianghan/article/details/36438365