Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does DalvikVM handle switch and try smali code

Tags:

dalvik

smali

I am trying to learn smali and I have a few question that I couldn't find by googling them.

1) I created a simple test case to better explain myself

const-string v1, "Start"
:try_start_0
const-string v1, "Try Block"
invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0

The .catch statement: does the two arguments mean take from that label to that label and catch it (the code between the two label) or does it mean start executing the try from :try_start_0 up until it reaches :try_end_0 (allows a goto jump to execute code not within the two labels)?

Is the labels for try always in the format try_start_%d or can they be any label?

2)Another case

packed-switch v0, :pswitch_data_0

const-string v1, "Default Case"

invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V

:goto_0

const-string v1, "The End"

invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V

return-void

:pswitch_0
const-string v1, "Case 1"

invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V

goto :goto_0

:pswitch_data_0
.packed-switch 0x1
:pswitch_0
.end packed-switch

The switch statement: Does it require that the switch statements lie between the switch data and the switch call? and also again the naming of the labels fixed or just that for convenience?

3)If the labels can be different, would baksmali ever produce smali code with different labels?

4)What are the optional lines that aren't always shown when decompiling a dex?

I know .parameter and .line are optional, but what are all the ones that might not be there?

Thank you in advance.

like image 990
Xonar Avatar asked Dec 31 '12 11:12

Xonar


1 Answers

1)

The first two labels (try_start_0 and try_end_0 in your example) define the range of code that the try block covers. If an exception happens within the covered code, then execution immediately jumps to the third label (catchall_0). The name of the label isn't important, it can be any valid identifier.

There is also the .catch directive, with is the same thing, except it only handles a specific type of exception (similar to java's catch statement).

A block of code can be covered by multiple catch statements, and at most 1 catch all statement. The location of the .catch statement is not important, however, the relative ordering of catch statements that cover the same code is import. For example, if you have

.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :handler1
.catch Ljava/lang/RuntimeException; {:try_start_0 .. :try_end_0} :handler2

The 2nd catch statement will never be used. If a RuntimeException is thrown in the covered code, the first catch will always get used, since a RuntimeException is an Exception.

However, if they were in the opposite order, it would work like you expect - the RuntimeException handler gets used for RuntimeExceptions, and the Exception handler gets used for any other type of exception.

And finally, unlike java, the range of code in the .catch statements does not need to be strictly nested. For example, it's perfectly legal to have something like

:a
const-string v1, "Start"
:b
const-string v1, "Try Block"
:c
invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V
:d
.catch Ljava/lang/RuntimeException; {:a .. :c} :d
.catch Ljava/lang/Exception; {:b .. :d} :d

You can also have some pretty weird constructions, like this.

.method public static main([Ljava/lang/String;)V
    .registers 3

    :second_handler
    :first_try_start
        new-instance v0, Ljava/lang/RuntimeException;
        invoke-direct {v0}, Ljava/lang/RuntimeException;-><init>()V
        throw v0
    :first_try_end
    .catch Ljava/lang/Exception; {:first_try_start .. :first_try_end} :first_handler
    :first_handler
    :second_try_start
        new-instance v0, Ljava/lang/RuntimeException;
        invoke-direct {v0}, Ljava/lang/RuntimeException;-><init>()V
        throw v0
    :second_try_end
    .catch Ljava/lang/Exception; {:second_try_start .. :second_try_end} :second_handler
.end method

Neither of the above examples would ever be generated from compiled java code, but the bytecode itself allows it.

2) The switch statements could be anywhere in relation to the switch statement or switch data. The label names here are arbitrary as well.

3) Baksmali can generate labels in one of 2 ways. The default way is to use the general "type" of label, and append the bytecode address of the label. If you specify the -s/--sequential-labels option, instead of using the bytecode address, it keeps a counter for each label type and increments it each time it generates a label of that type.

4) Generally anything that is part of the debug information. .parameter, .line, .prologue, .epilogue, .source, .local, .restart local, .end local... I think that about covers it.

like image 145
JesusFreke Avatar answered Oct 26 '22 04:10

JesusFreke