Giter Club home page Giter Club logo

obfuscate's Introduction

Source available on GitHub

Obfuscate

Guaranteed compile-time string literal obfuscation header-only library for C++14.

Quick start guide

  1. Copy obfuscate.h into your project
  2. Wrap strings with AY_OBFUSCATE("My String")

Now your project will not expose those strings in plain text in the binary image.

Note that these strings will still be accessible to determined hackers. Using obfuscation to hide private passwords or any other security sensitive strings is not recommended by the author.

Whats the problem?

When plain text string literals are used in C++ programs, they will be compiled as-is into the resultant binary. This causes them to be incredibly easy to find. One can simply open up the binary file in a text editor to see all of the embedded string literals in plain view. A special utility called strings exists which can be used to search binary files for plain text strings.

What does this library do?

This header-only library seeks to make it difficult (but not impossible) for embedded string literals in binary files to be found by encrypting them with an XOR cipher at compile-time using a constant expression, forcing the compiler to work with the encrypted string instead of the plain text literal. Usage of AY_OBFUSCATE additionally removes the need for a const pointer to the string, which more often than not (for small strings) convinces the compiler to inline the encrypted string, building it up at runtime in a series of assembly operations, protecting the binary image against simple XOR decryption attacks. Encrypted strings will then be decrypted at runtime to be utilised within the program.

Technical features

  • Guaranteed compile-time obfuscation - the string is compiled with a constexpr expression.
  • Global lifetime (per-thread) - the obfuscated string is stored in a thread local variable in a unique lambda.
  • Implicitly convertible to a char* - easy to integrate into existing codebases.
  • Random 64-bit key - obfusated with a random key each time.

By simply wrapping your string literal "My String" with AY_OBFUSCATE("My String") it will be encrypted at compile time with a random 64 bit key and stored in an ay::obfuscated_data object which you can manipulate at runtime. For convenience it is also implicitly convertable to a char*.

For example, the following program will not store the string "Hello World" in plain text anywhere in the compiled executable.

#include "obfuscate.h"

int main()
{
    std::cout << AY_OBFUSCATE("Hello World") << std::endl;
    return 0;
}

Examples of usage

Because the obfuscated string that is generated by AY_OBFUSCATE has global lifetime per-thread, it is completely fine to also use it in both a local and a temporary context.

char* var = AY_OBFUSCATE("string");
const char* var = AY_OBFUSCATE("string");
static const char* var = AY_OBFUSCATE("string");
std::string var(AY_OBFUSCATE("string"));
function_that_takes_char_pointer(AY_OBFUSCATE("string"));

Thread safety

This library can be used in a multi-threaded environment only if AY_OBFUSCATE is used in a local context per thread. This is because the obfuscated string is internally stored with thread_local storage. The following usage is supported:

void fun()
{
    auto var = AY_OBFUSCATE("Thread Safe");
    var.decrypt();
    std::cout << var << std::endl;
    var.encrypt();
}

int main()
{
    std::thread thread1(fun);
    std::thread thread2(fun);

    thread1.join();
    thread2.join();
    return 0;
}

Conversely, sharing an obfuscated string returned from AY_OBFUSCATE between multiple threads is not supported. In this case you must put locks in appropriate places in your code to ensure that only one thread accesses it at a time. The following usage is not supported:

int main()
{
    for (size_t i = 0; i < 1000; i++)
    {
        auto var = AY_OBFUSCATE("NOT Thread Safe");
        var.decrypt();
        
        std::thread thread([&var]() {
            std::cout << var << std::endl;
        });
        
        // We are encrypting the string here, but outputting it in
        // another thread at the same time. This will not work.
        var.encrypt();

        thread.join();
    }
    return 0;
}

Binary file size overhead

This does come at a small cost. In a very naive login program, which obfuscates two strings (username and password) the following binary file bloat exists.

Config Plain string literals Obfuscated strings Bloat
Release 18944 21504 2560 (13.5%)
Debug 95232 101888 6656 (7.0%)

This output is generated by running test_bloat.py

obfuscate's People

Contributors

a4865g avatar adamyaxley avatar ekrikelis avatar i-ky avatar inie0722 avatar oliviernemoz avatar pieceofsummer avatar sidelobe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

obfuscate's Issues

[Question] Free the allocated memory

Sorry if this is a dumb question since I am not so familiar with C++.

Let's say I declared a variable like this:

 char* secretKey = AY_OBFUSCATE("losdasd");

Do I need to free the memory allocated for secretKey after using it? Thanks for reading.

Default key is deterministic and extremely short.

#define AY_OBFUSCATE(data) AY_OBFUSCATE_KEY(data, '.')

Looks like the AY_OBFUSCATE macro uses the key . by default.
This makes decrypting the strings trivially easy (just xor each byte of the executable with . and you have the plaintext).

Generating the key at compile time and many characters long will make protect the strings from this kind of basic attack.

Clang fails to find a suitable conversion to `std::string`

The following two lines in obfuscate_test_bloat.cpp

const std::string username = AY_OBFUSCATE("root");
const std::string password = AY_OBFUSCATE("password");

trigger an error when building with Clang under MSVC:

error : no viable conversion from 'ay::obfuscated_data<sizeof ("root") / sizeof ("root"[0]), '.'>' to 'const std::string' (aka 'const basic_string<char, char_traits<char>, allocator<char> >')

I'm not really sure why it won't pick the operator char*() for conversion.

Explicitly adding a conversion operator fixes the issue (although I'm aware this isn't really ideal):

operator std::string()
{
    decrypt();
    return m_data;
}

Host: Windows 10 x64
MSVC Tools: 14.23.28105 (Visual Studio 2019 16.3.10)
Clang: 8.0.1 (installed through VS Installer)

To reproduce:

  • Use the python script to create the solution and project files.
  • Open the solution in MSVC.
  • Select all projects and switch their platform toolset to LLVM.
  • Try to compile obfuscate_test_bloat_on.

Haven't had a chance to test it under other systems though.

Empty data .

Empty data by some reason calling in atexit function.

Obfuscate obfuscator

Thanks for this really pretty piece of code. It is amazing and it works fine.

However for me there's a tiny problem with class and variable naming.
One class is called obfuscator and a variable is obfuscated_data. This shows up in the binary in case it is released with debug info (yes, not really a good idea), but google tells any hacker what's behind the scenes in this case.

Renaming to a less story-telling name would be nice. Hm, users of your header can do this on their own, but a hint might be good.

Fx

How to generate a separate key for each usage

Is there an easy way to do this to generate a separate password for each string at random? Without modifying the llvm source code. I have used a similar string encryption plugin on Android who generates a different password for each string in the java code.

VMProtect

Can I use it this way? VMProtectDecryptStringA (AY_OBFUSCATE ("test"))
The string is not recognized in the GUI I sent VMP

C++20 support

Hi Adam / maintainers

Came across your library in search for a mild obfuscation solution in my project.
I compule against C++20 standard and I though it could be useful to make the obfuscate.h file use the C++20 features consteval and the STL std::remove_cvref in case the header is compiled with C++20 standard enabled.

Are you interested if I share a solution to use these features on a separate branch?

Regards
Maarten

obfuscate literal byte arrays

I'd be great if this could obfuscate literal byte arrays a la

#include "obfuscate.hpp"

#define P99_PROTECT(...) __VA_ARGS__

int main(void)
{
    const auto x = AY_OBFUSCATE(P99_PROTECT({
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
    }));
    return 0;
}

(For P99_PROTECT, see here.)

Unfortunately, the above still gives

a.cpp:10:7: error: macro "AY_OBFUSCATE_KEY" passed 17 arguments, but takes just 2

operator char*

Is it probably better to replace the operator "operator char*()" with operator const char*() ?

error C3249: illegal statement or sub-expression for 'constexpr' function

Hi
Can you help me fix this error "statement may not appear in a constexpr function" in following section

constexpr void cipher (char* data, size_type size, key_type key)
{
// Obfuscate with a simple XOR cipher based on key
for ( i = 0; i < size; i++ )
{
data[i] ^= char (key >> ((i % 8) * 8));
}
}

Still decryptable

Someone send me this image, seems 64-bit key is easly decryptable. Is there more ways you can improve more? and break IDA's pseduocode?

image

Improve obfuscation

Someone told me AY obfuscator is easy to decrypt in IDA as the key was there but for me, i can't see anyway to decrypt in IDA. Can you possibly improve it more and allow more letters than one for the key?

C version possible?

Not an issue, more of a question.

I'm looking for a solution like this but for C instead of C++.
Is it even possible?

add support for wchar_t string leterals

for example, const std::wstring s = (const wchar_t *)AY_OBFUSCATE(L"test");

wchar_t is implementation-dependent, it's 2-bytes in Windows, while may be 4-bytes in Linux x86_64.

[question] String casting question

I was quite annoyed while i must use string(AY_OBFUSCATE("test")) each time i want to obfuscate string, i did small rewrite of library, but i'm not sure if that usage is safe. My code:

#define OBFUSCATE(data) \
    []() -> string {         \
        const ay::key_type key = AY_OBFUSCATE_DEFAULT_KEY; \
        static_assert(sizeof(decltype(key)) == sizeof(ay::key_type), "key must be a 64 bit unsigned integer"); \
        static_assert((key) >= (1ull << 56), "key must span all 8 bytes"); \
        constexpr auto n = sizeof(data)/sizeof(data[0]); \
        constexpr auto obfuscator = ay::make_obfuscator<n, key>(data); \
        static auto obfuscated_data = ay::obfuscated_data<n, key>(obfuscator); \
        return obfuscated_data.operator char *(); \
    }()

Can't convert to NSString

I'm developing tweak for iOS but i can't apply string obfuscation with NSString. Can you add support for it?

> Making all for tweak tweaker…
==> Preprocessing Tweak.xm…
==> Compiling Tweak.xm (arm64)…
Tweak.xm:98:22: error: no viable conversion from 'ay::obfuscated_data<sizeof
      ("string test") / sizeof ("string test"[0]), ','>' to 'NSString *'
            subTitle:O("string test")
                     ^~~~~~~~~~~~~~~~
/Volumes/iOS/tweaker/Includes/obfuscate.h:158:17: note: expanded from macro
      'O'
#define O(data) O_KEY(data, ',')
                ^~~~~~~~~~~~~~~~
/Volumes/iOS/tweaker/Includes/obfuscate.h:165:2: note: expanded from macro
      'O_KEY'
        []() -> ay::obfuscated_data<sizeof(data)/sizeof(data[0]), key>& { \
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Volumes/iOS/tweaker/Includes/obfuscate.h:96:3: note: candidate function
                operator char*()
                ^
/Volumes/iOS/tweaker/Includes/obfuscate.h:102:3: note: candidate function
                operator std::string()
                ^
/Volumes/iOS/tweaker/SCLAlertView/SCLAlertView.h:366:60: note: passing
      argument to parameter 'subTitle' here
- (void)showSuccess:(NSString *)title subTitle:(NSString *)subTitle clos...
                                                           ^
1 error generated.
make[3]: *** [/Volumes/iOS/tweaker/.theos/obj/arm64/Tweak.xm.1d85f210.o] Error 1
make[2]: *** [/Volumes/iOS/tweaker/.theos/obj/arm64/tweaker.dylib] Error 2
make[1]: *** [internal-library-all_] Error 2
make: *** [tweaker.all.tweak.variables] Error 2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.