C/C + + Encrypted Functions

The antispy™ C/C + + Function Encryption is a two-factor mechanism to protect functions from reverse engineering. Functions are quickly identified and found in a binary by means of pattern matchings, heuristics, signatures, strings.

In our function encryption, the code is tagged and encrypted in a post-processing. At the duration of the application, the code is decrypted at short notice and then encrypted again. Combined with anti-debugging techniques, call corruption and string as well as value encryption, it is almost impossible to restore sensitive code using static or dynamic ana


lysis. Unlike our other features, this feature requires a bit more expertise and experience. Currently, this technique is only supported on Windows.

First, your CMakeLists.txt needs to add the following.

POST _ PROCESS _ PE (<executeable_name>)</executeable_name>

The code to be encrypted is then marked in the source code.

#include<antispy ncrypted_function.hpp=""></antispy>

ANTI _ SPY _ CRYPT _ FUNC _ START (void, encrypted _ procedure)
    std:: Cout< "encrypted_procedure="" called."="">< std::endl;></ std::endl;>
ANTI _ SPY _ CRYPT _ FUNC _ END (encrypted _ procedure)

ANTI _ SPY _ CRYPT _ FUNC _ START (int, encrypted _ function, int a, int b)
    std:: Cout< "encrypted_function="" returning="" "="">< a="" +="" b="">< std::endl;></ std::endl;>
    Return a + b;
ANTI _ SPY _ CRYPT _ FUNC _ END (encrypted _ function)

int main (int argc, const char * * argv)
    Ensons _ procedure ();
    Const int res = encrypted_function(2, 3);
    std:: Cout< "encrypted_function="" returned="" "="">< res="">< std::endl;></ std::endl;>
    Return 0;

Im Auge des Reverse Engineerers

Before encryption, the code in the dissassembler looks like this.

push offset aEncrypted _ proc; "Entitled _ procedure called."
push ds:?cout@std@@3V? $basic _ ostream @ DU? $char; std::: basic _ ostream<>><char>std:: cout</char>
call call sub_401EA0
add esp, 8
Mov ecx, eax
push offset sub_4039E0
Ccall ds:?? 6? $basic _ ostream @ DU? $char _ traits @ D @ std @ @std @ @QAEAAV01 @ P6AAAV01@AAV01@@Z@Z; std:: Basic _ ostream<><char>>::<><><char></char></>Operator > & (*) (std: basic _ ostream<><char></char></>> &))</char>

The real point of this feature is recognizable to an experienced reverse engineer within seconds.

After encryption, however, that's what the feature looks like.

Out 0DEh, al
Mov ebx, 2F0269Ah
Shr dword ptr[ebp+1Ah], cl
Jz short sub_401000
db 2Eh
aad 6Dh
pop ds
add esi, [eax-4Dh]
bound ebx, [edi]
or esi, ecx
sbb eax, 8658ABE0h

This code no longer has any relation to the original and the detected instructions are random. This means that a reverse engineer first falls completely in the dark during static analysis and at this time cannot directly conclude whether this code is virtualized or encrypted.