安卓手机无法root的情况下使用busybox

安卓手机无法root的情况下,如何使用busybox

一、什么是BusyBox?

BusyBox 是标准 Linux 工具的一个单个可执行实现。BusyBox 包含了一些简单的工具,例如 cat 和echo,还包含了一些更大、更复杂的工具,例如 grep、find、mount 以及 telnet。有些人将 BusyBox 称为 Linux 工具里的瑞士军刀。简单的说BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令。

二、为什么要使用Busybox?

  • 手残党想要掌上玩转Linux命令行。
  • 迫于需要。有时候通过Linux命令来操纵数据会比编译型语言简单很多。

Android本身自带ToolBox,和BusyBox类似,不过命令少得可怜,且很多命令也精简只有基础功能了。网络上已经有各种安卓一键安装busybox的集成工具了,但都有前提,需要root权限才能安装。

我的手机也是无法root的,正巧拿来当实验了。

三、怎么做?

  1. Busybox编译完后其实就只是一个二进制文件。这个文件可以选择下载:https://busybox.net/downloads/binaries/,
    也可以选择下载源码编译:https://busybox.net/downloads/
    这里我选择下载源码编译吧。

2.编译busybox(我这里就选择1.20版本):

# 获取交叉编译工具链 
# 这里引用别人的博客:http://download.csdn.net/download/mybelief321/5563837 可以下载
# 如何配置?引用别人的博客:http://blog.csdn.net/u010661782/article/details/49020613

gcc

# 获取busybox源码
wget https://busybox.net/downloads/busybox-1.20.0.tar.bz2
# 解压
tar xf busybox-1.20.0.tar.bz2 -C /usr/local
# 创建软链接(可以不创,直接进。我习惯这么做。)
ln -s /usr/local/busybox-1.20.0 /usr/local/busybox
# 进入文件夹
cd /usr/local/busybox

makemenuconfig

# 配置.config文件
make menuconfig
# 以下为Menu中的选项修改
    ## 不使用动态链接库,才能保证每个命令都能使用
    #Busybox Settings --> Build Options --> Build Busybox as a static binary (no shared libs)  -  Enable this option by pressing \"Y\"
    ## 配置交叉编译工具,这里使用的是刚才配置的友善之臂交叉编译工具链。
    #Busybox Settings --> Build Options --> Cross compiler prefix  -  Set this option equal to \"arm-none-linux-gnueabi-\"
    ## 这个菜单可能会没有。没有就不配置吧。
    #Busybox Settings --> Installation Options --> Don\'t use /usr  -  Enable this option by pressing \"Y\"

menu1
menu2
menu31
menu32

make 

make

#将编译好的busybox(当前目录下)可执行文件拷贝出来
sz busybox

sz
busyboxTest

3.手机权限问题需要考虑。

  • 直接拷贝到sdcard里不会有执行权限,而且访问不到;
  • 命令行被调用时处于根目录,非root没有写权限,只有少部分读权限。权限太低,不可能创建在root里;
  • Android 操作系统会为每个应用程序设置一个用户, 这个用户对其安装目录(/data/data/包名/)下的文件有完整的权限;
  • assets 文件夹是存放不进行编译加工的原生文件,即该文件夹里面的文件不会像 xml, java 文件被预编译;目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。

    1. 创建测试项目(注释很清楚,我就不废话了)
  • 新建项目
  • 添加assets文件夹,并将busybox可执行文件复制进去

assets

  • 修改xml,定义命令输入框,命令执行按钮,命令清空按钮,文本地址选择按钮。
    <!-- 命令输入框-->
    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textPersonName"
        android:hint="Command"
        android:ems="10"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:id="@+id/editCmd"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <!-- 返回结果展示的列表-->
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/listRes"
        android:layout_below="@+id/btn_run"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />
    <!-- 执行命令的按钮-->
    <Button
        android:text="Run"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn_run"
        android:layout_below="@+id/editCmd"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />
    <!-- 添加文件的按钮-->
    <Button
        android:text="file"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/editCmd"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:id="@+id/btn_files" />
    <!-- 清空命令的按钮-->
    <Button
        android:text="clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn_clear"
        android:layout_below="@+id/editCmd"
        android:layout_centerHorizontal="true" />
  • 定义使用AssetsManager对象获取Assets文件夹下的文件并复制到 /data/data/包名/files/下(APP安装目录下/files/)的函数:
/**
     * 将文件从assets目录中拷贝到app安装目录的files目录下
     * @param context  应用程序的context
     * @param source 源文件名(Assets下的文件名)
     * @param destination 目标保存文件名(files下的文件名)
     * */
    private void copyFromAssets(Context context, String source,
                                String destination) throws IOException {
        /**
         * 获取assets目录下文件的输入流
         *
         * 1、获取AssetsManager : 调用 Context 上下文对象的 context.getAssets() 即可获取 AssetsManager对象;
         * 2、获取输入流 : 调用 AssetsManager 的 open(String fileName) 即可获取对应文件名的输入流;
         */
        InputStream is = context.getAssets().open(source);
        // 获取文件大小
        int size = is.available();
        // 创建文件的缓冲区
        byte[] buffer = new byte[size];
        // 将文件读取到缓冲区中
        is.read(buffer);
        // 关闭输入流
        is.close();
        /*
         *  打开app安装目录文件的输出流
         *  Context.MODE_PRIVATE  设置该文件只能被本应用使用,为私有数据
         */
        FileOutputStream output = context.openFileOutput(destination,
                Context.MODE_PRIVATE);
        // 将文件从缓冲区中写出到内存中
        output.write(buffer);
        //关闭输出流
        output.close();
    }
  • 使用JAVA代码通过Process对象执行shell命令:
/**
     *  执行 shell 脚本命令
     *  @param cmd  被执行的命令行
     *  @return 返回结果列表
     *  */
    private List<String> exec(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;
    }
  • OnCreate注册点击事件
    //文件URI返回代码
    private int FILE_PATH_RETURN_CODE = 1;
    //保存app安装路径
    private String app_path;
    //数组适配器(绑定执行结果输出的数据)
    private ArrayAdapter<String> arrayAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //获取app安装路径
        app_path = getApplicationContext().getFilesDir().getAbsolutePath();
        //获取组件
        //命令输入框
        final EditText textCmd = (EditText)findViewById(R.id.editCmd);
        //命令执行按钮
        Button btn_run = (Button)findViewById(R.id.btn_run);
        //命令执行按钮
        Button btn_clear = (Button)findViewById(R.id.btn_clear);
        //命令执行按钮
        Button btn_file = (Button)findViewById(R.id.btn_files);
        //命令结果展示框
        final ListView listRes = (ListView) findViewById(R.id.listRes);
        //命令执行按钮点击事件
        btn_run.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //查看busybox是否存在
                try {
                    // 查看文件是否存在, 如果不存在就进入catch
                    getApplicationContext().openFileInput("busybox");
                } catch (FileNotFoundException notfoundE) {
                    try {
                        /**
                         *  拷贝文件到app安装目录的files目录下
                         *  从assets文件夹中  拷贝到  /data/user/0/PACKAGE_NAME/files/
                         * */
                        copyFromAssets(getApplicationContext(), "busybox", "busybox");
                /*
                 *修改文件权限脚本
                 * chmod  UGO(000-777)  FILENAME
                 *      U:所有者
                 *      G:所属组
                 *      O:其他
                 *      0-7:000-111,rwx读写执行
                 */
                        String script = "chmod 700 " + app_path + "/busybox" ;
                        // 执行脚本
                        exec(script);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                //构造执行命令
                String cmdPath = "." + app_path + "/busybox ";
           //     System.out.println(cmdPath);
                String cmd = cmdPath +textCmd.getText().toString();
                //执行并获取结果
                List<String> results = exec(cmd);
                String[] res = new String[results.size()];
                results.toArray(res);
                //结果绑定在数组适配器上显示
                arrayAdapter = new ArrayAdapter<String>(MainActivity.this,
                        android.R.layout.simple_list_item_1,res);
                listRes.setAdapter(arrayAdapter);

            }
        });

        // 清空命令按钮点击事件
        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textCmd.setText("");
            }
        });

        //文件地址选择按钮点击事件
        btn_file.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //通过intent调用系统文件浏览器选择并返回文件数据
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                intent.setType("*/*");//设置文件类型
                //为添加Action执行环境添加一个可打开的分类
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                //调用Activity,并获取返回的数据
                startActivityForResult(intent,FILE_PATH_RETURN_CODE);
            }
        });
    }
  • 此时需要接收文件浏览器返回的数据,要重载onActivityResult函数:
/**
     *获取被调用Activity所返回的结果
     * @param requestCode requestCode用于与startActivityForResult中的requestCode中值进行比较判断,是以便确认返回的数据是从哪个Activity返回的。
     * @param resultCode resultCode是由子Activity通过其setResult()方法返回。适用于多个activity都返回数据时,来标识到底是哪一个activity返回的值。
     * @param data 一个Intent对象,带有返回的数据。可以通过data.getXxxExtra( );方法来获取指定数据类型的数据
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(resultCode== Activity.RESULT_OK){
            //如果是这个Activity定义的intent返回代码
            if(requestCode==FILE_PATH_RETURN_CODE){
                String uri = data.getDataString();
                //必须用decode,解析中文路径
                //去掉file://  7个字符
                uri = Uri.decode(uri);
                uri = uri.substring(7);
              //  System.out.println(uri);
                final EditText textCmd = (EditText)findViewById(R.id.editCmd);

                textCmd.setText(textCmd.getText().toString() + " "+uri);

            }
        }
    }
  • 最后,命令会涉及文件读写权限,AndroidManifest.xml中添加sd卡读写权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

5.测试结果:
ls
files
cat
grep

author

作者:林雍
原文链接:安卓手机无法root的情况下使用busybox

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值