Android 上实现非root的 Traceroute -- 非Root权限下移植可执行二进制文件 脚本文件

1. 原理思路


文件权限修改无法实现 : 如果 没有 root 权限, 就不能改变二进制文件的文件权限;

-- 将busybox推送到Android系统中 : 使用 adb push 命令, 将 busybox 传入到 sd 卡中, 注意, 上传到内存中无法实现;

-- 上传到sd卡成功 : 使用 adb push 文件名 手机中的文件全路径名 命令;

[plain]  view plain copy
  1. octopus@octopus:~/csdn$ adb push busybox-armv7l /sdcard/octopus/busybox  
  2. 3256 KB/s (1109128 bytes in 0.332s)  
--  上传到内存失败  : 使用 adb push 上传到内存中失败, 因为 adb 使用的是 system 用户, 只有 root 用户才有权限向内存中写入数据;

[plain]  view plain copy
  1. octopus@octopus:~/csdn$ adb push busybox-armv7l /data/busybox  
  2. failed to copy 'busybox-armv7l' to '/data/busybox': Permission denied  
--  查看并修改busybox权限失败  : system 用户没有修改 sd 卡文件模式的权限;

[plain]  view plain copy
  1. shell@android:/sdcard/octopus $ ll   
  2. -rw-rw-r-- root     sdcard_rw  1109128 2014-07-08 19:49 busybox  
  3. shell@android:/sdcard/octopus $ chmod 755 busybox                                
  4. 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 目录文件的输入流


[java]  view plain copy
  1. InputStream is = context.getAssets().open(source);  
--  获取AssetsManager  : 调用 Context 上下文对象的 context.getAssets() 即可获取 AssetsManager对象;

-- 获取输入流 : 调用 AssetsManager 的 open(String fileName) 即可获取对应文件名的输入流;


(2) 文件流相关操作


根据输入流获取文件大小 : 调用输入流的 inputStream.available() 方法;

[java]  view plain copy
  1. int size = is.available();  

将文件读取到缓冲区中  : 创建一个与文件大小相同的字节数组缓冲区, 输入流将数据存放到缓冲区中;

[java]  view plain copy
  1. byte[] buffer = new byte[size];  
  2. is.read(buffer);  
  3. is.close();  

将文件写到内存中 : 调用上下文对象的 openFileOutput(绝对路径名, 权限), 即可创建一个文件的输出流;

[java]  view plain copy
  1. FileOutputStream output = context.openFileOutput(destination, Context.MODE_PRIVATE);  
  2. output.write(buffer);  
  3. output.close();  



(3) 获取文件的绝对路径


获取app绝对安装路径 : 调用 上下文对象的 getFilesDir().getAbsolutePath() 方法;

[java]  view plain copy
  1. String filesPath = context.getFilesDir().getAbsolutePath();  


(4) 执行二进制文件


创建 Process 对象, 并使用该 process 执行shell脚本命令 : 

[java]  view plain copy
  1. Runtime runtime = Runtime.getRuntime();  
  2. process = runtime.exec(cmd);   

获取执行的命令行结果  : 

[java]  view plain copy
  1. InputStream is = process.getInputStream();  
  2. BufferedReader br = new BufferedReader(new InputStreamReader(is));  
  3. String line = null;    
  4. while ((line = br.readLine()) != null) {    
  5.     processList.add(line);   
  6. }  
  7. br.close();   


4. 代码示例


MainActivity 主程序代码 

[java]  view plain copy
  1. package cn.org.octopus.tracerouteandbusybox;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.FileNotFoundException;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.InputStreamReader;  
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. import android.content.Context;  
  13. import android.os.Bundle;  
  14. import android.support.v7.app.ActionBarActivity;  
  15. import android.view.View;  
  16. import android.widget.EditText;  
  17. import android.widget.TextView;  
  18.   
  19. /** 看不懂注释我就吃半斤狗粮 :-) */  
  20. public class MainActivity extends ActionBarActivity {  
  21.   
  22.     private EditText et_cmd;  
  23.     private String app_path;  
  24.     private TextView tv_result;  
  25.       
  26.     @Override  
  27.     protected void onCreate(Bundle savedInstanceState) {  
  28.         super.onCreate(savedInstanceState);  
  29.         setContentView(R.layout.home_activity);  
  30.           
  31.         /*初始化控件*/  
  32.         et_cmd = (EditText) findViewById(R.id.et_cmd);  
  33.         tv_result = (TextView) findViewById(R.id.tv_result);  
  34.         /* 获取app安装路径 */  
  35.         app_path = getApplicationContext().getFilesDir().getAbsolutePath();  
  36.           
  37.     }  
  38.   
  39.   
  40.     /** 按钮点击事件 */  
  41.     public void onClick(View view) {  
  42.         int id = view.getId();  
  43.         switch (id) {  
  44.         case R.id.copy_busybox: /* 拷贝busybox可执行文件 */  
  45.             varifyFile(getApplicationContext(), "busybox");  
  46.             break;  
  47.         case R.id.copy_traceroute:/* 拷贝traceroute可执行文件 */  
  48.             varifyFile(getApplicationContext(), "traceroute");  
  49.             break;  
  50.         case R.id.exe_busybox:/* 将busybox命令添加到Editext中 */  
  51.             String cmd = "." + app_path + "/busybox";  
  52.             System.out.println(et_cmd);  
  53.             et_cmd.setText(cmd);  
  54.             break;  
  55.         case R.id.exe_traceroute:/* 将traceroute命令添加到Editext中 */  
  56.             cmd = "." + app_path + "/traceroute 8.8.8.8";  
  57.             et_cmd.setText(cmd);  
  58.             break;  
  59.         case R.id.exe: /* 执行Editext中的命令 */  
  60.             cmd = et_cmd.getText().toString();  
  61.             /* 执行脚本命令 */  
  62.             List<String> results = exe(cmd);  
  63.             String result = "";  
  64.             /* 将结果转换成字符串, 输出到 TextView中 */  
  65.             for(String line : results){  
  66.                 result += line + "\n";  
  67.             }  
  68.             tv_result.setText(result);  
  69.             break;  
  70.   
  71.         default:  
  72.             break;  
  73.         }  
  74.     }  
  75.   
  76.     /** 验证文件是否存在, 如果不存在就拷贝 */  
  77.     private void varifyFile(Context context, String fileName) {  
  78.   
  79.   
  80.         try {  
  81.             /* 查看文件是否存在, 如果不存在就会走异常中的代码 */  
  82.             context.openFileInput(fileName);  
  83.         } catch (FileNotFoundException notfoundE) {  
  84.             try {  
  85.                 /* 拷贝文件到app安装目录的files目录下 */  
  86.                 copyFromAssets(context, fileName, fileName);  
  87.                 /* 修改文件权限脚本 */  
  88.                 String script = "chmod 700 " + app_path + "/" + fileName;  
  89.                 /* 执行脚本 */  
  90.                 exe(script);  
  91.             } catch (Exception e) {  
  92.                 e.printStackTrace();  
  93.             }  
  94.         }  
  95.     }  
  96.       
  97.     /** 将文件从assets目录中拷贝到app安装目录的files目录下 */  
  98.     private void copyFromAssets(Context context, String source,  
  99.             String destination) throws IOException {  
  100.         /* 获取assets目录下文件的输入流 */  
  101.         InputStream is = context.getAssets().open(source);  
  102.         /* 获取文件大小 */  
  103.         int size = is.available();  
  104.         /* 创建文件的缓冲区 */  
  105.         byte[] buffer = new byte[size];  
  106.         /* 将文件读取到缓冲区中 */  
  107.         is.read(buffer);  
  108.         /* 关闭输入流 */  
  109.         is.close();  
  110.         /* 打开app安装目录文件的输出流 */  
  111.         FileOutputStream output = context.openFileOutput(destination,  
  112.                 Context.MODE_PRIVATE);  
  113.         /* 将文件从缓冲区中写出到内存中 */  
  114.         output.write(buffer);  
  115.         /* 关闭输出流 */  
  116.         output.close();  
  117.     }  
  118.       
  119.     /** 执行 shell 脚本命令 */  
  120.     private List<String> exe(String cmd) {  
  121.         /* 获取执行工具 */  
  122.         Process process = null;   
  123.         /* 存放脚本执行结果 */  
  124.         List<String> list = new ArrayList<String>();    
  125.         try {    
  126.             /* 获取运行时环境 */  
  127.             Runtime runtime = Runtime.getRuntime();  
  128.             /* 执行脚本 */  
  129.             process = runtime.exec(cmd);   
  130.             /* 获取脚本结果的输入流 */  
  131.             InputStream is = process.getInputStream();  
  132.             BufferedReader br = new BufferedReader(new InputStreamReader(is));  
  133.             String line = null;    
  134.             /* 逐行读取脚本执行结果 */  
  135.             while ((line = br.readLine()) != null) {    
  136.                 list.add(line);   
  137.             }  
  138.             br.close();   
  139.         } catch (IOException e) {    
  140.             e.printStackTrace();    
  141.         }   
  142.         return list;  
  143.     }  
  144.       
  145. }  


home_activity.xml 布局文件代码 : 

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <LinearLayout  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:gravity="center"  
  11.         android:orientation="horizontal" >  
  12.   
  13.         <Button  
  14.             android:id="@+id/copy_busybox"  
  15.             android:layout_width="wrap_content"  
  16.             android:layout_height="wrap_content"  
  17.             android:onClick="onClick"  
  18.             android:text="拷贝busybox"  
  19.             android:textSize="7dp"  
  20.             android:textStyle="bold" />  
  21.   
  22.         <Button  
  23.             android:id="@+id/copy_traceroute"  
  24.             android:layout_width="wrap_content"  
  25.             android:layout_height="wrap_content"  
  26.             android:onClick="onClick"  
  27.             android:text="拷贝traceroute"  
  28.             android:textSize="7dp"  
  29.             android:textStyle="bold" />  
  30.   
  31.         <Button  
  32.             android:id="@+id/exe_busybox"  
  33.             android:layout_width="wrap_content"  
  34.             android:layout_height="wrap_content"  
  35.             android:onClick="onClick"  
  36.             android:text="执行busybox"  
  37.             android:textSize="7dp"  
  38.             android:textStyle="bold" />  
  39.   
  40.         <Button  
  41.             android:id="@+id/exe_traceroute"  
  42.             android:layout_width="wrap_content"  
  43.             android:layout_height="wrap_content"  
  44.             android:onClick="onClick"  
  45.             android:text="执行traceroute"  
  46.             android:textSize="7dp"  
  47.             android:textStyle="bold" />  
  48.     </LinearLayout>  
  49.   
  50.     <LinearLayout  
  51.         android:layout_width="match_parent"  
  52.         android:layout_height="wrap_content"  
  53.         android:orientation="horizontal" >  
  54.   
  55.         <EditText  
  56.             android:id="@+id/et_cmd"  
  57.             android:layout_width="0dp"  
  58.             android:layout_height="wrap_content"  
  59.             android:layout_weight="4"  
  60.             android:hint="输入要执行的命令"  
  61.             android:textStyle="bold" />  
  62.   
  63.         <Button  
  64.             android:id="@+id/exe"  
  65.             android:layout_width="0dp"  
  66.             android:layout_height="wrap_content"  
  67.             android:layout_weight="1"  
  68.             android:onClick="onClick"  
  69.             android:text="执行"  
  70.             android:textSize="10dp"  
  71.             android:textStyle="bold" />  
  72.     </LinearLayout>  
  73.   
  74.     <TextView  
  75.         android:id="@+id/tv_result"  
  76.         android:layout_width="match_parent"  
  77.         android:layout_height="match_parent"  
  78.         android:background="#000000"  
  79.         android:textColor="#FFF"  
  80.         android:textSize="10dp"  
  81.         android:textStyle="bold" />  
  82.   
  83. </LinearLayout>  


5. 执行结果


执行 busybox 程序 : 



执行 traceroute 程序 : 



示例代码下载 :

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值