V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iofomo
V2EX  ›  Android

[ASeeker] Android 源码捞针,服务接口扫描神器

  •  
  •   iofomo · 16 天前 · 1045 次点击

    ASeeker是一个Android源码应用系统服务接口扫描工具。

    项目已开源:

    ☞ Github ☜ 

    如果您也喜欢 ASeeker ,别忘了给我们点个星。

    说明

    ASeeker 项目是我们在做虚拟化分身产品( 『 空壳 』 )过程中的内部开发工具,目的是为了提升Android系统各版本适配效率。由于产品需支持 Android 9.x ~ Android 14.x,需在应用访问所有的系统服务接口时,将我们关心的参数进行修正和还原。

    这导致每个系统版本适配的工作量巨大,且很容易遗漏。因此我们开发了这个源码接口扫描工具,可以快速从Android源码中搜索我们需要的AIDL接口和服务,并安装定制的格式输出。

    感谢开源项目com.github.javaparser,因为它的存在才让ASeeker成为可能,这也是我们开源ASeeker的动力。

    ASeeker的特点:

    • 完整源码AIDL接口扫描。
    • 支持多目录关联递归类型查找识别。
    • 支持泛型类,内部类和继承类递归查找。
    • 支持匹配配置名单。
    • 支持Android代码语言规范格式化。
    • 支持查找结果的定制输出。

    如何使用

    # 确保 asseker.jar 和 res 在同一目录下
    # aseeker [-options]
    #   -p [SDK version code] [source code path]
    $ java -jar aseeker.jar -p 33 /Users/abc/android_13.0_r13
    

    输出结果目录:(包含扫描结果和执行过程日志)

    输出文件内容:(可自定义输出内容格式)

    package android.app.os.service;
    
    import android.app.os.base.ProxyServiceBase;
    
    // source code: /frameworks/base/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
    public class IAccessibilityInteractionConnectionCallback extends ProxyServiceBase {
    
        // 10.0 void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, int interactionId);// argument: AccessibilityNodeInfo:info -> CharSequence::mPackageName
        public static final String sMethod_setFindAccessibilityNodeInfoResult = "setFindAccessibilityNodeInfoResult";
        // 10.0 void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos, int interactionId);// argument: List<AccessibilityNodeInfo>:infos -> CharSequence::mPackageName
        public static final String sMethod_setFindAccessibilityNodeInfosResult = "setFindAccessibilityNodeInfosResult";
    
    }
    

    功能实现

    需求

    为了实现应用虚拟化,我们需要将应用与系统服务接口通信中包含包名,路径的参数,函数名和返回值的接口进行适配。在访问之前需要修正为安装应用的信息,访问结果需要还原为原应用的信息。

    因此,我们需要:

    1. 递归查找参数中包含类型为String的名字含包名的接口,如:packagepkg等。

      void func(String pkg);
      void func(ComponentName cn);// 因为 ComponentName 中有成员:mPackageName
      
    2. 递归查找返回值中包含类型为String的名字含包名的接口,如:packagepkg等。

      ComponentName getComponentName();
      
    3. 查找返回值为String但是函数名包含包名的接口。

      String getPackageName();
      
    4. 打印输出找到的具体路径。

          // 11.0 boolean enterPictureInPictureMode(IBinder token, PictureInPictureParams params);// argument: PictureInPictureParams:params -> List<RemoteAction>::mUserActions -> PendingIntent::mActionIntent
          public static final String sMethod_enterPictureInPictureMode = "enterPictureInPictureMode";
      

    文件预处理

    由于javaparser只支持基础的Java类语言规范,对于Android平台定制标签,关键字等不支持,所以需要对目标文件先进行格式化处理,去除这些属性。

    // @from: com.ifms.cmpt.aseeker.AidlFormator.java
    
    Pattern.compile("(?<![\\w])IN\\s+([a-zA-Z_])"),
    Pattern.compile("(?<![\\w])in\\s+([a-zA-Z_])"),
    Pattern.compile("(?<![\\w])OUT\\s+([a-zA-Z_])"),
    Pattern.compile("(?<![\\w])out\\s+([a-zA-Z_])"),
    Pattern.compile("(?<![\\w])INOUT\\s+([a-zA-Z_])"),
    Pattern.compile("(?<![\\w])inout\\s+([a-zA-Z_])"),
    
    private static final String PATTERN_AT = "@\\w[\\w.]*\\s*(\\([^)]*\\))?"; // rm @Nullable, @android.app.XXX(xxx)
    private static final String PATTERN_ABSTRACT = "\\)\\s*=\\s*\\d+\\s*;$";// rm ") = ${number};"
    private static final String PATTERN_BRIEF = "/\\*.*?\\*/";// rm "/*xxx*/"
    private static final String ONEWAY = "oneway ";
    private static final String PARCELABLE = "parcelable ";
    private static final String UNION = "union ";
    

    类查找

    为了可以准确识别类型,需要完整的查找到参数类型。

    1. 当前同目录下查找。
    2. 当前同工程目录下查找。
    3. framework/base目录下查找。
    4. Android SDK目录下查找(可在config.txt中配置ANDROID_HOME路径)。

    个性化配置

    1. 全局配置: config.txt

    # 配置 Android SDK 源码路径
    ANDROID_HOME=C:\Users\Administrator\AppData\Local\Android\Sdk
    # 配置最大递归访问深度,提升效率
    MAX_LEVEL=4
    

    2. 忽略类型: ignore.txt

    byte
    short
    int
    long
    char
    float
    double
    void
    boolean
    

    3. 忽略文件: ignore-file.txt

    忽略明确不需要关注的接口类,这样不会出现在结果中。

    # 系统服务使用
    RemoteServiceCallback.aidl
    
    # 系统 WiFi 管理模块,需要系统权限
    IWifiScanner.aidl
    

    4. 匹配类型: match.txt

    ApplicationInfo
    ComponentName
    PackageInfo
    ActivityInfo
    ServiceInfo
    ProviderInfo
    

    5. 文件映射: mapping.txt

    可以定制输出结果文件名。

    # rename out file
    # ${Android source file}=${target file}
    # such as:
    IActivityManager=IAMS
    

    6. 输出模板: template.java

    定制输出模板可以更好的和我们工程的代码融合,易于代码和结果对比。

    package android.app.os.service;
    
    import android.app.os.base.ProxyServiceBase;
    
    @templateFile@
    public class @templateClass@ extends ProxyServiceBase {
    
        @templateMethod@
    
    }
    
    5 条回复    2024-06-21 23:29:58 +08:00
    behindeye
        1
    behindeye  
       15 天前
    还是没明白具体能做什么,希望能提供个更具体的例子
    StinkyTofus
        2
    StinkyTofus  
       15 天前
    @behindeye #1 我的理解是类似于单元测试, 把系统接口都测一遍, 防止适配时遗漏了, 另外适配新安卓版本也会轻松很多。
    yippees
        3
    yippees  
       15 天前
    没有测试吧

    类似文件搜索文本
    iofomo
        4
    iofomo  
    OP
       14 天前
    @StinkyTofus 酷,是的
    iofomo
        5
    iofomo  
    OP
       14 天前
    @yippees 我们内部每次系统适配时一直在使用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2453 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 05:57 · PVG 13:57 · LAX 22:57 · JFK 01:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.