MQL-Obfuscator

 

I created an obfuscator for MQL (encryption of source code) for my own purposes and would like to know, if there is any kind of a general/common interest.

The obfuscator works so far without problems, but surely has some restrictions which would become visible with other code than mine. I could obfuscate object oriented code with <>120.000 lines, lots of #ifdef / #else / #endif statements which are processed by the integrated preprocessor, round about 8.000 different expressions whereby almost all were obfuscated. The software also supports some obfuscation commands within the code, which allow for different obfuscation levels, different outputs depending of who shall receive and see the final code. This allows for keeping some functions, enums, classes etc. in clear text, while the rest is encrypted.

Before I spend any further energy or even think about transforming it into a commercial product or whatever, I would like to figure out if there is some interest for such a product or not.

Here is a sample with a conditionally obfuscated code.

1. Main file contains the switches and includes the topmost-file



2. Part of the original code:

   #include "VObject_compat.mqh"
#else
   #include <DH\Wnd.mqh>
#endif   

//+------------------------------------------------------------------+
//| Drawing styles and colors                                        |
//+------------------------------------------------------------------+
//--- common
#define CONTROLS_FONT_NAME                  "Trebuchet MS"
#define CONTROLS_FONT_SIZE                  (10)
//--- Text
#define CONTROLS_COLOR_TEXT                 C'0x3B,0x29,0x28'
#define CONTROLS_COLOR_TEXT_SEL             White
#define CONTROLS_COLOR_BG                   White
#define CONTROLS_COLOR_BG_SEL               C'0x33,0x99,0xFF'
//--- Button
#define CONTROLS_BUTTON_COLOR               C'0x3B,0x29,0x28'
#define CONTROLS_BUTTON_COLOR_BG            C'0xDD,0xE2,0xEB'
#define CONTROLS_BUTTON_COLOR_BORDER        C'0xB2,0xC3,0xCF'
//--- Label
#define CONTROLS_LABEL_COLOR                C'0x3B,0x29,0x28'
//--- Edit
#define CONTROLS_EDIT_COLOR                 C'0x3B,0x29,0x28'
#define CONTROLS_EDIT_COLOR_BG              White
#define CONTROLS_EDIT_COLOR_BORDER          C'0xB2,0xC3,0xCF'


//+------------------------------------------------------------------+
//|                                                                  |
//| Class CWndObj                                                    |
//|                                                                  |
//|                                                                  |
//| Purpose: base class to work with chart objects                   |
//|                                                                  |
//+------------------------------------------------------------------+

class CWndObj : public CWnd
  {
protected:
   //--- parameters of the chart object
   string            m_text;                // object text
   color             m_color;               // object color
   color             m_color_background;    // object background color
   color             m_color_border;        // object border color
   string            m_font;                // object font
   int               m_font_size;           // object font size
   long              m_zorder;              // Z order
   ENUM_BORDER_TYPE  m_bordertype;          // object border type 


public:
                     CWndObj(void);
                    ~CWndObj(void);
   //--- set up the object
   string            Text(void)                          { return m_text; }
   bool              Text(const string value)            { if (value==m_text) return true; m_text=value; OnSetText(); Invalidate(); return true; }
   #ifdef __DH_OBJECT_CLASS
   string            DebugInfo(void)                     { return CObjectX::DebugInfo()+" ("+m_text+")"; }
   #endif
   color             Color(void) const                   { return(m_color); }
   bool              Color(const color value);
   color             ColorBackground(void) const         { return(m_color_background); }
   bool              ColorBackground(const color value);
   color             ColorBorder(void) const             { return(m_color_border); }
   bool              ColorBorder(const color value);
   bool              Font(const string value);
   string            Font(void) const                    { return(m_font); }
   int               FontSize(void) const                { return(m_font_size); }
   bool              FontSize(const int value);
   long              ZOrder(void) const                  { return(m_zorder); }
   bool              ZOrder(const long value);
   bool              Anchor(const ENUM_ANCHOR_POINT p)   { return __MT_Object_SetAnchor(m_chart_id,m_name,p); }
   ENUM_ANCHOR_POINT Anchor(void)                        { return __MT_Object_GetAnchor(m_chart_id,m_name); }

   //--- handlers of CVObject
   virtual bool      OnAssignChartObject(void)           { __MT_Object_XY_GetRect(m_chart_id,m_name,m_rect);
                                                           m_text=__MT_Object_GetText(m_chart_id,m_name); 
                                                           __MT_Object_GetFont(m_chart_id,m_name,m_font,m_font_size);
                                                           m_color=__MT_Object_GetColor(m_chart_id,m_name);
                                                           m_color_background=__MT_Object_GetColorBg(m_chart_id,m_name);
                                                           m_color_border=__MT_Object_GetColorBorder(m_chart_id,m_name);
                                                           m_bordertype=__MT_Object_GetBordertype(m_chart_id,m_name);
                                                           return CWnd::OnAssignChartObject(); }

   //--- handlers of CWnd   
   virtual bool      OnMove(void)                        { __MT_Object_XY_Move(m_chart_id,m_name,m_rect.left,m_rect.top); return CWnd::OnMove(); }
   virtual bool      OnResize(void)                      { __MT_Object_XY_Resize(m_chart_id,m_name,m_rect.Width(),m_rect.Height()); return CWnd::OnResize(); }
   virtual bool      OnDestroy(void)                     { __MT_Object_Delete(m_chart_id,m_name); return CWnd::OnDestroy(); }
   
   //--- own handlers
   virtual bool      OnSetText(void)                     { return true; }
   virtual bool      OnGetText(void)                     { m_text=_FetchText(); return true; }
   
   virtual string    _FetchText(void)                    { return __MT_Object_GetText(m_chart_id,m_name); }
   virtual bool      _StoreText(string value)            { return __MT_Object_SetText(m_chart_id,m_name,value); } 
   
   virtual bool      OnSetColor(void)                    { return __MT_Object_SetColor(m_chart_id,m_name,m_color); }
   virtual bool      OnSetColorBackground(void)          { return __MT_Object_SetColorBg(m_chart_id,m_name,m_color_background); }
   virtual bool      OnSetColorBorder(void)              { return __MT_Object_SetColorBorder(m_chart_id,m_name,m_color_border); }
   virtual bool      OnSetFont(void)                     { return __MT_Object_SetFont(m_chart_id,m_name,m_font,0); }
   virtual bool      OnSetFontSize(void)                 { return __MT_Object_SetFont(m_chart_id,m_name,NULL,m_font_size); }
   virtual bool      OnSetZOrder(void)                   { return __MT_Object_SetZOrder(m_chart_id,m_name,m_zorder); }
   
   #ifdef __VO_COMPAT
   virtual bool      OnShow()                            { return __MT_Object_SetVisible(m_chart_id,m_name,true); }
   virtual bool      OnHide()                            { return __MT_Object_SetVisible(m_chart_id,m_name,false); }
   #endif    
   //--- 
   
   virtual bool      OnUpdate(void)                      { return _StoreText(m_text); }
   
  };

3. The output, consisting of mixed code, encrypted and clear

/********File:WndObj.mqh:19********/
#define fu637570947474220151 "Trebuchet MS" //00027
#define fu637570947474220152 (10) //00028
#define fu637570947474220153 C'0x3B,0x29,0x28' //00030
#define fu637570947474220154 White //00031
#define fu637570947474220155 White //00032
#define fu637570947474220156 C'0x33,0x99,0xFF' //00033
#define fu637570947474220157 C'0x3B,0x29,0x28' //00035
#define fu637570947474220158 C'0xDD,0xE2,0xEB' //00036
#define fu637570947474220159 C'0xB2,0xC3,0xCF' //00037
#define fu637570947474220160 C'0x3B,0x29,0x28' //00039
#define fu637570947474220161 C'0x3B,0x29,0x28' //00041
#define fu637570947474220162 White //00042
#define fu637570947474220163 C'0xB2,0xC3,0xCF' //00043
class fu637570947474220164:public fu637570947474220005//00055
{//00056
protected://00057
string fu637570947474220165;//00059
color fu637570947474220166;//00060
color fu637570947474220167;//00061
color fu637570947474220168;//00062
string fu637570947474220169;//00063
int fu637570947474220170;//00064
long fu637570947474220171;//00065
ENUM_BORDER_TYPE fu637570947474220172;//00066
public://00069
fu637570947474220164(void);//00070
~fu637570947474220164(void);//00071
string Text(void){return fu637570947474220165;}//00073
bool Text(const string value){if(value==fu637570947474220165)return true;fu637570947474220165=value;fu637570947474220181();Invalidate();return true;}//00074
string fu637570947474218352(void){return CObjectX::fu637570947474218352()+" ("+fu637570947474220165+")";}//00076
color Color(void)const{return(fu637570947474220166);}//00078
bool Color(const color value);//00079
color ColorBackground(void)const{return(fu637570947474220167);}//00080
bool ColorBackground(const color value);//00081
color fu637570947474220176(void)const{return(fu637570947474220168);}//00082
bool fu637570947474220176(const color value);//00083
bool fu637570947474220177(const string value);//00084
string fu637570947474220177(void)const{return(fu637570947474220169);}//00085
int fu637570947474220178(void)const{return(fu637570947474220170);}//00086
bool fu637570947474220178(const int value);//00087
long fu637570947474220179(void)const{return(fu637570947474220171);}//00088
bool fu637570947474220179(const long value);//00089
bool fu637570947474220180(const ENUM_ANCHOR_POINT p){return fu637570947474218778(m_chart_id,m_name,p);}//00090
ENUM_ANCHOR_POINT fu637570947474220180(void){return fu637570947474218780(m_chart_id,m_name);}//00091
virtual bool fu637570947474220075(void){fu637570947474218681(m_chart_id,m_name,fu637570947474220124);//00094
fu637570947474220165=fu637570947474218707(m_chart_id,m_name);//00095
fu637570947474218698(m_chart_id,m_name,fu637570947474220169,fu637570947474220170);//00096
fu637570947474220166=fu637570947474218771(m_chart_id,m_name);//00097
fu637570947474220167=fu637570947474218773(m_chart_id,m_name);//00098
fu637570947474220168=fu637570947474218775(m_chart_id,m_name);//00099
fu637570947474220172=fu637570947474218777(m_chart_id,m_name);//00100
return fu637570947474220005::fu637570947474220075();}//00101
virtual bool fu637570947474220142(void){fu637570947474218677(m_chart_id,m_name,fu637570947474220124.fu637570947474218375,fu637570947474220124.fu637570947474218376);return fu637570947474220005::fu637570947474220142();}//00104
virtual bool fu637570947474220143(void){fu637570947474218679(m_chart_id,m_name,fu637570947474220124.Width(),fu637570947474220124.Height());return fu637570947474220005::fu637570947474220143();}//00105
virtual bool fu637570947474220077(void){fu637570947474218792(m_chart_id,m_name);return fu637570947474220005::fu637570947474220077();}//00106
virtual bool fu637570947474220181(void){return true;}//00109
virtual bool fu637570947474220182(void){fu637570947474220165=fu637570947474220183();return true;}//00110
virtual string fu637570947474220183(void){return fu637570947474218707(m_chart_id,m_name);}//00112
virtual bool fu637570947474220184(string value){return fu637570947474218706(m_chart_id,m_name,value);}//00113
virtual bool fu637570947474220185(void){return fu637570947474218769(m_chart_id,m_name,fu637570947474220166);}//00115
virtual bool fu637570947474220186(void){return fu637570947474218772(m_chart_id,m_name,fu637570947474220167);}//00116
virtual bool fu637570947474220187(void){return fu637570947474218774(m_chart_id,m_name,fu637570947474220168);}//00117
virtual bool fu637570947474220188(void){return fu637570947474218695(m_chart_id,m_name,fu637570947474220169,0);}//00118
virtual bool fu637570947474220189(void){return fu637570947474218695(m_chart_id,m_name,NULL,fu637570947474220170);}//00119
virtual bool fu637570947474220190(void){return fu637570947474218783(m_chart_id,m_name,fu637570947474220171);}//00120
virtual bool fu637570947474220079(){return fu637570947474218682(m_chart_id,m_name,true);}//00123
virtual bool fu637570947474220078(){return fu637570947474218682(m_chart_id,m_name,false);}//00124
virtual bool fu637570947474220074(void){return fu637570947474220184(fu637570947474220165);}//00128
};//00130
 

Since you probably would like to have both positive and negative feedback, for me personally I have no need for it!

It is however, an intriguing project, but my only interest in it would be one of curiosity of wanting to look "under the hood".

 
Fernando Carreiro:

Since you probably would like to have both positive and negative feedback, for me personally I have no need for it!

It is however, an intriguing project, but my only interest in it would be one of curiosity of wanting to look "under the hood".

Of course. It makes only sense for those who are obliged to provide source codes from time to time and who do not want to provide all parts of their work. By the way, could make sense to feed the MetaQuotes support, when they ask for source codes. 

Regarding "under the hood" ... you mean, how the processing is done or how to decrypt? I think, decryption is almost impossible, at least it would take that long that its getting kinda senseless, also because the function names change with every further output/update. 

If your interest is about the process, actually its not that complicated.

1. Of course you have to have a preprocessor which is capable of handling all the statements for conditional compiling, including/finding all the source files and build a kind of a basic code, without any #ifdef- or #include-stuff.

2. Based on that, a parser tracks down the code and looks for definitions, such as classes, functions, variables, enums etc. It does not need to know any predefined commands of the MQL language, as long as every integrated function uses the "::" operator as a prefix. It just must be able to "understand" how the syntax of such definitions works. This parser creates a list of all such expressions/definitions.

3. Due to some switches which can disable encryption partially, some expressions need to be filtered out. These expressions are collected in another list

4. All the filtered expressions are removed from the encryption list

5. The parser parsed the code again and replaces those expression which remain in the encryption list

Done. The whole procedure takes less than 10 seconds for >100.000 lines of code and <>8.000 expressions. 

I´ve been reading some documentation upfront about parsers and processes of obfuscation. My method is held kind of easy and is not perfect, but its at least an very much acceptable solution for my purposes. I would not have it done if I´d were able to find any existing software for that purpose - but there is no such. 

 
Doerk Hilger: Regarding "under the hood" ... you mean, how the processing is done

Yes, I meant how it all works! What original parser and/or preprocessor did you base it on?

 
Fernando Carreiro:

Yes, I meant how it all works! What original parser and/or preprocessor did you base it on?

I developed my own parser, took just a few hours and is less than 200 lines of code. It just need to distinguish between operators, expressions and different types of constants. The preprocessor is also my own code, but I had this already because of an "intelligent" search & replace tool I created some earlier for MQL.

 
Doerk Hilger: I developed my own parser, took just a few hours and is less than 200 lines of code. It just need to distinguish between operators, expressions and different types of constants. The preprocessor is also my own code, but I had this already because of an "intelligent" search & replace tool I created some earlier for MQL.
Thank you for the info!
 
Doerk Hilger:

I created an obfuscator for MQL (encryption of source code) for my own purposes and would like to know, if there is any kind of a general/common interest.

The obfuscator works so far without problems, but surely has some restrictions which would become visible with other code than mine. I could obfuscate object oriented code with <>120.000 lines, lots of #ifdef / #else / #endif statements which are processed by the integrated preprocessor, round about 8.000 different expressions whereby almost all were obfuscated. The software also supports some obfuscation commands within the code, which allow for different obfuscation levels, different outputs depending of who shall receive and see the final code. This allows for keeping some functions, enums, classes etc. in clear text, while the rest is encrypted.

Before I spend any further energy or even think about transforming it into a commercial product or whatever, I would like to figure out if there is some interest for such a product or not.

Here is a sample with a conditionally obfuscated code.

1. Main file contains the switches and includes the topmost-file



2. Part of the original code:

3. The output, consisting of mixed code, encrypted and clear

Hi Doerk,


Thank you for this interesting post. I believe this is of great benefit for the community. Is there any possibility to share your obfuscator? even if not in a final form, it would make a great seed project for others to collaborate and improve.

 
Bijan Shj #: Hi Doerk, Thank you for this interesting post. I believe this is of great benefit for the community. Is there any possibility to share your obfuscator? even if not in a final form, it would make a great seed project for others to collaborate and improve.

Interesting project - certainly more complex that things I work on...

But I thought such a tool already exists [link redacted by moderator]

Am I mistaken?

Discussions, recommendations or suggestions for 3rd party products and services is not allowed on the forum.

Reason: