this is a basic example of smali code with some comments. view it with ultraedit and syntax highlighting to get the full effect. this file is also included and updated in lesson 0 of the way of the android cracker.
for reference of dalvik opcodes, visit Dalvik opcodes.
update: if you like this, you may also want to see some example structures.
update #2: threw in a little bit about primitives and arrays.
for reference of dalvik opcodes, visit Dalvik opcodes.
update: if you like this, you may also want to see some example structures.
update #2: threw in a little bit about primitives and arrays.
# class name, also determines file path when dumped .class public Lcom/packageName/example; # inherits from Object (could be activity, view, etc.) # note class structure is L; .super Ljava/lang/Object; # original java file name .source "example.java" # these are class instance variables .field private someString:Ljava/lang/String; # finals are not actually used directly, because references # to them are replaced by the value itself # primitive cheat sheet: # V - void, B - byte, S - short, C - char, I - int # J - long (uses two registers), F - float, D - double .field public final someInt:I # the :I means integer .field public final someBool:Z # the :Z means boolean # Do you see how to make arrays? .field public final someCharArray:[C .field private someStringArray:[Ljava/lang/String; # this is the <init> of the constructor # it calls the <init> of it's super, which in this case # is Ljava/lang/Object; as you can see at the top # the parameter list reads: ZLjava/lang/String;I # Z - boolean # Ljava/lang/String; - java String object # (semi-colon after non-primitive data types) # I - integer # (no semi-colon) # also notice this constructor returns V, which means void .method public constructor <init>(ZLjava/lang/String;I)V # declare how many variable spaces we will need # we can have: v0, v1, v2, v3, v4 and v5 as variables. # smali/baksmali by default uses .registers # but you can change this by using --use-locals # apktool uses --use-locals and --sequential-labels .locals 6 # these are not always present and are usuaully taken # out by optimization/obfuscation but they tell us # the names of Z, Ljava/lang/String; and I before # when it was in Java .parameter "someBool" .parameter "someInt" .parameter "exampleString" # the .prologue and .line directives can be mostly ignored # sometimes line numbers are useful for debugging errors .prologue .line 10 # p0 means parameter 0 # p0, in this case, is like "this" from a java class. # we are calling the constructor of our mother class. # what would p1 be? invoke-direct {p0}, Ljava/lang/Object;-><init>()V # store string in v0 const-string v0, "i will not fear. fear is the mind-killer." # store 0xF hex value in v0 (or 15 in base 10) # this destroys previous value string in v0 # variables do not have types they are just registers # for storing any type of value. # hexadecimal is base 15 is used in all machine languages # you normally use base 10 # read up on it: # http://en.wikipedia.org/wiki/Hexadecimal const/4 v0, 0xF # create instance of StringBuilder in v1 new-instance v1, Ljava/lang/StringBuilder; # initialize StringBuilder with v2 # notice it returns V, or void const-string v2, "the spice must flow" invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V # append p1, which is our first paramater and is boolean # therefore we use append(Z) # notice how append returns a StringBuilder invoke-virtual {v1, p1}, Ljava/lang/StringBuilder;->append(Z)Ljava/lang/StringBuilder; # use move-result-object to store previous result in v1 move-result-object v1 # non-objects use move-result or move-result-wide # append v2 to our StringBuilder # notice how this append takes a string and not Z const-string v2, "some random string" invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v1 # call toString() on our StringBuilder # if you use Java you know that most objects have toString() invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v1 # send our new string to the log. # this can be used to debug and can be picked up with ddms, logcat # or log collector. as an exercise look up what the d() function does # in the android developer documentation. const-string v0, "Tag" invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I move-result v0 # get the current time in milliseconds # J denotes a float or wide return value invoke-static {}, Ljava/lang/System;->currentTimeMillis()J move-result-wide v2 # note!! since it is a wide value, it takes up v2 AND v3 # so we must use v4 next # try to reuse variables if possible. const-wide/16 v4, 0x300 # this takes up v4 and v5 div-long/2addr v2, v4 # divide v2 by v4 long-to-int v2, v2 # convert v2 to an integer # since i wrote this in my head, there was no Java # compiler to add the .line's in the right places # but normally they would relate to actual Java lines # these are often removed with proguard optimization .line 12 # store p1 as an instance variable (someBool) for this class # in java this may look like this.someBool = p1; iput-boolean p1, p0, Lcom/packageName/example;->someBool:Z .line 14 # do the same for p3 and someInt iput p3, p0, Lcom/packageName/example;->someInt:I # get the value from p0.someInt iget v0, p0, Lcom/packageName/example;->someInt:I # now we will invoke a static method. # {} means empty parameters then the full package name followed by -> # then the method and it's return value. everything must be there. invoke-static {}, Lcom/packageName/example;->someMethod()Ljava/lang/String; # for different types of invoke-*, try this: # http://www.netmite.com/android/mydroid/dalvik/docs/dalvik-bytecode.html # invoke-virtual and direct take the class instance as a first parameter. .line 16 return-void # meditate on the void. .end method # try and figure this one out .method public static someMethod()Ljava/lang/String; # could i have used fewer variables? .locals 4 new-instance v0, Ljava/lang/Long; invoke-static {}, Ljava/lang/System;->currentTimeMillis()J move-result-wide v1 invoke-direct {v0, v1, v2}, Ljava/lang/Long;-><init>(J)V invoke-static {v0}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String; move-result-object v1 # notice use of return-object and not just return return-object v1 .end method