Reversing Visual Basic
(SmartCheck Information )

 

General advice on reversing VB using SmartCheck (with OllyDbg) :

SmartCheck is a very useful program for reversing VB registration schemes and it's worth learning how to use it.

Always study the behaviour of a program, run the program a few times and see what messages are shown. Study the way the program acts. It can't be repeated enough : good study of the program can drastically reduce the amount of time needed for reversing afterwards... . For that, you can use debuggers, disassemblers, VB decompilers. Then comes SmartCheck in action. For general settings of SmartCheck, see Part09 in this series. After running once and trying to register with some bogus code, note down the Badboy and close the program (not SmartCheck). When you choose "Show All Events", a whole ocean of information can be seen. And it is very easy to mis the lines you need. Hence, click on the line you want to study before choosing "Show All Events". Usually, this is xxxxxx_Click in which xxxxxx is the name of the button refered to by the program. For programmers that didn't change the button's name, it is usually CommandX_Click where X starts from 1. Mostly, you will find the serial this way (often after mathematical calculations).

A couple of basic rules if you can't find the serial at first in SmartCheck :

1. Look first for the most used VB API's :  __vbavartsteq, __vbastrcmp and __vbastrcomp. Perhaps you find the correct code compared to the one you entered. BTW, "__" is a double "_".

2. If you can't find one of these 3, most probably the program uses the other comparison methods (see below). In that case, go through the lines and look for the Badboy message. A few lines above it, search for one or more of the VB commands (APIs) that you can use to breakpoint in Olly (see below). Start from the one nearest to the Badboy message line. Search how many breakpoints you find between clicking register button and  the Badboy message (manually or with the search function in SmartCheck). Now use Olly to break at the same place before the Badboy and keep this BP. This works because Smartcheck notes the lines down like they are executed in the program !

For example, if you set a BP on __vbafreestr, there might be a lot of them used after you click on the register button. And if the specific breakpoint you want, is shown as 10th __vbafreestr in SmartCheck, you have to press F9 nine times in Olly to get to the 10th __vbafreestr.

3. Run the program, enter your bogus registration key and click to register. Olly breaks unless you set the breakpoint wrongly.

4. Trace into EVERY call if necessary. Usually, it won't take long since you are near to the Badboy message. If you did not come across anything suspicious, go back to SmartCheck and look for the breakpoint just before this one. The investigated breakpoint might be after the compare routine.

 

 

The following is some code you will encounter in SmartCheck.

This is some important code you will find in Smartcheck. Try to understand it. It's really not that difficult.

I've used BOLD words to show what you see in SmartCheck. Words in RED mean that you have to take special note of them.

 


Len(String:"lena151") returns LONG:7

Explanation:
Get length of String "lena151" which is 7


Asc(String:"T") returns Integer:84

Explanation:
Get the decimal value of T which is 84


Mid$(String:"54321",long:4,VARIANT:Integer:1)

Explanation:
Get the fourth char from the string 54321 which is 2


Left(VARIANT:VT_DISPATCH:....., long:3)

Explanation:
Get the third char from the left


Hex$(VARIANT:Integer:247)

Explanation:
Converts 247 in hex which will give F7


__vbaVarAdd(VARIANT:Integer:2, VARIANT:Integer:97) returns .....

Explanation:
Add 2 and 97 which gives 99
But if both are Strings instead of Integers, you will get 297 instead.


__vbaVarDiv(VARIANT:Integer:97, VARIANT:Long:1) returns.....

Explanation:
Divide 97 by 1


__vbaVarMul(VARIANT:String:"1", VARIANT:String:"2") returns ...

Explanation:
Multiply 1 by 2


__vbaVarSub(VARIANT:String:"2", VARIANT:String:"34") returns ...

Explanation:
Subtract 34 from 2 which makes -32


****.Text eg. Text1.Text
If you click on the "+" sign next to it, you will get other lines under it. Look for SysAllocStringLen.
eg. SysAllocStringLen(PTR:00000000, DWORD:00000029) returns LPVOID:410584

Explanation:
Get the input you typed in the TextBox and placed it in memory location 00410584
Run the program in Olly and look at this address what is there. This will not always work.


__vbastrcmp(String:"zzzzz",String:"yyyyy")returns DWORD:0

Explanation:
__vbaStrCmp -- used for comparing Strings eg. "zzzzz" and "yyyyy"
Note: you might see the correct code compared to what you keyed in!
returns DWORD:0 -- In Olly, you will see that after this comparison, eax = 0


__vbaFreeStr(LPBSTR:0063F3F0)
Click on the "+" sign next to it and look for SysFreeString
eg. SysFreeString(BSTR:00410584)

Explanation:
The String located at memory location 00410584 is cleared.


__vbaVarCopy(VARIANT:String:"12345", VARIANT:Empty) returns DWORD:63FA30
 

Explanation:
"12345" is copied to memory location 004103CC
This is similar to __vbaVarMove


__vbaVarForInit(VARIANT:Empty, PTR:0063F920, PTR:0063F91.....)

Explanation:
Set up a For...Next Loop
There will usually be __vbaVarForNext somewhere below as well.


Mid(VARIANT:String:"abcdefg", long:1, VARIANT:Integer:1)

Explanation:
Get the 1st character in the string "abcdefg" starting from location 1. 


SysAllocStringByteLen(LPSTR:004103F0, DWORD:00000002) returns LPVOID:410434

Explanation:
String is copied to memory location 00410434
It is usually followed by __vbaStrVarVal(VARIATN:String"?") returns DWORD:410434


SysFreeString(BSTR:004103F0)

Explanation:
Free memory location 004103F0
These lines are especially good for "serial fishing" because when you click on them and look at the right window, you will see what Strings are being freed. Correct codes/serials are sometimes shown here.


__vbaVarCat(VARIANT:String:"aa", VARIANT:String:"bb") returns DWORD:63F974

Explanation:
Join "bb" to "aa" to form "aabb"


__vbaFreeVar(VARIANT:String:"abcdefg")
Click on the "+" sign next to it and look for SysFreeString
eg. SysFreeString(BSTR:0041035C)

Explanation:
Free "abcdefg" from memory location 0041035C
Here, if you click on the line and look at the right window, you can also see what is being freed.


__vbaVarTstEq(VARIANT:****, VARIANT:****) returns DWORD:0

Explanation:
__vbaVarTstEq is used to compare variants. If they are not the same, DWORD=0 (so eax=0)
If they are the same, DWORD will be FFFFFFFF (so eax=FFFFFFFF)
Similar to __vbaVarCmpEq


****.Text <-- "lena151, you are so stupid !" (String)

Explanation:
To display the String "lena151, you are so stupid !" in the Textbox


MsgBox(VARIANT:String:"lena151, how stupid !", Integer:0, VARIANT:String:"Wrong",VARIANT.....)

Explanation:
Create a Message Box with title "Wrong" and message "lena151, how stupid !"
 


__vbaVarTstNe(VARIANT:Const Double:9, VARIANT:String:"3") returns ...

Explanation:
__vbaVarTstNe means VARiant type data is TeSTed to see if they are Not Equal

 


 

COMPARE METHODS AND BREAKPOINTS

In Visual Basic, an author has different compare methods available to check for the correct serial. I will only explain the most used here.

1) STRING COMPARE

In this compare method, a string eg "Correct Password" is compared to the password you entered in textbox eg "Entered Password".
String data type consists of a sequence of contiguous characters that represent the characters themselves rather than their numeric values. A String can include letters, numbers, spaces, and punctuation. The String data type can store fixed-length strings ranging in length from 0 to approximately 63K characters and dynamic strings ranging in length from 0 to approximately 2 billion characters.

The code in VB will be:

If "Correct Password" = "Entered Password" then        <--Direct comparison of 2 Strings
GoTo Correct Message
Else
GoTo Wrong Message
End if

Breakpoints available include:
__vbastrcomp or __vbastrcmp                   <--Stands for STRing COMpare

 

2) VARIANT COMPARE

In this method, two variables (of Variant data type) are used to compare with each other.
Variant data type is a special data type that can contain numeric, string, or date data as well as user-defined types and the special values Empty and Null. The Variant data type has a numeric storage size of 16 bytes and can contain data up to the range of a Decimal, or a character storage size of 22 bytes (plus string length), and can store any character text.

An example of the code is like this:

Dim correct As Variant, entered As Variant    <--Defines "correct" and "entered" as Variant
correct = Correct Password                           <--Set "correct"as the "Correct Password"
entered = Text1.Text                                       <--Set "entered" as the password you entered
If correct = entered Then                                <--Compare using the Variant method
GoTo Correct Message
Else
GoTo Wrong Message
End If

In this method, the above breakpoints will not appear because the program no longer uses __vbastrcomp etc...

Breakpoint available:
__vbavartsteq                                             <--Stand for VARiant TeST EQual

3) LONG COMPARE

This is one of the common methods used as well. Two variables (of Long Data type) is used to compare with one another.
Long data type is a 4-byte integer ranging in value from -2,147,483,648 to 2,147,483,647.
Therefore, one limitation to this method is that what is compared must consist of numbers only. (Thank goodness, thus we will see less of such protection)

An example of the code is like this:

Dim correct As Long, entered As Long          <--Defines "correct" and "entered" as Long
correct = 12345                                        <--Set "correct" as the correct code
entered = Text1.Text                                 <--Set "entered" as the entered code
If entered = correct Then                           <--Compare using the Long method
GoTo Correct Message
Else
GoTo Wrong Message
End If

 

4) SINGLE COMPARE

This method uses two variables of Single data type to compare with each other.
It is a data type that stores single-precision floating-point variables as 32-bit (4-byte) floating-point numbers, ranging in value from -3.402823E38 to -1.401298E-45 for negative values, and 1.401298E-45 to 3.402823E38 for positive values.
Therefore, one limitation to this method is that what is compared must consist of numbers only. But sometimes, in calculations routine where your Username is converted to Serial, the correct serial can in the form of Single.

An example of the code is like this:

Dim correct As Single, entered As Single      <--Defines "correct" and "entered" as Single
correct = Correct Password                         <--Set "correct"as the "Correct Password"
entered = Text1.Text                                     <--Set "entered" as the password you entered
If correct = entered Then                              <--Compare using the Variant method
GoTo Correct Message
Else
GoTo Wrong Message
End If

 

5) DOUBLE COMPARE

This method uses two variables of Double data type to compare with each other.
It is a data type that holds double-precision floating-point numbers as 64-bit numbers in the range -1.79769313486232E308 to -4.94065645841247E-324 for negative values; 4.94065645841247E-324 to 1.79769313486232E308 for positive values.
As you can probably see, Double is very similar to Single. Therefore, one limitation to this method is that what is compared must consist of numbers only. But sometimes, in calculations routine where your Username is converted to Serial, the correct serial can be in the form of Double.

An example of the code is like this:

Dim correct As Double, entered As Double    <--Defines "correct" and "entered" as Double
correct = Correct Password                           <--Set "correct"as the "Correct Password"
entered = Text1.Text                                     <--Set "entered" as the password you entered
If correct = entered Then                              <--Compare using the Variant method
GoTo Correct Message
Else
GoTo Wrong Message
End If

 

6) INTEGER COMPARE

This method uses two variables of Integer data type to compare with each other.
It is a data type that holds integer variables stored as 2-byte whole numbers in the range -32,768 to 32,767. The Integer data type is also used to represent enumerated values.
Therefore, one limitation to this method is that what is compared must consist of numbers only. But sometimes, in calculations routine where your Username is converted to Serial, the correct serial can be in the form of Integer.

An example of the code is like this:

Dim correct As Integer, entered As Integer     <--Defines "correct" and "entered" as Integer
correct = Correct Password                           <--Set "correct"as the "Correct Password"
entered = Text1.Text                                      <--Set "entered" as the password you entered
If correct = entered Then                                <--Compare using the Variant method
GoTo Correct Message
Else
GoTo Wrong Message
End If

 

7) BYTE COMPARE

This method uses two variables of Byte data type to compare with each other.
It is a data type used to hold positive integer numbers ranging from 0-255. Byte variables are stored as single, unsigned 8-bit (1-byte) numbers.
Therefore, one limitation to this method is that what is compared must consist of numbers and only to the limit of 255. But sometimes, in calculations routine where your Username is converted to Serial, the correct serial can be in the form of Byte.

An example of the code is like this:

Dim correct As Byte, entered As Byte     <--Defines "correct" and "entered" as Byte
correct = Correct Password                   <--Set "correct"as the "Correct Password"
entered = Text1.Text                           <--Set "entered" as the password you entered
If correct = entered Then                     <--Compare using the Variant method
GoTo Correct Message
Else
GoTo Wrong Message
End If

 

8) CURRENCY COMPARE

This method uses two variables of Currency data type to compare with each other. Yes, it might sound weird, but it works!!
It is a data type with a range of -922,337,203,685,477.5808 to 922,337,203,685,477.5807. Use this data type for calculations involving money and for fixed-point calculations where accuracy is particularly important.
Therefore, one limitation to this method is that what is compared must consist of numbers only. But sometimes, in calculations routine where your Username is converted to Serial, the correct serial can be in the form of Currency.

An example of the code is like this:  (even without programming knowledge, this should be understandable for all)

Dim correct As Currency, entered As Currency      <--Defines "correct" and "entered" as Currency
correct = Correct Password                               <--Set "correct"as the "Correct Password"
entered = Text1.Text                                       <--Set "entered" as the password you entered
If correct = entered Then                                  <--Compare using the Variant method
GoTo Correct Message
Else
GoTo Wrong Message
End If

 


So, does this mean that with these 8 compare methods, we can break into every single compare routine? NO ! This is because comparisons can be made between Currency and String, Variant and Long etc...