Obfu-VBA
1 What is Obfuscation ?
Obfuscation is generally speaking an operation that consists in hiding the meaning of a piece of information, in making it ambiguous, deceiving or just hard to understand.
In the IT context, obfuscation is used to protect the intellectual property of a software in making its source code incomprehensible (for human thought) while keeping it compilable or interpretable for a computer.
Excel-VBA applications are particularly concerned by this issue : VBA source code is embedded in the workbook that contains the application. The password protection to the VBA code is insignificant since a few softwares from the market can open Excel files and are able to give access to the VBA code regardless of the password.
Obfu-VBA uses the 3 following methods to obfuscate VBA code of Excel Applications : removal of comments, removal of coding style (white lines, indentation and instructions on several lines) and renaming of the identifiers (variables, constantes, functions, procedures, parameters, modules, classes, userforms and controls).
2 Way of use
Obfu-VBA does not work straight on the Excel workbook that holds your VBA application. Here are the successive steps needed to obfuscate your application :
1 Create 1 input folder that will contain the objects you will export from your application and 1 output folder that will contain obfuscated objects.
2 Export all modules, class modules and userforms from your VBA project into the input folder : your application being opened in Excel, from the Excel VBA editor, do a right-click on each object containing VBA code and select "Export to a file..." (see the figure opposite). Then you can close your workbook.
3 Open in Excel the Obfu-VBA workbook, fullfill needed parameters (see chapter 3.1) and launch the process -that may last several minutes, depending on the size of the files to process.
4 Create a new workbook in Excel, copy if needed the sheets of your former workbook, import from Excel VBA editor the obfuscated objects contained in the output folder.
5 The creation of an obfuscated version of your Excel-VBA application is over. What you have to do then is check it works properly : first save it on the disk, run compiler (VBA editor -> Debug menu -> Compile) and fully test its smooth functioning.
In case of trouble (compilation fails, execution aborts, running does not conform to the original, obfuscation is not thorough), the first thing to do is to check that the recommandations of Obfu-VBA (see chapter 3.5) are followed. Once it is made, you can contact ToolOscope for support or evolution request.
3 Obfu-VBA application
3.1 The Project worksheet
This worksheet is the command interface of Obfu-VBA. Cells to be filled by the user are on yellow background (numbered in red from 2 to 9). Each of these cells has a comment that describes the expected content. These comments are resumed in the frame beside.
Once all input data have been entered, the user clicks on the "Launch Obfu-VBA" button to get process running, in 2 stages.
At each step, Obfu-VBA reads successively all input modules (7) that must be present in the input folder (5). During the second step, obfuscated modules are written in the output folder (6). The user can monitor the progress of the process by looking at the numbers of read and written lines displayed on the worksheet.
Names of .bas modules and .cls classes are darkened. Names of .frm userforms .frm are darkened too but not the names of the files that contain them. During the import of the obfuscated userforms, the names of files disappear.
You can duplicate that worksheet in the Obfu-VBA workbook, to keep one command sheet per project, for example. So, when you modify the clear source code of your projects and want to obfuscate them again, you won't waste time to parameter folders, modules... in Obfu-VBA.
Cells comments
1 You can duplicate this sheet in the same workbook as many times as you have different VBA projects to process.
2 Fill in the name of the sheet that contains reserved words.
Optional. If blank, reserved words may not be obfuscated as well, but performances may be reduced.
If filled in, the sheet must exist in the same workbook.
3 Fill in the name of the sheet that will show the code and the detected types of variables (65530 maximum lines).
Optional. If blank, the code will not be shown.
If filled in, the sheet must exist in the same workbook.
4 Fill in the name of the sheet that will show the mapping table between clear and obfuscated identifiers.
Optional. If blank, the mapping table will not be shown.
If filled in, the sheet must exist in the same workbook.
5 Fill in the path of the folder that contains the VBA files to get processed, previously exported from Excel.
Mandatory.
6 Fill in the path of the folder that will contain the obfuscated VBA files. These files will have to be manually import in a new Excel workbook to rebuild your application.
Mandatory.
7 Fill in this column the names of the VBA files exported from your Excel application, without their extension. These files have to be placed in the "Input" folder.
64 maximum files + memory limit of Excel-VBA projects.
8 Fill in the extension of each VBA file named in the cell to the left :
- cls for ModuleClass,
- bas for Modules,
- frm for UserForms.
9 Fill in this column the identifiers that must not be obfuscated.
Optional.
3.2 Reserved words
This optional input worksheet contains reserved key-words of VBA language. It can be improved in case of lacks.
Obfu-VBA analyses each word encountered in the code to process in order to determine if it has to be darkened. This keyword list saves time during processing.
Only the identifiers explicitely declared in your project will be darkened. Therefore, this reserved word list is not discriminatory.
3.3 The identifiers mapping table
During processing, Obfu-VBA digs out all identifiers declared in your project and relates each identifier to a darkened one. If the name of the mapping table sheet is parametered in the command worksheet, Obfu-VBA returns for each identifier its clear name, its darkened name, its type and its container in the case of a member of a class or a user type, according to its scope (project, module or local).
3.4 The read code worksheet
Obfu-VBA writes on this worksheet (if its name is defined on the command sheet) the read and analysed code - identifiers separated from other characters. Obfu-VBA shows the kind it has detected below each identifier, on 2 lines : label, reserved keyword, variable, function... and the type of the container.
3.5 The Help worksheet
This sheet contains recommandations about the source code to process :
- All variables must be declared (option explicit recommended) and typed (no variant by default).
- In case of obfucation of identifiers by mistake, declare those identifiers as exceptions.
- Events on controls must be declared as Private.
- Class contructors et destructorsmust be declared Private.
- Class constructor must be written "Class_Initialize" (Pay attention to the capital letters !).
- Class constructor must be written "Class_Terminate" (Pay attention to the capital letters !).
- identifiers must be written precisely the same way (case, accents...).
- Avoid giving the same name to a function (or sub) and to a type.
- Avoid using accents in identifiers.
- Declare as exceptions the controls or variables whose names are tested in a label.
4 Example : ObfuTest application
The ObfuTest small application does nothing important and has been written to test and show the functioning of Obfu-VBA. It consists of 1 code module, 1 class module and 1 userform, whose original and obfuscated versions are shown below.
4.1 Class module "MyClass.cls"
Source Code
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "MyClass"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Const MYCONST1 = "toto"
Const MYCONST2 = 3
Private mvar1 As String
Private mvar2 As Long
Public mvar3 As Boolean 'pour test de Me
Rem constructeur : son nom ne doit pas être obfuscaté
Private Sub Class_Initialize()
mvar1 = MYCONST1
mvar2 = MYCONST2
Me.mvar3 = False
End Sub
Rem destructeur : son nom ne doit pas être obfuscaté
Private Sub Class_Terminate()
MsgBox "Object of class MyClass destroyed !"
End Sub
Friend Property Let var1(parm1 As String)
mvar1 = parm1
End Property
Friend Property Get var1() As String
var1 = mvar1
End Property
Friend Property Let var2(parm1 As Long)
mvar2 = parm1
End Property
Friend Property Get var2() As Long
mvar2 = var2
End Property
Obfuscated code
VERSION 1.0 CLASS
BEGIN
MultiUse = -1
END
Attribute VB_Name = "F1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Const F12 = "toto"
Const F13 = 3
Private F14 As String
Private F15 As Long
Public F2 As Boolean
Private Sub Class_Initialize()
F14 = F12
F15 = F13
Me.F2 = False
End Sub
Private Sub Class_Terminate()
MsgBox "Object of class MyClass destroyed !"
End Sub
Friend Property Let F3(F16 As String)
F14 = F16
End Property
Friend Property Get F3() As String
F3 = F14
End Property
Friend Property Let F4(F16 As Long)
F15 = F16
End Property
Friend Property Get F4() As Long
F15 = F4
End Property
4.2 Code module "MyModule.bas"
Source Code
Attribute VB_Name = "MyModule"
Option Explicit
Public Type myType
mvar1 As String
mvar2 As Long
mvar3 As Boolean
End Type
Const MYCONST1 = "MyModule"
Const MYCONST2 = 4
Public Type my2ndType
mvar2(1 To 5) As myType
mvar1 As Boolean
End Type
Rem sub de test
Private Sub monsubPrive(ByRef pparm1 As String, ByVal pparm2 As Boolean, pparm3 As myType)
Dim mvar1 As String, lvarA As Boolean, mvar2 As my2ndType
pparm3.mvar1 = pparm1
With pparm3
.mvar2 = -3
End With
Rem 3 identificateur mvar2 qui désignent tous des variables différentes
mvar2.mvar2(5 + pparm3.mvar2).mvar2 = -1234567
lvarA = True
mvar1 = MYCONST1
MsgBox "monsubPrive : " & pparm3.mvar1 & " " & mvar1
End Sub
Public Sub lance()
Dim laClasse As MyClass, var2 As String, mvar1 As myType
Set laClasse = New MyClass
With ActiveSheet
.Cells(2, 2) = "Test démarré"
End With
Rem ne pas confondre les 2 "var2"
laClasse.var2 = 12345 - 1234
var2 = " toto "
monsubPrive "test", True, mvar1
MyUserForm.Show
End Sub
Obfuscated code
Attribute VB_Name = "F5"
Option Explicit
Public Type F6
F1 As String
F2 As Long
F3 As Boolean
End Type
Const F12 = "MyModule"
Const F13 = 4
Public Type F7
F1(1 To 5) As F6
F2 As Boolean
End Type
Private Sub F14(ByRef F15 As String, ByVal F16 As Boolean, F17 As F6)
Dim F18 As String, F19 As Boolean, F1A As F7
F17.F1 = F15
With F17
.F2 = -3
End With
F1A.F1(5 + F17.F2).F2 = -1234567
F19 = True
F18 = F12
MsgBox "monsubPrive : " & F17.F1 & " " & F18
End Sub
Public Sub lance()
Dim F15 As F1, F16 As String, F17 As F6
Set F15 = New F1
With ActiveSheet
.Cells(2, 2) = "Test démarré"
End With
F15.F4 = 12345 - 1234
F16 = " toto "
F14 "test", True, F17
F8.Show
End Sub
4.3 UserForm "MyUserForm.frm"
Source Code
VERSION 5.00
Begin {C62A69F0-16DC-11CE-9E98-00AA00574A4F} MyUserForm
Caption = "Test Obfu-VBA"
ClientHeight = 5250
ClientLeft = 45
ClientTop = 345
ClientWidth = 4950
OleObjectBlob = "MyUserForm.frx":0000
StartUpPosition = 1 'CenterOwner
End
Attribute VB_Name = "MyUserForm"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Private var1 As MyClass
Private var2 As myType
Private Sub Fermer_Click()
Unload MyUserForm
End Sub
Rem le nom de ce Sub ne doit pas être obfuscaté
Private Sub UserForm_Initialize()
Label1.Caption = "valeur initialisée par UserForm_Initialize"
Set var1 = New MyClass
End Sub
Private Sub CommandButton1_Click()
MsgBox "TextBox2.Value=" & var1.var1 'ne pas confondre l'instance de MyClass avec son membre de même nom
Rem les controles peuvent être qualifiés complètement ou pas du tout
MyUserForm.MultiPage1.Page2.TextBox2.Value = "-->" & var1.var1
End Sub
Private Sub TextBox2_Change()
Dim mvar1 As String, var_2 As Integer, _
var_3 As Boolean 'gestion d'une ligne avec caractère de continuation
Rem les controles peuvent être qualifiés complètement ou pas du tout
var1.var1 = TextBox2.Value
Rem gestion du with : ne pas confondre la variable locale mvar1 avec le membre .mvar1
With var2
.mvar1 = "string"
.mvar2 = 123456789
.mvar3 = True
End With
End Sub
Obfuscated code
VERSION 5.00
Begin {C62A69F0-16DC-11CE-9E98-00AA00574A4F} F8
Caption = "Test Obfu-VBA"
ClientHeight = 5250
ClientLeft = 45
ClientTop = 345
ClientWidth = 4950
OleObjectBlob = "MyUserForm.frx":0000
StartUpPosition = 1
End
Attribute VB_Name = "F8"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Private F12 As F1
Private F13 As F6
Private Sub F11_Click()
Unload F8
End Sub
Private Sub UserForm_Initialize()
FF.Caption = "valeur initialisée par UserForm_Initialize"
Set F12 = New F1
End Sub
Private Sub FB_Click()
MsgBox "TextBox2.Value=" & F12.F3
F8.FC.FE.F10.Value = "-->" & F12.F3
End Sub
Private Sub F10_Change()
Dim F14 As String, F15 As Integer, F16 As Boolean
F12.F3 = F10.Value
With F13
.F1 = "string"
.F2 = 123456789
.F3 = True
End With
End Sub
5 How to get Obfu-VBA ?
ToolOscope proposes to you a Shareware Licence :
- You would like to try Obfu-VBA : Register and download the software in full version for free. You are granted an evaluation license.
- "What's the need ?" : Remove from your work spaces all your copies of the software and all by-products generated by it.
- "This software is not bad, but..." : Ask for an evolution or a correction and describe precisely your needs.
- "It works and I will keep on using it or its by-products" : Send your greetings to its creator.
For all this, please go to the User Space.
Don't modify this software, don't broadcast it : ToolOscope manages that.