Friday, January 25, 2008

Reflector Addins

Last blog, I talked about the Reflector. After looking for more tool to smooth the work flow of debugging task, I found there are several add-ins that can make you life easier. Scott Hanselman even compiled the list of Codeplex-hosted add-ins in his site.
Well, I personally like the Diff and FileDisassembler, another add-in which is not hosted at the CodePlex. Diff is a tool that act like Windiff to your file compare, but it's used for assembly compare; while the FileDisassembler allows you to reverse-engineer the assembly to the source file, in case you loss your source code (and of course, if you wanna see how people code :-D), althought it might not 100% identical to the original code. (But hey, what you can ask for, since it is free!)

(Image from Reflector.FileDisassembler)

Must-have and go get it!

Sunday, January 13, 2008

Encryption is not safe in .Net, even it encrypts 128-bit blocks, if you do normal compilation!

With the release of .Net Reflector from Lutz Roeder, even dummy developer can de-compile your 10-years-effort application within seconds. It has become a open secret in the NET developers group and I think this is the main reason Microsoft releases some of the source code of framework libraries, although they often claim .NET is open architecture.

Reverse-engineering of your application is possible, when your source code is not obfuscated. For security purpose, developer maybe will use cryptographic services to encrypt user name & password and store it in clients'(users themselves) PC for reloading purpose. (So the application can log-in again for the same user without asking user name & password). This kind of information often could be a .ini/.config/.xml or any other ASCII file.

Cryptographic services help your client stores private and confidential information from others. The higher the bits used to perform encryption/decryption, the more difficult the hackers can hack your code. But now the problem is not coming from the algorithm but the .NET itself, if you are writing normal codes without obfuscating it.

Let's have a sample from MSDN using RijndaelManaged Class:
(The demo here is to urge the developers to tighten-up the security, not to encourage hackers!)


2) Browse to the .NET application you wish to de-compile. Drag-and-drop it to the .Net Reflector. (Sample provided; remove the "Config.ini" file to re-generate)

3) Browse to the default namespace. You might ask: How do you know it is default namespace? Normally it is same name with the application. If not sure, just browse one-by-one, since you can de-compile all the them :-D


4) Browse to default class. You might ask again: How do you know it is default class? Same answer with step (3).

Browse to default form/module. You might ask for 3rd time: How do you know it is default form/module? For C#, normally developers will name it as frmMain/frmMDI/frmLogin. In VB .Net, the entry point should be modmain module. Else, just follow step (3) :-)


5) Until here, maybe you have no choice but to look into all the possible methods (sometimes you can find the possible method like : frmLogin_Load, btnLogin_Click, etc). Click the methods to check the disassembler in the right pane.

Now you can see the user name & password are decrypted, before they are used to validate/compare with the user input.


6) Remember the configuration file in the form constructor. It's useful later to find out the where the encrypted information stored.


7) Click on the any method on the disassembler pane to drill down. If it requires additional assembly, message box will be prompted. Just click OK.


8) Again, Click on the method on the disassembler. You can find the decryption method. It uses Rijndael algorithm.


9) Oh, my God! It comes with IV and key, embeded in the application.

10) Copy decryption method, IV, key and build a simple console application. (Sample provided)

11) Pass-in the encrypted string to the console application built previously.
Done! Now you are a hacker! Oops, sorry, I meant you must tighten-up you source code compilation for security purpose.

p/s: Even in java, there're tons of de-compiler tools available. It's not surprise, since .NET is modeling from Java.

Saturday, January 12, 2008

Trivial but also Tricky : Result of using "is NULL" & "= NULL" in T-SQL is different

For the T-SQL (here I use MS-SQL), especially when you write stored procedure, you will normally receive parameter(s) from .NET/Java or any equivalent language to manipulate your client records. This is a normal design of three-tier application (Presentation Layer represents the UI that interact with user; Business Logic layer to code all your business logic; Data Access layer to deal with various kind of data storage apps)

For these received parameters, normally you will use some of it to retrieve (or perform checking or validation) some other data from other tables. You will write any T-SQL to perform SIUD(Select/Insert/Update/Delete) on records based on the business logic in database. In order to SUID on these records, your WHERE-statement must be written precisely, and of concisely. If the WHERE-statement is wrong, then the records SUID-ed will be corrupted.

Let's have simple example:
1) Create a simple table with nullable columns

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[_Test]') and
OBJECTPROPERTY(id, N'IsUserTable') = 1)drop table [dbo].[_Test]
GO

CREATE TABLE [dbo].[_Test] (
[col1] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[status] [int] NULL ) ON [PRIMARY]
GO

2) Insert 2 sample records into it
insert into _Test(col1, status)
values('First row', NULL)

insert into _Test(col1, status)
values('Second row', 1)
3) Create a stored procedure to determine the record could be found in database or not

IF EXISTS (Select * from sysobjects where name = '_spTest' and xtype = 'P')
DROP PROCEDURE _spTest
GO
CREATE PROCEDURE dbo._spTest
@p1 int
As
IF EXISTS ( Select * from _Test where status = @p1)
PRINT 'Records found !'
ELSE
PRINT 'No records found !'
GO

4) Now try to execute it

execute _spTest 1
execute _spTest NULL

Oh, where's another records?

6) And this is quoted from MSSQL BOL (Book On-Line) / T-SQL Reference:
To determine if an expression is NULL, use IS NULL or IS NOT NULL rather than comparison operators (such as = or !=). Comparison operators return UNKNOWN if either or both arguments are NULL.

Now, you realized you used the comparison operators to execute it unknowingly!

7) So, in order to access the particular data accurately, the correct stored procedure should be written (Of course, this is simple scripts only, COALESCE or any other keywords can help you to SIUD the huge records efficiently) as

IF EXISTS (Select * from sysobjects where name = '_spTest' and xtype = 'P')
DROP PROCEDURE _spTest
GO

CREATE PROCEDURE dbo._spTest
@p1 int
As
IF (@p1 IS NULL)
BEGIN
IF EXISTS ( Select * from _Test where status IS NULL)
PRINT 'Records found, with status is null!'
ELSE
PRINT 'No records found with status is null!'
END
ELSE
BEGIN
IF EXISTS ( Select * from _Test where status = @p1)
PRINT 'Records found!'
ELSE
PRINT 'No records found!'
END
GO

8) Now try to execute it again

execute _spTest 1
execute _spTest NULL
9) Correct!