Android全局可调试(ro.debuggable = 1)的一种另类改法

网上流传比较多的,是重打包boot.img。读aosp的init进程源码,发现通过patch init进程也可以实现相同目的。

首先看一下init进程对ro只读属性的检查:

/* property_service.c */
int property_set(const char *name, const char *value)
{
...
    pi = (prop_info*) __system_property_find(name);

    if(pi != 0) {
        /* ro.* properties may NEVER be modified once set */
        if(!strncmp(name, "ro.", 3)) return -1;  /* 如果是只读属性,不允许set,返回-1 */

        __system_property_update(pi, value, valuelen);
    }
...

从上面代码看出,如果将“ro.”改为“\0”即空字符串,即可绕过property_set对可读属性的检查。

同时为了防止误修改,我们查看init进程是否还有其它使用“ro.”字符串的地方,只找到一处,位于check_perms函数中:

/*
 * Checks permissions for setting system properties.
 * Returns 1 if uid allowed, 0 otherwise.
 */
static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
{
    int i;
    unsigned int app_id;

    if(!strncmp(name, "ro.", 3))
        name +=3;

    if (uid == 0)
        return check_mac_perms(name, sctx);
...

分析init进程的汇编代码,发现property_set函数地址位于check_perms函数之前,因此只要修改搜索到的第一处内存即可。

使用ptrace实现,代码如下:

[email protected]:~/Android_prj/patch_init_process$ cat 1.c
#include <stdio.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <memory.h>
#include <string.h>

int main(int argc, char **argv) {
        int rc;
        unsigned long maps, mape, addr, test, fake;
        FILE *fp;
        char line[512];
        char *buffer, *ro;

        fp = fopen("/proc/1/maps", "r");
        if (!fp) {
                perror("fopen");
                return 1;
        }
        memset(line, 0, sizeof(line));
        fgets(line, sizeof(line), fp);
        fclose(fp);
        rc = sscanf(line, "%08x-%08x", &maps, &mape);
        if (rc < 2) {
                perror("sscanf");
                return 1;
        }
        buffer = (char *) malloc(mape - maps);
        if (!buffer) {
                perror("malloc");
                return 1;
        }
        rc = ptrace(PTRACE_ATTACH, 1, 0, 0);
        if (rc < 0) {
                perror("ptrace");
                return rc;
        }
        for (addr = maps; addr < mape; addr += 4) {
                test = ptrace(PTRACE_PEEKTEXT, 1, (void *) addr, 0);
                *((unsigned long *)(buffer + addr - maps)) = test;
        }

        ro = memmem(buffer, mape - maps, "ro.", 3);
        if (ro) {
                printf("Patching init.\n");
                fake = 0;
                rc = ptrace(PTRACE_POKETEXT, 1, (void *)(maps + ro - buffer), &fake);
                if (rc < 0) {
                        perror("ptrace");
                }
        }
        free(buffer);
        rc = ptrace(PTRACE_DETACH, 1, 0, 0);

        return rc;
}

编译并在Nexus 5中运行:

$ arm-linux-androideabi-gcc 1.c -o patch_init

运行后kill掉zygote进程:

[email protected]:/data/local/tmp # ps |grep zygote
ps |grep zygote
root      18887 1     860616 56352 ffffffff 400e26d8 S zygote
[email protected]:/data/local/tmp # kill -9 18887

zygote进程结束后,会自动被init进程拉起。待zygote重启后,执行:

[email protected]:/data/local/tmp # setprop ro.debuggable 1
setprop ro.debuggable 1
[email protected]:/data/local/tmp # getprop ro.debuggable
getprop ro.debuggable
1

以上,ro.debuggable属性已经被修改。只要手机不重启,此修改一直生效,手机重启后需重新patch。

原文地址:https://www.cnblogs.com/gm-201705/p/9863930.html

时间: 2024-10-10 00:29:30

Android全局可调试(ro.debuggable = 1)的一种另类改法的相关文章

简单实现Android手机“全局可调试”(ro.debuggable = 1)的方法【锤子坚果3】

在Android真机上调试程序有一个前提,就是这个apk包必须有 debuggable=true 的属性才行.而除了自己开发的apk能够控制打包属性之外,其他的程序发行之后显然不会设这个值为 true 的(不然随随便便就能被Debug ,岂不是很没安全感 ).为了调试这些第三方的apk,我们可以从整个手机系统入手 —— 因为除了每个apk中的 debuggable 标志以外,这个标志还可以在系统中全局指定,换句话说,只要把系统里的 debuggable 值设为true,那么不管apk的这个属性是

Android全局资源访问

package com.example.metrox.l12; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.

Android全局异常捕捉

// 定义自定义捕捉 package com.xiaosw.test; import java.io.File; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.Thread.UncaughtExceptionHandler;

Android TextView里直接显示图片的三种方法

方法一:重写TextView的onDraw方法,也挺直观就是不太好控制显示完图片后再显示字体所占空间的位置关系.一般如果字体是在图片上重叠的推荐这样写.时间关系,这个不付源码了. 方法二:利用TextView支持部分Html的特性,直接用api赋图片.代码如下: //第一种方法在TextView中显示图片 String html = "<img src='" + R.drawable.circle + "'/>"; ImageGetter imgGett

Android图表库MPAndroidChart(十四)——在ListView种使用相同的图表

Android图表库MPAndroidChart(十四)--在ListView种使用相同的图表 各位好久不见,最近挺忙的,所有博客更新的比较少,这里今天说个比较简单的图表,那就是在ListView中使用相同的图标,因为我们在下篇会讲解使用不同的图表,相同的图表还是比较简单的,我们来看下效果图 具体怎么去实现呢,这里我们先写点铺垫,比如我们需要一个基类的Activity ViewPagerBaseActivity package com.liuguilin.mpandroidchartsample

android基础之点击监听器的2种监听实现

点击监听器接口:onClickListener 抽象函数 onClick(View v) 有2个方法实现监听: 1:当前类继承点击监听器接口 package com.example.button; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; im

Android代码学习--点击事件的几种写法

由来:常规的写法参见<写一个apk>,每次点击按钮,按钮先查找文本框等元素,然后再操作,其实查找操作是很费时的操作,因此将该定义放到Activity的onCreate中:Oncreate只会执行一次,这样Activity一旦执行,就先创建好控件们了. 第二种方法:通过匿名内部类的方法:就是button.setOnClickListener(new OnClickListener(){ //实现OnClickListener接口 @Override public void onClick(Vie

Android一个应用多个图标的几种实现方式

本文标签: Android activity-alias 新需求我的应用将有多个ICON入口..最终选择了 activity-alias , 其实实现多图标有好几种方式 1. 多Activity + intent-filter方式 因为launcher会扫描app中含有以下intent-filter属性的标签, 有的话就会将其添加到桌面.所以只要在你想添加到桌面的activity下加上以下标签即可. <intent-filter> <action android:name="a

【转】android创建Popwindow弹出菜单的两种方式

方法一的Activity [java] view plaincopy package com.app.test02; import android.app.Activity; import android.os.Bundle; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import