使用python脚本来实现AndResGuard框架的反资源混淆脚本

前言

最近反编译其他人APP的时候发现其他人使用了微信的资源混淆,所以记录一下如何使用python脚本解决AndResGuard框架反混淆资源

1.首先我们写一个小例子

public class MyActivity extends Activity{
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        int color=getResources().getColor(R.color.colorPrimary);
        String str=getResources().getString(R.string.app_name);
        Drawable drawable=getResources().getDrawable(R.mipmap.ic_launcher);
    }
}

这个是我们的例子,我们先使用AndResGuard混淆一下,看看我们的结果

public class MyActivity
  extends Activity
{
  protected void onCreate(@Nullable Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    getResources().getColor(2130771969);
    getResources().getString(2131099648);
    getResources().getDrawable(2131034112);
  }
}

可以看到资源变成了一堆数字,然后我们再看看apktool反编译出来的资源


屏幕快照 2018-12-17 下午2.24.02.png
屏幕快照 2018-12-17 下午2.24.25.png

而混淆资源对应的参照表就在混淆的res/values/public.xml里,规则为代码资源int转16进制查找public.xml里对应的name,然后去找string、layout、mipmap、drawable、id、style、color

比如上面的getDrawable(2131034112)转为16进制是0x7f050000,public.xml里对应的

屏幕快照 2018-12-17 下午2.28.35.png

图片对应a,那么资源文件里就是上面的a.png了

分析smali语法

.class public Lcom/hw/mytestdemo/MyActivity;    #类路径
.super Landroid/app/Activity;   #超类
.source "MyActivity.java"   #类名


# direct methods    #表示该类的不带参数的构造方法
.method public constructor ()V
    .locals 0

    .prologue
    .line 12
    invoke-direct {p0}, Landroid/app/Activity;->()V

    return-void
.end method


# virtual methods   #虚方法  简单的理解就是@override方法就是虚方法
.method protected onCreate(Landroid/os/Bundle;)V  #void 方法onCreate入口
    .locals 5   #2个参数,Bundle和Nullable 对应5个寄存器(v0~v4)
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;    #参数1,Bundle类型的param savedInstanceState
        .annotation build Landroid/support/annotation/Nullable; #参数2,Nullable注解
        .end annotation
    .end param  #参数完毕

    .prologue   #代码开始
    .line 15    #行数
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V   //对应 super.onCreate(savedInstanceState);

    .line 16    #16行对应invoke-virtual调用虚方法getResources()
    invoke-virtual {p0}, Lcom/hw/mytestdemo/MyActivity;->getResources()Landroid/content/res/Resources;

    move-result-object v3   #移动上一次方法调用的返回值,move-result-object返回的是一个object,所以返回的是Resource对象

    const v4, 0x7f010001    #对应参数R.color.colorPrimary  public.xml 里为0x7f010001

    invoke-virtual {v3, v4}, Landroid/content/res/Resources;->getColor(I)I  调用虚方法getColor(),I表示是int

    move-result v0 move-result-object返回的是一个对象,move-result返回的则是基本数据类型
    #下面的基本都和上面分析的是一样的了,这里就不多分析了
    .line 17
    .local v0, "color":I
    invoke-virtual {p0}, Lcom/hw/mytestdemo/MyActivity;->getResources()Landroid/content/res/Resources;

    move-result-object v3

    const/high16 v4, 0x7f060000

    invoke-virtual {v3, v4}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;

    move-result-object v2

    .line 18
    .local v2, "str":Ljava/lang/String;
    invoke-virtual {p0}, Lcom/hw/mytestdemo/MyActivity;->getResources()Landroid/content/res/Resources;

    move-result-object v3

    const/high16 v4, 0x7f050000

    invoke-virtual {v3, v4}, Landroid/content/res/Resources;->getDrawable(I)Landroid/graphics/drawable/Drawable;

    move-result-object v1

    .line 19
    .local v1, "drawable":Landroid/graphics/drawable/Drawable;
    return-void
.end method     #onCreate方法结束

可以看到资源ID都是以16进制存在的,我们可以根据这个规律来替换这些16进制int来更方便的让我们理解smali,下面开始编写python脚本

import os
import xml.dom.minidom as xmldom

public='public.xml'
target='MyActivity.smali'

class replaceHex():
    def __init__(self):
        self.target = target
        self.public=public

    def traverseXml(self):
        domobj=xmldom.parse(self.public)
        elementobj = domobj.documentElement
        subElementObj = elementobj.getElementsByTagName("public")
        for i in range(len(subElementObj)):
            yield {
                'type': subElementObj[i].getAttribute("type"),
                'name': subElementObj[i].getAttribute("name"),
                'id':subElementObj[i].getAttribute("id")
            }
    def replace(self):
        xml=self.traverseXml()
        with open(self.target,'r',encoding="utf-8") as f1,open("%s.bak" % self.target, "w", encoding="utf-8") as f2:
            content=str(f1.read())
            for i in xml:
                content=content.replace(i.get('id'),i.get('type')+'/'+i.get('name')+'['+i.get('id')+']')
            f2.write(content)
            os.remove(self.target)
            os.rename("%s.bak" % self.target, self.target)

r=replaceHex()
r.replace()

首先读取出public.xml,然后根据id替换smali文件,这里只提供一个思路,具体替换反编译的.java还是smali还是集体替换大家自由发挥,反编译结果如下

.class public Lcom/hw/mytestdemo/MyActivity;    #类路径
.super Landroid/app/Activity;   #超类
.source "MyActivity.java"   #类名


# direct methods    #表示该类的不带参数的构造方法
.method public constructor ()V
    .locals 0

    .prologue
    .line 12
    invoke-direct {p0}, Landroid/app/Activity;->()V

    return-void
.end method


# virtual methods   #虚方法  简单的理解就是@override方法就是虚方法
.method protected onCreate(Landroid/os/Bundle;)V  #void 方法onCreate入口
    .locals 5   #2个参数,Bundle和Nullable 对应5个寄存器(v0~v4)
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;    #参数1,Bundle类型的param savedInstanceState
        .annotation build Landroid/support/annotation/Nullable; #参数2,Nullable注解
        .end annotation
    .end param  #参数完毕

    .prologue   #代码开始
    .line 15    #行数
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V   //对应 super.onCreate(savedInstanceState);

    .line 16    #16行对应invoke-virtual调用虚方法getResources()
    invoke-virtual {p0}, Lcom/hw/mytestdemo/MyActivity;->getResources()Landroid/content/res/Resources;

    move-result-object v3   #移动上一次方法调用的返回值,move-result-object返回的是一个object,所以返回的是Resource对象

    const v4, color/b[0x7f010001]    #对应参数R.color.colorPrimary  public.xml 里为color/b[0x7f010001]

    invoke-virtual {v3, v4}, Landroid/content/res/Resources;->getColor(I)I  调用虚方法getColor(),I表示是int

    move-result v0 move-result-object返回的是一个对象,move-result返回的则是基本数据类型
    #下面的基本都和上面分析的是一样的了,这里就不多分析了
    .line 17
    .local v0, "color":I
    invoke-virtual {p0}, Lcom/hw/mytestdemo/MyActivity;->getResources()Landroid/content/res/Resources;

    move-result-object v3

    const/high16 v4, string/a[0x7f060000]

    invoke-virtual {v3, v4}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;

    move-result-object v2

    .line 18
    .local v2, "str":Ljava/lang/String;
    invoke-virtual {p0}, Lcom/hw/mytestdemo/MyActivity;->getResources()Landroid/content/res/Resources;

    move-result-object v3

    const/high16 v4, mipmap/a[0x7f050000]

    invoke-virtual {v3, v4}, Landroid/content/res/Resources;->getDrawable(I)Landroid/graphics/drawable/Drawable;

    move-result-object v1

    .line 19
    .local v1, "drawable":Landroid/graphics/drawable/Drawable;
    return-void
.end method     #onCreate方法结束

总结

smali语法值得更加深入学习

你可能感兴趣的:(使用python脚本来实现AndResGuard框架的反资源混淆脚本)