In the modern day of the .NET framework, many users tend to rely heavily on this system which they have become so accustomed to. Unfortunately, this system comes with many drawbacks. The .NET framework allows you to quickly develop applications but in time critical circumstances the bytecode interpreter falls drastically short. In the following document, I will present you with a scenario in which you might wish to use a low level language to preform a time critical procedure for your .NET application. The languages I will be using in this document will be Visual Basic .NET and Intel Assembly (NASM).
The Scenario
As an application developer, you have been selected as part of a development team to design a login screen. The user should be able to enter their username and password in two seperate controls, then click the "Login" button to connect to the server. When the "Login" button is selected the password is to be encrypted using a simple in-house hashing algorithm and the username and password are to be stored in global variables named g_strUsername and g_strPassword so they can be used by other developers in the development team.
Getting Started
As with any project, we will start out by creating a Visual Basic .NET Windows Application solution. Name the solution "LogonScreen" and set the form's Size property to 381,298. Also lets set the name of the form to frmLogon and the title to "Connect to Network". With that, our forms properties are set. Next add two labels to the form, one with the Text property set to "Username:" and the other set to "Password:". These label's don't need to have their name value's set because we won't be bothering with them in code. If you want to name them, go ahead. Next add two TextBox controls to the right of the labels that you have just placed on the form. Set the name of the TextBox control next to the "Username:" label to txtUsername. Set the name of the TextBox control next to the "Password:" label to txtPassword and then set "*" as the PasswordChar property. Next, add a button to the form and name it btnLogin and set it's Text property to "Login". Finally, center align the username and password controls then right align the login button to the password TextBox. This completes the design phase of our .NET application.
Writing the Code
Double-click the login button to bring up code view with the btnLogin_Click handler already filled out for us. Before we write our handler we must add two imports; System and System.Runtime.InteropServices. These imports will allow us to create our Cphr586 class of external procedures. So lets look at our code as it is now.
Imports System
Imports System.Runtime.InteropServices
Public Class frmLogon
Dim g_strUsername As String
Dim g_strPassword As String
Private Sub btnLogin_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handler btnLogin.Click
End Sub
End Class
You'll notice I've also added two global variables to the frmLogon namespace; g_strUsername and g_strPassword. These variables are needed per request by the scenario layed out above. So we added them while we were adding the imports.
Next step will be to create our Cphr586 class to be used by our btnLogin_Click event. This is what allows us to use low level languages such as Assembly in our .NET applications. Before I discuss this in detail, lets take a quick look at the code.
Public Class Cphr586
<DllImport("cphr586.dll")> _
Public Shared Function _
Encrypt(ByVal lpszPlainText As String) As Int32
End Function
End Class
This code creates a class namespace in which we can access features of an external dynamically linked library (DLL). The first line within the class definition specifies the file in which we would like to import a procedure from. This could be system DLLs or, as we have done here, custom DLLs. The following line declares the procedure that we plan to import as a 'Public Shared Function'. All this means is that the procedure can be used by other classes. The next line is our Visual Basic procedure prototype for our imported routine. This tells Visual Basic .NET what arguments can be passed to the procedure and what the return value will be. In this scenario we are taking a string value as an argument and returning a 32-bit value in EAX so we use Int32 as our return value. The last two lines simply close everything up. So we add this code to the bottom of our Form1.vb file below the "End Class" line for frmLogon and we save our project before we continue.
Now that we are able to import our routine, we need to write our event handler to grab the value of txtUsername and txtPassword, save the value in txtUsername into g_strUsername, use our external routine to encrypt the value obtained from txtPassword and convert it from a 32-bit hash to a string and store it into g_strPassword. Also, if either g_strUsername or g_strPassword are empty we should error first instead of trying to assign anything. So lets do some code.
Imports System
Imports System.Runtime.InteropServices
Public Class frmLogon
Dim g_strUsername As String
Dim g_strPassword As String
Private Sub btnLogin_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handler btnLogin.Click
Dim dw32BitHash As Int32
Select Case 0
Case Me.txtUsername.Text.Length
Me.txtPassword.Text = ""
MessageBox.Show("Please enter a valid username.", _
"Error")
Case Me.txtPassword.Text.Length
Me.txtUsername.Text = ""
MessageBox.Show("Please enter a valid password.", _
"Error")
Case Else
g_strUsername = Me.txtUsername.Text
dw32BitHash = Cphr586.Encrypt( _
Me.txtPassword.Text.ToString _
)
g_strPassword = dw32BitHash.ToString
End Select
End Sub
End Class
Public Class Cphr586
<DllImport("cphr586.dll")> _
Public Shared Function _
Encrypt(ByVal lpszPlainText As String) As Int32
End Function
End Class
What we've done here isn't that difficult. We have created a Select condition to find out if either Me.txtUsername.Text.Length or Me.txtPassword.Text.Length are equal to 0, if so it clears the opposite TextBox control (just in case) and displays a message box to inform the user of the error. If neither of those conditions are met, we can preform our normal operation. First it copies Me.txtUsername.Text into g_strUsername so it will be accessable by the other programmers. Then Cpher586.Encrypt (our assembly routine) is called using Me.txtPassword.Text.ToString as an argument. The value is returned into a local variable that we created as an Int32 named dw32BitHash. We can then use Visual Basic .NET's conversion utility ToString to help us assign the value to g_strPassword. And with that we have completed the Visual Basic side of the application. We can now use the Build option to create an executable. If you try to run the executable you will find that it won't work, the problem is we don't yet have our cphr586.dll file. Below is a copy of the CPHR586.ASM file. Save this file somewhere in your project folder and follow the steps in the comments to build it.
mov ECX, EAX
mov ESI, [EBP+8]
cmp ECX, 0
jne .LT1
mov EAX, -1
leave
ret
.LT1: xor EAX, EAX
xor EBX, EBX
push ECX
add ECX, ESI
.LT2: cmp ECX, ESI
je .LT3
mov BL, BYTE [ESI]
shl EAX, 1
add EAX, EBX
mov EBX, 029Ah
mul EBX
inc ESI
xor EBX, EBX
jmp .LT2
.LT3: pop ECX
pop ESI
pop EBX
add EAX, ECX
leave
ret
Final Steps
Once you have built the cphr586.dll file, copy the file into the same directory as your executable. This should be bin/Release or bin/Debug depending on how you have your project setup. Now run the executable again, enter a username and password, and click Login. Nothing happens... Try adding a MessageBox.Show(g_strPassword,"Test") to the last line of the btnLogin_Click handler then build, run, and test again. Cool huh! You get a string containing a 32-bit hash which shows that the value you passed really was passed through the external procedure.
Conclusion
As you can see, adding low level routines to Visual Basic .NET is a fairly simple task. What makes it better is, this can also be done through C# and other .NET based languages. Because of this, you are capable of making your .NET framework applications run much faster than you previously could. Also imagine having access to all the low level system features which you sometimes find yourself locked away from when dealing with the .NET framework. You could easily write front-ends for system services or ring-0 applications in C# or VB and have all of your system critical code written in C or ASM.
I personally don't use .NET programming outside of various class projects, but I hope this document has opened some doors for you. If you find this information useful, all I ask is that you share it with someone and help to keep the information underground alive.
Regards,
~Synfire
Cast your vote on this article *Note: the order of the votes has been reversed.
Nice article, you failed to mention that this method would work for C, Pascal or almost any other language though.
Also a slight description of what the assembler code is doing might have been a good idea.
Apart from that, a pretty good and useful article.
total waste of time. why code in .NET at all if you needed the speed? it's a bloated byte code language.
so you know asm? big deal. your code is sloppy as hell and totally uncommented. no need to stink up these pages
By: liuyuan - 08:12 am Wednesday September 03rd, 2008
anthro, I can't wait for you to write up some articles =] This article was great, but from your comment, it seems like you could do better? Please share you knowledge with us noobs :>
By: arkaros - 11:13 am Tuesday September 09th, 2008
Any one who say that .NET sux are idiots who dont want to adjust to the future. .NET is fast and easy to learn and there for many people will use it. I say .NET is the future and that hackers should adjust to the future event tho not relly on it.
By: finitelife - 03:10 am Monday September 29th, 2008
arkaros, use english. Who said that .NET is the future? 'hackers' don't have to adjust to the future... that just doesn't make sense. Do you know what words mean? NM. Phate- good read. The asm could use a little commenting, but not too much. No point in doing it all for us... :)
This site is the collective work of the
HackThisSite staff. Please don't reproduce in part or whole without permission.
Page Generated: Wed, 08 Oct 2008 03:33:28 -0500 Exec:
9