Skip to content
BlogPaper
Go back

Crackmes: EasyVM (Medium)

Edit page

Crackmes : EasyVM (Medium)

Key takeaways

Case Summary

The objective of this challenge is to find the key via opcode and understand how the data run in the program. It is necessery to reverse engineer the custom Virtual Machine interpreter to find a valid 10-character licence key. The algorithm obfuscated using a custom instruction set and dynamic bytecode generation.

Analyst

Static Analyst

1.png Firstly, let’s execute this binary on safety. The program requires 10-characters License Key so it is unnecessery to think about what string should have been an input.

Upon entering whatever random string, the program outputs “This license key is corrupted.” and loop back to the input prompt.

2.png

An analyst of the loop shows a lot of commands and bytes here, and they are all stored in fking_opcode arrays after all.

3.png

Next, The code invokes the VM_INTERPRETER function with two parameters, first one is the 8th of the input_string and the opcode array.

4.png

Certain characters have been identified as components of OPCODE structure within the machine language, defined as <opcode> <operand>, <mode>(e.g.,mov eax, 4.).

Given the custom VM architecture, the code functions similarly to Assembly language. For example, the ‘A’ opcode triggers an addition operation, adding the current result to another operand.

These characters correspond to specific instructions, as defined below: :

A : ADD
S : SUBTRACT
X : XOR
O : OUTPUT (STORAGE)
I : INITIALIZE

5.png

Ultimately, the return value is stored in KEY_LICENSE. A result of zero indicates that the correct key has been entered.

Dynamic Analyst

6.png

The VM_INTERPRETER is putted breakpoint in order to get the opcode parameter. It is not hard to realize that some characters of input string will be there.

Input CharacterPosition (Index)Corresponding VM Instruction
Character 11I (Load)
Character 27I (Load)
Character 349I (Load)
Character 455I (Load)
Character 597I (Load)
Character 6103I (Load)
Character 7145I (Load) - Note: Character 7 is very far behind
Character 8112A (Add) - This is the place you are looking for!
Character 8151I (Load again at the end)

Finally, it is important to find what the characters should be, so the data is analyzed to obtain the key. Formula : <opcode> <operand>, <mode> PART 1: PROCESSING THE FIRST INPUT PAIR (Input 0, 1)

x = (input[0] - 75) + (input[1] - 69)

IndexInstruction (Bytecode)Logical Meaning
0I |input|0result = input (Load character 1)
3O |1|Atmp​ = result
6I |input​|0result = input​ (Load character 2)
9O |2|Atmp​ = result
12I |1|Aresult = tmp​ (Get input)
15S |‘K’|0result -= ‘K’ (75)
18O |8|Atmp​ = result
21I |2|Aresult = tmp​
24S |‘E’|0result -= ‘E’ (69)
27O |9|Atmp​ = result
30I |8|Aresult = tmp​
33A |9|Aresult += tmp​
36O |10|Atmp​ = result (Total variable)

PART 2: PROCESSING THE NEXT INPUT PAIR (Input 2, 3)

x += (input[2] - 89) + (input[3] - 45)

IndexInstruction (Bytecode)Logical Meaning
48I |input​|0result = input​ (Load character 3)
51O |1|Atmp​ = result
54I |input​|0result = input​ (Load character 4)
57O |2|Atmp​ = result
60I |1|Aresult = tmp​ (Get input​)
63S |‘Y’|0result -= ‘Y’ (89)
66O |8|Atmp​ = result
69I |2|Aresult = tmp​ (Get input​)
72S |’-‘|0result -= ’-’ (45)
75O |9|Atmp​ = result
78I |8|Aresult = tmp​
81A |9|Aresult += tmp​
84A |10|Aresult += tmp​
87O |10|Atmp​ = result

PART 3: PROCESSING THE COMPLEX INPUT GROUP (Input 4, 5, 7) x += input[4] + input[7] - 75 - input[5]

IndexInstruction (Bytecode)Logical Meaning
96I |input​|0result = input​ (Load character 5)
99O |1|Atmp​ = result
102I |input​|0result = input​ (Load character 6)
105O |2|Atmp​ = result
108I |1|Aresult = tmp​ (Get input​)
111A |input​|0result += input​ (Add character 8)
114S |‘K’|0result -= ‘K’ (75)
117S |2|Aresult -= tmp​
120A |10|Aresult += tmp​
123O |10|Atmp​ = result

PART 4: PROCESSING THE LAST INPUT PAIR (Input 6, 7) x += input[6] - input[7]

IndexInstruction (Bytecode)Logical Meaning
144I |input​|0result = input​ (Load character 7)
147O |1|Atmp[1] = result
150I |input​|0result = input[7]​ (Reload character 8)
153O |2|Atmp[2] = result
156I |1|Aresult = tmp[1]
159S |2|Aresult -= tmp[2]​ (Subtract​)
162A |10|Aresult += tmp[10]​
165O |10|Atmp[10] = result

Final overall expression

x = (input[0] - 75) + (input[1] - 69)
  + (input[2] - 89) + (input[3] - 45)
  + input[4] + input[7] - 75 - input[5]
  + input[6] - input[7]
  = 0

Lastly, the license key consists of ‘KEY-KAA’ plus any number of trailing characters.

For some instances : KEY-KAAKATJRI KEY-KAAKAT123 KEY-KAAVIETNAMESE KEY-KAA_HOANGSA_TRUONGSA_BELONG_TO_VIETNAM 7.png


Edit page
Share this post on:

Previous Post
Malware Injection in Window Operating System 101
Next Post
Xworm - Malware Analysis