Lena's Tuts: 02. Keyfiling the reverseme + assembler

Posts 16 of 6 · Page 1 of 1
Lena's Tuts: 02. Keyfiling the reverseme + assembler
"I've decided to stop calling this series 'Corrections' because there are very few problems, and I don't want to be disrespectful since these tuts are excellent and for the most part correct." -why06

Lena's Tuts Summaries
02. Keyfiling the reverseme + assembler


Intro:
Ok. Lets get started. This one is all about Keyfiling. It uses the ReverseMe.exe from tutorial one so if you finished that one this should be a breeze. However it introduces some new concepts you should look out for. I will be covering those as well as presenting some supplemental tutorials and information for those interested.

What this Covers?
  • Hexadecimal and Binary Number Systems
  • Windows API's: ReadFile & CreateFile
  • Loop Disassembly
  • If-Else Logic


Summary:
This Tutorial is actually very easy, up until you get to this point:
Code:
004010AE    .  85C0                     TEST EAX,EAX                                  ;  kernel32.BaseThreadInitThunk
004010B0       75 02                    JNZ SHORT reverseM.004010B4
004010B2    .  EB 43                    JMP SHORT reverseM.004010F7
004010B4    >  33DB                     XOR EBX,EBX
004010B6    .  33F6                     XOR ESI,ESI
004010B8    .  833D 73214000 10         CMP DWORD PTR DS:[402173],10
004010BF       7C 36                    JL SHORT reverseM.004010F7                    ;  int numOfGs = 0;
004010C1    >  8A83 1A214000            MOV AL,BYTE PTR DS:[EBX+40211A]               ;  for(int i = 0; Buffer[i]; i++)
004010C7    .  3C 00                    CMP AL,0                                      ;  {
004010C9    .  74 08                    JE SHORT reverseM.004010D3                    ;  if(Buffer[i] == 'G')numOfGs++;
004010CB    .  3C 47                    CMP AL,47                                     ;  }
004010CD    .  75 01                    JNZ SHORT reverseM.004010D0
004010CF    .  46                       INC ESI
004010D0    >  43                       INC EBX
004010D1    .^ EB EE                    JMP SHORT reverseM.004010C1
004010D3    >  83FE 08                  CMP ESI,8                                     ;  if(numOfGs >=8)goto good;
004010D6       7C 1F                    JL SHORT reverseM.004010F7
004010D8    .  E9 28010000              JMP reverseM.00401205                         ;  else goto bad;
Now it is perfectly possibly to get past this without worrying about the higher level principles behind it, but at some point you will want to understand how high-level loops are assembled. The tutorial did not cover this so I will be in this summary. To start off I highly recommend taking a look at these two tutorials: x86 Disassembly/Branches - Wikibooks, collection of open-content textbooks and x86 Disassembly/Loops - Wikibooks, collection of open-content textbooks.

Now lets break down the code into parts.
Code:
004010AE    .  85C0                     TEST EAX,EAX                                  ;  kernel32.BaseThreadInitThunk
004010B0       75 02                    JNZ SHORT reverseM.004010B4
004010B2    .  EB 43                    JMP SHORT reverseM.004010F7
This correlates into a If-Then-Else statement common seen in C++ as:
Code:
if(condition)//do something
else //do something else
This first thing to realize when converting disassembled logic branches to C++ is that the conditions are always reversed. This means that we treat:
Code:
004010AE    .  85C0                     TEST EAX,EAX                                  ;  kernel32.BaseThreadInitThunk
004010B0       75 02                    JNZ SHORT reverseM.004010B4
as...
Code:
if(eax != 0)// goto reverseM.004010B4
And the mandatory JMP after JNZ serves as the else

Code:
if(eax != 0)// goto reverseM.004010B4
else //goto badboy
Now lets try to generate code for the rest of this disassembly. The first step is to identify (action) (initialization) and (conditions)
Code:
004010B4    > \33DB                     XOR EBX,EBX                                   ;  initialize to 0
004010B6    .  33F6                     XOR ESI,ESI                                   ;  initialize to 0
004010B8    .  833D 73214000 10         CMP DWORD PTR DS:[402173],10                  ;  if(*lpdword >= 16) //condition
004010BF       7C 36                    JL SHORT reverseM.004010F7
004010C1    >  8A83 1A214000            MOV AL,BYTE PTR DS:[EBX+40211A]               ;  Buffer[i];
004010C7    .  3C 00                    CMP AL,0                                      ;  if(Buffer[i] != 0)
004010C9    .  74 08                    JE SHORT reverseM.004010D3
004010CB    .  3C 47                    CMP AL,47                                     ;  if(Buffer[i] == 'G')
004010CD    .  75 01                    JNZ SHORT reverseM.004010D0
004010CF    .  46                       INC ESI                                       ;  numberOfGs++;
004010D0    >  43                       INC EBX                                       ;  i++;
004010D1    .^ EB EE                    JMP SHORT reverseM.004010C1
004010D3    >  83FE 08                  CMP ESI,8                                     ;  if(numberOfGs >=8)goto good;
004010D6       7C 1F                    JL SHORT reverseM.004010F7
004010D8    .  E9 28010000              JMP reverseM.00401205                         ;  else goto bad;
What we have here is a for loop.

The initialization is at the top:
Code:
004010B4    > \33DB                     XOR EBX,EBX                                   ;  initialize to 0
004010B6    .  33F6                     XOR ESI,ESI                                   ;  initialize to 0
The action is in the middle:
Code:
004010CF    .  46                       INC ESI                                       ;  numberOfGs++;
004010D0    >  43                       INC EBX                                       ;  i++;
Now on to the logic. All loops in disassembly are variations of do-while loops. This is because a while loop is just a do-while with a condition for entering the loop. See: x86 Disassembly/Loops - Wikibooks, collection of open-content textbooks

We treat these initial conditions just like if statements and therefore the conditions are reversed. The next step is to find the bottom of the loop. In this case it's:
Code:
004010D1    .^ EB EE                    JMP SHORT reverseM.004010C1
Now that we have all the part we can begin rebuilding.
Code:
int i = 0;
int numberOfGs = 0;
if(*lpdword >= 16)
{
	do
	{
		if(Buffer[i] == 'G')
		{
			numberOfGs++;
			i++;
		}
	}while(Buffer[i])
}

if(numberOfG's >= 8)//goto good
else //goto bad
And this can be consolidated into a for loop:

Code:
int numberOfGs = 0;
if(*lpdword >= 16)
{
	for(int i = 0; Buffer[i]; i++)
	{
		if(Buffer[i] == 'G')
		{
			numberOfGs++;
			i++;
		}
	}
}
else //goto bad

if(numberOfG's >= 8)//goto good
else //goto bad
Not this may not be exactly right, but the important part is to be able to see highlevel concepts in otherwise monotonous branch statements. It helps to better understand disassembly if you can organize each part into a logical unit.


Error:
Lastly there is one error in Lena's tut. She claims that the lpdword parameter named pBytesRead in ReadFile API was the buffer the bytes were read from. this is not true. It is just a DWORD pointer that holds the number of bytes read from the file.

*This File is included to decrease stress on tuts4you as well as provide a backup in case of server failure.*
snd-reversingwithlena-tutorial02.tutorial.rarattachment deleted · 77 downloads before removal
The read file has to read 46 bytes in a certain adress and puts it in a buffer.
Why is this? You dont even use it when creating the keyfile.dat
Quote Originally Posted by Skulhead = hacked. View Post
The read file has to read 46 bytes in a certain adress and puts it in a buffer.
Why is this? You dont even use it when creating the keyfile.dat
Probabably to support variable length keyfiles, and doesn't it read 0x46 aka 70 bytes?
Quote Originally Posted by Hell_Demon View Post
Probabably to support variable length keyfiles, and doesn't it read 0x46 aka 70 bytes?
I thought 46h 70d, but ty.
Shouldn't it be

Code:
int i = 0;
int numberOfGs = 0;
if(*lpdword >= 16)
{
	do
	{
		if(Buffer[i] == 'G')
			numberOfGs++;
			
                i++;

	}while(Buffer[i])
}
The EBX register gets incremented regardless of the jump of the if-clause.
Or am I wrong?
Awesome! Couple of error's, But thank you =)
Posts 16 of 6 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Need help?