Crackmes: 4N006135 level-2

I found this crackme really interesting and I've learned a couple of stuff that will come useful within my long way into the reverse engineering learning process. I thought it would be a good idea to save somewhere a few notes that I took during the static analysis of these executables.

The "4N006135" by borismilner, is zip file that contains a total of 4 x86 binaries, each of those with an increasing level of difficulty. level-0 an level-1 are pretty straight forward while level-2 and level-3 took me some time and the Intel Software Developer's Manual constantly at hand.
In this blog post I'll focus my attention on (some aspects of) level-2 and how I built the relative keygen in Python.

REP executes an instruction (STOS) and decrease the value of ECX until ECX is 0. The value of ECX is 20h so 32 times.
STOS(B) copies the value (1 byte) contained in AL to [EDI] and increments/decrements (depending on the Direction Flag) EDI by 1. B can be replaced by W or D to copy value of 2 or 4 bytes respectively.

In Python:

s = bytearray(chr(0x4f) * 32)

I'm using bytearray instead of string because we'll need to modify part of this value (strings are immutable in Python).

The value 40D020h already came up, but what it is? By observing all the remaining instructions of the program we can deduct that this is the memory location that will hold the final key (that we have to guess calculate) computed using a custom algorithm and the user ID random value.
So, quick recap:EDI - pointer to the memory location where the key is stored. This at the moment contains a string of 32 "O"sEBX - the random User ID

The BT instruction takes the bit 0 of EBX and stores the result in the Carry Flag (CF). JNB jumps if CF is 0.
We are basically checking if the user ID number is even or not. If the number is odd the first value of the key will be 2Ah (symbol "*") otherwise remains "O".

Let's add this into our python script:

if ((uid % 2) != 0):
s[0] = chr(0x2a)

Then the program checks if the number of user ID is bigger than 0B16B00B5h :))

Then the Parity Flag (PF) is evaluated. This is, however, done over the value of EDI, which now will be 40D022h (we "inc EDI" twice since now). 404D022h in binary is "10000001101000000100000" and so the PF will always be 0.