☠️
Uriel Berdeja
  • General
    • Virtual Machines Setup Notes
    • C++17 and C++20 Interesting Features
  • Windows
    • A walkthrough over Themida anti-debug techniques
    • Structured Exception Handlers
    • Win32 Authorization System
    • .NET CLR process internals
    • ClickOnce Technical Details
    • WebDAV Technical Details
    • Monikers
  • Uncategorized
    • Snippets
    • Windows Various Notes
    • Index of ingest resources
    • Tooling Resources
    • TODO List
Powered by GitBook
On this page
  • Compile-Time Function Generation
  • Compile-Time Random Number Generator

Was this helpful?

  1. General

C++17 and C++20 Interesting Features

PreviousVirtual Machines Setup NotesNextA walkthrough over Themida anti-debug techniques

Last updated 7 months ago

Was this helpful?

Compile-Time Function Generation

Metaprogramming is very useful when writing polymorphic code that can be used to evade static analysis detections, not only because it permutes the filehash on each compilation, it can be also used for flow graph obfuscation, api hammering among other practical evasion uses.

Consider the following code snippet:

template<size_t size, class Fn>
auto bloat(Fn fn) -> void
{
    [&] <auto... Indexes>(std::index_sequence<Indexes...>) {
        (((fn(Indexes))), ...);
    }(std::make_index_sequence<size>{});
}

We're using a template function, that accepts two template parameters, size and Fn. Defines a lambda function that pases all outer scope parameters as reference [&] and accepts and index_sequence as parameter.

This lambda function is called immediately, so let's expand the the function, instantiate and unfold it:

[&] <size_t... Indexes>(std::index_sequence<0, 1, 2, 3, 4>) {
    (((fn(Indexes))), ...);
}(std::index_sequence<0, 1, 2, 3, 4>{});

Seen this way, the magic resides in the folding expression (((fn(Indexes))), ...);

This is an unary right fold, folding can be intepreted linguistically as reducing a list to a single value, a common use case is checking wheter all of the values in a list are true:

(... && args);

This unary left fold becomes

In this case, of boolean values can be represented as:

((true && true) && true) && false

In the above case of the lambda function, the comma binary operator is used hich is meant to evaluate the first operator, discard the value and assign the value of the second operator and a right unary unfold would be:

(((fn(5), fn(4)), fn(3), fn(2)))

So evaluation will start backward as it reads in the pseudocode above.

When the source code is compile let's say passing 4 as the size template parameter and using a simple printf function:

bloat<4>([](size_t i) {
    printf("%zu",i);
});

Compiler will produce and output the printf function 4 times each

Compile-Time Random Number Generator

This is actually not a random number generator, but it does generates different numbers at compile time, which might be used for creating complex control flow obfuscation functionality. Use it wisely as it could bloat the heavily the size of your binary.

C++ has an standar MACRO, which is supported by GCC, MSVC and CLANG, which is __TIME__, it will resolve at compilation phase, replacing the macro with the actual timestamp in Y-m-d H:m:s format, it can be used to generate a random 2-12 numbers range using constexpr in C++

constexpr unsigned int time_to_int(const char* time_str) {
    unsigned int hours = (static_cast<unsigned int>(time_str[0] - '0') * 10 +
        static_cast<unsigned int>(time_str[1] - '0'));
    unsigned int minutes = (static_cast<unsigned int>(time_str[3] - '0') * 10 +
        static_cast<unsigned int>(time_str[4] - '0'));
    unsigned int seconds = (static_cast<unsigned int>(time_str[6] - '0') * 10 +
        static_cast<unsigned int>(time_str[7] - '0'));
    return (hours * 3600) + (minutes * 60) + seconds;
}
int main() {
    constexpr unsigned int seed = (time_to_int(__TIME__) % 10) + 2;
    bloat<seed>([](size_t i) {
        printf("%zu",i);
    });
}

This will invoke printf different number of times in each compilation!

((E1∧E2)∧En−1)∧En(( E_1 \wedge E_2 ) \wedge E_n-1) \wedge E_n ((E1​∧E2​)∧En​−1)∧En​