3, xpl0it 2015/11/02, but

0 x00 overview


Share the notes of learning SO reverse before, the content is relatively simple, Daniel can skip.

0x01 ARM register


1.1. General purpose register

1. Ungrouped register :R0~R7 2. Grouped register :R8~812 R13:SP, commonly used as a stack pointer, always pointing to the top of the stack, when a data (32 bits) pushed onto the stack, SP(R13 value minus 4) float down to the next address, that is, the new top of the stack, when the data popped off the stack, SP(R13 plus 4) floats up to the new top of the stack. R14: Connection register (LR), R14 gets a backup of R15(program counter PC) in R14 when executing BL subroutine call instructions, otherwise R14 is used as a general purpose register. R15: Program counter (PC): Used to control the execution order of instructions in a program. During normal operation, the PC points to the next instruction that the CPU runs. After each value, the value of PC will be automatically modified to point to the next instruction, so as to ensure that the instructions are executed in a certain order. When the execution order of the program changes (such as transfer), you need to modify the value of the PC.Copy the code

1.2. Status register

CPSR(R16): Current program status register, used to store the current operation information in ALU, control the allowed and forbidden interrupts, set the working mode of the processor, etc. SPSRs: Five backup program status registers for exception handling. When an exception occurs, the SPSR is used to save the current value of the CPSR. When the exception exits, the SPSR can restore the CPSR.Copy the code

N, Z, C and V are all conditional code flags whose contents can be changed by the result of operation.

Z: zero flag, Z=1 means that the result of the operation is 0, Z=0 means that the result of the operation is not 0 C: carry flag, when the addition operation produces carry flag, C=1, otherwise C=0, borrow flag, weight loss operation produces borrow flag, C=0, Otherwise, C=1 V: indicates an overflow flag. V=1 indicates that an overflow occurs, and V=0 indicates that no overflow occursCopy the code

1.3. Address space

When the program executes normally, each ARM instruction executes, the current instruction counter increases by 4 bytes.Copy the code

0x02 Assembly language


2.1. Assembly instruction format

<opcode>{<cond>}{S}<Rd>,<Rn>{,<OP2>} is essential, and the content in {} can be omitted <opcode>: indicates the operation code, for example, ADD indicates arithmetic addition. {<cond>}: indicates the condition field of instruction execution, such as EQ and NE. <Rd>: indicates the destination register <Rn>: indicates the first operand, is register <op2>: indicates the second operand, Can be immediate, register, or register shift operand examples: ADDEQS R0,R1,#8; Where the opcode is ADD, the condition field cond is EQ,S indicates that the execution of this instruction affects the value of the CPSR register, the destination register Rd is R0, the first operand register Rd is R1, and the second operand OP2 is the immediate number #8Copy the code

2.2. Optional suffixes for instructions

S: Condition flags in the program status register will be refreshed after the instruction is executed ADDS R1,R0,#2! The address expression in the instruction contains! LDR R3,[R0,#2]! LDR R3,[R0,#2]! LDR R3,[R0,#2]! After instruction is executed, R0 = R0 + 2Copy the code

2.3. Conditional implementation of instructions

The conditional suffix of an instruction only affects whether the instruction is executed, not its contentCopy the code
Condition code Mnemonic suffix mark meaning
0000 EQ Z setting equal
0001 NE Z reset Not equal to the
0010 CS C instruction An unsigned number is greater than or equal to
0011 CC C reset The unsigned number is less than
0100 MI N setting A negative number
0101 PL N reset Positive or zero
0110 VS V setting The overflow
0111 VC V zero Not overflow
1000 HI Set C and Z to zero The unsigned number is greater than
1001 LS C is cleared and Z is set An unsigned number is less than or equal to
1010 GE N equals V Signed number greater than or equal to
1011 LT N does not equal V The signed number is less than
1100 GT Z is cleared and (N equals V) The signed number is greater than
1101 LE Z transpose or N does not equal V. A signed number is less than or equal to
1110 AL ignore Unconditional execution

Example: ADDEQ R4,R3,#1 equal then add, that is, CPSR Z is set when this instruction is executed, otherwise not.

2.4.ARM instruction classification

mnemonics Command Function Description mnemonics Command Function Description
ADC With carry addition instruction MRC Data transfer instruction from the coprocessor register to the ARM register
ADD Add instruction MRS Instruction to transfer the contents of CPSR or SPSR to the general purpose register
AND Logic and instruction MSR An instruction to transfer a general purpose register to CPSR or SPSR
B Branch instruction MUL 32-bit multiplication instruction
BIC Bit clear instruction MLA 32 bit multiply plus instruction
BL Branch instruction with return MVN Data fetch reverse transmission instruction
BLX Branch instruction with return and state switching ORR Logic or instruction.
BX Branch instruction with state switching RSB Reverse subtraction instruction
CDP Coprocessor data manipulation instructions RSC Reverse subtraction instruction with dislocation
CMN Compare the inverse instruction SBC Belt dislocation subtraction instruction
CMP More instructions STC Coprocessor registers write memory instructions
EOR Xor instruction STM Batch memory word write instruction
LDC Instructions for data transfer from memory to coprocessor STR Register-to-memory data storage instructions
LDM Load multiple register instructions SUB Subtraction instructions
LDR An instruction to load data from memory to a register SWI Software interrupt instruction
MCR Instruction for data transfer from the ARM register to the coprocessor register TEQ Equality test instruction
MOV Data transfer instruction TST Bit test instruction

2.5.ARM addressing

Addressing is a way to find the actual physical address of an operand based on the operand information in the instructionCopy the code

2.5.1 Immediate digital addressing

MOV R0,#15,#15 is the immediate numberCopy the code

2.5.2 Register addressing

ADD the contents of R1 and R2, and store the result in register R0Copy the code

2.5.3 Register indirect addressing

LDR R0, [R4] takes the value of register R4 as the address of the operand and gets an operand from memory into register R0Copy the code

2.5.4 Register shift addressing

MOV R0,R1,LSL R3 Move the value of R1 R3 bits to the left, and then store the result in R0Copy the code

2.5.5 Base address change Address addressing

LDR R0,[R1,#4] LDR R0,[R1,#4] LDR R0,[R1,#4] R1 = R1+4 LDR R0,[R1],#4 R0 = [R1],R1 = R1+4 LDR R0,[R1,R2] R0 = [R1+R2]Copy the code

2.5.6. Multi-register addressing

A single instruction can complete the transfer of multiple register values (up to 16 general purpose registers), using "-" for successive registers, otherwise using ", "LDMIA R0! ,{r1-r4} R1 =[R0],R2=[R0+4],R3=[R0+8],R4=[R0+12] Suffix IA indicates that R0 increases in length after each play load/store operation.Copy the code

2.5.7. Relative addressing

Add the current value of the program counter PC as the base address and the address label in the instruction as the offset to get the effective address of the operand. proc MOV R0,#1 ...Copy the code

2.5.8. Stack addressing

Working in first-in, first-out mode, the stack pointer is represented by R13 and always points to the top of the stack, while LDMFD and STMFD represent POP out of the stack and PUSH STMFD R13! ,{R0 - R4}; LDMFD R13! ,{R0 - R4};Copy the code

2.6. Data processing instructions

2.6.1. MOV instruction

MOV {<cond>}{S} Rd,op2 pass OP2 to Rd R1, R0 pass R0 to Rr1 MOV PC,R14 pass R14 pass PC, MOV R1,R0,LSL #3 shift the value of register R0 3 bits left to R1 MOV R0,#5 will immediately pass the number 5 to R0Copy the code

2.6.2. MVN command

MVN {<cond>}{S}Rd, op2 invert op2 to Rd MVN R0,#0 invert 0 to R0, R0 = -1 MVN R1,R2 invert R2 and save the result to R1Copy the code

2.6.3. Shift instruction

LSL logic shift left LSR logic shift right ASR arithmetic shift right ROR loop shift right RRX loop with extension shift rightCopy the code

2.6.4. ADD the ADD instruction

ADD{<cond>}{S}Rd, Rn, op2 ADD R0,R1,R2 R0 = R1 + R2 ADD R0,R1,#5 R0 = R1 + 5 ADD R0,R1,R2,LSL #2 R0 = R1 + (R2 left 2 bit)Copy the code

2.6.5. ADC with carry add instruction

ADC{<cond>}{S} Rd,Rn,op2 add the value of Rn to the operand op2, plus the value of the C conditional flag bit in CPSR, and save the result to an example in Rd: Add the first 64-bit operand to R2 and R3, and add the second 64-bit operand to R4 and R5. Add ADDS to ADDS R0,R2,R4 and the lower 32 bits to add the carryCopy the code

2.6.6. SUB subtraction instruction

SUB{<cond>}{S} Rd,Rn,op2 Rd = Rn - op2 SUB R0,R1,R2 R0 = R1 - R2 SUB R0,R1,#6 R0 = R1 -6 SUB R0,R2,R3,LSL #1 R0 = R2 - (R3 moves 1 bit to the left)Copy the code

2.6.7. SBC with debit subtraction instruction

SBC{<cond>}{S} Rd,Rn,op2 Subtract the value of Rn from the operand op2, subtract the inverse of the C flag in CPSR, and save the result to Rd, Rd = Rn-op2 -! Let the first 64-bit operand be stored in R2,R3, and the second 64-bit operand be stored in R4,R5. The result is stored in R0,R1. SUBS R0,R2,R4 subtracts 32 bits lower than CPSR SBC R1,R3,R5 subtracts 32 bits higher than CPSR SBC R1,R3,R5. Get rid of the inverse of CCopy the code

2.6.8. RSC reverse subtraction instruction with borrowing

RSC{<cond>}{S} Rd,Rn,op2 Subtract the operand op2 from Rn, then subtract the inverse of the C flag bit in CPSR, and save the result to Rd, Rd = op2-rn -! CCopy the code

2.6.9. Logical operation instructions

AND {< cond >} {S} Rd, Rn, op2, bitwise AND Rd = Rn AND op2 ORR {< cond >} {S} Rd, Rn, op2 bitwise OR, Rd = an Rn OR op2 EOR {< cond >} {S} Rd, Rn, op2 bitwise exclusive OR, Rd = Rn EOR op2Copy the code

2.6.10. CMP comparison command

CMP{<cond>}{S} Rd,Rn, OP2 compares the value of Rn with op2, and updates the value of the conditional flag bit in CPSR (actually performs a subtraction, but does not store the result). When the operand Rn is greater than OP2, the instruction with GT suffix can be executed (according to the corresponding instruction to determine whether to execute, Such as GT,LT, etc.) CMP R1,#10 compare R1 and 10 and set CPSR flag bit ADDGT R0,R0,#5 If R1>10, execute ADDGT command and add R0 to 5Copy the code

2.6.11. CMN inverse value comparison instruction

CMN{<cond>}{S} Rd,Rn,op2 Take the value of Rn and OP2 to compare, and update the value of the conditional flag bit in CPSR (actually add Rn and OP2), the following instructions can decide whether to execute according to the conditional flag bit. CMN R0,R1 Add R0 and R1 and set the value of CPSRCopy the code

2.6.12. The MUL/MLA/SMULL SMLAL/UMULL/UMLAL multiplication instructions

MUL 32-bit multiplication instruction MLA 32-bit multiplication instruction SMULL 64-bit signed number multiplication instruction SMLAL 64-bit signed number multiplication instruction UMULL 64-bit unsigned number multiplication instruction MUL{<cond>}{S} Rd,Rm,Rs Rd = Rm * Rs MULS R0,R1,R2 MLA{<cond>}{S} Rd,Rm,Rs,Rn Rd = (Rm * Rs) + Rn MLAS R0,R1,R2,R3Copy the code

2.7. Data loading and storage instructions

mnemonics instructions operation
LDR {} Rd, addr Load word data Rd = [addr]
LDRB {} Rd, addr Load unsigned byte data Rd = [addr]
LDRT {} Rd, addr Load word data in user mode Rd = [addr]
LDRBT {} Rd, addr Loads unsigned byte data in user mode Rd = [addr]
LDRH {} Rd, addr Load unsigned halfword data Rd = [addr]
LDRSB {} Rd, addr Load signed byte data Rd = [addr]
LDRSH {} Rd, addr Load signed halfword data Rd = [addr]
STR {} Rd, addr Store word data [addr] = Rd
STRB {} Rd, addr Storing bytes of data [addr] = Rd
STRT {} Rd, addr Stores word data in user mode [addr] = Rd
STRBT {} Rd, addr Stores bytes of data in user mode [addr] = Rd
Addr, STRH {} Rd Store half-word data [addr] = Rd
LDM{}{type}Rn{! }, regs, Multi-register loading reglist = [Rn…]
STM{}{type}Rn{! }, regs, Multi-register storage [Rn…] = reglist
SWP{}Rd,Rm,[Rn] Register and memory word data exchange Rd=[Rn],[Rn]=Rm(Rn! = Rd or Rm)
SWP{}B Rd,Rm,[Rn] Register and memory byte data exchange Rd = [Rn],[Rn] = Rm(Rn! = Rd or Rm)

2.7.1. LDR/STR word data load/store instruction

LDR/STR{<cond>}{T}Rd,addr LDR instruction is used to load a 32-bit word data into the destination register Rd from the memory. When the program counter PC is used as the destination register, the word data read from the memory by the instruction is used as the destination address, so as to realize the jump of the program flow. The STR instruction is used to store a 32-bit word data from the source register into memory, as opposed to LDR. The suffix T is optional. LDR R0,[R1] LDR R0,[R1,R2] LDR R0,[R1,R2] Read word data with memory address R1+R2 into memory R0 LDR R0,[R1,R2,LSL #2] read word data with memory address R1+R2*4 into memory R0 STR R0,[R1,R2]! R0 word data is stored in the memory location R1+R2, and the new address R2+R2 is written to R2 STR R0,[R1,#8]! [R1,R2,LSL #2] write the new address R2+8 into the storage cell at the memory address R1+R2*4. R1 LDR R0,[R1],#8, R1+8, R1 LDR R0,[R1],R2, R1+8, R1 LDR R0,[R1], Write the new address R1+R2 to R1 LDR R0,[R1],R2,LSL #2 read the word data with memory address R1 into register R0, and write the new address R1+R2*4 to R1Copy the code

2.7.2. LDRB/STRB byte data loading/storage instructions

The LDRB/STRB{<cond>}{T}Rd,addr LDRB instruction is used to load an 8-bit byte data from the memory into the destination register, and at the same time clear the 24 bits high of the register. When the program counter PC is the destination register, the word data read from the memory by the instruction is taken as the destination address. Thus can realize the procedure flow jump. The STRB instruction is used to store an 8-bit byte of data from the source register into memory, as opposed to the LDRB. The suffix T is optional.Copy the code

2.7.3. LDRH/STRH half-word data loading/storage instructions

LDRH/STRH{<cond>}{T}Rd,addr LDRH instruction is used to load a 16-bit half-word data from the memory into the destination register, and at the same time clear the high 16 bits of the register. When the program counter PC is the destination register, the instruction reads the word data from the memory as the destination address. Thus can realize the procedure flow jump. The STRH instruction is used to store a 16-bit halfword data from the source register into memory, as opposed to LDRH. The suffix T is optional.Copy the code

2.7.4. LDM/STM Batch data loading/storage instruction

LDM/STM{<cond>}{<type>}Rn{! },<regs>{^} LDM is used to read data from a piece of continuous memory indicated by the base address register into multiple registers pointed to by the register list. The starting address of the memory unit is the value of the base address register Rn. Each register is represented by the register list regs. STM is used to store the values in multiple registers pointed by the register list into a piece of continuous memory pointed by the base address register. The starting address of the memory unit is the value of the base address register Rn, and each register is represented by the register list regS. This instruction is generally used to stack data in multiple registers. Type Indicates the type, which is used for data storage and reading in the following cases: IA: the address value is added after each transmission. IB: Address value added before each transmission. DA: Address value minus after each transmission. DB: minus the address value before each transmission. The stack operation has the following situations: FD: full decrement stack ED: empty decrement stack FA: full increment stack EA: empty increment stackCopy the code

2.7.5. SWP word data exchange instruction

SWP {< cond >} < Rd >, < Rm > / < an Rn > Rd = [Rn], [Rn] = Rm, when the Rm and purpose registers Rd for the same register, SWP R0,R1,[R2] R0 = [R2],[R2] = R1 SWP R0,R0,[R1] R0 = [R1],[R1] = R0 The SWPB instruction is used to load the byte data in the memory pointed to register Rn into the destination register Rd, clear the high 24 bits of the destination register, and store the word data in Rm into the memory pointed to Register Rn.Copy the code

2.8. Branch statements

mnemonics instructions operation
B{cond}label Branch instruction PC<-label
BL{cond}label Branch instruction with return PC<-label, LR= address of the first instruction after BL
BX{cond}Rm Branch instruction with state switching PC =Rm &0xffffffe, T=Rm[0] &1
BLX{cond}label Rm Bring back and branch of state switch | PC = label, T = 1 PC; PC =Rm &0xffffffe, T=Rm[0] &1; LR = address of the first instruction after BLX

2.8.1. Branch instruction B

B{<cond>}label Jump to label, PC=label Example: Backword SUB R1,R1,#1 CMP R1,#0 compare R1 and 0 BEQ forward Switch to Forware and run SUB R1,R2,#3 SUB R1,R1,#1 forward ADD R1,R2,#4 ADD R2,R3,#2 B Backword Automatically switch to Backword and runCopy the code

2.8.2. Branch instruction BL with return

BL{<cond>}label saves the current contents of the PC in R14(LR) before the jump, so it can be executed by reloading the contents of R14 into the PC and going back to the instruction after the jump instruction. This instruction is used to implement the call of the subroutine, whose return can be achieved by copying the value of the LR register into the PC register. Example: BL func jumps to the statement executed after the subroutine ADD R1,R2,#2 is called and returns the address.... Func subroutines... MOV R15,R14 copy the return address to PC, realize the return subroutineCopy the code

2.8.3. Branch instruction BX with state switch

BX{<cond>} Rm When executing BX instruction, if conD meets the condition, the processor will judge whether bit [0] of Rm is 1. If it is 1, it will automatically set the flag T of CPSR register during jump, and interpret the code of target address as Thumb code to execute, then the processor will switch to Thumb state, otherwise, If Rm bit [0] is 0, the CPSR register flag T will be reset automatically during the jump, and the code at the target address will be interpreted as ARM code to execute, that is, the processor will switch to ARM state.Copy the code

Note: The effect of BX LR is equivalent to that of MOV PC, LR. That is, jump to the address stored in LR. Non-zero values stored in R0 are returned.

So what address does LR store? Lr is the Link Register (LR). In THE ARM architecture, LR has two special uses: one is to store the return address of the subroutine; Second, when an exception occurs, the value saved in LR is equal to the value of PC when the exception occurs minus 4 (or minus 2). Therefore, in various exception modes, the execution can continue according to the value of LR back to the corresponding position before the exception occurs.

When a subroutine is invoked via BL or BLX instructions, the hardware automatically stores the subroutine return address in the R14 register. When the subroutine returns, the value of LR is copied to the program counter PC to achieve the subroutine return.

2.9 the stack

2.9.1. In and out of the stack

Out of the stack using LDM instruction, into the stack using STM instruction. LDM and STM instructions often implement stack operations with the following parameters. FD: full decrement stack. ED: Empty decrement stack. FA: full increment stack. EA: Empty increment stack. A full stack means that SP(R13) points to the last used address or full position on the stack (that is, SP points to the last data item on the stack); In contrast, an empty stack means that SP points to the first unused address or empty location on the stack. LDMFD and STMFD refer to POP and PUSH, respectivelyCopy the code

2.9.2. PUSH the instructions

PUSH{cond} regList PUSH the register onto the full decrement stack PUSH{r0,r4-r7} PUSH the contents of the r0,r4-r7 registers onto the stackCopy the code

2.9.3. POP instructions

POP{cond} regList POP POP data from the full decrement stack to the register POP{r0,r4-r7} POP the r0, R4-R7 registers from the stackCopy the code

0x03 Creating an Android NDK program


3.1. NDK program creation process

1. Create an Android application. 2. Right click on the program -->Android Tools-->Add Native Support --> name the so file (e.g. HelloJNI). The JNI directory will then be created in the application, containing the NDK files we will write. 3. Create a Java file in a SRC package (for example com.example.hellojni). 4. Create the build_headers. XML file in the root directory of the program, open it with ANT Editor (ANT is required for ADT), use Alt +/ to call up the autoprompt, and select Bulidfile Template to create the template file. Code examples are shown below. 5. Open the ANT tool, select the first "Add" button (a small plus sign), and add build_headers. XML will add HelloJNI to ANT.Copy the code

3.2. Write programs

3.2.1. CLASS files

Create class file in com.example.hellojni package.

To get int. Java code

package com.example.hellojni;
public class GetInt {
    public static native int getInt();
}
Copy the code

Get string. For Java code

package com.example.hellojni;    

public class GetString {

    public static native String getStr();

    public native String getString();

    public native int add(int a, int b);    

}
Copy the code

GetFor. Java code for

package com.example.hellojni;    

public class GetFor {
    public static native int getFor1(int n);
    public static native int getFor2(int n);
}
Copy the code

GetIfElse. Java code for

package com.example.hellojni;    

public class GetIfElse {
    public static native String getIfElse(int n);
}    
Copy the code

GetWhile. Java code for

package com.example.hellojni;    

public class GetWhile {
    public static native int getWhile(int n);
}
Copy the code

GetSwitch. Java code for

package com.example.hellojni;    

public class GetSwitch {
    public static native int getSwitch(int a,int b,int i);
}
Copy the code

MainActivity. Java code for

package com.example.hellojni; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class MainActivity extends ActionBarActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); //tv.setText(String.valueOf(GetInt.getInt())); //tv.setText(GetString.getStr()); //tv.setText(String.valueOf(GetFor.getFor1(4))); //tv.setText(String.valueOf(GetFor.getFor2(4))); //tv.setText(String.valueOf(GetWhile.getWhile(5))); //tv.setText(GetIfElse.getIfElse(20)); TV. SetText (String. The valueOf (GetSwitch GetSwitch,2,2) (4)); } static{ System.loadLibrary("HelloJNI"); }}Copy the code

Build_headers. The XML code for

<? The XML version = "1.0" encoding = "utf-8"? > <! - = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 2014-10-28 morning 8:05:50 HelloJNI description 0xExploit ====================================================================== --> <project name="HelloJNI" default="BuildAllHeaders"> <description> description </description> <! -- ================================= target: BuildAllHeaders ================================= --> <target name="BuildAllHeaders"> <antcall target="BuildGetStringHeader"></antcall> <antcall target="BuildGetIntHeader"></antcall> <antcall target="BuildGetForHeader"></antcall> <antcall target="BuildGetWhileHeader"></antcall> <antcall target="BuildGetIfElseHeader"></antcall> <antcall target="BuildGetStringHeader"></antcall> </target> <! -- - - - - - - - - - - - - - - - - - target: depends - - - - - - - - - - - - - - - - - --> <target name="BuildGetStringHeader"> <javah destdir="./jni" classpath="./bin/classes/" class="com.example.hellojni.GetString"></javah> </target> <target name="BuildGetIntHeader"> <javah destdir="./jni" classpath="./bin/classes/" class="com.example.hellojni.GetInt"></javah> </target> <target name="BuildGetForHeader"> <javah destdir="./jni" classpath="./bin/classes/" class="com.example.hellojni.GetFor"></javah>  </target> <target name="BuildGetWhileHeader"> <javah destdir="./jni" classpath="./bin/classes/" class="com.example.hellojni.GetWhile"></javah> </target> <target name="BuildGetIfElseHeader"> <javah destdir="./jni" classpath="./bin/classes/" class="com.example.hellojni.GetIfElse"></javah> </target> <target name="BuildGetSwitchHeader"> <javah destdir="./jni" classpath="./bin/classes/" class="com.example.hellojni.GetSwitch"></javah> </target> </project>Copy the code

Then double-click HelloJNI in ANT and F5 refresh the project. You can see that there are 6 more files in the jni directory, com_example_hellojni_getfor. h, etc. Inside these files are the function.h interface files. There is no specific code, you need to copy the function inside the helloJni. CPP file in the Jni directory, and then implement the specific part of the function.

The code for hellojni.cpp is

#include <jni.h>
#include <com_example_hellojni_GetInt.h>
#include <com_example_hellojni_GetString.h>
#include <com_example_hellojni_GetFor.h>
#include <com_example_hellojni_GetIfElse.h>
#include <com_example_hellojni_GetWhile.h>
#include <com_example_hellojni_GetSwitch.h>    

int nums[5] = {1, 2, 3, 4, 5};    

JNIEXPORT jstring JNICALL Java_com_example_hellojni_GetString_getStr
  (JNIEnv *env, jclass){
    return env->NewStringUTF("static method call");
}    

/*
 * Class:     com_example_hellojni_GetString
 * Method:    getString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_hellojni_GetString_getString
  (JNIEnv *env, jobject){
    return env->NewStringUTF("method call");
}    

/*
 * Class:     com_example_hellojni_GetString
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_hellojni_GetString_add
  (JNIEnv *, jobject, jint a, jint b){
    return a+b;
}    


JNIEXPORT jint JNICALL Java_com_example_hellojni_GetInt_getInt
  (JNIEnv *, jclass){
    return 8;
}    

JNIEXPORT jint JNICALL Java_com_example_hellojni_GetFor_getFor1
  (JNIEnv *, jclass, jint n){
    int i = 0;
    int s = 0;
        for (i = 0; i < n; i++){
            s += i * 2;
        }
        return s;
}    

JNIEXPORT jint JNICALL Java_com_example_hellojni_GetFor_getFor2
  (JNIEnv *, jclass, jint n){
    int i = 0;
        int s = 0;
        for (i = 0; i < n; i++){
            s += i * i + nums[n-1];
        }
        return s;
}
JNIEXPORT jint JNICALL Java_com_example_hellojni_GetWhile_getWhile
  (JNIEnv *, jclass, jint n){
        int i = 1;
        int s = 0;
        while(i <= n){
            s += i++;
        }
        return s;
}
JNIEXPORT jstring JNICALL Java_com_example_hellojni_GetIfElse_getIfElse
  (JNIEnv *env, jclass, jint n){
        if(n < 16){
            return env->NewStringUTF("he is a boy");
        } else if(n < 30){
            return env->NewStringUTF("he is a young man");
        } else if(n < 45){
            return env->NewStringUTF("he is a strong man");
        } else{
            return env->NewStringUTF("he is an old man");
        }
}
JNIEXPORT jint JNICALL Java_com_example_hellojni_GetSwitch_getSwitch
  (JNIEnv *, jclass, jint a, jint b, jint i){
    switch (i){
        case 1:
            return a + b;
            break;
        case 2:
            return a - b;
            break;
        case 3:
            return a * b;
            break;
        case 4:
            return a / b;
            break;
        default:
            return a + b;
            break;
        }
}
Copy the code

Above is some examples of the code, the following to analyze the reverse ARM code. The following disassembly code is obtained through IDA, as for the use of IDA, you can read a book.

3.2.2. Get int () method

The getInt() method code looks like this:

JNIEXPORT jint JNICALL Java_com_example_hellojni_GetInt_getInt
  (JNIEnv *, jclass){
    return 8;
}
Copy the code

The decompiled code looks like this:

EXPORT Java_com_example_hellojni_GetInt_getInt Java_com_example_hellojni_GetInt_getInt MOVS R0, #8 ; R0 = 8 BX LR ; The subroutine returns R0Copy the code

3.2.3. GetStr () method

The method code for getStr() looks like this:

JNIEXPORT jstring JNICALL Java_com_example_hellojni_GetString_getStr
  (JNIEnv *env, jclass){
    return env->NewStringUTF("static method call");
}
Copy the code

The decompiled code looks like this:

EXPORT Java_com_example_hellojni_GetString_getStr Java_com_example_hellojni_GetString_getStr PUSH {R3,LR} ; Add R3 and LR to LDR R2, [R0]; LDR R1, =(astaticMethodCa-0xf7A) MOVS R3, #0x29C; LDR R1, =(astaticMethodCa-0xf7A) MOVS R3, #0x29C; R3=0x29C ADD R1, PC ; "static method call" ; R1="static method call" LDR R3, [R2,R3] ; R2 offset R3, is NewStringUTF, you can view the JNI API(Android Software Security and Reverse Analysis also described in section 7.6), as shown in the figure below, all the functions are attached. BLX R3 ; Call NewStringUTF. The first argument, R0, is JNIEnv, the subroutine returns, and the second argument is R1Copy the code

3.2.3. GetFor1 () method

The method code for getFor1() is as follows:

JNIEXPORT jint JNICALL Java_com_example_hellojni_GetFor_getFor1
  (JNIEnv *, jclass, jint n){
    int i = 0;
    int s = 0;
        for (i = 0; i < n; i++){
            s += i * 2;
        }
        return s;
}
Copy the code

The decompiled code looks like this:

The code is explained as follows:

EXPORT Java_com_example_hellojni_GetFor_getFor1 Java_com_example_hellojni_GetFor_getFor1 MOVS R0, #0 ; R0 = 0 MOVS R3, R0 ; R3 = 0 B loc_FB0 ; Jump to loc_FB0; --------------------------------------------------------------------------- loc_FAA ; CODE XREF: Java_com_example_hellojni_GetFor_getFor1+Ej LSLS R1, R3, #1 ; ADDS R0, R0, R1 to the left (i.e. R1=R3*2); R0=R0+R1 ADDS R3, #1 ; R3=R3+1 loc_FB0 ; CODE XREF: Java_com_example_hellojni_GetFor_getFor1+4j CMP R3, R2 ; Compare R3 with R2, which is the first parameter, n BLT loc_FAA; If R3 is less than R2, jump to loc_FAA BX LR; Otherwise, the subroutine returns R0; End of function Java_com_example_hellojni_GetFor_getFor1Copy the code

3.2.4. GetWhile () method

The code for getWhile() is as follows:

JNIEXPORT jint JNICALL Java_com_example_hellojni_GetWhile_getWhile
  (JNIEnv *, jclass, jint n){
        int i = 1;
        int s = 0;
        while(i <= n){
            s += i++;
        }
        return s;
}
Copy the code

The decompilation results in:

The code is explained as follows:

EXPORT Java_com_example_hellojni_GetWhile_getWhile Java_com_example_hellojni_GetWhile_getWhile MOVS R0, #0 ; R0 = 0 MOVS R3, #1 ; R3 = 1 B loc_FEA ; Jump to loc_FEA; ------------------------------------------------------------- loc_FE6 ; CODE XREF: le_hellojni_GetWhile_getWhile+Cj ADDS R0, R0, R3 ; R0=R0+R3 ADDS R3, #1 ; R3=R3+1 loc_FEA ; CODE XREF: le_hellojni_GetWhile_getWhile+4j CMP R3, R2 ; Compare R3 with R2, where R2 is the first parameter, i.e. N BLE loc_FE6; If R3 is less than R2, jump to loc_FE6 BX LR; Otherwise R0 is returned; End of function Java_com_example_hellojni_GetWhile_getWhileCopy the code

3.2.5. GetIfElse () method

The code for getIfElse() is as follows

JNIEXPORT jstring JNICALL Java_com_example_hellojni_GetIfElse_getIfElse (JNIEnv *env, jclass, jint n){ if(n < 16){ return env->NewStringUTF("he is a boy"); } else if(n < 30){ return env->NewStringUTF("he is a young man"); } else if(n < 45){ return env->NewStringUTF("he is a strong man"); } else{ return env->NewStringUTF("he is an old man"); }}Copy the code

The decompilation results in:

The code is explained as follows:

EXPORT Java_com_example_hellojni_GetIfElse_getIfEls Java_com_example_hellojni_GetIfElse_getIfElse PUSH {R4,LR} ; R4, LR into the stack. MOVS R3, #0xA7 ; R3=167 LDR R4, [R0] ; R4=*env LSLS R3, R3, #2; R3=R3 shift 2 bits CMP R2, #0xF; Compare R2(that is, n) with 16 BGT loc_1002; If R2>16, go to loc_1002 LDR R1, =(aheisaboy-0x1002); With the next instruction, R1="he is a boy" ADD R1, PC; "he is a boy" B loc_101A ; Jump to loc_101A; ------------------------------------------------------------- loc_1002 ; CODE XREF: le_hellojni_GetIfElse_getIfElse+Aj CMP R2, #0x1D BGT loc_100C LDR R1, =(aHeIsAYoungMan - 0x100C) ADD R1, PC ; "he is a young man" B loc_101A ; ------------------------------------------------------------- loc_100C ; CODE XREF: le_hellojni_GetIfElse_getIfElse+14j CMP R2, #0x2C BGT loc_1016 LDR R1, =(aHeIsAStrongMan - 0x1016) ADD R1, PC ; "he is a strong man" B loc_101A ; ------------------------------------------------------------- loc_1016 ; CODE XREF: le_hellojni_GetIfElse_getIfElse+1Ej LDR R1, =(aHeIsAnOldMan - 0x101C) ADD R1, PC ; "he is an old man" loc_101A ; CODE XREF: le_hellojni_GetIfElse_getIfElse+10j ; le_hellojni_GetIfElse_getIfElse+1Aj ... LDR R3, [R4,R3] ; The offset of R4, R3*4, is NewStringUTF BLX R3; The first argument is R0, and the second argument is R1 POP {R4,PC}; It is usually the opposite of the first line. Put LR into the PC, which is the address of the next command, and changing its value is a jump. End of function Java_com_example_hellojni_GetIfElse_getIfElseCopy the code

3.2.6. GetSwitch () method

The code for getSwitch() is as follows:

JNIEXPORT jint JNICALL Java_com_example_hellojni_GetSwitch_getSwitch (JNIEnv *, jclass, jint a, jint b, jint i){ switch (i){ case 1: return a + b; break; case 2: return a - b; break; case 3: return a * b; break; case 4: return a / b; break; default: return a + b; break; }}Copy the code

The decompilation results in:

The code is explained as follows:

EXPORT Java_com_example_hellojni_GetSwitch_getSwitch Java_com_example_hellojni_GetSwitch_getSwitch arg_0 = 0 PUSH {R3,LR} LDR R1, [SP,#8+arg_0] ADDS R0, R2, R3 SUBS R1, #1 CMP R1, #3 ; switch 4 cases BHI locret_105C ; Jumptable 0000103E default case, jump to default, return R0, R0=R2+R3 MOVS R0, R1 BL __gnu_thumb1_case_uqi; switch jump ; ------------------------------------------------------------- jpt_103E DCB 2 ; jump table for switch statement DCB 4 DCB 6 DCB 9 ; ------------------------------------------------------------- loc_1046 ; CODE XREF: le_hellojni_GetSwitch_getSwitch+Ej ADDS R0, R2, R3 ; jumptable 0000103E case 0 B locret_105C ; jumptable 0000103E default case ; ------------------------------------------------------------- loc_104A ; CODE XREF: le_hellojni_GetSwitch_getSwitch+Ej SUBS R0, R2, R3 ; jumptable 0000103E case 1 B locret_105C ; jumptable 0000103E default case ; ------------------------------------------------------------- loc_104E ; CODE XREF: le_hellojni_GetSwitch_getSwitch+Ej MOVS R0, R3 ; jumptable 0000103E case 2 MULS R0, R2 B locret_105C ; jumptable 0000103E default case ; ------------------------------------------------------------- loc_1054 ; CODE XREF: le_hellojni_GetSwitch_getSwitch+Ej MOVS R0, R2 ; jumptable 0000103E case 3 MOVS R1, R3 BLX __divsi3 locret_105C ; CODE XREF: le_hellojni_GetSwitch_getSwitch+Aj ; le_hellojni_GetSwitch_getSwitch+18j ... POP {R3,PC} ; jumptable 0000103E default case ; End of function Java_com_example_hellojni_GetSwitch_getSwitchCopy the code