Using KUNAI (Chapter2 - Disassembler)
byIntroduction to Kunai’s disassembler
In the previous post, we saw an introduction to Kunai, a static analysis tool aimed to analyze DEX files, both from the DEX perspective, and also from a Intermmediate Representation perspective. We could also see a brief introduction to the architecture of the tool graphically with two schemas.
In this post we will see a brief introduction to the Disassembler, in this case we will just focus on the next part of the architecture:
As we can see in the picture, the disassembler of Kunai is a Linear Sweep Disassembly and Recursive Traversal Disassembly, an idea for the future is implementing different algorithms of disassembly improving the efficiency of the algorithm.
Two main algorithms exist for disassembly:
-
Linear Sweep Disassembly: this algorithm takes a bunch of bytes, and starting from the first to the last byte it tries to disassembly all the instructions it finds. In case it gets some error in one of the bytes, the algorithm can go to the next one.
-
Recursive Traversal Disassembly: in opposite to the previous algorithm, in this one the disassembler tries to start its process in the entry point of the binary, and from that point it starts disassemblying the file and it follows the control flow of the program.
Both algorithms have pros and cons, for example the former while it will disassembly all the bytes, it can misdisassembly some data bytes as instructions, since the algorithm is not able to differentiate them. Then the latter, while it can avoid data after jump instructions, it can leave some bytes out of the process if there’s not a control flow that jumps directly to those bytes (e.g. indirect jumps).
In the paper Practical Analysis of Stripped Binary Code, you can find an algorithm that uses the Recursive Traversal Disassembly algorithm, together with a collection of heuristics in order to increase precision of the disassembly, this algorithm contains two functions, one very common in Recursive Traversal Disassembly that starts disassembly process, and looks for new possible paths to continue disassembly (FindFunctions), and once this process has finished, it runs another function that uses a set of precalculated function prologues in order to discover newer functions that were not discovered in previous process (FindPrologues), more information about the process can be found in Chapter 3 of the book Surreptitious Software: Obfuscation, Watermarking and Tamperproofing for software protection, also you can find a whole chapter about this in the book Practical Binary Analysis, and different papers exists about the topic, for example Disassembly of Executable Code Revisited. It’s planned to include some improvements of the linear sweep and also other algorithms to Kunai’s disassembler.
Using Kunai’s disassembler
After all the theory about disassemblers, we’ll start working with the disassembler from Kunai. Kunai implements both a Linear Sweep Disassembly and Recursive Traversal algorithm, in Dalvik the disassembly process commonly is easier because the bytes that belongs to a method are given by the method itself, we do not have to create any algorithm to recover the methods from the code.
In the previous post, we already said that Kunai when it receives a DEX file, it does nothing more than parsing its header, so whenever we want to use another analysis from Kunai, we have to get a reference to the object, and then ask the object to apply the analysis. Same will happen with the disassembler, if we want Kunai to disassembly our target, we will have to obtain a reference to disassembler object, and then apply it. Why don’t we directly apply the analysis? this is an easy to answer question, Kunai tries to be as modular as possible. Avoiding doing expensive analysis, give the chance to some analyst to obtain results quickly, if you just one to obtain data from the header, it will take seconds in a long DEX to finish, instead of several minutes to apply disassembly, and then cross-references and so on.
In the example we’ll see in this post, we will create a very basic disassembler (similar to objdump tool in Linux), and then we will count all the different instructions that appear in the method, and how many times repeat each one.
Let’s start with the headers and the beginning of the code:
#include <iostream>
#include <list>
#include <KUNAI/DEX/dex.hpp>
int
main(int argc, char **argv)
{
bool use_recursive = false;
if (argc == 1 || (argc > 1 && !strcmp("-h", argv[1])))
{
std::cerr << "[-] USAGE: " << argv[0] << " <dex_file> <class_name> <method_name> [-r]\n";
std::cerr << "\t-r: optional argument, use recursive disassembly algorithm\n";
return 1;
}
// check that 4 arguments were given
if (argc < 4)
{
std::cerr << "[-] USAGE: " << argv[0] << " <dex_file> <class_name> <method_name> [-r]\n";
std::cerr << "\t-r: optional argument, use recursive disassembly algorithm\n";
return 1;
}
// check if one argument more was given
// check if it is correct
if (argc > 4 && strcmp("-r", argv[4]))
{
std::cerr << "The option " << argv[4] << " is not recognized...\n\n\n";
std::cerr << "[-] USAGE: " << argv[0] << " <dex_file> <class_name> <method_name> [-r]\n";
std::cerr << "\t-r: optional argument, use recursive disassembly algorithm\n";
return 1;
}else if (argc > 4 && !strcmp("-r", argv[4]))
{
use_recursive = true;
}
We will use the common std::cout and std::cerr to show the information and the errors of the programs, so we will need to use the iostream library. Then we will go with Kunai, this time, we will use the dex.hpp which contains the classes to manage the DEX file. Then, we will start the main function that will be the only one we will have as it is a simple “script”. Inside of the main function we will check that 4 arguments are given, being the first one the name of the program (argv[0]), and then: DEX file, class name and finally method name. We will use the two arguments to retrieve the method we want to disassembly. We will include some other arguments parsing in order to allow a user use or not the recursive traversal disassembler, the kind of disassembler to use have to be configured, being by default a linear sweep disassembly algorithm.
Let’s continue with something we already saw in previous post, the parsing of the DEX file using the DEX object from Kunai.
// watch info and error messages from Kunai
spdlog::set_level(spdlog::level::err);
auto class_name = std::string(argv[2]);
auto method_name = std::string(argv[3]);
std::ifstream dex_file;
dex_file.open(argv[1], std::ios::binary);
auto fsize = dex_file.tellg();
dex_file.seekg(0, std::ios::end);
fsize = dex_file.tellg() - fsize;
dex_file.seekg(0);
auto dex_object = KUNAI::DEX::get_unique_dex_object(dex_file, fsize);
if (!dex_object->get_parsing_correct())
{
std::cerr << "Error analyzing " << argv[1] << ", maybe DEX file is not correct...\n";
return 2;
}
Again we set the log level from Kunai using spdlog (library used by Kunai for logging). After that, we save in string objects the arguments with the class name, and the argument with the method name. Then we can start opening the DEX file given, and after calculating its size, we create a unique DEX object, this is a std::unique_ptr which holds the DEX information in Kunai. Finally we’ll check if the parsing process was correct.
// first of all obtain the disassembler object
auto dex_disassembler = dex_object->get_dex_disassembler();
// if recursive disassembly is requested by the user
// use this one!
if (use_recursive)
dex_disassembler->set_disassembler_type(KUNAI::DEX::RECURSIVE_TRAVERSAL_DISASSEMBLER);
// because obtaining the dex object does not apply
// any analysis, we have to apply disassembly by
// ourselves
dex_disassembler->disassembly_analysis();
// check that all the disassembly was correct
if (!dex_disassembler->get_disassembly_correct())
{
std::cerr << "Error in the disassembly of " << argv[1] << ", maybe some method was incorrect...\n";
return 3;
}
From the DEX object we obtain the DexDisassembler object, with this object we can decide if we want the recursive traversal disassembler, in that case we will set it using a specific enum for it (KUNAI::DEX::RECURSIVE_TRAVERSAL_DISASSEMBLER). Then we will apply the disassembly process, that once it finishes it will contain the instructions for each method. From the DexDisassembler object we run its method disassembly_analysis, this will traverse all the methods from the DEX file, and will fill the previous commented variable with all the instructions. Then we can check if the process was correct or not for showing information to the user.
// instruction_map_t = std::map<std::tuple<classdef_t, encodedmethod_t>, std::map<std::uint64_t, instruction_t>>;
// instruction_map_t is a map that contains as key a tuple with the class and method
// and as value a map that contains ordered the address of the instruction
// and the instruction.
auto instruction_map = dex_disassembler->get_instructions();
Then we obtain a reference to the instructions structure, this variable is a std::map with a little bit complex structure, the key for the map is a std::tuple that contains a classdef_t object and encodedmethod_t object. Finally the value is a std::map that contains a std::uint64_t with the address or idx of the instruction in the method, and finally the instruction_t object.
Let’s go over this structure looking for the class and the method we want:
// let's create the variable that will hold all those instructions
// that appear and how many times appear.
std::unordered_map<std::uint32_t, size_t> instruction_counter;
for (const auto& disassembly : instruction_map)
{
auto& classdef = std::get<0>(disassembly.first);
auto& encoded_method = std::get<1>(disassembly.first);
if (classdef == nullptr || encoded_method == nullptr)
continue;
if (!class_name.compare(classdef->get_class_idx()->get_name()) &&
!method_name.compare(*encoded_method->get_method()->get_method_name()))
{
std::cout << "Disassembly of " << class_name << "->" << method_name << "\n";
for (const auto &instructions : disassembly.second)
{
std::cout << std::right << std::setfill('0') << std::setw(8) << std::hex << instructions.first << " ";
auto &raw_values = instructions.second->get_raw();
if (raw_values.size() > 8)
{
auto remaining = 8 - (raw_values.size() % 8);
size_t aux = 0;
for (auto value : raw_values)
{
std::cout << std::right << std::setfill('0') << std::setw(2) << std::hex << (std::uint32_t)value << " ";
aux++;
if (aux % 8 == 0)
{
std::cout << "\n"
<< " ";
}
}
for (std::uint8_t i = 0; i < remaining; i++)
std::cout << " ";
}
else
{
for (auto value : raw_values)
std::cout << std::right << std::setfill('0') << std::setw(2) << std::hex << (std::uint32_t)value << " ";
for (std::uint8_t i = 0, remaining_size = 8 - raw_values.size(); i < remaining_size; i++)
std::cout << " ";
}
instructions.second->show_instruction();
std::cout << std::endl;
auto &instr = instructions.second;
auto op = instr->get_OP();
if (instruction_counter.find(op) == instruction_counter.end())
instruction_counter[op] = 0;
instruction_counter[op] += 1;
}
break;
}
}
First of all we will create the std::unordered_map that will hold the instructions and the count of those instructions, then we will go through the instructions structure, we want to obtain data only from a specific method, then we will compare names in order to obtain that data. To do that we will have to retrieve name from the classdef_t object, first obtaining the class_t object, and from it the name of the class. And from the encodedmethod_t we obtain the methodid_t and from it the method name. Once we have found the method we are interested, we can go over the instructions.
As we said at the beginning, what we’ll do is to write a disassembler, then we will print the name of the method to disassembly, and after that we will go over each of the instructions, first we show the address, second the bytes of the instruction (using a format similar to other disassemblers), and after that we invoke the method show_instruction that will format the disassembly of that specific instruction, so we do not have to care about what kind of Instruction object is (check the picture at the beginning of the post to see all the instruction types). Then, we will retrieve its op-code, and we’ll start counting instructions.
std::cout << "\n\nInstruction counter program\n";
std::cout << "Number of different instructions present in the method: " << instruction_counter.size() << "\n";
for (const auto & op_instr : instruction_counter)
{
auto op_num = op_instr.first;
auto op_str = dex_object->get_dalvik_opcode_object()->get_instruction_name(op_num);
std::cout << op_str << " [" << op_num << "] appears: " << op_instr.second << " times\n";
}
return 0;
}
Finally we will go over the variable we created to count the instructions, and we’ll show what instruction appears in the method, and how many times appear. Let’s compile the program, and run it with a example DEX:
$ g++ -std=c++17 instruction-counter.cpp -o instruction-counter -lkunai
$ ./instruction-counter ../tests/test-modexp/Main.dex "LMain;" "modexp"
Disassembly of LMain;->modexp
00000000 00 00 nop
00000002 00 00 nop
00000004 12 00 const/4 v0, 0
00000006 12 11 const/4 v1, 1
00000008 12 02 const/4 v2, 0
0000000a 12 13 const/4 v3, 1
0000000c 35 60 13 00 if-ge v0, p2, 19
00000010 44 02 05 00 aget v2, p1, v0
00000014 33 12 07 00 if-ne v2, v1, 7
00000018 92 03 03 04 mul-int v3, v3, p0
0000001c b4 73 rem-int/2addr v3, p3
0000001e 01 32 move v2, v3
00000020 28 02 goto 2
00000022 01 32 move v2, v3
00000024 92 03 02 02 mul-int v3, v2, v2
00000028 b4 73 rem-int/2addr v3, p3
0000002a 00 00 nop
0000002c d8 00 00 01 add-int/lit8 v0, v0, 1
00000030 28 ee goto -18
00000032 0f 02 return v2
Instruction counter program
Number of different instructions present in the method: b
return [f] appears: 1 times
add-int/lit8 [d8] appears: 1 times
rem-int/2addr [b4] appears: 2 times
if-ne [33] appears: 1 times
mul-int [92] appears: 2 times
aget [44] appears: 1 times
goto [28] appears: 2 times
move [1] appears: 2 times
if-ge [35] appears: 1 times
const/4 [12] appears: 4 times
nop [0] appears: 3 times
Here we can see the output of the disassembler, and finally the instruction counting. As we can see only 11 (0xb) different instructions exists, and as the method is not so big, they do not appear so many times.
Let’s go now with a method used as interpreter in a VM-based obfuscation:
$ ./instruction-counter ../tests/test-vm/PCodeVM.dex "LPCodeVM;" "exec"
Disassembly of LPCodeVM;->exec
00000000 00 00 nop
00000002 13 00 ff 00 const/16 v0, 255
00000006 13 01 80 00 const/16 v1, 128
0000000a 12 52 const/4 v2, 5
0000000c 12 73 const/4 v3, 7
0000000e 12 64 const/4 v4, 6
00000010 12 35 const/4 v5, 3
00000012 13 06 09 00 const/16 v6, 9
00000016 13 07 08 00 const/16 v7, 8
0000001a 13 08 0a 00 const/16 v8, 10
0000001e 13 09 0b 00 const/16 v9, 11
00000022 12 2a const/4 v10, 2
00000024 12 0b const/4 v11, 0
00000026 12 0c const/4 v12, 0
00000028 12 1d const/4 v13, 1
0000002a 2b 0f a3 04 00 00 packed-switch p1, 1187
00000030 0f 0f return p1
00000032 00 00 nop
00000034 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000038 d8 0f 0f fe add-int/lit8 p1, p1, -2
0000003c 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000040 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000044 44 01 00 0f aget v1, v0, p1
00000048 b0 df add-int/2addr p1, v13
0000004a 44 0f 00 0f aget p1, v0, p1
0000004e 34 f1 03 00 if-lt v1, p1, 3
00000052 12 0d const/4 v13, 0
00000054 59 ed 01 00 iput v13, p0, I LPCodeVM;.b
00000058 0f 0c return v12
0000005a 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000005e d8 00 0f 01 add-int/lit8 v0, p1, 1
00000062 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000066 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
0000006a 44 02 01 09 aget v2, v1, v9
0000006e 4b 02 01 0f aput v2, v1, p1
00000072 00 00 nop
00000074 d8 0f 00 01 add-int/lit8 p1, v0, 1
00000078 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
0000007c 54 e2 10 00 iget-object v2, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000080 46 03 02 04 aget-object v3, v2, v4
00000084 4d 03 02 00 aput-object v3, v2, v0
00000088 d8 00 0f ff add-int/lit8 v0, p1, -1
0000008c d8 03 0f ff add-int/lit8 v3, p1, -1
00000090 46 03 02 03 aget-object v3, v2, v3
00000094 b1 df sub-int/2addr p1, v13
00000096 4d 0b 02 0f aput-object v11, v2, p1
0000009a 1f 03 07 00 check-cast v3, [B
0000009e 21 3f array-length p1, v3
000000a0 4b 0f 01 00 aput p1, v1, v0
000000a4 0f 0c return v12
000000a6 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000000aa b1 df sub-int/2addr p1, v13
000000ac 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000000b0 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000000b4 44 01 00 0f aget v1, v0, p1
000000b8 4b 01 00 08 aput v1, v0, v8
000000bc 00 00 nop
000000be d8 01 0f 01 add-int/lit8 v1, p1, 1
000000c2 59 e1 14 00 iput v1, p0, I LPCodeVM;.stkidx
000000c6 44 02 00 09 aget v2, v0, v9
000000ca 4b 02 00 0f aput v2, v0, p1
000000ce 00 00 nop
000000d0 d8 0f 01 01 add-int/lit8 p1, v1, 1
000000d4 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000000d8 4b 05 00 01 aput v5, v0, v1
000000dc 0f 0c return v12
000000de 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000000e2 b1 df sub-int/2addr p1, v13
000000e4 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000000e8 d8 00 0f ff add-int/lit8 v0, p1, -1
000000ec 54 e1 10 00 iget-object v1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
000000f0 d8 02 0f ff add-int/lit8 v2, p1, -1
000000f4 46 02 01 02 aget-object v2, v1, v2
000000f8 d8 03 0f ff add-int/lit8 v3, p1, -1
000000fc 4d 0b 01 03 aput-object v11, v1, v3
00000100 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
00000104 1f 02 07 00 check-cast v2, [B
00000108 44 0f 01 0f aget p1, v1, p1
0000010c 48 0f 02 0f aget-byte p1, v2, p1
00000110 4b 0f 01 00 aput p1, v1, v0
00000114 0f 0c return v12
00000116 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000011a b1 df sub-int/2addr p1, v13
0000011c 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000120 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000124 d8 01 0f ff add-int/lit8 v1, p1, -1
00000128 44 02 00 01 aget v2, v0, v1
0000012c 44 03 00 0f aget v3, v0, p1
00000130 b5 32 and-int/2addr v2, v3
00000132 4b 02 00 01 aput v2, v0, v1
00000136 b1 df sub-int/2addr p1, v13
00000138 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
0000013c 44 0f 00 0f aget p1, v0, p1
00000140 4b 0f 00 08 aput p1, v0, v8
00000144 0f 0c return v12
00000146 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000014a d8 00 0f 01 add-int/lit8 v0, p1, 1
0000014e 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000152 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
00000156 44 02 01 06 aget v2, v1, v6
0000015a 4b 02 01 0f aput v2, v1, p1
0000015e b1 d0 sub-int/2addr v0, v13
00000160 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000164 d8 0f 00 ff add-int/lit8 p1, v0, -1
00000168 54 e2 10 00 iget-object v2, p0, [Ljava/lang/Object; LPCodeVM;.lstk
0000016c d8 03 00 ff add-int/lit8 v3, v0, -1
00000170 46 03 02 03 aget-object v3, v2, v3
00000174 d8 04 00 ff add-int/lit8 v4, v0, -1
00000178 4d 0b 02 04 aput-object v11, v2, v4
0000017c 1f 03 07 00 check-cast v3, [B
00000180 44 02 01 00 aget v2, v1, v0
00000184 48 02 03 02 aget-byte v2, v3, v2
00000188 4b 02 01 0f aput v2, v1, p1
0000018c b1 d0 sub-int/2addr v0, v13
0000018e 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000192 d8 0f 00 ff add-int/lit8 p1, v0, -1
00000196 44 02 01 0f aget v2, v1, p1
0000019a 44 00 01 00 aget v0, v1, v0
0000019e b0 02 add-int/2addr v2, v0
000001a0 4b 02 01 0f aput v2, v1, p1
000001a4 0f 0c return v12
000001a6 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000001aa b1 df sub-int/2addr p1, v13
000001ac 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000001b0 d8 00 0f ff add-int/lit8 v0, p1, -1
000001b4 54 e1 10 00 iget-object v1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
000001b8 d8 03 0f ff add-int/lit8 v3, p1, -1
000001bc 46 03 01 03 aget-object v3, v1, v3
000001c0 d8 04 0f ff add-int/lit8 v4, p1, -1
000001c4 4d 0b 01 04 aput-object v11, v1, v4
000001c8 54 e4 0d 00 iget-object v4, p0, [I LPCodeVM;.istk
000001cc 1f 03 07 00 check-cast v3, [B
000001d0 44 05 04 0f aget v5, v4, p1
000001d4 48 03 03 05 aget-byte v3, v3, v5
000001d8 4b 03 04 00 aput v3, v4, v0
000001dc 00 00 nop
000001de d8 00 0f 01 add-int/lit8 v0, p1, 1
000001e2 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000001e6 46 00 01 02 aget-object v0, v1, v2
000001ea 4d 00 01 0f aput-object v0, v1, p1
000001ee 0f 0c return v12
000001f0 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000001f4 d8 00 0f 01 add-int/lit8 v0, p1, 1
000001f8 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000001fc 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
00000200 44 02 01 08 aget v2, v1, v8
00000204 4b 02 01 0f aput v2, v1, p1
00000208 d8 00 00 fd add-int/lit8 v0, v0, -3
0000020c 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000210 54 ef 10 00 iget-object p1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000214 46 02 0f 00 aget-object v2, p1, v0
00000218 4d 0b 0f 00 aput-object v11, p1, v0
0000021c 1f 02 07 00 check-cast v2, [B
00000220 d8 0f 00 01 add-int/lit8 p1, v0, 1
00000224 44 0f 01 0f aget p1, v1, p1
00000228 b0 a0 add-int/2addr v0, v10
0000022a 44 00 01 00 aget v0, v1, v0
0000022e 8d 00 int-to-byte v0, v0
00000230 4f 00 02 0f aput-byte v0, v2, p1
00000234 0f 0c return v12
00000236 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000023a b1 df sub-int/2addr p1, v13
0000023c 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000240 d8 00 0f ff add-int/lit8 v0, p1, -1
00000244 54 e1 10 00 iget-object v1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000248 d8 02 0f ff add-int/lit8 v2, p1, -1
0000024c 46 02 01 02 aget-object v2, v1, v2
00000250 d8 03 0f ff add-int/lit8 v3, p1, -1
00000254 4d 0b 01 03 aput-object v11, v1, v3
00000258 54 e3 0d 00 iget-object v3, p0, [I LPCodeVM;.istk
0000025c 1f 02 07 00 check-cast v2, [B
00000260 44 04 03 0f aget v4, v3, p1
00000264 48 02 02 04 aget-byte v2, v2, v4
00000268 4b 02 03 00 aput v2, v3, v0
0000026c d8 0f 0f fd add-int/lit8 p1, p1, -3
00000270 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000274 46 00 01 0f aget-object v0, v1, p1
00000278 4d 0b 01 0f aput-object v11, v1, p1
0000027c 1f 00 07 00 check-cast v0, [B
00000280 d8 01 0f 01 add-int/lit8 v1, p1, 1
00000284 44 01 03 01 aget v1, v3, v1
00000288 b0 af add-int/2addr p1, v10
0000028a 44 0f 03 0f aget p1, v3, p1
0000028e 8d ff int-to-byte p1, p1
00000290 4f 0f 00 01 aput-byte p1, v0, v1
00000294 0f 0c return v12
00000296 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000029a d8 00 0f 01 add-int/lit8 v0, p1, 1
0000029e 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000002a2 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000002a6 44 01 00 07 aget v1, v0, v7
000002aa 4b 01 00 0f aput v1, v0, p1
000002ae 0f 0c return v12
000002b0 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000002b4 d8 00 0f 01 add-int/lit8 v0, p1, 1
000002b8 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000002bc 54 e1 10 00 iget-object v1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
000002c0 d8 02 00 fe add-int/lit8 v2, v0, -2
000002c4 46 02 01 02 aget-object v2, v1, v2
000002c8 d8 03 00 fe add-int/lit8 v3, v0, -2
000002cc 4d 0b 01 03 aput-object v11, v1, v3
000002d0 4d 02 01 0f aput-object v2, v1, p1
000002d4 54 ef 0d 00 iget-object p1, p0, [I LPCodeVM;.istk
000002d8 d8 03 00 fe add-int/lit8 v3, v0, -2
000002dc d8 04 00 fd add-int/lit8 v4, v0, -3
000002e0 44 04 0f 04 aget v4, p1, v4
000002e4 4b 04 0f 03 aput v4, p1, v3
000002e8 b1 50 sub-int/2addr v0, v5
000002ea 4d 02 01 00 aput-object v2, v1, v0
000002ee 0f 0c return v12
000002f0 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000002f4 d8 00 0f 01 add-int/lit8 v0, p1, 1
000002f8 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000002fc 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
00000300 44 02 01 06 aget v2, v1, v6
00000304 4b 02 01 0f aput v2, v1, p1
00000308 b1 d0 sub-int/2addr v0, v13
0000030a 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000030e d8 0f 00 ff add-int/lit8 p1, v0, -1
00000312 54 e2 10 00 iget-object v2, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000316 d8 03 00 ff add-int/lit8 v3, v0, -1
0000031a 46 03 02 03 aget-object v3, v2, v3
0000031e d8 04 00 ff add-int/lit8 v4, v0, -1
00000322 4d 0b 02 04 aput-object v11, v2, v4
00000326 1f 03 07 00 check-cast v3, [B
0000032a 44 02 01 00 aget v2, v1, v0
0000032e 48 02 03 02 aget-byte v2, v3, v2
00000332 4b 02 01 0f aput v2, v1, p1
00000336 b1 d0 sub-int/2addr v0, v13
00000338 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000033c 44 0f 01 00 aget p1, v1, v0
00000340 4b 0f 01 08 aput p1, v1, v8
00000344 0f 0c return v12
00000346 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000034a b1 df sub-int/2addr p1, v13
0000034c 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000350 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000354 44 01 00 0f aget v1, v0, p1
00000358 4b 01 00 06 aput v1, v0, v6
0000035c 00 00 nop
0000035e d8 00 0f 01 add-int/lit8 v0, p1, 1
00000362 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000366 54 e0 10 00 iget-object v0, p0, [Ljava/lang/Object; LPCodeVM;.lstk
0000036a 46 01 00 02 aget-object v1, v0, v2
0000036e 4d 01 00 0f aput-object v1, v0, p1
00000372 0f 0c return v12
00000374 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000378 b1 df sub-int/2addr p1, v13
0000037a 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
0000037e 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000382 d8 01 0f ff add-int/lit8 v1, p1, -1
00000386 44 02 00 01 aget v2, v0, v1
0000038a 44 0f 00 0f aget p1, v0, p1
0000038e b5 2f and-int/2addr p1, v2
00000390 4b 0f 00 01 aput p1, v0, v1
00000394 0f 0c return v12
00000396 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000039a d8 01 0f 01 add-int/lit8 v1, p1, 1
0000039e 59 e1 14 00 iput v1, p0, I LPCodeVM;.stkidx
000003a2 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
000003a6 4b 00 01 0f aput v0, v1, p1
000003aa 0f 0c return v12
000003ac 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000003b0 b1 df sub-int/2addr p1, v13
000003b2 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000003b6 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000003ba d8 01 0f ff add-int/lit8 v1, p1, -1
000003be 44 02 00 01 aget v2, v0, v1
000003c2 44 0f 00 0f aget p1, v0, p1
000003c6 b0 f2 add-int/2addr v2, p1
000003c8 4b 02 00 01 aput v2, v0, v1
000003cc 0f 0c return v12
000003ce 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000003d2 d8 00 0f 01 add-int/lit8 v0, p1, 1
000003d6 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000003da 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
000003de 44 02 01 07 aget v2, v1, v7
000003e2 4b 02 01 0f aput v2, v1, p1
000003e6 b1 d0 sub-int/2addr v0, v13
000003e8 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000003ec d8 0f 00 ff add-int/lit8 p1, v0, -1
000003f0 54 e2 10 00 iget-object v2, p0, [Ljava/lang/Object; LPCodeVM;.lstk
000003f4 d8 03 00 ff add-int/lit8 v3, v0, -1
000003f8 46 03 02 03 aget-object v3, v2, v3
000003fc d8 04 00 ff add-int/lit8 v4, v0, -1
00000400 4d 0b 02 04 aput-object v11, v2, v4
00000404 1f 03 07 00 check-cast v3, [B
00000408 44 00 01 00 aget v0, v1, v0
0000040c 48 00 03 00 aget-byte v0, v3, v0
00000410 4b 00 01 0f aput v0, v1, p1
00000414 0f 0c return v12
00000416 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000041a d8 00 0f 01 add-int/lit8 v0, p1, 1
0000041e 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000422 54 e0 10 00 iget-object v0, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000426 54 e1 08 00 iget-object v1, p0, Ljava/lang/Object; LPCodeVM;.g
0000042a 4d 01 00 0f aput-object v1, v0, p1
0000042e 0f 0c return v12
00000430 52 ef 13 00 iget p1, p0, I LPCodeVM;.peekidx
00000434 d8 00 0f 01 add-int/lit8 v0, p1, 1
00000438 59 e0 13 00 iput v0, p0, I LPCodeVM;.peekidx
0000043c 54 e0 10 00 iget-object v0, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000440 46 01 00 0f aget-object v1, v0, p1
00000444 4d 0b 00 0f aput-object v11, v0, p1
00000448 5b e1 0a 00 iput-object v1, p0, Ljava/lang/Object; LPCodeVM;.i
0000044c 0f 0c return v12
0000044e 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000452 d8 00 0f 01 add-int/lit8 v0, p1, 1
00000456 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000045a 54 e0 10 00 iget-object v0, p0, [Ljava/lang/Object; LPCodeVM;.lstk
0000045e 46 01 00 02 aget-object v1, v0, v2
00000462 4d 01 00 0f aput-object v1, v0, p1
00000466 0f 0c return v12
00000468 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000046c d8 00 0f 01 add-int/lit8 v0, p1, 1
00000470 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000474 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000478 44 01 00 06 aget v1, v0, v6
0000047c 4b 01 00 0f aput v1, v0, p1
00000480 0f 0c return v12
00000482 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000486 b1 df sub-int/2addr p1, v13
00000488 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
0000048c 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000490 44 0f 00 0f aget p1, v0, p1
00000494 4b 0f 00 07 aput p1, v0, v7
00000498 0f 0c return v12
0000049a 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000049e d8 01 0f 01 add-int/lit8 v1, p1, 1
000004a2 59 e1 14 00 iput v1, p0, I LPCodeVM;.stkidx
000004a6 54 e2 0d 00 iget-object v2, p0, [I LPCodeVM;.istk
000004aa 4b 00 02 0f aput v0, v2, p1
000004ae b1 d1 sub-int/2addr v1, v13
000004b0 59 e1 14 00 iput v1, p0, I LPCodeVM;.stkidx
000004b4 d8 0f 01 ff add-int/lit8 p1, v1, -1
000004b8 44 00 02 0f aget v0, v2, p1
000004bc 44 01 02 01 aget v1, v2, v1
000004c0 b5 10 and-int/2addr v0, v1
000004c2 4b 00 02 0f aput v0, v2, p1
000004c6 0f 0c return v12
000004c8 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000004cc d8 00 0f 01 add-int/lit8 v0, p1, 1
000004d0 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000004d4 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
000004d8 44 02 01 07 aget v2, v1, v7
000004dc 4b 02 01 0f aput v2, v1, p1
000004e0 00 00 nop
000004e2 d8 0f 00 01 add-int/lit8 p1, v0, 1
000004e6 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000004ea 4b 0d 01 00 aput v13, v1, v0
000004ee b1 df sub-int/2addr p1, v13
000004f0 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000004f4 d8 00 0f ff add-int/lit8 v0, p1, -1
000004f8 44 02 01 00 aget v2, v1, v0
000004fc 44 0f 01 0f aget p1, v1, p1
00000500 b0 f2 add-int/2addr v2, p1
00000502 4b 02 01 00 aput v2, v1, v0
00000506 0f 0c return v12
00000508 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000050c b1 df sub-int/2addr p1, v13
0000050e 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000512 54 e0 10 00 iget-object v0, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000516 4d 0b 00 0f aput-object v11, v0, p1
0000051a 0f 0c return v12
0000051c 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000520 b1 df sub-int/2addr p1, v13
00000522 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000526 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
0000052a 44 0f 00 0f aget p1, v0, p1
0000052e 59 ef 01 00 iput p1, p0, I LPCodeVM;.b
00000532 0f 0c return v12
00000534 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000538 b1 df sub-int/2addr p1, v13
0000053a 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
0000053e 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000542 44 0f 00 0f aget p1, v0, p1
00000546 39 0f 03 00 if-nez p1, 3
0000054a 12 0d const/4 v13, 0
0000054c 59 ed 01 00 iput v13, p0, I LPCodeVM;.b
00000550 0f 0c return v12
00000552 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000556 b1 df sub-int/2addr p1, v13
00000558 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
0000055c 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000560 d8 02 0f ff add-int/lit8 v2, p1, -1
00000564 44 03 00 02 aget v3, v0, v2
00000568 44 04 00 0f aget v4, v0, p1
0000056c b0 43 add-int/2addr v3, v4
0000056e 4b 03 00 02 aput v3, v0, v2
00000572 00 00 nop
00000574 d8 02 0f 01 add-int/lit8 v2, p1, 1
00000578 59 e2 14 00 iput v2, p0, I LPCodeVM;.stkidx
0000057c d8 03 02 fe add-int/lit8 v3, v2, -2
00000580 44 03 00 03 aget v3, v0, v3
00000584 4b 03 00 0f aput v3, v0, p1
00000588 00 00 nop
0000058a d8 0f 02 01 add-int/lit8 p1, v2, 1
0000058e 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000592 4b 01 00 02 aput v1, v0, v2
00000596 0f 0c return v12
00000598 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000059c d8 00 0f 01 add-int/lit8 v0, p1, 1
000005a0 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000005a4 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000005a8 13 01 1f 00 const/16 v1, 31
000005ac 4b 01 00 0f aput v1, v0, p1
000005b0 0f 0c return v12
000005b2 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000005b6 d8 00 0f 01 add-int/lit8 v0, p1, 1
000005ba 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000005be 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000005c2 4b 0d 00 0f aput v13, v0, p1
000005c6 0f 0c return v12
000005c8 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000005cc d8 0f 0f fd add-int/lit8 p1, p1, -3
000005d0 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000005d4 54 e0 10 00 iget-object v0, p0, [Ljava/lang/Object; LPCodeVM;.lstk
000005d8 46 01 00 0f aget-object v1, v0, p1
000005dc 4d 0b 00 0f aput-object v11, v0, p1
000005e0 1f 01 07 00 check-cast v1, [B
000005e4 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000005e8 d8 02 0f 01 add-int/lit8 v2, p1, 1
000005ec 44 02 00 02 aget v2, v0, v2
000005f0 b0 af add-int/2addr p1, v10
000005f2 44 0f 00 0f aget p1, v0, p1
000005f6 8d ff int-to-byte p1, p1
000005f8 4f 0f 01 02 aput-byte p1, v1, v2
000005fc 44 0f 00 09 aget p1, v0, v9
00000600 b0 df add-int/2addr p1, v13
00000602 4b 0f 00 09 aput p1, v0, v9
00000606 0f 0c return v12
00000608 54 ef 0d 00 iget-object p1, p0, [I LPCodeVM;.istk
0000060c 52 e0 14 00 iget v0, p0, I LPCodeVM;.stkidx
00000610 d8 01 00 ff add-int/lit8 v1, v0, -1
00000614 b1 d0 sub-int/2addr v0, v13
00000616 44 00 0f 00 aget v0, p1, v0
0000061a 8d 00 int-to-byte v0, v0
0000061c 4b 00 0f 01 aput v0, p1, v1
00000620 0f 0c return v12
00000622 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000626 d8 00 0f 01 add-int/lit8 v0, p1, 1
0000062a 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000062e 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
00000632 4b 05 01 0f aput v5, v1, p1
00000636 b1 d0 sub-int/2addr v0, v13
00000638 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000063c d8 0f 00 ff add-int/lit8 p1, v0, -1
00000640 44 02 01 0f aget v2, v1, p1
00000644 44 03 01 00 aget v3, v1, v0
00000648 b0 32 add-int/2addr v2, v3
0000064a 4b 02 01 0f aput v2, v1, p1
0000064e b1 d0 sub-int/2addr v0, v13
00000650 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000654 d8 0f 00 ff add-int/lit8 p1, v0, -1
00000658 44 02 01 0f aget v2, v1, p1
0000065c 44 00 01 00 aget v0, v1, v0
00000660 b7 20 xor-int/2addr v0, v2
00000662 4b 00 01 0f aput v0, v1, p1
00000666 0f 0c return v12
00000668 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000066c d8 00 0f 01 add-int/lit8 v0, p1, 1
00000670 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000674 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000678 44 01 00 08 aget v1, v0, v8
0000067c 4b 01 00 0f aput v1, v0, p1
00000680 0f 0c return v12
00000682 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000686 d8 00 0f 01 add-int/lit8 v0, p1, 1
0000068a 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000068e 54 e1 10 00 iget-object v1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000692 46 02 01 04 aget-object v2, v1, v4
00000696 4d 02 01 0f aput-object v2, v1, p1
0000069a 00 00 nop
0000069c d8 0f 00 01 add-int/lit8 p1, v0, 1
000006a0 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000006a4 54 e2 0d 00 iget-object v2, p0, [I LPCodeVM;.istk
000006a8 44 03 02 09 aget v3, v2, v9
000006ac 4b 03 02 00 aput v3, v2, v0
000006b0 b1 df sub-int/2addr p1, v13
000006b2 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000006b6 d8 00 0f ff add-int/lit8 v0, p1, -1
000006ba d8 03 0f ff add-int/lit8 v3, p1, -1
000006be 46 03 01 03 aget-object v3, v1, v3
000006c2 d8 04 0f ff add-int/lit8 v4, p1, -1
000006c6 4d 0b 01 04 aput-object v11, v1, v4
000006ca 1f 03 07 00 check-cast v3, [B
000006ce 44 0f 02 0f aget p1, v2, p1
000006d2 48 0f 03 0f aget-byte p1, v3, p1
000006d6 4b 0f 02 00 aput p1, v2, v0
000006da 0f 0c return v12
000006dc 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000006e0 d8 00 0f 01 add-int/lit8 v0, p1, 1
000006e4 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000006e8 54 e1 10 00 iget-object v1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
000006ec 46 02 01 03 aget-object v2, v1, v3
000006f0 4d 02 01 0f aput-object v2, v1, p1
000006f4 00 00 nop
000006f6 d8 0f 00 01 add-int/lit8 p1, v0, 1
000006fa 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000006fe 54 ef 0d 00 iget-object p1, p0, [I LPCodeVM;.istk
00000702 44 01 0f 09 aget v1, p1, v9
00000706 4b 01 0f 00 aput v1, p1, v0
0000070a 0f 0c return v12
0000070c 54 ef 0d 00 iget-object p1, p0, [I LPCodeVM;.istk
00000710 44 00 0f 08 aget v0, p1, v8
00000714 b0 d0 add-int/2addr v0, v13
00000716 4b 00 0f 08 aput v0, p1, v8
0000071a 0f 0c return v12
0000071c 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000720 d8 00 0f 01 add-int/lit8 v0, p1, 1
00000724 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000728 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
0000072c 4b 0c 00 0f aput v12, v0, p1
00000730 0f 0c return v12
00000732 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000736 d8 00 0f 01 add-int/lit8 v0, p1, 1
0000073a 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000073e 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000742 13 01 62 00 const/16 v1, 98
00000746 4b 01 00 0f aput v1, v0, p1
0000074a 0f 0c return v12
0000074c 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000750 d8 00 0f 01 add-int/lit8 v0, p1, 1
00000754 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000758 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
0000075c 13 01 5f 00 const/16 v1, 95
00000760 4b 01 00 0f aput v1, v0, p1
00000764 0f 0c return v12
00000766 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000076a b1 df sub-int/2addr p1, v13
0000076c 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
00000770 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000774 44 0f 00 0f aget p1, v0, p1
00000778 38 0f 03 00 if-eqz p1, 3
0000077c 12 0d const/4 v13, 0
0000077e 59 ed 01 00 iput v13, p0, I LPCodeVM;.b
00000782 0f 0c return v12
00000784 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000788 d8 00 0f 01 add-int/lit8 v0, p1, 1
0000078c 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000790 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000794 4b 0a 00 0f aput v10, v0, p1
00000798 0f 0c return v12
0000079a 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000079e b1 df sub-int/2addr p1, v13
000007a0 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000007a4 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000007a8 d8 01 0f ff add-int/lit8 v1, p1, -1
000007ac 44 02 00 01 aget v2, v0, v1
000007b0 44 0f 00 0f aget p1, v0, p1
000007b4 b4 f2 rem-int/2addr v2, p1
000007b6 4b 02 00 01 aput v2, v0, v1
000007ba 0f 0c return v12
000007bc 52 ef 13 00 iget p1, p0, I LPCodeVM;.peekidx
000007c0 d8 00 0f 01 add-int/lit8 v0, p1, 1
000007c4 59 e0 13 00 iput v0, p0, I LPCodeVM;.peekidx
000007c8 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000007cc 44 0f 00 0f aget p1, v0, p1
000007d0 59 ef 01 00 iput p1, p0, I LPCodeVM;.b
000007d4 0f 0c return v12
000007d6 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000007da 52 e0 02 00 iget v0, p0, I LPCodeVM;.c
000007de b1 0f sub-int/2addr p1, v0
000007e0 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000007e4 59 ef 13 00 iput p1, p0, I LPCodeVM;.peekidx
000007e8 0f 0c return v12
000007ea 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000007ee d8 00 0f 01 add-int/lit8 v0, p1, 1
000007f2 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000007f6 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000007fa 4b 01 00 0f aput v1, v0, p1
000007fe 0f 0c return v12
00000800 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000804 d8 00 0f 01 add-int/lit8 v0, p1, 1
00000808 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000080c 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
00000810 13 02 2b 00 const/16 v2, 43
00000814 4b 02 01 0f aput v2, v1, p1
00000818 b1 d0 sub-int/2addr v0, v13
0000081a 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000081e d8 0f 00 ff add-int/lit8 p1, v0, -1
00000822 44 02 01 0f aget v2, v1, p1
00000826 44 03 01 00 aget v3, v1, v0
0000082a b0 32 add-int/2addr v2, v3
0000082c 4b 02 01 0f aput v2, v1, p1
00000830 00 00 nop
00000832 d8 0f 00 01 add-int/lit8 p1, v0, 1
00000836 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
0000083a b1 af sub-int/2addr p1, v10
0000083c 44 0f 01 0f aget p1, v1, p1
00000840 4b 0f 01 00 aput p1, v1, v0
00000844 0f 0c return v12
00000846 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000084a d8 00 0f 01 add-int/lit8 v0, p1, 1
0000084e 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
00000852 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
00000856 52 e1 02 00 iget v1, p0, I LPCodeVM;.c
0000085a 4b 01 00 0f aput v1, v0, p1
0000085e 0f 0c return v12
00000860 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000864 d8 00 0f 01 add-int/lit8 v0, p1, 1
00000868 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000086c 54 e0 10 00 iget-object v0, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000870 46 01 00 03 aget-object v1, v0, v3
00000874 4d 01 00 0f aput-object v1, v0, p1
00000878 0f 0c return v12
0000087a 54 ef 10 00 iget-object p1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
0000087e 52 e0 14 00 iget v0, p0, I LPCodeVM;.stkidx
00000882 d8 01 00 ff add-int/lit8 v1, v0, -1
00000886 46 01 0f 01 aget-object v1, p1, v1
0000088a b1 d0 sub-int/2addr v0, v13
0000088c 4d 0b 0f 00 aput-object v11, p1, v0
00000890 5b e1 0a 00 iput-object v1, p0, Ljava/lang/Object; LPCodeVM;.i
00000894 0f 0c return v12
00000896 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
0000089a d8 00 0f 01 add-int/lit8 v0, p1, 1
0000089e 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000008a2 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
000008a6 4b 0c 01 0f aput v12, v1, p1
000008aa b1 d0 sub-int/2addr v0, v13
000008ac 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000008b0 44 0f 01 00 aget p1, v1, v0
000008b4 4b 0f 01 09 aput p1, v1, v9
000008b8 0f 0c return v12
000008ba 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000008be b1 df sub-int/2addr p1, v13
000008c0 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000008c4 54 e0 0d 00 iget-object v0, p0, [I LPCodeVM;.istk
000008c8 44 0f 00 0f aget p1, v0, p1
000008cc 4b 0f 00 06 aput p1, v0, v6
000008d0 0f 0c return v12
000008d2 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
000008d6 d8 00 0f 01 add-int/lit8 v0, p1, 1
000008da 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000008de 54 e1 0d 00 iget-object v1, p0, [I LPCodeVM;.istk
000008e2 4b 0c 01 0f aput v12, v1, p1
000008e6 b1 d0 sub-int/2addr v0, v13
000008e8 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
000008ec 44 0f 01 00 aget p1, v1, v0
000008f0 4b 0f 01 07 aput p1, v1, v7
000008f4 00 00 nop
000008f6 d8 0f 00 01 add-int/lit8 p1, v0, 1
000008fa 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
000008fe 4b 0c 01 00 aput v12, v1, v0
00000902 0f 0c return v12
00000904 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000908 b1 df sub-int/2addr p1, v13
0000090a 59 ef 14 00 iput p1, p0, I LPCodeVM;.stkidx
0000090e 54 e0 10 00 iget-object v0, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000912 46 01 00 0f aget-object v1, v0, p1
00000916 4d 0b 00 0f aput-object v11, v0, p1
0000091a 4d 01 00 03 aput-object v1, v0, v3
0000091e 0f 0c return v12
00000920 52 ef 14 00 iget p1, p0, I LPCodeVM;.stkidx
00000924 d8 00 0f 01 add-int/lit8 v0, p1, 1
00000928 59 e0 14 00 iput v0, p0, I LPCodeVM;.stkidx
0000092c 54 e1 10 00 iget-object v1, p0, [Ljava/lang/Object; LPCodeVM;.lstk
00000930 46 02 01 04 aget-object v2, v1, v4
00000934 4d 02 01 0f aput-object v2, v1, p1
00000938 d8 0f 00 ff add-int/lit8 p1, v0, -1
0000093c d8 02 00 ff add-int/lit8 v2, v0, -1
00000940 46 02 01 02 aget-object v2, v1, v2
00000944 d8 03 00 ff add-int/lit8 v3, v0, -1
00000948 4d 0b 01 03 aput-object v11, v1, v3
0000094c 54 e3 0d 00 iget-object v3, p0, [I LPCodeVM;.istk
00000950 1f 02 07 00 check-cast v2, [B
00000954 21 22 array-length v2, v2
00000956 4b 02 03 0f aput v2, v3, p1
0000095a d8 0f 00 ff add-int/lit8 p1, v0, -1
0000095e b1 d0 sub-int/2addr v0, v13
00000960 44 00 03 00 aget v0, v3, v0
00000964 23 00 07 00 new-array v0, v0, [B
00000968 4d 00 01 0f aput-object v0, v1, p1
0000096c 0f 0c return v12
0000096e 00 00 nop
00000970 00 01 37 00 01 00 00 00
7b 6d 54 48 36 28 1b 0e
eb e0 d6 c9 b8 ad 9e 91
84 79 71 59 2c 1f fc ef
cf c4 b7 94 85 79 6f 4f
38 2c 1f 12 03 f6 d2 c1
b6 a5 8e 63 43 36 06 e3
be 8e 76 5a 3e 18 04 packed-switch-payload (size)55 (first/last key)1
[0x47b,0x46d,0x454,0x448,0x436,0x428,0x41b,0x40e,0x3eb,
0x3e0,0x3d6,0x3c9,0x3b8,0x3ad,0x39e,0x391,0x384,0x379,
0x371,0x359,0x32c,0x31f,0x2fc,0x2ef,0x2cf,0x2c4,0x2b7,
0x294,0x285,0x279,0x26f,0x24f,0x238,0x22c,0x21f,0x212,
0x203,0x1f6,0x1d2,0x1c1,0x1b6,0x1a5,0x18e,0x163,0x143,
0x136,0x106,0xe3,0xbe,0x8e,0x76,0x5a,0x3e,0x18,0x4]
Instruction counter program
Number of different instructions present in the method: 1d
new-array [23] appears: 1 times
rem-int/2addr [b4] appears: 1 times
if-eqz [38] appears: 1 times
xor-int/2addr [b7] appears: 1 times
if-nez [39] appears: 1 times
aput-byte [4f] appears: 3 times
int-to-byte [8d] appears: 4 times
and-int/2addr [b5] appears: 3 times
iput-object [5b] appears: 2 times
array-length [21] appears: 2 times
sub-int/2addr [b1] appears: 26 times
aget-object [46] appears: 18 times
nop [0] appears: f times
if-lt [34] appears: 1 times
aput-object [4d] appears: 1e times
const/16 [13] appears: a times
iget-object [54] appears: 45 times
const/4 [12] appears: b times
aget-byte [48] appears: 7 times
packed-switch [2b] appears: 1 times
packed-switch-payload [100] appears: 1 times
iget [52] appears: 38 times
return [f] appears: 38 times
add-int/lit8 [d8] appears: 60 times
aget [44] appears: 44 times
check-cast [1f] appears: c times
iput [59] appears: 56 times
add-int/2addr [b0] appears: c times
aput [4b] appears: 40 times
Here we have a much bigger method, but even with that only 29 instructions are used, in anycase the disassembler shows the content of the method correctly and using a familiar format for all those who are used to analyzing smali code. We can see the complexity of this method in a graph generated also with Kunai and its Intermmediate Representation (MjolnIR):
Remember that you can download Kunai on its Github repository.
With this we have seen a very brief introduction to the disassembler from Kunai, each one of the instructions contains a different format that you can find in Kunai’s documentation, or directly inside of the header of the instruction.
I hope this set of blogposts become handy for all those who want to start using Kunai for their analysis, and don’t forget to leave your issues in the Github repository!
See you in the next post.