Skip to content

A utility for hiding strings in your compiled C/C++ binary

Notifications You must be signed in to change notification settings

wizardy0ga/FormCrypt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Typing SVG

A string obfuscation tool for C/C++




Project Info

FormCrypt is a tool for encrypting strings in your C code. The string will be hidden in a structure that mimics an x86 or x64 assembly function. This tool was inspired by the string obfuscation methods used by the FormBook malware variant, which is described in this research article.

Technical Info

FormBook used encrypted buffers known as 'enc_bufs' to hide its strings. These buffers attempted to masquerade as functions by pre-pending a function prologue at the beginning of the buffer. When this data is viewed in a disassembler, a function prologue will appear. At first glance, it will appear to be a function. If looked at closer, the 'function' can quickly turn to garble.

FormBook Function Prolog

Image sourced from Arbor Networks

Further reading about FormBook can be found in this stormshield article or in this article from arbor networks.

How This Implementation Works

FormCrypt attempts to mimic the obfuscation technique employed by the FormBook malware. FormCrypt provides the C code necessary for hiding strings which will appear as functions in a disassembler. It does this by pre-pending a function prologue & epilogue to the encrypted buffer. Each string is encrypted with the RC4 cipher which has been modified to extract the encryption key for the buffer prior to processing the data.

The ENCRYPTED_BUFFER structure is shown below. The Key member is allocated enough space to pre-pend the function prologue. This structure is only intended to be created with the NEW_BUFFER macro.

typedef struct _ENCRYPTED_BUFFER {
	char Key[PROLOGUE_SIZE + KEY_SIZE];
	char Buffer[];
} ENCRYPTED_BUFFER, * PENCRYPTED_BUFFER;

This is the NEW_BUFFER macro. When called, the macro will inject the function prologue & epilogue at the beginning & and of the structure respectively. A null byte is also injected between the Ciphertext and FUNCTION_EPILOG placements. The null byte allows DecryptRc4Buffer to calculate the correct string length for decrypting the data so that the epilogue is not processed.

#define NEW_BUFFER(VariableName, Ciphertext, Cipherkey) \
	ENCRYPTED_BUFFER VariableName = {                   \
		.Key	= { FUNCTION_PROLOG, Cipherkey },       \
		.Buffer = { Ciphertext, 0x00, FUNCTION_EPILOG } \
	}                                                   \

In the examples below, the string HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run has been hidden in an encrypted buffer generated with the FormCrypt utility.

x64 Encrypted Buffer Disassembly

x64 Demo Buffer

x64 Encrypted Buffer Memory Dump

x64 Buffer Dump (Encrypted)

x64 Decrypted Buffer Memory Dump

x64 Buffer Dump (Decrypted)

Usage

FormCrypt.py

To start, you'll need to encrypt your strings with the FormCrypt.py script. The script will accept your strings as key value pairs from the command line or an input file. Use python FormCrypt.py -h for further information about the arguments.

The key value pairs are separated by an = sign. The left half represents the name of the variable to create for the ENCRYPTED_BUFFER structure and the right half sets the string value contained by the encrypted buffer.

MyEncryptedBuffer=HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

The script will produce two files using the names FormCrypt.c & FormCrypt.h. These files contain the code & variable definitions necessary to create & process your encrypted strings.

Integration Into Your Codebase

Include the FormCrypt.h in the part of your project codebase where you need to access the functions or strings. By default, the structures are defined globally in the FormCrypt.h header file. You can move these to a local function if desired.

FormCrypt.h Exports

Name Type Description
DecryptRc4Buffer( PENCRYPTED_BUFFER pEncryptedBuffer ) Function Used for decrypting or re-encrypting an encrypted buffer. Takes a pointer to the structure as an argument.

To decrypt or re-encrypt your buffer, just call DecryptRc4Buffer with a pointer to the structure you want to decrypt as an argument.

Example Code

#include <stdio.h>

/* ---------------- FormCrypt.h ----------------------*/
#define SHADOW_SPACE_SIZE 0x20
#define KEY_SIZE 12
#ifndef ARCH_X86
#define PROLOGUE_SIZE 8
#define FUNCTION_PROLOG 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, SHADOW_SPACE_SIZE
#define FUNCTION_EPILOG 0xCC, 0xCC, 0xCC, 0x48, 0x83, 0xC4, SHADOW_SPACE_SIZE, 0x5D, 0xC3
#endif
#ifdef ARCH_X86
#define PROLOGUE_SIZE 6
#define FUNCTION_PROLOG 0xCC, 0xCC, 0xCC, 0x55, 0x8B, 0xEC
#define FUNCTION_EPILOG 0xCC, 0xCC, 0xCC, 0x89, 0xEC, 0x5D, 0xC3
#endif

typedef struct _ENCRYPTED_BUFFER {
    char Key[PROLOGUE_SIZE + KEY_SIZE];
    char Buffer[];
} ENCRYPTED_BUFFER, * PENCRYPTED_BUFFER;

void DecryptRc4Buffer(PENCRYPTED_BUFFER pEncryptedBuffer);

#define NEW_BUFFER(VariableName, Ciphertext, Cipherkey) \
	ENCRYPTED_BUFFER VariableName = {                   \
		.Key	= { FUNCTION_PROLOG, Cipherkey },       \
		.Buffer = { Ciphertext, 0x00, FUNCTION_EPILOG } \
	}                                                   \

#define MYENCRYPTEDBUFFER_TEXT 0x32,0xE2,0x11,0xA8,0x9C,0x4B,0x24,0x0D,0xD4,0x86,0x49,0x71,0xAF,0xE1,0x3C,0x29,0x8C,0x86,0x14,0xC2,0x60,0x45,0x33,0xC5,0x82,0xF5,0x7E,0x9F,0xEB,0x19,0x29,0xAB,0xD7,0xDF,0x4F,0x06,0x75,0xC0,0x61,0x41,0x18,0xEA,0x98,0xCD,0x3E,0xEF,0xE1,0x88,0x5C,0x88,0x80
#define MYENCRYPTEDBUFFER_KEY 0xE4,0x26,0xAF,0x28,0x47,0x03,0x87,0xB0,0xE1,0x97,0x76,0x74

NEW_BUFFER(MyEncryptedBuffer, MYENCRYPTEDBUFFER_TEXT, MYENCRYPTEDBUFFER_KEY);

/*---------------- End FromCrypt.h -----------------------*/

/* --------------- FormCrypt.c --------------------------*/
#ifdef ARCH_X86

unsigned int StringLengthA(const char* String)
{
    const char* String2;

    for (String2 = String; *String2; ++String2);

    return (String2 - String);
}

#endif

#ifndef ARCH_X86

unsigned long long StringLengthA(const char* String)
{
    const char* String2;

    for (String2 = String; *String2; ++String2);

    return (String2 - String);
}

#endif

void DecryptRc4Buffer(PENCRYPTED_BUFFER pEncryptedBuffer) {
    unsigned char S[256];
    unsigned char TrueKey[KEY_SIZE];
    unsigned char temp;
    unsigned int i, j = 0, k;

    // Seperate key from fake function prologue
    for (int x = 0; x < KEY_SIZE; x++) {
        TrueKey[x] = pEncryptedBuffer->Key[PROLOGUE_SIZE + x];
    }

    // Key Scheduling Algorithm (KSA)
    for (i = 0; i < 256; i++) {
        S[i] = i;
    }
    for (i = 0; i < 256; i++) {
        j = (j + S[i] + TrueKey[i % KEY_SIZE]) % 256;
        temp = S[i];
        S[i] = S[j];
        S[j] = temp;
    }

    // Pseudo-Random Generation Algorithm (PRGA)
    i = j = 0;
    for (k = 0; k < StringLengthA(pEncryptedBuffer->Buffer); k++) {
        i = (i + 1) % 256;
        j = (j + S[i]) % 256;
        temp = S[i];
        S[i] = S[j];
        S[j] = temp;
        pEncryptedBuffer->Buffer[k] ^= S[(S[i] + S[j]) % 256];
    }
}
/* ----------------- End FormCrypt.c -------------------*/

int main() {

    printf("[+] Encrypted buffer is located at 0x%p.\n\t> Press enter to decrypt buffer.", &MyEncryptedBuffer);
    getchar();
    
    DecryptRc4Buffer(&MyEncryptedBuffer);
    printf("[+] Decrypted buffer. Content: %s\n\t> Press enter to re-encrypt buffer.", MyEncryptedBuffer.Buffer);
    getchar();

    DecryptRc4Buffer(&MyEncryptedBuffer);
    printf("[+] Re-encrypted buffer.\n\t> Press enter to decrypt buffer.");
    getchar();

    DecryptRc4Buffer(&MyEncryptedBuffer);
    printf("[+] Decrypted buffer. Content: %s\n\t> Press enter to re-encrypt buffer.", MyEncryptedBuffer.Buffer);
    getchar();
    
    DecryptRc4Buffer(&MyEncryptedBuffer);
    printf("[+] Re-encrypted buffer.\n\t> Press enter to quit.");
    getchar();
    
    return 0;
}

About

A utility for hiding strings in your compiled C/C++ binary

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published