android - (ART/DVM) 在 :try_end instruction results in VerifyError 之前插入指令

标签 android reverse-engineering dex smali

我已经使用 smali/baksmali 一段时间了,并且我在一定程度上理解了这些说明。最近,我遇到了一个非常奇怪的错误。 在对齐的 try-catch block 之后插入指令会导致运行时发生冲突类型VerifyError。 我对可能的原因做了一些假设,包括假设 ART 不接受期望可移动结果的调用,但事实并非如此。我还尝试插入 sput 指令来检查它是否有效,但它不起作用。但对于我见过的一些方法,在同一位置插入 put 指令效果很好,这让我相信这是一个对齐问题。但我不知道这是基于什么规则。

根据我的理解,当寄存器的类型可能通过分支到不同的条件或goto语句而更改时,就会发生冲突类型错误。但在这种情况下,我似乎无法弄清楚在哪里跳转可以保证这种情况发生。

以该方法为例

.method private static zzd(Ljava/lang/String;)I
    .locals 7

    const/4 v0, 0x0

    const/4 v1, 0x2

    const/4 v2, 0x3

    const/4 v3, 0x1

    :try_start_0
    const-string v4, "[.-]"

    .line 19
    invoke-static {v4}, Lcom/a/b/c/d/zzax;->zza(Ljava/lang/String;)Lcom/a/b/c/d/zzax;

    move-result-object v4

    invoke-virtual {v4, p0}, Lcom/a/b/c/d/zzax;->zza(Ljava/lang/CharSequence;)Ljava/util/List;

    move-result-object v4

    .line 20
    invoke-interface {v4}, Ljava/util/List;->size()I

    move-result v5

    if-ne v5, v3, :cond_0

    .line 21
    invoke-static {p0}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I

    move-result p0

    return p0

    .line 22
    :cond_0
    invoke-interface {v4}, Ljava/util/List;->size()I

    move-result v5

    if-lt v5, v2, :cond_1

    .line 23
    invoke-interface {v4, v0}, Ljava/util/List;->get(I)Ljava/lang/Object;

    move-result-object v5

    check-cast v5, Ljava/lang/String;

    invoke-static {v5}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I

    move-result v5

    const v6, 0xf4240

    mul-int v5, v5, v6

    .line 24
    invoke-interface {v4, v3}, Ljava/util/List;->get(I)Ljava/lang/Object;

    move-result-object v6

    check-cast v6, Ljava/lang/String;

    invoke-static {v6}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I

    move-result v6

    mul-int/lit16 v6, v6, 0x3e8

    add-int/2addr v5, v6

    .line 25
    invoke-interface {v4, v1}, Ljava/util/List;->get(I)Ljava/lang/Object;

    move-result-object v4

    check-cast v4, Ljava/lang/String;

    invoke-static {v4}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I

    move-result p0

    # Inserting any instruction here causes a type p0 to become a conflicted type

    :try_end_0
    .catch Ljava/lang/IllegalArgumentException; {:try_start_0 .. :try_end_0} :catch_0

    add-int/2addr v5, p0

    return v5

    :catch_0
    move-exception v4

    const-string v5, "LibraryVersionContainer"

    .line 29
    invoke-static {v5, v2}, Landroid/util/Log;->isLoggable(Ljava/lang/String;I)Z

    move-result v2

    if-eqz v2, :cond_1

    new-array v1, v1, [Ljava/lang/Object;

    # Trying to insert the value of p0 into the object array causes the VerifyError

    aput-object p0, v1, v0

    aput-object v4, v1, v3

    const-string p0, "Version code parsing failed for: %s with exception %s."

    .line 31
    invoke-static {p0, v1}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

    move-result-object p0

    .line 32
    invoke-static {v5, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

    :cond_1
    const/4 p0, -0x1

    return p0
.end method

最佳答案

baksmali 的 --register-info 标志是你的 friend 。它将为每条指令添加注释,其中包含有关寄存器类型的详细信息。它应该准确地向您显示寄存器类型发生冲突的位置,包括传入边缘和来自每个边缘的传入类型。

baksmali d --off --register-info ARGS,DEST,FULLMERGE -b "" blah.dex

例如这是关于 p0 的评论从您的原始源开始,在 try_end 之前添加一条指令(例如 invoke-static {v4}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I )后,它在 catch block 处发生冲突。

#p0=(Conflicted):merge{0x3:(Reference,Ljava/lang/String;),0x4:(Reference,Ljava/lang/String;),0x9:(Reference,Ljava/lang/String;),0xd:(Reference,Ljava/lang/String;),0x12:(Reference,Ljava/lang/String;),0x1d:(Reference,Ljava/lang/String;),0x22:(Reference,Ljava/lang/String;),0x23:(Reference,Ljava/lang/String;),0x2c:(Reference,Ljava/lang/String;),0x31:(Reference,Ljava/lang/String;),0x32:(Reference,Ljava/lang/String;),0x3a:(Reference,Ljava/lang/String;),0x3e:(Reference,Ljava/lang/String;),0x3f:(Reference,Ljava/lang/String;),0x44:(Integer)}

每个传入边都来自 try block 中的指令,这些指令可能会引发异常。通过在 move-result p0 之后添加可以抛出异常的新指令try block 末尾的指令,您将向 catch block 添加一个新的传入边缘,以及 p0 的值该边 ( Integer ) 与所有其他边的类型不兼容,因此合并类型被视为 CONFLICTED .

合并注释中的数字指的是传入边的代码偏移量。当您使用 --code-offsets 选项进行反汇编时(--off 是该选项的快捷方式),baksmali 将为每条指令添加带有代码偏移量的注释,因此您可以将寄存器信息注释中的代码偏移量与实际指令。

值得注意的是,合并注释中的代码偏移量指的是实际可以抛出的指令之前的指令。如果抛出异常,则抛出的指令不会影响任何寄存器,因此传入类型来自前一条指令的后指令类型。

关于android - (ART/DVM) 在 :try_end instruction results in VerifyError 之前插入指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65513195/

相关文章:

android - 找不到我的 apk 的重新编译版本

linux - 根据头信息计算ELF文件的大小

android - Google Play 服务 - 包含 dex 错误

android - 如果已经运行,则阻止启动主要 Activity

android - 尝试使用 Activity 的 EditText 中的字符串作为记录 Activity 的文件名

android - java.lang.IllegalMonitorStateException : unlock of unowned monitor at java. util.Random.nextGaussian(Random.java:187)

android - 在 spyk 对象上 stub 方法会立即调用原始方法

assembly - Ghidra:自动将字节设置为 Unicode/CString

android - 通过类加载器从 dex 文件访问应用程序类

android - Android Studio 3.0 Beta4 上的 Dex 错误