andrivet / ADVobfuscator

Obfuscation library based on C++11/14 and metaprogramming
1.39k stars 238 forks source link

String obfuscation fails #8

Closed parsifall closed 8 years ago

parsifall commented 8 years ago

I've compiled a C++ project in which I encrypted strings using the OBFUSCATED4(...) macro. I modified it by put it inside std::string() constructor so that it becomes something like '#define OBFUSCATED4 std::string(MetaString4...)' so I can assign it to a std::string for example: std::string myStr = OBFUSCATED4("MyString");. Now, when I disassemble the code I can see all string characters one by one, sometimes in random order. I also use clang to compile and I set the -O2 compiler flag. Any suggestion?

Amadeus- commented 8 years ago

I'm not sure how the clang compiler works; however, with Visual Studio 2015 (using the default settings for creating a project, etc.), you have to compile in 'release' configuration for the string obfuscation to work. Otherwise, if you compile in the default configuration, which is 'debug', it will do what you're reporting.

I'm not sure which setting it is (probably something with the linker), but changing from 'debug' to 'release' configurations in Visual Studio made the OBFUSCATED4() macro work as it should.


[andrivet: I would suggest mentioning this in the documentation. Also, I just now opened the VS solution you included with the project and it was set to 'debug' configuration. I'm not sure if you can force it to be 'release' by default on other computers or not, but you might want to look into that.]

Amadeus- commented 8 years ago

Here's what I used for testing:

C++

int main()
{

    std::cout << OBFUSCATED4("Hello World");
    return 0;
}

Disassembly when compiled in Visual Studio with default 'debug' configuration:

.text:004136B8                 push    offset str      ; "Hello World"
.text:004136BD                 lea     ecx, [ebp+var_D8] ; this
.text:004136C3                 call    j_??0?$MetaString4@$00$0FJ@U?$Indexes@$0A@$00$01$02$03$04$05$06$07$08$09@ADVobfuscator@andrivet@@@ADVobfuscator@andrivet@@QAE@PBD@Z ; andrivet::ADVobfuscator::MetaString4<1,89,andrivet::ADVobfuscator::Indexes<0,1,2,3,4,5,6,7,8,9,10>>::MetaString4<1,89,andrivet::ADVobfuscator::Indexes<0,1,2,3,4,5,6,7,8,9,10>>(char const *)
.text:004136C8                 mov     ecx, eax        ; this
.text:004136CA                 call    j_?decrypt@?$MetaString4@$00$0FJ@U?$Indexes@$0A@$00$01$02$03$04$05$06$07$08$09@ADVobfuscator@andrivet@@@ADVobfuscator@andrivet@@QAEPBDXZ ; andrivet::ADVobfuscator::MetaString4<1,89,andrivet::ADVobfuscator::Indexes<0,1,2,3,4,5,6,7,8,9,10>>::decrypt(void)
.text:004136CF                 push    eax             ; Str
.text:004136D0                 mov     eax, ds:__imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::basic_ostream<char,std::char_traits<char>> std::cout
...etc..

Disassembly when compiled in Visual Studio 2015 with default 'release' configuration:

.text:0040100D                 mov     [ebp+var_4], eax
.text:00401010                 mov     dl, 60h
.text:00401012                 mov     dword ptr [ebp+_Val], 0E042860h
.text:00401019                 mov     [ebp+var_10], 31450B0Fh
.text:00401020                 xor     eax, eax
.text:00401022                 mov     [ebp+var_C], 0E051A08h
.text:00401029                 mov     [ebp+var_8], 0
.text:0040102D                 nop     dword ptr [eax]
.text:00401030
.text:00401030 loc_401030:                             ; CODE XREF: _main+40j
.text:00401030                 lea     ecx, [edx+eax]
.text:00401033                 xor     [ebp+eax+_Val+1], cl
.text:00401037                 inc     eax
.text:00401038                 cmp     eax, 0Bh
.text:0040103B                 jnb     short loc_401042
.text:0040103D                 mov     dl, [ebp+_Val]
.text:00401040                 jmp     short loc_401030
.text:00401042 ; ---------------------------------------------------------------------------
.text:00401042
.text:00401042 loc_401042:                             ; CODE XREF: _main+3Bj
.text:00401042                 mov     ecx, ds:__imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; _Ostr
.text:00401048                 lea     edx, [ebp+_Val+1] ; _Val
.text:0040104B                 mov     [ebp+var_8], 0
.text:0040104F                 call    ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char const *)
parsifall commented 8 years ago

I fixed it by using the clang optimization off pragmatic expression, altought I didn't run the executable yet. I hope this won't have any significant repercussion regarding speed and program stability.

andrivet commented 8 years ago

In debug build, the original string is present. This is by design. It is mentioned in the white paper. I will see if I add it to the README (for me, it was obvious but apparently, this is not the case of everybody).