Android资源热修复之修改aapt源码

导语 : 在Windows下定制自己的aapt!

一、环境配置

1.1 软件和源码

Codeblocks下载地址:< mingw64下载地址:<https://jaist.dl.sourceforge.net/project/tdm-gcc/TDM- GCC%20Installer/> aapt源码地址(为了避免麻烦,特地弄好了aaptCodeblocks项目,直接从我的githubclone下来就能在Codeblocks中用):https://github.com/ClaymanTwinkle/aapt

1.2 软件配置

软件安装好了就要先配置下

1.2.1Codeblocks配置Compiler

步骤一: 选择进入工具栏 Settings » Compiler,如下图所示;

步骤二: (1)选择Global compiler settings; (2)在Selected compiler中选择GNU GCC Compiler,然后下方点击Copy按钮,就会出现Copy of GNU GCC Compiler; (3)在下方Toolchain executables配置mingw64,相关配置如下图所示; (4)最后选择OK即可;

配置好编译环境后,就可以打开项目了;进入aapt/aapt-v24中打开aapt-v24.workspace

工程目录结构如下图所示;

1.2.2 为每个工程配置Compiler

步骤一:右键一个工程,在右键菜单中选择Build Options

步骤二:第一次配置的时候,会出现一个弹窗,如下图;选择刚刚自己创建的Copy of GNU GCC Compiler,点击确定;

步骤三:注意,如果此时,出现以下对话框,请选择

对每个工程重复以上步骤;

二、改aapt源码

没错,如果上面的步骤都弄成功了,现在就可以改aapt源码了,是的,在Windows上改aapt源码,想想就激动! 普及一下一个小知识,在R.Java中可以看到系统资源的id都是以0x01开头的,而自己的资源id都是以0x7f开头的;这也就是说0x010x7f之间的的值我们都可以拿来用。 废话不多说,赶紧动手!

2.1 试改0x7f0x66

(1)在CodeBlocks中打开aapt-v24,找到我们要找的入口类main.cpp;同时也找到了入口方法main

(2)找到这个main.cpp有什么用,怎么修改0x7f呢?

我们可以这样,按快捷键Ctrl+F(真的很好用!),在aapt-v24中搜索0x7f,如下图所示;

搜索结果如下,这样我们就找到赋值0x7f的地方了;

ResourceTable.cpp这个类中;

(3)既然找到了位置,那赶紧改下这个值试试(直接改硬编码不太优雅,后面介绍一种优雅的方式),修改结果如下图所示;

接着,打包出自己的aapt吧!

(4)右键aapt-v24,在右键菜单中选择build或者rebuild,编译成功,打包出aapt.exe

aapt\aapt-v24\bin\Debug目录下可以看到打包好的aapt-24.exe

(5)打包好了,是骡子是马牵出来溜溜吧。

随便找个Android工程,然后在cmd中敲出类似这样一段命令行生成R.java

aapt-v24.exe p -f -m -I C:\Android\sdk\platforms\android-25\android.jar -J C:\Users\andyqtchen\Desktop\plurals -M C:\Android\workspace\AndroidQQ_Lite_proj/QQLite//AndroidManifest.xml -S C:\Android\workspace\AndroidQQ_Lite_proj/QQLite/res

结果……出乎意料啊,居然错了,是啊,哪有那么容易,想得美;但是,这些log好像是aapt自己内部打印出来吧?让我们看看这些log是从哪里打印出来的!

(6)神一样的快捷键Ctrl+F,搜~,结果如下图所示;

原来是在androidfw工程下的ResourceTypes.cpp搞的鬼! 先看看ResourceTypes.cpp耍的是什么把戏!

原来是这么回事,aapt除了会在aapt-v24中赋值,在androidfw中后面还会做一个判断拦截;

那么我在这里再加一个或者packageId==0x66就ok了(又一不文明操作,请勿模仿)! 改完重新rebuild androidfw,然后rebuild aapt-24打包出aapt.exe; 重新生成一次R.java,接下来就是见证奇迹的时刻!

2.2 定制化aapt

好了,上面的2.1只是小打小闹的一个实验而已,接下来要定制下随意修改资源ID前缀(packageId)的aapt

步骤一、定义一个单例

我在androidfw中定义一个单例,用来记录0x7f(默认值)或者其他自定义packageId的值;

// BlinkPackageId.h文件
#ifndef __BlinkPackageId_h
#define __BlinkPackageId_h

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

class BlinkPackageId
{
        ssize_t mPackageId;
public:
        static BlinkPackageId* getInstance()
        {
                static BlinkPackageId instance;
                return &instance;
        }
        ssize_t getPackageId();
        void setPackageId(ssize_t packageId);
        void setPackageId(const char* packageId);
protected:
        struct Object_Creator
        {
                Object_Creator()
                {
                        BlinkPackageId::getInstance();
                }
        };
        static Object_Creator _object_creator;
        BlinkPackageId() {
                mPackageId=0x7f;
        }
        ~BlinkPackageId() {
        }
};
#endif



// BlinkPackageId.cpp文件
#include 

#include 
#include 
#include 
using namespace std;

// char2int
static uint32_t apkgetHex(char c, bool* outError){
    if (c >= '0' && c <= '9') {
        return c - '0';
    } else if (c >= 'a' && c <= 'f') {
        return c - 'a' + 0xa;
    } else if (c >= 'A' && c <= 'F') {
        return c - 'A' + 0xa;
    }
    *outError = true;
    return 0;
}

// string2int
static ssize_t apkStringToInt(const android::String8& s){
    size_t i = 0;
    ssize_t val = 0;
    size_t len=s.length();
    if (s[i] < '0' || s[i] > '9') {
        return -1;
    }
    // Decimal or hex?
    if (s[i] == '0' && s[i+1] == 'x') {
        i += 2;
        bool error = false;
        while (i < len && !error) {
            val = (val*16) + apkgetHex(s[i], &error);
            i++;
        }
        if (error) {
            return -1;
        }
    } else {
        while (i < len) {
            if (s[i] < '0' || s[i] > '9') {
                return false;
            }
            val = (val*10) + s[i]-'0';
            i++;
        }
    }
    if (i == len) {
        return val;
    }
    return -1;
}

BlinkPackageId::Object_Creator BlinkPackageId::_object_creator;

ssize_t BlinkPackageId::getPackageId(){
        return mPackageId;
}
void BlinkPackageId::setPackageId(ssize_t  packageId){
        mPackageId=packageId;
}
void BlinkPackageId::setPackageId(const char* packageId){
        android::String8 str = android::String8(packageId);
        mPackageId=apkStringToInt(str);
}

步骤二、改造aapt命令行

定个需求,要加个--blink-package-id命令参数,后面带packageId;

锁定到aapt-v24工程下main.cpp源代码:

ResourceTable.cpp,将0x7f改成BlinkPackageId::getInstance()->getPackageId()

然后到androidfw工程下,把BlinkPackageId::getInstance()->getPackageId()放到if中:

ok!大功告成!

看看效果!!!

aapt-v24.exe p -f -m -I C:\Android\sdk\platforms\android-25\android.jar -J C:\Users\andyqtchen\Desktop\plurals -M C:\Android\workspace\AndroidQQ_Lite_proj/QQLite//AndroidManifest.xml -S C:\Android\workspace\AndroidQQ_Lite_proj/QQLite/res --blink-package-id 0x55

参考文章

如何实现携程动态加载插件中对aapt的改造 Android中如何修改编译的资源ID值(默认值是0x7F…可以随意改成0x02~0x7E)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程坑太多

『中级篇』Docker Compose的安装和基本使用(39)

PS: docker-compose的概念有直观的理解,包括compose的命令行和使用。 建议使用docker-compose up -d 后台来运行,如果不...

552
来自专栏编程坑太多

『中级篇』Docker Compose的安装和基本使用(39)

PS: docker-compose的概念有直观的理解,包括compose的命令行和使用。

895
来自专栏Java架构师历程

docker学习笔记(命令)

1092
来自专栏张善友的专栏

【实验手册】使用Visual Studio Code 开发.NET Core应用程序

.NET Core with Visual Studio Code 目录 概述... 2 先决条件... 2 练习1: 安装和配置.NET Core以及Visu...

2069
来自专栏王磊的博客

让Team Foundation Server/TFS自动记住用户名密码解决方案

在使用Team Foundation Server(以下简称TFS) 的时候,在每次打开Visual Studio TFS时候,需要输入用户名和秘密,比较麻烦。...

3505
来自专栏张善友的专栏

【实验手册】使用Visual Studio Code 开发.NET Core应用程序

1939
来自专栏翻译

如何在CentOS 6上安装和配置phpMyAdmin

phpMyAdmin是一个Web上的数据库管理工具,它提供了一个美观的GUI界面来帮助管理MySQL数据库。phpMyAdmin支持多个MySQL服务器,相比于...

441
来自专栏Jerry的SAP技术分享

Sublime Text插件的离线安装-使用htmlprettify美化您的HTML代码

Sublime Text是广大程序员喜欢的文本编辑器,Jerry觉得它最强大之处在于开放的架构,有丰富的插件为其提供各种各样额外的功能。

644
来自专栏A周立SpringCloud

Docker系列教程02-Docker安装(CentOS7/Ubuntu/macOS/Windows)

第二章 Docker安装 2.1 CentOS 2.1.1 系统要求 CentOS 7或更高版本 centos-extras 仓库必须处于启用状态,该仓库默认启...

36312
来自专栏finleyMa

docker学习系列5 nginx 容器

docker run 其实等于 docker create + start 因为tag为 1.15 的 nginx 镜像并不在本地,会先下载再运行

632

扫码关注云+社区