"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.*