ESET CrackMe - CONFidence 2o1o
For several years, Eset has been sponsoring a conference on the practical aspects of information security - CONFidence . And every year we offer a task in the form of crackme, for the quick solution of which valuable prizes are awarded. This year, our Polish office , which officially opened at the beginning of the year, prepared a very original assignment. After all, the conference was held in their hometown, in Krakow.
If you want to try your hand, then do not read the information by rolling, as there we published a description of the registration code verification algorithm. Download crackme here .
You can get acquainted with the passage of last year's crackme here , but, in our opinion, this year the task is more interesting. We did not know in advance the principles of its successful passage, and we passed it in the same conditions as the contest participants.
The technological basis for calculating the correct registration code was laid down by a virtual machine that performs calculations with the entered data based on the simplest bit operations. This kind of code virtualization is used to build software protection against illegal distribution and copying. For example, the protectors VmProtect and Themida (popularly considered to be one of the most difficult protections for reverse analysis) also use technologies to convert the original program code into some byte code. This bytecode is already executed by the handlers of the virtual machine, which is largely redundant to complicate the reverse analysis and restoration of the logic of the original algorithm.
Let us return to our virtual machine, which has 8 pseudo-registers at its disposal, we will call them conditionally: rA, rB, rC, rD, rE, rF, rG, rH. Each register has a size of 1 bit. The set of supported commands is as follows:
ret - shutdown of the virtual machine;
set < register_name > - set the value of the register to a single state;
jz < register_name > - conditional control transfer command (if the contents of the register are 0, then control transfer is performed to the next procedure (the procedures are located in memory sequentially));
and <register_name1>, <register_name2> - logical operation, the result is stored in the first register;
mov<register_name1>, <register_name2> - copy the contents of the second register to the first;
mov <register_name, <address> - copy the contents of the memory (bit) at the specified address to the specified register;
mov <address>, <register_name> - copy the contents of a given register (bit) to a given address in memory. The
size of a virtual machine instruction has a fixed size and is 2 bytes. The principle of encoding instructions can be depicted as the following scheme:
This virtual machine converts the contents of the memory in accordance with the control sequence (which just needs to be found), which is also located in memory: the
beginning of memory + 0x00: control sequence (16 bytes)
beginning of memory + 0x10: hash value from the entered name (16 bytes)
beginning of memory + 0x20: encrypted hash value (16 bytes)
beginning of memory + 0x30: result of conversion of a virtual machine function (16 bytes)
The cycle of processing virtual machine commands does not look too it’s tough compared to analogues of commercial protectors.
For a more convenient analysis of the bytecode of the commands executed by the virtual machine, we wrote a processor module for the IDA Pro disassembler, which greatly simplified our further analysis. This is how the set of commands looks before they are converted by our processor module:
And the picture below shows the processing option by the processor module:
We gave the name to the commands, similar to the analogues we already knew from x86 assembler. But further analysis showed the redundancy of the initial set of commands, because the addition operation modulo two (exclusive or) was expressed through equivalent calculations using other Boolean operations. After that, we decided to implement optimization in our processor module, which greatly reduced after that the volumes of the analyzed code calculating the registration number.
We decided so far not to upload the source code of the generator of the correct registration numbers, so that you still have a research fuse, see for yourself this crackme.
But nevertheless, as an example, we give a few correct combinations:
Name: habrahabr
Registration Code:984116e52ad86d6bd144b11b975a595e
Name: SVH
Registration Code: 271a300e1174f46f944c5c67dc59dd57
Name: CONFidence
Registration Code: 24a2b8dc7c1578de64f8e8e114c2bf00
If you want to try your hand, then do not read the information by rolling, as there we published a description of the registration code verification algorithm. Download crackme here .
You can get acquainted with the passage of last year's crackme here , but, in our opinion, this year the task is more interesting. We did not know in advance the principles of its successful passage, and we passed it in the same conditions as the contest participants.
The technological basis for calculating the correct registration code was laid down by a virtual machine that performs calculations with the entered data based on the simplest bit operations. This kind of code virtualization is used to build software protection against illegal distribution and copying. For example, the protectors VmProtect and Themida (popularly considered to be one of the most difficult protections for reverse analysis) also use technologies to convert the original program code into some byte code. This bytecode is already executed by the handlers of the virtual machine, which is largely redundant to complicate the reverse analysis and restoration of the logic of the original algorithm.
Let us return to our virtual machine, which has 8 pseudo-registers at its disposal, we will call them conditionally: rA, rB, rC, rD, rE, rF, rG, rH. Each register has a size of 1 bit. The set of supported commands is as follows:
ret - shutdown of the virtual machine;
set < register_name > - set the value of the register to a single state;
jz < register_name > - conditional control transfer command (if the contents of the register are 0, then control transfer is performed to the next procedure (the procedures are located in memory sequentially));
and <register_name1>, <register_name2> - logical operation, the result is stored in the first register;
mov<register_name1>, <register_name2> - copy the contents of the second register to the first;
mov <register_name, <address> - copy the contents of the memory (bit) at the specified address to the specified register;
mov <address>, <register_name> - copy the contents of a given register (bit) to a given address in memory. The
size of a virtual machine instruction has a fixed size and is 2 bytes. The principle of encoding instructions can be depicted as the following scheme:
This virtual machine converts the contents of the memory in accordance with the control sequence (which just needs to be found), which is also located in memory: the
beginning of memory + 0x00: control sequence (16 bytes)
beginning of memory + 0x10: hash value from the entered name (16 bytes)
beginning of memory + 0x20: encrypted hash value (16 bytes)
beginning of memory + 0x30: result of conversion of a virtual machine function (16 bytes)
The cycle of processing virtual machine commands does not look too it’s tough compared to analogues of commercial protectors.
For a more convenient analysis of the bytecode of the commands executed by the virtual machine, we wrote a processor module for the IDA Pro disassembler, which greatly simplified our further analysis. This is how the set of commands looks before they are converted by our processor module:
And the picture below shows the processing option by the processor module:
We gave the name to the commands, similar to the analogues we already knew from x86 assembler. But further analysis showed the redundancy of the initial set of commands, because the addition operation modulo two (exclusive or) was expressed through equivalent calculations using other Boolean operations. After that, we decided to implement optimization in our processor module, which greatly reduced after that the volumes of the analyzed code calculating the registration number.
We decided so far not to upload the source code of the generator of the correct registration numbers, so that you still have a research fuse, see for yourself this crackme.
But nevertheless, as an example, we give a few correct combinations:
Name: habrahabr
Registration Code:984116e52ad86d6bd144b11b975a595e
Name: SVH
Registration Code: 271a300e1174f46f944c5c67dc59dd57
Name: CONFidence
Registration Code: 24a2b8dc7c1578de64f8e8e114c2bf00