Home Reversing Rogues #1 - WindowsAV - [repne scasw]
Post
Cancel

Reversing Rogues #1 - WindowsAV - [repne scasw]


Recently, I’ve been delving into the world of serial creation routines in ancient rogue software—for fun and profit. I’m very much a novice, but I’ve embraced my inner reverse engineer and now my idea of fun involves grappling with assembly in the pursuit of seemingly pointless endevours. So, for educational purposes, today we’ll be crafting a keygen for the rogue malware known as WindowsAV and learn a little about the repne scasw instruction.

Presented here are my notes, with commentary added very much as an after thought. Good Luck!

Virus Total Results

virus total results Virus Total Results

First Run

shows many fake infections Showing many infections on a clean VM box

Analysis

I used the ScyllaHide plugin to attach to the running rogue.

  1. Entered ‘abcd efgh ijkl mnop’ as a serial key and allow the error message to appear.
  2. Pause debugging -> alt-F9 to run to user code.
  3. Press ‘OK’ on the error message box

Following the steps above will break right after the call to the offending message box. Scrolling up above this we see a ‘jne’ instruction that would allow us to jump over the error msg as long as eax returns from the call not equaling zero. (because test eax,eax will set zero flag if eax is zero)

Let’s set a break on the call just before ‘jne’ instruction and submit the serial again. Breakpoint set on call before jne

The First Check

We break, step into this call (f7) and we are presented with a short set of instructions. Let’s step into the only call shown.

Step into this Call

We then find ourselves with a much more substantial set of instructions.

math instructions

We step until the movsx edx, ax instruction (0x5D4623). Here, AX (which currently holds the last letter of our serial: ‘p’ (0x70 in hex) ) is being moved into the edx register. Then some math is performed:edx*2+633906

The hex value of the last character in our serial (0x70 in this case) is multiplied by 2 and then added with 0x633906. Shortly after that the value is then AND’d with dword ptr ss:[ebp+c].

After running a few times, the value pointed to by [ebp+c] was found to always be 0x04 as shown below.

[ebp+c] = 0x04

The result from the above math is moved into EAX and will be the value that is tested upon return. So, we now have a formula that should help us determine what the last character can be: (char *2+0x633906) AND 0x04 != 0

Using a calculator in ‘hex’ mode, we can test some characters. Currently, we have the lowercase letter ‘p’(hex=0x70) as our last character.

(0x70*2+633906) AND 0x04 = 0 <—BAD

Let’s try the zero ‘0’(hex=0x30) character:

(0x30*2+633906) AND 0x04 = 4 <—GOOD

This is good as it will not return zero and therefore the ‘jne’ instruction will jump over our error message. Let’s change the last char of our serial to ‘0’ and test it out.

changed last character to ‘0’

We can see that we will successfully jump over the first error message. Which leads us right to another set of checks each with a jump to another error message.

The Second Checks

Another set of checks

Here we can see that:

  • esi must be 2
  • edi must be 4
  • ptr ebp-A0 must be 3
  • ptr ebp-A4 must b 1

Otherwise, we will jump to the error message located at 00410EB9.

Let’s scroll up and see if we notice where these values are being set. Scrolling up we can see:

Calls that seem to be setting the values

Each of these sections make the same call to 0x005DE780. Lets set a break at 0x00410992 which is the first call to 0x005DE780. Submit a serial. After breaking we notice a couple of things:

eax holds first 4 chars, ecx holds ‘F’ (0x46)

EAX points to the first 4 chars of our serial and ECX contains the capital letter ‘F’ (0x46). Upon return from this call, eax will be moved into esi, which as mentioned above needs to be ‘2’.

We step into the call as well as two more succeeding calls ( call 0x4F156C and 0x53Ae3C ) Step into this call

Step into this call as well

And we end up here:

Meat and Potatoes

Stepping through this code we end up on the repne scasw instruction.


I was not completely familiar with this instruction at the time so I did some googling…

Repeat while NOT equal

Cmp AX with word at EDI

repne scasw will iterate through WORDS starting at the address pointed to by EDI searching for AX (0x0046) and decrement the counter in ECX each loop through. If AX (0x0046) is found, the zero flag(ZF) will be set and the loop will exit.

Let’s take a look at what is in EDI at the moment in the dump.

Shows the first four chars of our serial (0x0061, 0x0062, 0x0063, 0x0064)

Below shows the important values during the run of the repne scasw instruction. We can see that (in this case) the counter hits 0 and the ZF is 0 meaning that 0x0046 was not found.

Loop # AX EDI ECX Start ECX End ZF
 1 0x0046  0x0061 4 3 0
 2 0x0046  0x0062 3
 3 0x0046  0x0063 2
 4 0x0046 0x0064


So, AX was not found. Meaning the letter ‘F’ was not found in the first four chars of our serial and we jump to instructions which xor eax, eax and retn. Not good as this means ‘0’ will be moved into esi instead of the ‘2’ that we need.

At this point I ran again to the breakpoint set at 0x00410992. Then ran (f9) through all of the breaks to see which chunk of the serial as well as which letters were being loaded into EAX and ECX respectively prior to each of the calls to 0x005DE780. Remember, we already know the first one:

eax holds first 4 chars, ecx holds ‘F’ (0x46)

Here’s what we will find for the others:

Letters that are loaded into ECX before each call

Knowing this information, let’s put the proper letter into each chunk of the serial and see what happens. Here’s the serial we are trying now:

F, C, A, E

Stepping into the first call (0x00410992) and making our way to the repne scasw, here is what we have, prior to the instruction running, in the registers and values pointed to by EDI (in the dump).

Alriiiiighty, here’s what goes down when the repne scasw instruction is executed now.

Loop # AX EDI ECX Start ECX End ZF
 1 0x0046  0x0046 4 3 1
 2 -  - -
 3 -  - -
 4 - -



0x0046(‘F’) is now found

  • repne scasw will execute
  • imediately find 0x0046 at the first WORD pointed to by EDI
  • ZF will be set
  • ECX will be decremented and the loop will exit.

Below we can see the register and flag values after the repne scasw instruction has executed

Shows ECX at 3 and ZF set

Continue stepping the code and we see that a jump takes us to a new set of instructions.

Instructions that move position to EAX

This chunk of code simply moves the position that the letter was found to EAX. So, since ‘F’ (0x0046) was found as the 1st letter in the serial, ‘1’ is moved to EAX. This will be the value that is then moved into ESI upon return.

Putting it all together so far:

  • We know that in order to pass the next set of checks, ESI, EDI, EBP-A4 and EBP-A0 all need to be equal to certain values ().
  • We know that these values are set within the instructions above
  • The instructions above search for a certain letter in each chunk (4chars) of the serial.
  • The position that the letter is found, is moved into EAX and ultimately into the registers above.
  • Therefore, we know what position each letter is supposed to be placed into the serial.

Recall the images below:

We now know these are the positions that each respective letter should be Shows position that each letter should be found

AND

These are the letters for each chunk of the serial Shows letter for each of the 4 chunks of serial

Let’s put each letter into the correct position:

Shows letter for each of the 4 chunks of serial

Running through the breaks we will see that we successfully pass the second checks. Which leads us to the Final check.

Final Check

Checks last character of serial is between 1 and 3

From the image above, the final bit of instructions simply convert the last char of the serial to it’s numerical value and then checks to see if that value is between 1 and 3 included. In other words, the last character of the serial must be a number between 1 and 3 included.

Let’s write a keygen and get the heck out of here.

Keygen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import random

# useable letters and numbers (No 'F, C, A, E')
chars = 'BDGHIJKLMNOPQRSTUVWXYZ'

# useable numbers for the last character of serial
nums = '123'

# Serial Format:  *F** - ***C - **A* - E**1

x = '*F**-***C-**A*-E**$'
serial = ''

for char in x:
    if char == '*':
        char = random.choice(chars)
    if char  == '$':
        char = random.choice(nums)
    serial += char
    
print(serial)

Testing the Keygen

Testing a code generated by our keygen and magically we have no more errors and we are fully licensed. yay…

Keys generated by our keygen

Success Modal

Fully licensed with no more definitely real infections…

This post is licensed under CC BY 4.0 by the author.