1. 原理思路

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

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

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

[plain] view plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  1. InputStream is = context.getAssets().open(source);

--  获取AssetsManager  : 调用 Context 上下文对象的 context.getAssets() 即可获取 AssetsManager对象;

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

(2) 文件流相关操作

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

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

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

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

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

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

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

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

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

(4) 执行二进制文件

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

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

获取执行的命令行结果  :

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

home_activity.xml 布局文件代码 :

[html] view plaincopy
  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. <LinearLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="wrap_content"
  9. android:gravity="center"
  10. android:orientation="horizontal" >
  11. <Button
  12. android:id="@+id/copy_busybox"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:onClick="onClick"
  16. android:text="拷贝busybox"
  17. android:textSize="7dp"
  18. android:textStyle="bold" />
  19. <Button
  20. android:id="@+id/copy_traceroute"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:onClick="onClick"
  24. android:text="拷贝traceroute"
  25. android:textSize="7dp"
  26. android:textStyle="bold" />
  27. <Button
  28. android:id="@+id/exe_busybox"
  29. android:layout_width="wrap_content"
  30. android:layout_height="wrap_content"
  31. android:onClick="onClick"
  32. android:text="执行busybox"
  33. android:textSize="7dp"
  34. android:textStyle="bold" />
  35. <Button
  36. android:id="@+id/exe_traceroute"
  37. android:layout_width="wrap_content"
  38. android:layout_height="wrap_content"
  39. android:onClick="onClick"
  40. android:text="执行traceroute"
  41. android:textSize="7dp"
  42. android:textStyle="bold" />
  43. </LinearLayout>
  44. <LinearLayout
  45. android:layout_width="match_parent"
  46. android:layout_height="wrap_content"
  47. android:orientation="horizontal" >
  48. <EditText
  49. android:id="@+id/et_cmd"
  50. android:layout_width="0dp"
  51. android:layout_height="wrap_content"
  52. android:layout_weight="4"
  53. android:hint="输入要执行的命令"
  54. android:textStyle="bold" />
  55. <Button
  56. android:id="@+id/exe"
  57. android:layout_width="0dp"
  58. android:layout_height="wrap_content"
  59. android:layout_weight="1"
  60. android:onClick="onClick"
  61. android:text="执行"
  62. android:textSize="10dp"
  63. android:textStyle="bold" />
  64. </LinearLayout>
  65. <TextView
  66. android:id="@+id/tv_result"
  67. android:layout_width="match_parent"
  68. android:layout_height="match_parent"
  69. android:background="#000000"
  70. android:textColor="#FFF"
  71. android:textSize="10dp"
  72. android:textStyle="bold" />
  73. </LinearLayout>

5. 执行结果

执行 busybox 程序 :

执行 traceroute 程序 :

示例代码下载 :

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

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

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

  1. Mac OS 在远程主机(Linux 系统)上使用命令执行 sql 脚本文件(使用的是 MySQL 数据库)

    文章目录 使用命令 mysql 执行脚本文件 连接远程主机后,直接使用命令 mysql 进入 MySQL 的 bin 目录后,再执行 mysql 命令 使用命令 source 执行脚本文件 sql 脚 ...

  2. Android之在linux终端执行shell脚本文件(通过aapt)得到apk包名

    1.问题 我们在ubuntu上经常想看到apk的包名,然后在终端通过pidcat.py packageName 过滤日志,我们常用的办法手机连接电脑,然后打开这个app adb shell dumps ...

  3. linux无需管理员运行sh,linux下权限问题,如何让无root管理员权限的用户执行需root权限执行的脚本文件...

    匿名用户 1级 2013-07-12 回答 看了前面几位回答者我觉得应当采取一种简单的方法. 看你的意图允许任何人挂载/dev/sda5并且访问它 那么可以如此,任何人都可以挂载硬盘而无需密码,包括其 ...

  4. jmeter安装包_分布式执行jmeter脚本步骤(非GUI)

    备注:[Linux查看服务器是32位还是64位命令] uname -m getconf LONG_BIT 1.Linux环境安装jmeter 可参考https://www.cnblogs.com/su ...

  5. Android应用.三星i9000系列(4).SuperOneClick获取Root权限的原理

    Android应用.三星i9000系列(4).SuperOneClick获取Root权限的原理 草木瓜 20110408 一.前言 经过笔者自己测试与分析,得出结论:所以Android手机获取Root ...

  6. 如何在 SubSystem for Android 上安装应用?

    如何在 SubSystem for Android上安装应用? 2022年3月19日更新: 原先的 Apk文件安装程序 加入了广告,且软件源代码有盗窃原作者的嫌疑(目前不能确定,如有冒犯请谅解)所以更 ...

  7. android 使用ios字体大小,字体大小在iOS和Android上有所不同

    在Android上的网络视图中,我加载了一个包含HTML5画布的html文件.将文字写入画布时,它非常小.如果我在PC浏览器或IOS上的Web视图中加载相同的html文件,则看起来正确.据我所知,我已 ...

  8. 如何在 Android上恢复已删除的照片? 3个有效方法请收藏

    有时,我们会错误地删除令人难忘的照片.视频和其他数据.这无疑是一个令人沮丧的情况,但不要担心:我们将修复它并帮助您恢复丢失的文件.在本文中,我们将讨论在一些简单的方法和快速恢复软件的帮助下恢复已删除照 ...

  9. android非root状态,修改文件权限,非Root权限的Android上运行可执行文件

    使用 NDK 编译可执行文件,即 Android.mk 文件应该是编译 target 应该是 BUILD_EXECUTABLE include $(BUILD_EXECUTABLE) 假设,编出的目标 ...

最新文章

  1. Fluke OTDR新增SmartLoop双向测试功能
  2. 【Python刷题】_3
  3. 为JVM分配内存:一个案例研究
  4. CSS快速入门-箭头和图标
  5. 搜狐视频怎么开启青少年模式
  6. 【JAVA 第四章 流程控制语句】课后习题 冒泡排序的运用
  7. unity android屏幕自适应,Android应用开发之unity打开移动摄像头,并自适应屏幕显示摄像头数据。兼容android和ios...
  8. swift 闭包简写实际参数名$0、$1等理解
  9. 中计算均方误差_为什么分类问题不使用均方误差作为代价函数
  10. coreseek4.1
  11. 计算机主机无法开机故障原因,电脑电源保护无法开机怎么办
  12. 蓝牙耳机连接成功,但是每次关闭电脑后,重启电脑,连接耳机,没有声音——stereo模式没有声音
  13. 签章服务器系统,优泰科技首页_电子签名 手写批注 电子印章 全文批注
  14. 查看服务器配置以及常用命令
  15. 为什么有的公司会规定所有接口都用 POST请求?
  16. 论文研读-社交媒体可视化-地图隐喻转发地图R-Map
  17. 强大的GeoPandas,几行代码实现点转线功能
  18. 开源项目-OA自动化管理系统
  19. Xilinx ZynqMP相关
  20. 【重庆科技学院学报(自然科学版)】投稿经验分享

热门文章

  1. mysql时间分钟比较_MySql中时间比较方法 周 小时 分钟
  2. 云计算/大数据/Hadoop2.0/MongoDB/数据挖掘分析/视频教程
  3. ipfs星际文件系统初体验
  4. IT十年人生过客-十七-软通我来了
  5. mysql 围栏_使用纬度,经度和半径在PHP和MySQL中进行地理围栏
  6. 数风流人物还看今朝|前后端分离微服务项目常用中间件以及指令
  7. 手机端怎么限制wifi网速
  8. Tian Ji -- The Horse Racing 贪心算法
  9. ipadpro如何分屏_不再泡面!大学生如何用iPad高效学习
  10. 天气预报数据保存APP的制作