转自http://blog.apkudo.com/2012/07/26/enabling-hierarchyviewer-on-rooted-android-devices/

The HierarchyViewer is an Android SDK tool that gives developers the ability to introspect on all aspects of an application’s layout at runtime. The tool can be extremely useful for developers when debugging the view state of an application across a realm of devices. Unfortunately, the Android SDK has limited this tool to “devices running a developer version of the Android system”. I personally had no idea what Android meant by this statement, so we spent some time investigating the implementation of the ViewServer in Android OS and fortunately found that the HierarchyViewer can be enabled with any Android device as long as it has root access.

Android HierarchyViewer in Tree Mode on the Galaxy SII

So how does it actually work? The HierarchyViewer utilizes a service running on the device called ViewServer located in

frameworks/base/services/java/com/android/server/ViewServer.java

When launched, ViewServer opens up a socket on local port 4939 and receives commands from a client (usually HierarchyViewer) to dump the current view state of the device. The ViewServer dispatches these calls via binder to the ViewRoot class, which serializes the view state and transmits it to the client over the socket. The WindowManagerService manages the ViewServer and provides a hook (via binder service call) to spawn the service.

A client can only launch the ViewServer if the device’s properties ro.debuggable=1 and ro.secure=0, and the client contains manifest.dump permission (in the usual case, HierarchyView, as the client, has these permissions via adb). Although Google Engineer Romain Guy has been very adamant that the ViewServer is not enabled for production devices, we’ve found a pretty easy way to bypass its restrictions if you have root. The portion of the code dictating the restrictions can be found in line 5501 of WindowManagerService.java and is shown below.

  public boolean startViewServer(int port) {
if (isSystemSecure()) {
return false;
} if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
return false;
}
  private boolean isSystemSecure() {
return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
"0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
}

One can go about bypassing these restrictions in two ways: patch the WindowManagerService to allow anyone to spawn the server _or_ modify the ro.debuggable and ro.secure properties in the default.prop file. Because of the potential negative ramifications of modifying the ro.debuggable and ro.secure properties in Android (not to mention the fact that the default.prop file is part of the ramdisk, which makes editing it a bitch), we decided to patch the WindowManagerService. The patch is minimally invasive and provides a good intro into the power of patching the Android framework.

In order to perform this patch you will need the smali/baksmali tools, dextopt-wrapper, and access to a rooted device with BusyBox installed. If you have no idea what these tools are or how they work, you may want to do some reading first. We’ve only tested this on the HTC One S and a 4.0.3 Galaxy S II, so if you brick your device we’ll feel bad but can’t really do anything about it (hey, maybe we’ll send you a t-shirt).

Step 1 – Backup the phone’s /system/framework/ on your machine

$ mkdir ./system
$ mkdir ./system/framework
$ adb pull /system/framework/ ./system/framework/

Important: Make sure the directory structure matches the device’s for step 3.

Step 2 – Grab the bootclasspath from the device

$ adb shell
# echo $BOOTCLASSPATH

Copy this path.

Step 3 – Disassemble (baksmali) the services odex

$ baksmali -x -a 14 -c <copied bootclasspath> ./system/framework/services.odex

-x = odex
-a = api level 14
-c = classes (loaded from the bootclasspath, separated by colon)
If you’ve done this correctly you will now see a directory called ‘out’, otherwise verify you’ve pulled the jars and bootclasspath correctly.

Step 4 – In your favorite text editor, open up WindowManagerService.smali

$ emacs out/com/android/server/wm/WindowManagerService.smali

Search for isSystemSecure(). This is the method they use (only for ViewServer) to verify the system is not secure. We happened to find this on line 4815. Note: In 4.0 they moved WindowManagerService into the wm directory, it may just be in out/com/android/server/

Step 5 – Patch the return value of isSystemSecure() to always return false

.method private isSystemSecure()Z
.registers 4 .prologue
.line 5965
const-string v0, "1" const-string v1, "ro.secure" const-string v2, "1" invoke-static {v1, v2}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; move-result-object v1 invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_22 const-string v0, "0" const-string v1, "ro.debuggable" const-string v2, "0" invoke-static {v1, v2}, Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; move-result-object v1 invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_22 const/4 v0, 0x1 :goto_21 return v0 :cond_22
const/4 v0, 0x0 goto :goto_21
.end method

We can see from above that the v0 register contains the return value of this method. Let’s add a simple

const/4 v0, 0x0

in the line 41 above return v0 to ensure this method will always return false, giving the WMS the go ahead to spawn view server. Easy enough, right?

Step 6 – Reassemble into Dex

$ smali ./out -o classes.dex

-o = output file (classes.dex is the default name for apks in Android)

Step 7 – Zip dex

$ zip services_hacked.jar ./classes.dex

Step 8 – Remount /system

$ adb remount

OR

$ adb shell
# mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system

Step 9 – Push dexopt-wrapper and services_hacked.jar onto /data/local/tmp

$ adb push ./services_hacked.jar /data/local/tmp
$ adb push ./dexopt-wrapper /data/local/tmp

Step 10 – Optimize the services_hacked.jar into services_hacked.odex

$ adb shell
# cd /data/local/tmp
# chmod 777 ./dexopt-wrapper

Important: We need to feed in the bootclasspath into dexopt, but because we have modified a member of that class path, we need to make sure we don’t include it. To do this, copy bootclasspath (via method in step 2) and omit the “:/system/framework/services.jar”. Forgetting this step will likely result in a boot loop.

# ./dexopt-wrapper ./services_hacked.jar ./services_hacked.odex <copied bootclasspath excluding ":/system/framework/services.jar">

Our final command looked something like

./dexopt-wrapper ./services_hacked.jar ./services_hacked.odex /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/framework2.jar:/system/framework/android.policy.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar:/system/framework/sechardware.jar:/system/framework/wimax.jar

A great way to check that this command has worked is to see that the /system/framework/services.odex and the services_hacked.odex are nearly identical in size. The two files shouldn’t differ by more than 1KB.

Step 11 – Copy in the signature

Each odex is signed with a 20 byte signature located at a 52 byte offset within the odex. Let’s trick the OS into thinking our hacked odex matches the system signature by copying it from the original

# busybox dd if=/system/framework/services.odex of=/data/local/tmp/services_hacked.odex bs=1 count=20 skip=52 seek=52 conv=notrunc

if = input file
of = output file
bs = block size (1 byte)
count = number of blocks
skip = input file offset
seek = output file offset
conv=notrunc – don’t truncate the output file.

Step 12 – Replace the original odex with the hacked version

# dd if=/data/local/tmp/services_hacked.odex of=/system/framework/services.odex

Step 13 – Let the device reset

The previous step should result in a software reset, and it may be worthwhile to logcat as this loads. If you see the Dalvik logs stating “some deps went away” or “not all deps represented” then you’ve definitely screwed up step 10. These errors are a result of passing in the wrong bootclasspath to dexopt-wrapper. If this causes a bootloop, see step 16.

Step 14 – Launch ViewServer

WindowManagerService provides a (heavily undocumented) hook into spawning ViewServer. To start the server on port 4939,

$ adb shell service call window 1 i32 4939

To stop the server

$ adb shell service call window 2

To check if the server is running

$ adb shell service call window 3

If ViewServer is running, you should see

Result: Parcel(00000000 00000001   '........')

Step 15 – Launch HierarchyViewer

$ ./sdk/tools/hierarchyviewer

You will now see your rooted phone available in the HierarchyViewer. Double click on a layout to introspect on that view tree.

Step 16 (if you get stuck in a bootloop)

Don’t panic! Simply push the backed up services.odex to system/framework to revert to your previous state.

$ adb push ./system/framework/services.odex /system/framework/services.odex

Note, you should make sure you don’t reboot when if you get a bootloop. In some cases the OS will not be at a state at which your SU binary is functional (I’ve seen it segfault many times). If you don’t have root your only option is to reflash the device via fastboot or other bootloader.

Although this API is not meant to be public, it’s extremely useful to developers when debugging their UI. It’s a shame you have to jump through so many hoops to obtain this functionality. I hope to see Android keep the ViewServer in further builds and provide a means of using the HierarchyViewer on production phones as well.

(As an aside: we refered to HierarchyViewer as the “usual client” of ViewServer above. Other clients are certainly possible. One issue with HierarchyViewer is it’s pretty damn slow – we’ve been working on our own optimized client over here at Apkudo, which will be the subject of a future blog!)

Enabling HierarchyViewer on Rooted Android Devices的更多相关文章

  1. ADT eclipse打开时出现Error: Error parsing C:\Users\admin*\.android\devices.xml

    Error: Error parsing C:\Users\admin*\.android\devices.xml  在ADT eclipse打开项目的时候出现此提示,但是又不影响使用. 原因:之前安 ...

  2. 3.Appium运行时出现:Original error: Android devices must be of API level 17 or higher. Please change your device to Selendroid or upgrade Android on your device

    参考博客:https://blog.csdn.net/niubitianping/article/details/52624417 1.错误信息:Original error: Android dev ...

  3. Remote Debugging Android Devices

    Remote Debugging Android Devices //在电脑上远程调试安卓设备 By Kayce Basques Technical Writer at Google By Meggi ...

  4. flutter doctor出现问题 [!] Android toolchain - develop for Android devices (Android SDK version 28.0.3) X Android license status unknown. Try re-installing or updating your Android SDK Manager. 的解决方案

    首先,问题描述: flutter doctor Doctor summary (to see all details, run flutter doctor -v): [√] Flutter (Cha ...

  5. Benchmark Test On Android Devices

    一.Android设备上的Benckmark测试概述 同PC相比,在Android设备上的性能测试还没有一个公认的标准.也没有PC上那么多的测试程序集.但我们可以通过一些工具所得到的信息更好的了解设备 ...

  6. Snapdragon connect to android devices

    怎么都连不上,连不上连不上... 用adb devices是列出来的,开发者选项也设置了, 后来查了下 把adb的路径拖到系统环境变量里就可以了.终于连上了,今天不用加班了...

  7. Android手机流量分析工具介绍

    一.20 Best Android Hacking Apps And Tools Of 2018 首先罗列常见的Android手机hacking的工具 #1The Android Network Ha ...

  8. Multipath TCP and load balancers

    Load balancers play a very important role in today’s Internet. Most Internet services are provided b ...

  9. hook框架frida添加至于安卓应用中

    转载至于https://koz.io/using-frida-on-android-without-root/ Frida is a great toolkit by @oleavr, used to ...

随机推荐

  1. 64bit Ubuntu, Android AAPT, R.java

    Ubuntu 13.10 aapt: error while loading shared libraries: libstdc++.so.6: cannot open shared object f ...

  2. Error: Most middleware (like bodyParser) ...

    运行NodeJS时出现如下错误: Error: Most middleware (like bodyParser) is no longer bundled with Express and must ...

  3. 作业三--Linux内核分析

    一.Linux内核源码 arch目录支持不同CPU的源代码,是内核源码中比较大的文件. fs文件系统Linux内核的源码放在kernel目录中. 二.构造一个简单的Linux系统MenuOS 三.使用 ...

  4. Xcode8兼容iOS7手记-b

    对于Xcode8的发布,苹果也是来了个大的跳跃,默认最低支持的iOS版本为8.0,当然也并不是说8.0以下就直接放弃了,虽然表现出来的是这样,毕竟使用8.0以下系统的还是大有人在的,老项目要兼容iOS ...

  5. Java 8 VM GC Tuning Guide Charter2

    第二章 Ergonomics Ergonomics is the process by which the Java Virtual Machine (JVM) and garbage collect ...

  6. [转载]非常完善的Log4net详细说明

    前言 此篇文章是我见过写得最好的一片关于Log4Net的文章,内容由简入难,而且面面俱到,堪称入门和精通的佳作,特从懒惰的肥兔的转载过来. 1.概述 log4net是.Net下一个非常优秀的开源日志记 ...

  7. WCF入门(七)——异常处理1

    首先以一个简单的例子演示一下远程调用发生异常的结果: 服务器端代码如下: [ServiceContract] public interface IService1 { [OperationContra ...

  8. 2013年山东省第四届ACM大学生程序设计竞赛 Alice and Bob

      Alice and Bob Time Limit: 1000ms   Memory limit: 65536K 题目描述 Alice and Bob like playing games very ...

  9. intellij idea 12、13 win8 下 中文输入覆盖的问题(搜狗输入法或者其他输入法)

    最近升级到idea12,发现中文输入存在问题,输入中文的时候会出现空格,并且覆盖后面的字符,这个问题让我很郁闷. 假设idea的安装位置为:D:\Program Files\JetBrains\Int ...

  10. 心情记录&考试总结 3.30

    并不知道现在要干什么,本人像是一只大颓狗 Em..怎么说呢,今天考完了一场奇怪的试 准确的说,画风很不正常的试 第一题集体爆零 第二题暴力20分 第三题暴力40分,乱搞有加成 改题的话, 第一题有奇怪 ...