This article is the third in the Android reverse series. It begins to introduce the relevant knowledge of Dalvik VIRTUAL machine, understand dex and SMALI file formats, and get familiar with Dalvik bytecode and instruction set. Once you have a general understanding of Dalvik instruction set, you can start simple decompilation static analysis. In the following part, four components of Android development and a simple EXAMPLE of APK development using Eclipse are mentioned. In the end, a cracking example is used to deepen the knowledge and concepts of the whole paper and further familiarizing with the use of tools and Dalvik instruction set.

A, Dalvik

1. Introduction to Dalvik

Dalvik is a virtual machine specially designed by Google for Android operating system. Dalvik VM is register-based, while JVM is based on stack. Dalvik has its own file execution format, DEX (Dalvik Executable), while the JVM executes Java bytecode. The Dalvik VM is faster and takes up less space than the JVM.

We can’t modify a certain logic in Java code, so we need to translate the Java code into smali code, which is a dex file into a SMALI file. It can be understood that the SMALI in Dalvik can be modified, but the Java code cannot be modified. Therefore, we want to crack the code, that is, change the Java code to smALI code, modify the SMALI code and then compile it back. Meanwhile, the Java logic has changed.

Smali format is an intuitive and readable form of DEX format

Smali files can be thought of as Davilk’s bytecode files

See the follow-up introduction to Smali

2. Dalvik register nomenclature

In the Dalvik VIRTUAL machine parameter passing method, if a function uses M registers and the parameters of the function are N, then the parameter uses the last N registers and the local variable uses the first M-N registers from the beginning

The Dalvik register has two nomenclatures

V nomenclature

The v naming method uses a lowercase letter “V” to indicate the local variables and parameters used in the function. All registers are named in ascending order starting from v0.

Parameter register V (M-N) VM Local variable register v0 vn

P nomenclature

Basically similar, the main is that the parameter register is named using P register, while the local variable register is still named using V register

Parameter register P0 PN Variable register v0 vN

3, V naming Smali code analysis

The Smali code is shown below, starting with the first line

static public DecryptDemo->getHelloWorld(Ljava/lang/string; I)Ljava/lang/string;Copy the code

The first line calls a getHelloWorld() method. The parentheses indicate two arguments, Ljava/lang/String and I, with semicolons; Separated, the return value is of type Ljava/lang/String

Regsize :[5] indicates that there are five registers

The first red box calls the method to store the values of the v2 and v3 registers and returns a v2. In the second red box, the method is called to store the values of registers V0 and V4, returning a v0.

Invoke-virtual virtual method invocation. The invoked method is recognized at runtime as the actual invocation, with reference to the actual object referenced by the instance, dynamically recognized

4. Code analysis of P naming method Smali

Again, the first line shows that a getHelloWorld() method is called with two arguments, Ljava/lang/String and I, using a semicolon; Separated, the return value is of type Ljava/lang/String

invoke-virtual {v1, p0}, Ljava/lang/stringBuilder; ->append (Ljava/lang/String;) Ljava/lang/StringBuilder; move-result-object v1Copy the code

The first red box calls an append method in the LJava/lang/StringBuilder class to concatenate the passed String and return LJava/lang/StringBuilder with an incoming argument at p0 and an outgoing argument at v1. A move-result-object is returned

The second red box is similar in that it calls an append method to concatenate the incoming String and returns a LJava/lang/StringBuilder type with an incoming argument at p1 and an outgoing argument at v0

Dex file decompiler tool

Dalvik VM does not support the direct execution of JAVA bytecode, so it translates, reconstructs, interprets and compresses the compiled.class file. This process is processed by DX, and the generated product ends in.dex, which is called dex file.

The tools and processes involved in the whole compilation/decompilation are as follows:

1) Compile the SMALI file flow

.java ==> .class ==> .dex ==> .smali
Copy the code

2) The dx.jar script packages the class file as a dex file

dx --dex --output=Test.dex com/xxx/ooo/Test.class
Copy the code

3) The baksmali. jar script decompiles dex files into smali files

java -jar baksmali.jar -o smali_out/ source.dex
Copy the code

4) The smali.jar script packages smali files into dex files

java -jar smali.jar smali_out/ -o source.dex
Copy the code

6. Dalvik bytecode type

Davilk bytecode has only two types: primitive and reference types, and objects and arrays are both reference types.

Both the basic type and the void type, which has no return value, are represented by an uppercase letter representing the object type by the letter L plus the fully qualified name of the object and the array type by [

What is a fully qualified name?

In the case of String, whose full name is java.lang.String, its fully qualified name is Java /lang/String; . The Java. Lang. String. “” Replace “/” with a semicolon at the end; Do the terminator

The specific rules are as follows:

Type Descriptor Java type V voidZ BooleanB byteS stringC charI intJ longF floatD doubleL Java object type \[Array typeCopy the code

To explain Java object types: L can stand for any class in a Java type, such as java.lang.String in Java code, which is described in Davlik as Ljava/lang/String

2. Dalvik instruction set

The above is just a brief understanding of Dalvik bytecode, and the specific logic involved in each method still needs to be explained by Dalvik instruction set. Dalvik instruction set is introduced below. Since Dalvik VIRTUAL machine is based on register architecture, its instruction set style is more inclined to assembly instruction in x86

Data definition instruction

The const directive defines data such as variables, constants, classes, etc. in code

instruction describe
const/4 vA,#+B Assign the value to register vA by expanding the value symbol to 32
const-wide/16 vAA,#+BBBB Assign a register to vAA after extending the numeric symbol to 64 bits
const/high16 vAA, #+BBBB0000 Extend the zero on the right of the value to 32 bits and assign to register vAA
const-string vAA,string[@BBBB](https://github.com/BBBB “@BBBB”) High string is assigned to register vAA by string index
const-class vAA,type[@BBBB](https://github.com/BBBB “@BBBB”) Get a class reference by type index and assign it to register vAA

Data manipulation instruction

The move directive is used to manipulate data in code

instruction describe
move vA,vB Assign the value of the vB register to the vA register, both of which are 4 bits
move/from16 vAA,VBBBB Assign the value of the vBBBB register (16 bits) to the vAA register (7 bits),from16 indicating that the source register vBBBB is 16 bits
move/16 vAAAA,vBBBB Assign the value of register vBBBB to register vAAAA,16 means that both source register vBBBB and target register vAAAA are 16 bits
move-object vA,vB Assign an object reference in the vB register to the vA register, which is 4 bits, as is the vB register
move-result vAA Assign the single-word (32-bit) non-object result of the last invoke instruction (method call) operation to the vAA register
move-result-wide vAA Assign the binary (64-bit) non-object result of the previous invoke instruction operation to the vAA register
mvoe-result-object vAA Assign the result of the object operated on by the previous Invoke instruction to the vAA register
move-exception vAA Save the exception that occurred at the previous run time to the vAA register

More instructions

CMP/CMPL is used to compare two register values, CMP greater than the result means 1, CMPL greater than the result means -1.

instruction instructions
cmpl-float vAA,vBB,vCC Compares two single-precision floating point numbers. If the value in the vBB register is greater than that in the vCC register, -1 is returned to the vAA, 0 is returned for equality, and 1 is returned for less
cmpg-float vAA,vBB,vCC Compare two single-precision floating-point numbers and return 1 if the value in the vBB register is greater than the vCC value, 0 for equality, and -1 for less than
cmpl-double vAA,vBB,vCC Compare two double-precision floating-point numbers, returning -1 if the value in the vBB register is greater than the vCC value, 0 if equal, and 1 if less
cmpg-double vAA,vBB,vCC Compare a double – precision floating-point number
cmp-double vAA,vBB,vCC Equivalent to CMPG -double vAA,vBB,vCC instruction

Jump instruction

Davlik provides three jump instructions for jumping to different addresses: goto, Swicth and if

instruction operation
goto +AA Unconditionally jump to the specified offset (AA is the offset)
packed-switch vAA,+BBBBBBBB The value in the vAA register is the value that needs to be determined in the switch branch, and the value in the BBBBBBBB register is the index value in the offset table (Packed -switch-payload).
spare-switch vAA,+BBBBBBBB The random branch hop command is similar to the Packed -switch, except that the index value in the BBBBBBBB offset table (spread-switch-payload) is payload
if-eq vA,vB,target The equality in the vA and vB registers is equivalent to if(a==b) in Java, such as if-eq v3,v10,002c, which means jump to current position+002c if the condition is true. The rest are similar
if-ne vA,vB,target Equivalent to if(a! =b)
if-lt vA,vB,target The value in the vA register is less than vB, equivalent to if(a ‘<‘ b) in Java.
if-gt vA,vB,target Equivalent to if(a > b) in Java
if-ge vA,vB,target Equivalent to if(a ‘>=’ b) in Java
if-le vA,vB,target Equivalent to if(a ‘<=’ b) in Java

Return instructions

The return directive returns the result of the execution of a method

instruction instructions
return-void Return nothing
return vAA Returns a 32-bit value of a non-object type
return-wide vAA Returns a 64-bit value of a non-object type
return-object vAA A reference to an object type is returned

Method call instruction

Invoke-virtual: invokes the instance's virtual method (normal method)invoke-super: invokes the instance's parent/base class method invoke-direct: invokes the instance's direct method invoke-static: Invoke-interface: Invokes the instance's interface methodCopy the code

Instance operation instruction

The operation object instance is related

instruction describe
new-instance vAA,type[@BBBB](https://github.com/BBBB “@BBBB”) Constructs an object of the specified type to assign a reference to the vAA register. Array objects are not included here
instance-of vA,vB,type[@CCCC](https://github.com/CCCC “@CCCC”) Determines if the reference to an object in the vB register is of the specified type, if so, assign v1 to 1, otherwise 0
check-cast vAA,type[@BBBB](https://github.com/BBBB “@BBBB”) Converts a reference to an object in the vAA register to the specified type. On success, the result is assigned to vAA; otherwise, a ClassCastException is thrown.

Null operation instruction

Nop directives have no practical meaning and are generally used for code alignment

There are also some instructions not introduced, a little understanding of the next can be, in the actual test encountered to explain learning

Three, Android development four components

When it comes to Android development, it is inevitable to mention its four components Activity, Service, BroadcastReceiver and ContentProvider, whose functions are respectively

BroadcastReceiver provides BroadcastReceiver functions. ContentProvider supports multiple applications to store and read dataCopy the code

1

An Activity provides an interface for users to complete related operations. An APK usually contains multiple activities that can be invoked only after being declared in the Android manifest.xml.

Activity Lifecycle

To start the AcElasticity process, call the onCreate() method to create an Acelasticity, call the onStart() method to make it visible instead of invisible, and call the onResume() method to enable users to manipulate the interface to gain focus and to run On Advantage. Call onPause() to make the page unfocused (call onResume() to get the focus to continue), and call onStop() to make the page invisible (if the dialog box is visible). At this point, the onRestart() method can be called to restore to the onStart() state, or after onDestroy(), the AcElasticity interface disappears and the AcElasticity process ends.

B: Yes, it is

If a Service does not end when we exit an application, it is still running in the background, when do we need a Service? For example, when we play music, we might want to do other things while listening to music. When we quit the music application, if we don’t use Service, we can’t hear the song, so we need Service. Or when we get data from an application over the network, When the data is different at different times, we can use Service to update the data periodically in the background, instead of retrieving the data every time we open the application.

Service Life cycle

A Service life cycle is not as complex as an Activity. It inherits onCreate(), onStart(), and onDestroy(). When we first start the Service, we call onCreate() and onStart(). When the Service is stopped, the onDestroy() method is executed. It is important to note that if the Service is already started, when we start it again, the onCreate () method is not executed, but the onStart() method is executed directly.

3. BroadcastReceiver

BroadcastReceiver receives and sends system-wide notifications, allowing any Android application to receive messages from the system and other applications

4. ContentProvider

ContentProvider is used to share data between different applications. It provides a complete mechanism that allows one application to access data in another application while ensuring the security of the accessed data. Using ContentProvider is the standard way for Android to share data across applications

There are two ways to implement ContentProvider:

  1. Use existing content providers to read and manipulate data in programs

  2. Create your own content provider to provide external access to our program’s data.

An application provides an external access interface API to its data through a content provider, which can be accessed by any other application. For example, the Android phone book, SMS, and media library programs all provide similar access apis.

Iv. Use Eclipse development tools

This section takes a quick look at Eclipse and develops a simple APK to run on an emulator/real machine

1. Create an Android app project

1) Create an Android Application Project

2) Enter the name of the new application

3) Set the icon of the application

4) Select blank components

Select the Activity component, there are different types, you can choose, here select the blank component first

Then select Finish

2. Introduction of project files

After creating the project in step 1, the following page is displayed

The main program code mainactivity. Java can be found in the left project bar. Double-click to view it

Androidmanifest.xml is the manifest file for any application. It contains all of the application’s declarations and some configuration information, such as the version of Android and some android icon names

Eclipse provides the following graphical and code operations for manifest.xml

3. Build projects

Just add some components in the left sidebar. For further study, please develop your own Google Android

4. Run projects

Export the new project to run

Select lightning Simulator

Double-click the start

Five, jADX-GUI decompiler tool use

Here is an introduction to the simple use of Jadx tool steel, and then into the cracking example of section 6

Tip: Just drag it in and click on the search class to complete the decompilation

1. Loading files and introduction

Load snake APK file, there are two main decompile files, source code and resource file, resource file corresponding to the file in APK (here with compression software open APK file view)

2. Simple search classes

3. Function jump

Select the function and press Ctrl+ to jump directly to the function declaration. For example, BuyFailed() here

Six, snake APK crack

1, Snake APK cracking introduction

The BuyFailed() and BuySccess() functions can be repositioned or modified, but cannot be modified in the Java code layer. It can only be modified in the Smali code layer. Let’s take a look at the Smali code and some underlying knowledge

2. Study on apK program

Click the buy button on the store page and the payment failure is displayed as shown below.

Our goal: to buy all skins for free

3, Jadx tool decompilation analysis

Drag into the file, search for the location of “payment cancellation”, and simply check the code. It can be found that both payment cancellation and payment failure will jump to BuyFailed() method, while successful payment will jump to BuySccess() method. We can think of overwriting the successful method to achieve the effect of free purchase. Then follow up the analysis at the Smali code layer.

4, Android Killer decompiling tools | Smali code analysis

Drag the APK program into Android Killer to decompile, search for the word “cancel payment” in project search, and jump to the SMali code that contains that character

However, there is a small problem. How can I be sure that the SMali code here corresponds to the Java code I just saw? Android Killer provides the ability to decomcompile back to Java code. Click the logo at the top of the image below to view the Java source code, and you can see that it is consistent.

5, replace | smali code to compile

Find the smALI code that successfully paid, as shown in the red box below

Overwrites the smALI code where the payment failed and the payment was cancelled

Save and compile back

6, check the effect

As you can see, it’s already available for free