Fun challenge. I went for finding just the key algorithm rather than fully devirtualizing, but the code is pretty clear. Here some sample keys:
- Notice Validate is virtualized using VMP, and returns a string which is later displayed. => returned value is probably the name.
- Notice that VM reads code using method 0x06000046. Also notice that field 0x04000048 is the virtual program counter and field 0x0400004A contains the stack.
- Use this harmony script to perform a VM trace that dumps the program counter, stack contents and calls.
- First run with garbage data reveals it requires a base64 string.
- Second run, with a random base64 string reveals the key consists of three parts: first and second part are both 32 bytes, the rest is of arbitrary length.
- Third run with hex data 00010203...4b4c4d4e4f reveals all that is necessary to create a keygen (full trace https://pastebin.com/Qcc2ULc6)
- Notice it creates a new instance of Rfc2898DeriveBytes using 'tetris' as password, the first 32 bytes of the serial as salt, and 1000 iterations
- Notice it creates a new instance of RijndaelManaged with blocksize = 256, mode = CBC, padding = PKCS7, and IV = the second part of the serial.
- Notice it attempts to decrypt the remaining part of the serial using this instance of RijndaelManaged.
- Keygen is simply doing the reverse of all operations in the trace.
- Notice the decrypted data is returned and displayed => encrypted data is username encrypted using the same algorithm.