如何使用org.jf.dexlib2写入或重写dex文件?

问题描述 投票:0回答:1

我在网上找了好久。但没有用。请帮助或尝试给出一些如何实现这一目标的想法。 而且这里有一个demo但是我看不懂。我想知道dexlib2是否可以用来写入或重写dex文件

DexRewriter rewriter = new DexRewriter(new RewriterModule() {
public Rewriter<String> getTypeRewriter(Rewriters rewriters) {
    return new Rewriter<String>() {
        public String rewrite(String value) {
            if (value.equals("Lorg/blah/MyBlah;")) {
                 return "Lorg/blah/YourBlah;";
             }
             return value;
         }
     };
 }
});
DexFile rewrittenDexFile = rewriter.rewriteDexFile(dexFile);
java android dalvik dex smali
1个回答
0
投票

您有两种方法来重写 dex 文件。但在此之前,您需要了解一些基础知识。 首先,dex文件有类。每个类都有字段和方法。字段很简单。但方法有方法实现。这实际上是代码。该实现(代码)由指令组成。这些指令有多种类型。 例如,instruction21c 用于“const-string”。 您可以从以下对象的 dex 中读取其中的每一个 -

  1. 类:DexBackedClassDef 和 ClassDef
  2. 方法:DexBackedMethod 和 Method
  3. 字段:DexBackedField 和 Field
  4. 方法实现:DexBackedMethodImplementation 和 MethodImplementation
  5. MethodReference:DexBackedMethodReference 和........等等。

所以基本上你可以使用两个类来读取每个对象 - 一个是 Dexbacked,另一个是直接的。 区别在于 DexBackedObject 仅具有加载的 dex 文件上的指针。他们不保存任何数据。当调用这些对象的字段和方法时,它们会从 dex 文件中读取它们。否则它们是空的。 与它们不同的是,直接对象已经填充了数据。

然后来了-

  1. 方法参考
  2. 现场参考
  3. 类型参考
  4. 字符串参考

这些都是MethodImplementation(代码)的一部分。例如

const-string v1, "hellow World"

这条指令是指令21c。 该指令的操作码是“const-string” 该指令的RegisterA = v1 该指令的 Reference 类型为 StringReference。

再举个例子-

调用静态 p0, Lmyclass;->myMethod(LmyParam1;LmyParam2;):LmyRetType;

这整行代码在方法实现中生成了一条指令。 该指令的引用是 MethodReference 类型。 我希望你明白 xxxxxReference 类的含义。

然后我们来到 ImmutableXXXXXXXXXX——这些是什么? 例如 - ImmutableClassDef、ImmutableMethod、ImmutableMethodReference 等。 好吧,它们与上面的相同,如果你想改变一些东西,你必须创建一个新的 ImmutableXXXXX。例如,如果我想更改

const-string v1,"hellow world" to const-string v1, "i am manoj"
那么我无法编辑现有指令。相反,我必须创建一个新指令,在其中我将从原始数据复制除“hellow world”之外的大部分数据。为了创建这个新指令,我将使用 ImmutableInstruction。在这种情况下 - 新的 ImmutableInstructions21c。

现在我们来回答你的问题。如何编辑它以及如何理解示例。

第一种方法是使用重写器-

重写器接受方法作为接口。正如您所知,在 java 中,接口用于将方法作为参数传递。所以重写器接受一个方法作为参数。 在此方法中,方法参数是 classDef、Method、Field、Instruction 等。如果您不想更改,则可以返回原始对象。或者使用 ImmutableXXX 创建一个新对象,如果想要更改某些内容则返回它。 当您完成向重写器提供这些编辑方法后,您只需将 dex 文件提供给重写器即可。然后重写器将读取所有内容,即。 ClassDefs、方法、字段、指令、注释...并将它们扔给您的方法。 您定义的方法将编辑它们或按原样返回它们。从那里,它将使用它们编写一个新的 dex 文件。

DexRewriter rewriter = new DexRewriter  // the DexRewriter which will do the actual reading and writing of dex file. but its only parameter is a 'middleMan' method.
new RewriterModule() {} // this is our middle man
public Rewriter<String> getTypeRewriter(Rewriters rewriters) {} // this is our first worker which works under this middle man boss. this worker is expert in throwing found Types (like Lbla/bla/bla;) and getting modified ones from you.

// there can be many workers expert in different things. such as StringRewriter, MethodRewriters etc. you can also add them below it using @override.

//for example, MethodRewriter will throw all found methods at you and collect them as you modify or return as is.

public String rewrite(String value) {} //write code that edits throwed objects under this method.
//for example i want to replace Lmybla; to Lyourbla; everywhere in dex file- so i will write following code-
public String rewrite(String value) {
    if(value.equals("Lmybla;"){ 
        return "Lyourbla;";  //return edited.
    }else{
        return value; //dont touch, return as it.
    }
}

此示例代码适用于类型。这只是字符串。但如果您想编辑 .. 例如,可以说 .. .a 字段。那么你必须返回一个 ImmutableField 对象。

if(someCondition){
   return new ImmutableField(value.definingClass,value.Type,value.name);
}

类似这样的事情。

编辑dex文件的第二种方法-

第二种方法是使用dexPool。 dexPool 有很多池。如 stringPool、methodPool、fieldPool 等。 dexPool 使用其 intern() 方法读取类、方法等。 并收集其池中的所有中间项目。 所以在实习了整个dex文件之后,它的StringPool充满了在dex文件中找到的所有字符串..MethodPool充满了....等等。 然后它以 dex 文件格式重新排列所有这些池并写入 dex 文件。

所以如果你想编辑一些东西。首先列出原始 dex 文件的 ClassDef 列表。 然后选择一个你想要编辑的ClassDef。然后用新的 ImmutableClassDef 替换它

然后让 dexPool 内部化列表中的所有 classDef。并制作一个新的输出 dex 文件。

我已经使用这个 dexlib2 4 个月了。我希望我总结得很好。谢谢你。

© www.soinside.com 2019 - 2024. All rights reserved.