DotNetBrowser uses ConfuserEx to protect its assemblies. The code protected by this solution conflicts with SmartAssembly.


During the attempt to create the SmartAssembly project with the assembly which references DotNetBrowser you can see the following error: 'Non-negative number required. Parameter name: count'.


To avoid this error you need to create the wrapping library which will interact with DotNetBrowser. Then you can reference this wrapper to the assembly that should be obfuscated. The wrapping library should not reference DotNetBrowser library directly. Instead of this, the wrapper should use the reflection.


First of all, you need to create the library which will contain single interface. This interface describes which actions you need to perform with the browser:


C#

public interface IBrowserProxy : IDisposable
{
    string GetWebPageHtml(string url);
}


VB.NET

Public Interface IBrowserProxy
    Inherits IDisposable

    Function GetWebPageHtml(url As String) As String
End Interface



Next, you need to create the assembly which will implement this interface. This assembly will reference the DotNetBrowser library and the library with the previously declared interface:


C#

public class BrowserProxy : IBrowserProxy
{
    private Browser browser;
    private ManualResetEvent pageLoadEvent;

    public BrowserProxy()
    {
        browser = BrowserFactory.Create();
        browser.FinishLoadingFrameEvent += (sender, args) =>
        {
            if (args.IsMainFrame)
            {
                pageLoadEvent.Set();
            }
        };
        pageLoadEvent = new ManualResetEvent(false);
    }

    public string GetWebPageHtml(string url)
    {
        pageLoadEvent.Reset();
        browser.LoadURL(url);
        pageLoadEvent.WaitOne();
        return browser.GetHTML();
    }

    public void Dispose()
    {
        browser.Dispose();
    }
}


VB.NET

Public Class BrowserProxy
    Implements IBrowserProxy

    Dim ReadOnly browser As Browser
    Dim ReadOnly pageLoadEvent As ManualResetEvent

    Public Sub New()
        browser = BrowserFactory.Create()
        AddHandler browser.FinishLoadingFrameEvent, Sub(sender, e)
            If (e.IsMainFrame) Then
                pageLoadEvent.Set()
            End If
        End Sub
        pageLoadEvent = new ManualResetEvent(false)
    End Sub

    Public Function GetWebPageHtml(url As String) As String Implements IBrowserProxy.GetWebPageHtml
        pageLoadEvent.Reset()
        browser.LoadURL(url)
        pageLoadEvent.WaitOne()
        return browser.GetHTML()
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        browser.Dispose()
    End Sub
End Class



In the target application, you need to reference the interfaces library and then dynamically load the implementation of the IBrowserProxy interface:


C#

class Program
{
    static void Main(string[] args)
    {
        //Load library with the implementation
        IBrowserProxy proxy = GetProxyFromAssembly("DotNetBrowserProxy.dll");

        //Use proxy interface
        string githubHtml = proxy.GetWebPageHtml("github.com");
        Console.WriteLine(githubHtml);

        proxy.Dispose();

        Console.ReadKey();
    }

    static IBrowserProxy GetProxyFromAssembly(string assemblyFileName)
    {
        if (File.Exists(assemblyFileName))
        {
            //Load assembly from file
            Assembly proxyAssembly = Assembly.LoadFrom(assemblyFileName);
            //Get the implementation type of the IBrowserProxy interface
            Type browserProxyType = proxyAssembly.GetTypes()
                .FirstOrDefault(type => type.IsClass && type.GetInterface("IBrowserProxy") != null);

            if (browserProxyType != null)
            {
                //Instantiate and return the implementation type
                IBrowserProxy proxy = (IBrowserProxy) Activator.CreateInstance(browserProxyType);
                return proxy;
            }
        }

        return null;
    }
}


VB.NET

Module Module1
    Sub Main()
        Dim proxy As IBrowserProxy = 
                GetProxyFromAssembly("../../../DotNetBrowserProxy/bin/Debug/DotNetBrowserProxy.dll")
        Dim githubHtml As String = proxy.GetWebPageHtml("github.com")
        Console.WriteLine(githubHtml)

        proxy.Dispose()

        Console.ReadKey()
    End Sub

    Private Function GetProxyFromAssembly(assemblyFileName As String) As IBrowserProxy
        If File.Exists(assemblyFileName) Then
            Dim proxyAssembly As Assembly = Assembly.LoadFrom(assemblyFileName)
            Dim browserProxyType As Type =
                    proxyAssembly.GetTypes().FirstOrDefault(
                        Function(type) type.IsClass AndAlso type.GetInterface("IBrowserProxy") IsNot Nothing)
            If browserProxyType IsNot Nothing Then
                Dim proxy = CType(Activator.CreateInstance(browserProxyType), IBrowserProxy)
                Return proxy
            End If
        End If
        Return Nothing
    End Function
End Module


There are few notes regarding the usage:

  • All compiled libraries and DotNetBrowser libraries should be located in the same directory
  • You need to obfuscate the proxy library and the target library
  • You should NOT obfuscate the implementation library (which references DotNetBrowser)


Also, you can find the C# and VB.NET sample Visual Studio solutions attached to this article.