What's Wrong With Detours?

Detours is a developer library provided by Microsoft to hook (re-routing) functions, so you can intercept all calls to, for example, CreateFile, in an application.

Unfortunately, free version of Detours supports 32-bit applications only. If one needs to work with 64-bit code, Detours Professional Edition is available and it costs $10000.

BoxedApp SDK To The Rescue

BoxedApp SDK provides functions to hook functions, both 32-bit and 64-bit code are supported, there are a lot of bindings: for C++, C#, VB.Net, VB6, Delphi and others.

Consider the following code that shows how to prevent opening a file with some name:

typedef HANDLE (WINAPI *P_CreateFileW)(
	LPCWSTR lpFileName,
	DWORD dwDesiredAccess,
	DWORD dwShareMode,
	LPSECURITY_ATTRIBUTES lpSecurityAttributes,
	DWORD dwCreationDisposition,
	DWORD dwFlagsAndAttributes,
	HANDLE hTemplateFile);
P_CreateFileW g_pCreateFileW;

HANDLE WINAPI My_CreateFileW(
	LPCWSTR lpFileName,
	DWORD dwDesiredAccess,
	DWORD dwShareMode,
	LPSECURITY_ATTRIBUTES lpSecurityAttributes,
	DWORD dwCreationDisposition,
	DWORD dwFlagsAndAttributes,
	HANDLE hTemplateFile)
{
	if (0 == lstrcmpiW(lpFileName, L"1.txt"))
	{
		SetLastError(ERROR_FILE_EXISTS);
		return INVALID_HANDLE_VALUE;
	}
	else
		return g_pCreateFileW(
				lpFileName,
				dwDesiredAccess,
				dwShareMode,
				lpSecurityAttributes,
				dwCreationDisposition,
				dwFlagsAndAttributes,
				hTemplateFile);
}
...
BoxedAppSDK_Init();

PVOID pCreateFileW = GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "CreateFileW");

HANDLE hHook__CreateFileW = BoxedAppSDK_HookFunction(pCreateFileW, &My_CreateFileW, TRUE);

g_pCreateFileW = (P_CreateFileW)BoxedAppSDK_GetOriginalFunction(hHook__CreateFileW);

FILE* f = fopen("1.txt", "r");

// f is NULL
...

BoxedAppSDK_UnhookFunction(hHook__CreateFileW);
						
        [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
        static extern TCreateFile GetProcAddress(IntPtr hModule, string procName);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("kernel32.dll")]
        static extern void SetLastError(uint dwErrCode);

        public const Int32 ERROR_FILE_NOT_FOUND = 2;

        public delegate IntPtr TCreateFile(
            [MarshalAs(UnmanagedType.LPWStr)]string lpFileName,
            [MarshalAs(UnmanagedType.U4)]int dwDesiredAccess,
            [MarshalAs(UnmanagedType.U4)]int dwShareMode,
            IntPtr lpSecurityAttributes,
            [MarshalAs(UnmanagedType.U4)]int dwCreationDisposition,
            [MarshalAs(UnmanagedType.U4)]int dwFlagsAndAttributes,
            IntPtr hTemplateFile);

        static TCreateFile pCreateFileW = null;

        static IntPtr My_CreateFileW(
            [MarshalAs(UnmanagedType.LPWStr)]string lpFileName,
            [MarshalAs(UnmanagedType.U4)]int dwDesiredAccess,
            [MarshalAs(UnmanagedType.U4)]int dwShareMode,
            IntPtr lpSecurityAttributes,
            [MarshalAs(UnmanagedType.U4)]int dwCreationDisposition,
           [MarshalAs(UnmanagedType.U4)]int dwFlagsAndAttributes,
            IntPtr hTemplateFile)
        {
            if (lpFileName.Contains(@"\1.txt"))
            {
                SetLastError(ERROR_FILE_NOT_FOUND);
                return new IntPtr(-1);
            }
            return pCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
                        dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
        }


        /// 
        /// The main entry point for the application.
        /// 
        [STAThread]
        static void Main()
        {            
            BoxedAppSDK.NativeMethods.BoxedAppSDK_Init();
            pCreateFileW = GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateFileW");
            
            IntPtr hookCreateFileW =
                    BoxedAppSDK.NativeMethods.BoxedAppSDK_HookFunction(pCreateFileW, new TCreateFile(My_CreateFileW), true);

            pCreateFileW = (TCreateFile)BoxedAppSDK.NativeMethods.BoxedAppSDK_GetOriginalFunction(hookCreateFileW, typeof(TCreateFile));            
            
            try
            {
                System.IO.File.WriteAllText(Application.StartupPath+ "\\1.txt", "some data...");
            }
            catch (Exception ex)
            {
                MessageBox.Show("It works! You got exception:\r\n " + ex.Message);
            }

            BoxedAppSDK.NativeMethods.BoxedAppSDK_UnhookFunction(hookCreateFileW);            
        }
    }
						
type
TCreateFileW = 
   function(lpFileName: PWideChar;
            dwDesiredAccess, dwShareMode: Integer;
            lpSecurityAttributes: PSecurityAttributes;
            dwCreationDisposition, dwFlagsAndAttributes: DWORD;
            hTemplateFile: THandle): THandle; stdcall;

var
   OriginalCreateFileW: TCreateFileW;

function My_CreateFileW(
         lpFileName: PWideChar;
         dwDesiredAccess, dwShareMode: Integer;
         lpSecurityAttributes: PSecurityAttributes;
         dwCreationDisposition, dwFlagsAndAttributes: DWORD;
         hTemplateFile: THandle): THandle; stdcall;
begin
   if 0 = lstrcmpiW(lpFileName, '1.txt') then
   begin
      Result := INVALID_HANDLE_VALUE;
      SetLastError(ERROR_ALREADY_EXISTS);
   end
   else
      Result := 
        OriginalCreateFileW(
           lpFileName, 
           dwDesiredAccess,
           dwShareMode, 
           lpSecurityAttributes, 
           dwCreationDisposition, 
           dwFlagsAndAttributes, 
           hTemplateFile);
end;

var
   pCreateFileW: Pointer;
   hHook__CreateFileW: THandle;

begin
  Application.Initialize;

  BoxedAppSDK_Init;

  pCreateFileW := GetProcAddress(GetModuleHandle('kernel32.dll'), 'CreateFileW');
  hHook__CreateFileW := BoxedAppSDK_HookFunction(pCreateFileW, @My_CreateFileW, TRUE);
  OriginalCreateFileW := BoxedAppSDK_GetOriginalFunction(hHook__CreateFileW);

  // This line produces an exception because we prevent creating / opening '1.txt'
  TFileStream.Create('1.txt', fmCreate or fmOpenRead);

  BoxedAppSDK_UnhookFunction(hHook__CreateFileW);
end.