奇怪的赋值,TextView到Bundle,反编译后,为什么?
Strange assignment, TextView to Bundle, after decompiling, why?
我创建了一个简单的应用程序,一个计数器应用程序,它在按下按钮时将整数递增 1 并更新文本视图。代码如下:
public class MainActivity extends Activity {
public static int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = (TextView) findViewById(R.id.count);
textView.setText(Integer.toString(count));
final Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
count++;
textView.setText(Integer.toString(count));
}
});
}
...
}
在使用 dex2jar 和 jd-gui 反编译同一个应用程序后,我收到了以下代码:
public class MainActivity extends Activity {
public static int count = 0;
protected void onCreate(final Bundle paramBundle) {
super.onCreate(paramBundle);
setContentView(2130903040);
paramBundle = (TextView)findViewById(2131296257);
paramBundle.setText(Integer.toString(count));
((Button)findViewById(2131296256)).setOnClickListener(new View.OnClickListener() {
public void onClick(View paramAnonymousView) {
MainActivity.count += 1;
paramBundle.setText(Integer.toString(MainActivity.count));
}
});
}
...
}
在下一行:
paramBundle = (TextView)findViewById(2131296257);
paramBundle.setText(Integer.toString(count));
系统如何将textview设置为paramBundle?为什么会这样? paramBundle 是 Bundle 类型,TextView 不是 Bundle 的子类,而且根据反编译版本,Bundle 是最终的。反编译时出错了吗?是反编译器的信息有误还是为什么会得到这个结果?
编辑:
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.locals 3
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.prologue
.line 17
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 18
const/high16 v2, 0x7f030000
invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->setContentView(I)V
.line 20
const v2, 0x7f090001
invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v1
check-cast v1, Landroid/widget/TextView;
.line 21
.local v1, "textView":Landroid/widget/TextView;
sget v2, Lcom/example/rawa/helloworld/MainActivity;->count:I
invoke-static {v2}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 22
const/high16 v2, 0x7f090000
invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
.line 23
.local v0, "button":Landroid/widget/Button;
new-instance v2, Lcom/example/rawa/helloworld/MainActivity;
invoke-direct {v2, p0, v1}, Lcom/example/rawa/helloworld/MainActivity;-><init>(Lcom/example/rawa/helloworld/MainActivity;Landroid/widget/TextView;)V
invoke-virtual {v0, v2}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 30
return-void
.end method
我绝对不是smali专家,只是个新手。但我也使用 apktool 解码了应用程序并收到了上面的 smali 代码。根据我的理解,savedinstance (paramBundle) 被加载到 p1(=v3) 并在 onCreate 中使用,并且在第 20 行或第 21 行中没有以任何方式使用它。对我来说,这是一个反编译错误?请记住,apktool 允许再次构建应用程序,因此在反编译时不会丢失任何数据。
您提供的 smali 代码看起来是正确的。 运行 该应用程序也适用于原始源代码。但是jd-gui提供的代码连编译都编译不了.
我很好奇并用 dex2jar 反编译了你的应用程序。我将结果 MainActivity.class 上传到 this website。
有趣的部分:一些反编译器(Procyon and Fernflower) generated the correct code and made separate variables for both the Bundle and the TextView. JAD and CFR然而犯了与jd-gui相同的错误。他们都使用TextView 的 Bundle 变量。
看来您可以将错误归咎于 jd-gui。遗憾的是,我不能告诉你为什么会这样。
原因是局部变量的类型发生了变化,但部分反编译器未能正确处理
这是用 dex2jar + javap:
反编译的 onCreate
代码
protected void onCreate(android.os.Bundle);
Code:
0: aload_0
1: aload_1
2: invokespecial #20 // Method android/app/Activity.onCreate:(Landroid/os/Bundle;)V
5: aload_0
6: ldc #21 // int 2130903040
8: invokevirtual #25 // Method setContentView:(I)V
11: aload_0
12: ldc #26 // int 2131230720
14: invokevirtual #30 // Method findViewById:(I)Landroid/view/View;
17: checkcast #32 // class android/widget/TextView
20: astore_1
21: aload_1
22: getstatic #12 // Field count:I
25: invokestatic #38 // Method java/lang/Integer.toString:(I)Ljava/lang/String;
28: invokevirtual #42 // Method android/widget/TextView.setText:(Ljava/lang/CharSequence;)V
31: aload_0
32: ldc #43 // int 2131230721
34: invokevirtual #30 // Method findViewById:(I)Landroid/view/View;
37: checkcast #45 // class android/widget/Button
40: new #6 // class com/example/test/MainActivity
43: dup
44: aload_0
45: aload_1
46: invokespecial #48 // Method com/example/test/MainActivity."<init>":(Lcom/example/test/MainActivity;Landroid/widget/TextView;)V
49: invokevirtual #52 // Method android/widget/Button.setOnClickListener:(Landroid/view/View$OnClickListener;)V
52: return
这里aload_0
是MainActivity对象的局部变量,aload_1
是Bundle对象的局部变量。问题的根源出现在代码 #20,当 它将刚刚检索到的 TextView 对象的引用存储到局部变量 1 (astore_1
) 中,该变量之前存储了 Bundle目的!
这样做是因为 Bundle 对象不用于该方法的其余部分,因此重用其局部变量而不是新变量更有效。然而,这也意味着反编译器需要加倍努力才能生成正确的 Java 代码。
我创建了一个简单的应用程序,一个计数器应用程序,它在按下按钮时将整数递增 1 并更新文本视图。代码如下:
public class MainActivity extends Activity {
public static int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = (TextView) findViewById(R.id.count);
textView.setText(Integer.toString(count));
final Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
count++;
textView.setText(Integer.toString(count));
}
});
}
...
}
在使用 dex2jar 和 jd-gui 反编译同一个应用程序后,我收到了以下代码:
public class MainActivity extends Activity {
public static int count = 0;
protected void onCreate(final Bundle paramBundle) {
super.onCreate(paramBundle);
setContentView(2130903040);
paramBundle = (TextView)findViewById(2131296257);
paramBundle.setText(Integer.toString(count));
((Button)findViewById(2131296256)).setOnClickListener(new View.OnClickListener() {
public void onClick(View paramAnonymousView) {
MainActivity.count += 1;
paramBundle.setText(Integer.toString(MainActivity.count));
}
});
}
...
}
在下一行:
paramBundle = (TextView)findViewById(2131296257);
paramBundle.setText(Integer.toString(count));
系统如何将textview设置为paramBundle?为什么会这样? paramBundle 是 Bundle 类型,TextView 不是 Bundle 的子类,而且根据反编译版本,Bundle 是最终的。反编译时出错了吗?是反编译器的信息有误还是为什么会得到这个结果?
编辑:
# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
.locals 3
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.prologue
.line 17
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 18
const/high16 v2, 0x7f030000
invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->setContentView(I)V
.line 20
const v2, 0x7f090001
invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v1
check-cast v1, Landroid/widget/TextView;
.line 21
.local v1, "textView":Landroid/widget/TextView;
sget v2, Lcom/example/rawa/helloworld/MainActivity;->count:I
invoke-static {v2}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
.line 22
const/high16 v2, 0x7f090000
invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Landroid/widget/Button;
.line 23
.local v0, "button":Landroid/widget/Button;
new-instance v2, Lcom/example/rawa/helloworld/MainActivity;
invoke-direct {v2, p0, v1}, Lcom/example/rawa/helloworld/MainActivity;-><init>(Lcom/example/rawa/helloworld/MainActivity;Landroid/widget/TextView;)V
invoke-virtual {v0, v2}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V
.line 30
return-void
.end method
我绝对不是smali专家,只是个新手。但我也使用 apktool 解码了应用程序并收到了上面的 smali 代码。根据我的理解,savedinstance (paramBundle) 被加载到 p1(=v3) 并在 onCreate 中使用,并且在第 20 行或第 21 行中没有以任何方式使用它。对我来说,这是一个反编译错误?请记住,apktool 允许再次构建应用程序,因此在反编译时不会丢失任何数据。
您提供的 smali 代码看起来是正确的。 运行 该应用程序也适用于原始源代码。但是jd-gui提供的代码连编译都编译不了.
我很好奇并用 dex2jar 反编译了你的应用程序。我将结果 MainActivity.class 上传到 this website。
有趣的部分:一些反编译器(Procyon and Fernflower) generated the correct code and made separate variables for both the Bundle and the TextView. JAD and CFR然而犯了与jd-gui相同的错误。他们都使用TextView 的 Bundle 变量。
看来您可以将错误归咎于 jd-gui。遗憾的是,我不能告诉你为什么会这样。
原因是局部变量的类型发生了变化,但部分反编译器未能正确处理
这是用 dex2jar + javap:
反编译的onCreate
代码
protected void onCreate(android.os.Bundle);
Code:
0: aload_0
1: aload_1
2: invokespecial #20 // Method android/app/Activity.onCreate:(Landroid/os/Bundle;)V
5: aload_0
6: ldc #21 // int 2130903040
8: invokevirtual #25 // Method setContentView:(I)V
11: aload_0
12: ldc #26 // int 2131230720
14: invokevirtual #30 // Method findViewById:(I)Landroid/view/View;
17: checkcast #32 // class android/widget/TextView
20: astore_1
21: aload_1
22: getstatic #12 // Field count:I
25: invokestatic #38 // Method java/lang/Integer.toString:(I)Ljava/lang/String;
28: invokevirtual #42 // Method android/widget/TextView.setText:(Ljava/lang/CharSequence;)V
31: aload_0
32: ldc #43 // int 2131230721
34: invokevirtual #30 // Method findViewById:(I)Landroid/view/View;
37: checkcast #45 // class android/widget/Button
40: new #6 // class com/example/test/MainActivity
43: dup
44: aload_0
45: aload_1
46: invokespecial #48 // Method com/example/test/MainActivity."<init>":(Lcom/example/test/MainActivity;Landroid/widget/TextView;)V
49: invokevirtual #52 // Method android/widget/Button.setOnClickListener:(Landroid/view/View$OnClickListener;)V
52: return
这里aload_0
是MainActivity对象的局部变量,aload_1
是Bundle对象的局部变量。问题的根源出现在代码 #20,当 它将刚刚检索到的 TextView 对象的引用存储到局部变量 1 (astore_1
) 中,该变量之前存储了 Bundle目的!
这样做是因为 Bundle 对象不用于该方法的其余部分,因此重用其局部变量而不是新变量更有效。然而,这也意味着反编译器需要加倍努力才能生成正确的 Java 代码。