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 放到 project文件夹下的 res/assets/ 文件夹下;

2. 实现策略

文件初始放置 : 将 交叉编译好的 busybox 文件放在 project文件夹的 /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();

	}

	/** button点击事件 */
	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

时间: 2024-10-07 00:06:19

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

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 权限,

如何正确的在 Android 上使用协程 ?

前言 你还记得是哪一年的 Google IO 正式宣布 Kotlin 成为 Android 一级开发语言吗?是 Google IO 2017 .如今两年时间过去了,站在一名 Android 开发者的角度来看,Kotlin 的生态环境越来越好了,相关的开源项目和学习资料也日渐丰富,身边愿意去使用或者试用 Kotlin 的朋友也变多了.常年混迹掘金的我也能明显感觉到 Kotlin 标签下的文章慢慢变多了(其实仍然少的可怜).今年的 Google IO 也放出了 Kotlin First 的口号,许多

【Android】使用persist属性来调用脚本文件

Android系统中有许多属性,属性由两个部分组成:name & value,可以使用这些属性来记录系统设置或进程之间的信息交换.Android系统在启动过程时会按序从以下几个文件中加载系统属性: 1./default.prop 2./system/build.prop 3./system/default.prop 4./data/local.prop 5./data/property/* 属性会按照以上文件的顺序进行加载,并且后加载的属性值会更新原先的属性值.在系统重启后,有的属性会消失,但可

linux下非root用户如何修改root权限的文件

在linux下会出现把一些配置文件参数配错.root密码忘记等导致系统无法启动或进入root的窘迫境地,本文以redhat  enterprise linux server 6.4为例介绍root身份修改root权限配置文件的参数后,root无法登录,然后通过linux的rescue模式改回配置文件,巧妙以非root身份修改了root权限的文件的解决方案. 首先,插入linux安装盘重启系统,等到引导进入安装会话,上下移动方向键,选rescue installed system: 第二,进入修复

Android 相册图片选取+自定义裁剪方式(非系统裁剪)

不多说,直接上代码(裁剪的代码摘自网络.)(项目可运行) 主要是系统自身的剪切方式在有些机型上会程序崩溃的问题. 1 package com.jichun.activity; 2 3 import java.io.FileNotFoundException; 4 5 import com.jichun.view.CropCanvas; 6 7 import android.app.Activity; 8 import android.content.ContentResolver; 9 impo

以非root权限安装nginx及运行

本章主要讲如何在无root权限(包含无sudo权限)条件下于centos命令行中安装nginx以及在大于1024的端口(这里用8080)上运行. 1. 安装 两种方式,一是下载预编译好的rpm包安装,二是下载源码后自己编译. 如果是通过下载rpm方式安装,首先要找对应centos版本的rpm包. 通过命令 cat /etc/*release* 的输出可以看到centos系统的版本,在我能访问的某个云主机上显示如下: 使用curl -G <URL>命令来浏览网址http://nginx.org/

Android Studio如何import module(针对非gradle)

同样的,非gradle编译的工程和gradle编译的在import module上同样有一些区别.包括操作上,显示上的一些区别,以前的文章中,只要没有标注"非gradle"字样的,都是针对使用gradle来build的. 说到这,估计很多人会问,怎样的算是使用gradle来进行build的,怎样的不算,区别很简单,你只要看到工程根目录下,或者module目录下有没有build.gradle这个文件,有就是使用gradle来build,没有就是非gradle.(当然不只这一个区别,还有一

android 上传前签名

Android程序签名详解.打包.发布到Google play步骤   . 分类: CNDN李伟 CSDN android android应用签名 android应用发布 google play发布  2012-09-03 12:49 8674人阅读 评论(0) 收藏 举报 androidgoogle工具eclipsedos优化 目录(?)[+] 本文主要讲解Android应用程序签名相关的理论知识,包括:什么是签名.为什么要给应用程序签名.如何给应用程序签名等. 1.什么是签名?      如

Android上定义播放器控件UniversalVideoView

在Android上播放视频最简单的方法是使用SDK中内置的VideoView,然后加上MediaController来控制视频播放暂停等,但是这样有一个缺点是无法定制自己的控制UI,所以这里提供一个自定义播放控件,它可以设置多种自定义属性(如loading样式,错误视频等),并且很容易在全屏与非全屏之间切换,另外支持Android V2.3及以上系统. 项目地址: https://github.com/linsea/UniversalVideoView 使用方法 完整的使用方法请参考项目里的Sa