Tuesday, May 31, 2016

Handling the application crash in Managed and Unmanaged code

Even though, if we handle the exceptions in our program, there are few scenarios which our application fail to catch those errors using the try… catch. In this article, I will be explaining a way to handle those kinds of exceptions in our program.


When an exception occurs in our program, the operating system will try to find a handler for that exception in the program, if it didn’t find any exception handler for that exception, then it will call the top level exception handler program which is Dr.Watson. The path of the Dr.Watson is configured in the registry key and the operating system will use that information to call that program. We can also create our own exception handler program to replace the Dr.Watson.

Handling the “Unhandled Exception” in Unmanaged Code (C++/VC++)

If we override the SetUnhandledExceptionFilter() method in our C++ program, that method will get called when all the exception handlers failed in our program. We need to call/register that function while starting of our program. We need to pass our method name to the SetUnhandledExceptionFilter() method as a parameter.

#include "stdafx.h"
#include

LONG WINAPI UnhandledException(PEXCEPTION_POINTERS pExceptionPtrs)
{

MessageBox(NULL,TEXT("Caught the unhanlded exception"), TEXT("Test Application"), 0);
return EXCEPTION_EXECUTE_HANDLER;
}

int _tmain(int argc, _TCHAR* argv[])
{

::SetUnhandledExceptionFilter(UnhandledException);

int *p =0;
*p =0; //Generates the crash

return 0;

}
As dereferencing the NULL-Pointer and assigning a value to it in user mode is not allowed the operating system indicates a fault and throws a SEH-exception. Those exceptions cannot be handled even by try - catch statements. In this case, the UnhandledException() method will get called. Once that method gets called, as a programmer, we have the complete control of that exception. Here, we can create dump (mini dump) which will have the details information about the crash and this will be very much help ful for the developer to analyze the issue and provide the solutions.


Creating Mini dump

To create a mini dump we can use the dbghelp.dll which is from Microsoft. That dll comes along with the Microsoft Debug diagnostics tool. I have modified the UnhandledException() method to generate the dump file when we get the crash.

#include "stdafx.h"
#include 
#include  //Has method to generate the crash.

// based on dbghelp.h
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, 
MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, 
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
 CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);

LONG WINAPI UnhandledException(PEXCEPTION_POINTERS pExceptionPtrs) 
{
MessageBox(NULL,TEXT("Caught the unhanlded exception"), TEXT("Test Application"), 0);
LONG retval = EXCEPTION_CONTINUE_SEARCH;
HWND hParent = NULL; // find a better value for your app
HMODULE hDll = NULL;

char szDbgHelpPath[_MAX_PATH];
if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
{

char *pSlash = _tcsrchr( szDbgHelpPath, '\\' );
 if (pSlash)
 {

  _tcscpy( pSlash+1, "DBGHELP.DLL" );
  hDll = ::LoadLibrary( szDbgHelpPath );
 }

}

if (hDll==NULL)
{
// load any version we can
hDll = ::LoadLibrary( "DBGHELP.DLL" );
}

LPCTSTR szResult = NULL;
if (hDll)
{
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );

if (pDump)
{
char szDumpPath[_MAX_PATH];
char szScratch [_MAX_PATH];

if (!GetTempPath( _MAX_PATH, szDumpPath ))
_tcscpy( szDumpPath, "c:\\temp\\" );


_tcscat( szDumpPath, "SampleApp" );
_tcscat( szDumpPath, ".dmp" );

if (::MessageBox( NULL, "Something bad happened in your program, would you 
                 like to save a diagnostic file?", "SampleApp", MB_YESNO )==IDYES)

{

// create the file
HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, 
                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

if (hFile!=INVALID_HANDLE_VALUE)

{
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = pExceptionPtrs;
ExInfo.ClientPointers = NULL;

// write the dump
BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, 
               &ExInfo, NULL, NULL );

if (bOK)
{
sprintf( szScratch, "Saved dump file to '%s'", szDumpPath );
szResult = szScratch;
retval = EXCEPTION_EXECUTE_HANDLER;
}

else
{
sprintf( szScratch, "Failed to save dump file to '%s' (error %d)", 
                           szDumpPath, GetLastError());
szResult = szScratch;
}
::CloseHandle(hFile);

}

else
{
sprintf( szScratch, "Failed to create dump file '%s' (error %d)", szDumpPath, 
                     GetLastError());
szResult = szScratch;
}
}
}
else
{
szResult = "DBGHELP.DLL too old";
}
}
else
{
szResult = "DBGHELP.DLL not found";
}

if (szResult)
::MessageBox( NULL, szResult, "SampleApp", MB_OK );

return retval;
return EXCEPTION_EXECUTE_HANDLER; 

} 


int _tmain(int argc, _TCHAR* argv[])
{
::SetUnhandledExceptionFilter(UnhandledException); 
int *p =0;
*p =0;
return 0;

}
The created dump file can be analyzed/opened in Microsoft Visual studio or Microsoft Debug Diagnostics tool.

Crashrpt (https://code.google.com/p/crashrpt/) is a open source exception handling framework available to handle the unhandled exception in our application. This tool also generates the crash dump and sent that report to the software vendor over the internet.

Handling the “Unhandled Exception” in Managed code (.NET WinForm)

There are two event handlers are available to deal the unhandled exception in .NET

Application.ThreadException Event

This event will only be raised when the unhandled exception occurs in WinForM UI thread.

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace HandleCrash_CSharp
{

static class Program
{
[STAThread]

static void Main()

{

Application.ThreadException +=

new System.Threading.ThreadExceptionEventHandler(MyApplication_ThreadException);

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());

}

public static void MyApplication_ThreadException (object sender, System.Threading.ThreadExceptionEventArgs e)
{

DialogResult result = DialogResult.Abort;

try
{

result = MessageBox.Show("Unhandled exception occured\n\n"
+ e.Exception.Message + e.Exception.StackTrace,
"Application Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);

}
finally
{
         if (result == DialogResult.Abort)
        {

               Application.Exit();

        }
}
}
}

}

AppDomain.CurrentDomain.UnhandledException Event

The UnhandledException event on AppDomain, any exception in the current AppDomain will trigger that event. This includes not only the main application thread (the UI thread), but any other threads as well.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace HandleCrash_CSharp
{
static class Program
{

[STAThread]
static void Main()
{

AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(MyCurrentDomain_UnhandledException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());

}

static void MyCurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try

{

Exception ex = (Exception)e.ExceptionObject;
MessageBox.Show("Unhandled exception occured\n\n" + ex.Message + ex.StackTrace,

"Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);

}

finally

{

Application.Exit();

}

}
}

}

A discussion with my application Hacker

In this article, I am sharing my best/worst experience which was happened 5 years ago.

About the application
I was working for a company and there we have developed a web based eCommerce application for one of our client.  Since our client wants a Rich User Interface, we have decided to use the Flash as a front-end. So, as per our architecture the Flash application will to communicate with ASP.Net web service to display/process any data and the web service will communicate with the SQLServer for storing/retrieving the data. I this, I am the responsible to developing web service and implementing the payment gate way which is credit card payment process. This application launched in one of big cinema hall.

Environment Setup
One day, our client receives a shocking email by saying that “I can book you entire cinema hall for just Rs.1 and let me know if you need a solution, so we can discuss further on this”.

Since we are developers the email has been forwarded to us for further actions.  We have verified our database log and found that a transaction was done for Rs.1. As per the log, that person continuously tried that transaction for two days and he finally succeeds on his goal.

We have discussed a lot about how come it is possible and we have also tried to find the loop hole in our application.  Only one thing we thought could be a problem, which is, we are not re validating the amount in web service which we received from our front end.  Now, we have implemented that validation also, but we are not sure whether that will solve this problem.  We are also studied few things about the Hacking and we didn't conclude anything about the cause for this problem.

So, we have updated all our finding to the client and we have requested to reply to that email and asked them to schedule a meeting.

Discussion
The meeting is scheduled and we are all waiting for the person who sent an email and a 17 year old boy came to the meeting and he is the person who did this. Personally, I am very much shocked know that a small boy is working this kind of activities.

He explained what he did to achieve his goal.  As we all know, when we browse the Flash based web site, the Flash file (swf) will get stored into the local machine.  He has a tool (de-compiler) which can generate a entire source of the Flash file (swf), using that he had generated the source for our Flash file. Then he ran that swf file on this machine, and during the payment he changed the amount to Rs.1 in the front end. Since we are also not having any validation on this, the entire transition is success for him.

There is another tool, which prevents the Flash file to de-compile. He also shows the demo of that tool.  Finally we have modified our flash file as per his suggestion and also we have re deployed our web service which the amount validations check.

Conclusion
De-compilers are very much use full, to regenerate the source code if we lost it.

As a developer, we are all concentrating only on how to develop and implement our logic and we are not thinking about de-compilers.  Because of this some time, our logic can be stolen by someone. 

All COM dll/exe and Java class files and .Net assembly can be de-complied.  There are few tools are available to prevent that.

Install Shield : Pass Product Name and Verion to ISCmdBld.exe

In Installshield, if you compile the .ism then the name of the msi would be the same as file name. 

If you want to include the build version along with the name then those information needs to be passed dynamically during the compilation of ism. Also, the version number of the product can be passed dynamically. Hence, we no need to modify the ism file for the version change.

"[InstallShield installed path]\2015\System\ISCmdBld.exe" -p  [ism file path] -y %[productversion]% -z ProductName=%[productname]%

For Standalone installation,

"[InstallShield installed path]\2015 SAB\System\ISCmdBld.exe" -p  [ism file path] -y %[productversion]% -z ProductName=%[productname]%