Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Programming Self-generating Code for Windows Applications

4.89/5 (742 votes)
29 Feb 2008CPOL4 min read 1   832  
Executing VC++ codes in STACK or HEAP

Introduction

Self-generating code technology is a very important means to counteract disassembler. You should use this technology to protect your applications although it's a "bad" programming style. There are two documented ways of modifying application code at least. First, kernel32.dll exports the WriteProcessMemory function, intended as follows from its name, for modifying the memory of a process. Second, practically all operating systems, Windows and Linux included, allow the code placed on the stack to be modified. I like the second way, because it is more freedom and less limitation when I try creating self-generating code for Windows applications in VC++ IDE. A FAQ is to cause an exception with the subsequent abnormal termination of the application.

Screenshot - error.jpg

I try to resolve these questions, and get some experience as follows:

The function code must be relocatable code:

  1. Only use local variable, don't use global variable, static variable, and constant string variable.
  2. If the function code wants to invoke another function, the pointer of the function should be passed to it.

Some may have a question about Self-generating code: What's the advantage of it?

The answer is that it can conceal crucial or key information, such as procedures for generating the key or for verifying the serial number.

Using the Code

Step 1: Encrypt My_function Code into a Header File

The following code is my function which I want to execute in the stack. Of course you can modify it, add your own code and test it, then you can get your own experience. If you like, you can share it here or write another article and publish it on The Code Project.

C++
//
void __stdcall my_function( int x,
     int y,
     char* str_a,
     char* str_b,
     void* (__cdecl *_memcpy )( void *dest, const void *src, size_t count ),
     int (__cdecl *_sprintf )( char *buffer, const char *format, ... ),
     void* (__cdecl *_malloc )( size_t size ),
     void (__cdecl *_free )( void *memblock ),
     size_t (__cdecl *_strlen )( const char *string ),
     int (__stdcall* _MessageBox)(HWND hWnd, LPCTSTR lpText, 
     LPCTSTR lpCaption, UINT uType)
)
{
    char* pTemp;
    int str_a_len=_strlen(str_a);
    int str_b_len=_strlen(str_b);   
    pTemp=(char*)_malloc(str_a_len+str_b_len+20);

    if(x>y)
    {
        //_sprintf(pTemp,"%s%s",str_a,str_b);       
        //error:constant string variable
        _memcpy(pTemp,str_a,str_a_len);
        _memcpy(pTemp+str_a_len,str_b,str_b_len);
        pTemp[str_a_len+str_b_len]=0;

        //_MessageBox(NULL,pTemp,"",MB_OK);         
        //error:constant string variable
        _MessageBox(NULL,pTemp,str_a,MB_OK);
    }
    else
    {
        //_sprintf(pTemp,"%s%s",str_b,str_a);
        //error:constant string variable
        _memcpy(pTemp,str_b,str_b_len);
        _memcpy(pTemp+str_b_len,str_a,str_a_len);
        pTemp[str_a_len+str_b_len]=0;

        //MessageBox(NULL,pTemp,"title",MB_OK);
        //error:constant string variable
        _MessageBox(NULL,pTemp,str_b,MB_OK); 
    }

    for(int i=0;i<10;i++)
    {
        int j=1;
        j^=i;
    }

    _free(pTemp);
}  
//

In my_function, I try to invoke some running time library functions and Windows API function, in order to compare parameter X and Y to display different message boxes.

In order to execute this function in the stack, first I should encrypt my_function code. This job is implemented in the project named My_function. If you read it, you can find a function named void __stdcall my_function_END(). In order to calculate the length of my function, my_function_END function must follow on the heels of my_function.

void encrypt_my_function() and bool encrypt_function(BYTE* _my_function,unsigned int n_my_function_size,char* function_name) are used to encrypt my_function code data into a temporary buffer, void build_h(BYTE* pInBuf,int InBufSize,char* function_name) function will write the encrypted code data into a header file.

C++
//
bool encrypt_function(BYTE* _my_function,unsigned int n_my_function_size,
    char* function_name)
{
    BYTE* buff=(BYTE*)malloc(n_my_function_size);
    if(buff==NULL) return false;

    //Note: Here is just a simple encryption algorithm,
    //you should replace it with your own.
    //There are a lot of encryption algorithms which you can get 
    //from the Internet.
    for(UINT i=0;i<n_my_function_size;i++) buff[i]=_my_function[i]^99;

    build_h(buff,n_my_function_size,function_name);
    free(buff);
    return true;
}

//
//
void encrypt_my_function()
{
    void ( __stdcall *_my_function)(int x,
        int y,
        char* str_a,
        char* str_b,
        void* (__cdecl *_memcpy )( void *dest, 
        const void *src, size_t count ),
        int (__cdecl *_sprintf )( char *buffer, const char *format, ... ),
        void* (__cdecl *_malloc )( size_t size ),
        void (__cdecl *_free )( void *memblock ),
        size_t (__cdecl *_strlen )( const char *string ),
        int (__stdcall* _MessageBox)(HWND hWnd, LPCTSTR lpText, 
        LPCTSTR lpCaption, UINT uType)
                                    );
    void ( __stdcall *_my_function_END)();
    unsigned int n_my_function_size;
    char* function_name="myfunction";

    _my_function=my_function;
    _my_function_END=my_function_END;
    n_my_function_size=abs((UINT)_my_function_END-(UINT)_my_function)+1;
    //calculate the length of my_function

    if(encrypt_function((BYTE*)_my_function,n_my_function_size,function_name))
    {
        AfxMessageBox(
            "My function is encrypted successfully ! 
            The encrypted code is included in myfunction.h file.");
    }
    else
    {
        AfxMessageBox("My function is encrypted unsuccessfully !");
    }
}
//

Myfunction.h is generated by My_function project.

A header file which includes the encrypted code data would look as follows:

C++
//
//myfunction.h

unsigned char myfunction_00001_code[]="\
\xe8\x27\x47\x6f\x30\x36\x35\xe8\x17\x47\x53\x34\x33\
x9c\xb5\xe8\x0f\x47\x47\xe8\
\x9b\x36\x9c\xb5\xe8\xbb\xee\x2f\x58\x77\x32\x9c\x37\
x47\x5b\xe8\x37\x47\x43\xe8\
\x93\xe8\x27\x47\x47\xe0\xa7\x6f\x58\xb3\x1d\x5f\xe8\
x27\x47\x7f\x34\x33\x35\x9c\
\x37\x47\x53\x30\xee\x6f\x5d\x36\x32\x9c\x37\x47\x5f\
xe8\x27\x47\x57\xe0\xa7\x7b\
\xee\x77\x7d\x09\x63\x33\x35\x09\x63\xa5\x67\x59\x63\
x9c\x37\x47\x2b\x35\x9c\x37\
\x47\x57\xe0\xa7\x67\x3c\x3d\x3e\x38\xa1\x4b\x63\x30\
x36\x35\x9c\x37\x47\x53\xe8\
\x2f\x47\x4b\x60\xbd\x34\x32\x30\x9c\x37\x47\x5f\xe0\
xa7\x7b\xa5\x67\x58\x63\x09\
\x63\x0b\x17\x33\x23\x63\x35\x09\x63\x9c\x76\x1b\x50\
x23\x63\x09\x63\x36\x35\x09\
\x63\x9c\x37\x47\x2b\x35\x9c\x37\x47\x57\xe0\xa7\x67\
x3c\x3d\x3e\x38\xa1\x4b\x63\
\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xa0";
#define myfunction_00001_code_LEN 193

#define myfunction_ARRAY_NUM 1
#define myfunction_CODE_LEN 193

//

Note: If you want to define an unsigned char variable like unsigned char myfunction_00001_code[], it's maxlength is 2048. This is the limitation of VC++ 6.0 IDE. So, if the function code is too long, I must write the encrypted code data into multi unsigned char variables.This function can be realized in build_h which looks as follows:

C++
//
void build_h(BYTE* pInBuf,int InBufSize,char* function_name)
{
    DWORD syslen=InBufSize;
    BYTE* sysbuffer=pInBuf;

    char hname[MAX_PATH];
    sprintf(hname,"%s%s",function_name,".h");

    HANDLE hHandle=CreateFileA(hname,
        GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);

    SetFilePointer(hHandle,0,0,FILE_BEGIN);

    DWORD RW;
    char _code_end[]="\";
    int l_end=strlen(&_code_end[0]);

    char cname[MAX_PATH];
    char* pszSlash=hname;

    char TX[5];
    int count=0;
    int arrary_num=1;
    int ar_num=0;

    WriteFile(hHandle,"\r",1,&RW,NULL);
    WriteFile(hHandle,"\n",1,&RW,NULL);

    WriteFile(hHandle,"//",2,&RW,NULL);
    WriteFile(hHandle,hname,strlen(hname),&RW,NULL);
    WriteFile(hHandle,"\r",1,&RW,NULL);
    WriteFile(hHandle,"\n",1,&RW,NULL);
    WriteFile(hHandle,"\r",1,&RW,NULL);
    WriteFile(hHandle,"\n",1,&RW,NULL);

    WriteFile(hHandle,
        "//Created by Your Name",strlen("//Created by Your Name"),&RW,NULL);
    WriteFile(hHandle,"\r",1,&RW,NULL);
    WriteFile(hHandle,"\n",1,&RW,NULL);

    WriteFile(hHandle, "//your email", strlen("//your email"), &RW, NULL);

    WriteFile(hHandle,"\r",1,&RW,NULL);
    WriteFile(hHandle,"\n",1,&RW,NULL);

    for(UINT i=0;i<syslen;i++){
        if(ar_num==0){
            WriteFile(hHandle,"\r",1,&RW,NULL);
            WriteFile(hHandle,"\n",1,&RW,NULL);

            int ee=sprintf(cname,"%s","unsigned char ");
            ee+=sprintf(cname+ee,"%s",pszSlash);
            ee=ee-2;
            ee+=sprintf(cname+ee,"%s%05d","_",arrary_num);
            ee=sprintf(cname+ee,"%s",_code[]=\"\\\r\n");
            int l=strlen(&cname[0]);
            WriteFile(hHandle,cname,l,&RW,NULL);
        }

        WriteFile(hHandle,"\\x",2,&RW,NULL);
        sprintf(TX,"%02x",sysbuffer[i]);
        WriteFile(hHandle,TX,2,&RW,NULL);
        count++;
        ar_num=ar_num+4;

        if (count==20){
        count=0;
        WriteFile(hHandle,"\\",1,&RW,NULL);
        WriteFile(hHandle,"\r",1,&RW,NULL);
        WriteFile(hHandle,"\n",1,&RW,NULL);
        }

        if(ar_num>2030){

        arrary_num=arrary_num+1;
        WriteFile(hHandle,_code_end,l_end,&RW,NULL);

        WriteFile(hHandle,"\r",1,&RW,NULL);
        WriteFile(hHandle,"\n",1,&RW,NULL);

        char len[MAX_PATH];
        int ee=sprintf(len,"%s","#define ");
        ee+=sprintf(len+ee,"%s",cname+14);
        ee=ee-7;
        ee+=sprintf(len+ee,"%s","_LEN ");
        ee+=sprintf(len+ee,"%d",ar_num/4);
        WriteFile(hHandle,len,ee,&RW,NULL);

        WriteFile(hHandle,"\r",1,&RW,NULL);
        WriteFile(hHandle,"\n",1,&RW,NULL);

        ar_num=0;
        count=0;
        }
    } 

    double yushu=fmod(syslen*1.0,508.0);
    if(yushu!=0){
        WriteFile(hHandle,_code_end,l_end,&RW,NULL);

        WriteFile(hHandle,"\r",1,&RW,NULL);
        WriteFile(hHandle,"\n",1,&RW,NULL);

        char len[MAX_PATH];
        int ee=sprintf(len,"%s","#define ");
        ee+=sprintf(len+ee,"%s",cname+14);
        ee=ee-7;
        ee+=sprintf(len+ee,"%s","_LEN ");
        ee+=sprintf(len+ee,"%d",ar_num/4);
        WriteFile(hHandle,len,ee,&RW,NULL);

        WriteFile(hHandle,"\r",1,&RW,NULL);
        WriteFile(hHandle,"\n",1,&RW,NULL);
    }

    WriteFile(hHandle,"\r",1,&RW,NULL);
    WriteFile(hHandle,"\n",1,&RW,NULL);

    char lLen[MAX_PATH];
    int ee=sprintf(lLen,"%s","#define ");
    ee+=sprintf(lLen+ee,"%s",cname+14);
    ee=ee-17;
    ee+=sprintf(lLen+ee,"%s","ARRAY_NUM ");
    ee+=sprintf(lLen+ee,"%d",arrary_num);


    WriteFile(hHandle,lLen,ee,&RW,NULL);

    WriteFile(hHandle,"\r",1,&RW,NULL);
    WriteFile(hHandle,"\n",1,&RW,NULL);


    ee=sprintf(lLen,"%s","#define ");
    ee+=sprintf(lLen+ee,"%s",cname+14);
    ee=ee-17;
    ee+=sprintf(lLen+ee,"%s","CODE_LEN ");
    ee+=sprintf(lLen+ee,"%d",syslen);


    WriteFile(hHandle,lLen,ee,&RW,NULL);

    WriteFile(hHandle,"\r",1,&RW,NULL);
    WriteFile(hHandle,"\n",1,&RW,NULL);
    CloseHandle(hHandle);
}
//

After generating myfunction.h which includes the encrypted code data of my_funcion, I create a project named self_engendered_code. In this project, My_function is decrypted and then executed in the stack or any other memory buffer such as heap buffer allocated by malloc although some consider that it is not permitted.

Step 2: Decrypt My_function Code and Execute

First, include myfunction.h in the self_engendered_code project. Second, define some macro in order to load the multi unsigned char variables into one memory buffer.

C++
//
#include "..\\\self_engendered_code\\My_function\\myfunction.h"
#define _founc(x) myfunction_##x##_code
#define _founc_len(x) myfunction_##x##_code_LEN
unsigned char p_my_function[1024];
//

void Load_my_function() can decrypt My_function code into a memory buffer: p_my_function here is a global variable. It can be replaced with a local variable which is defined in the function body, that is the local function stack.

C++
//
void Load_my_function()
{
    int code_len=myfunction_CODE_LEN;
    unsigned char* pcode=
        (unsigned char*)malloc(code_len*sizeof(unsigned char));

    if(pcode==NULL)
    {
        #ifdef _DEBUG
            AfxMessageBox("Memory used up!");
        #endif

        return;
    }

    int p;
    int hp=0;

    for(int k=1;k<=myfunction_ARRAY_NUM;k++)
    {
        switch (k)
        {
        //The number of case equal to myfunction_ARRAY_NUM 
        //defined in myfunction.h.
            case 1:
                for(p=0;p<_founc_len(00001);p++) pcode[hp+p]=_founc(00001)[p];
                hp=hp+p;
                break;
            /*
            case 2:
                for(p=0;p<_founc_len(00002);p++) pcode[hp+p]=_founc(00002)[p];
                hp=hp+p;
                break;
            case 3:
                for(p=0;p<_founc_len(00003);p++) pcode[hp+p]=_founc(00003)[p];
                hp=hp+p;
                break;
            case 4:
                for(p=0;p<_founc_len(00004);p++) pcode[hp+p]=_founc(00004)[p];
                hp=hp+p;
            break;
            .
            .
            .

            */
            default:
            break;
        } 
    }

    //Note: Here is just a simple encryption algorithm, you should 
    //replace it with your own.
    //There are a lot of encryption algorithms which you can get 
    //from the Internet. 
    for(int i=0;i<code_len;i++) p_my_function[i]=pcode[i]^99;
}
//

At last, execute My_function in the STACK.

C++
//
void Run_my_function()
{
    int x=1;//8
    int y=2;
    char str_a[]=" HELLO MY_FOUNCTION ! ";
    char str_b[]=" Hello my_function ! ";

    void* (__cdecl *_memcpy )( void *dest, const void *src, size_t count );
    int (__cdecl *_sprintf )( char *buffer, const char *format, ... );
    void* (__cdecl *_malloc )( size_t size );
    void (__cdecl *_free )( void *memblock );
    size_t (__cdecl *_strlen )( const char *string );
    int (__stdcall* _MessageBox)(HWND hWnd, LPCTSTR lpText, 
        LPCTSTR lpCaption, UINT uType);

    _memcpy=memcpy;
    _sprintf=sprintf;
    _malloc=malloc;
    _free=free;
    _strlen=strlen;
    _MessageBox=MessageBox;

    void ( __stdcall *_my_function)(int x,
        int y,
        char* str_a,
        char* str_b,
        void* (__cdecl *_memcpy )( void *dest, 
        const void *src, size_t count ),
        int (__cdecl *_sprintf )( char *buffer, const char *format, ... ),
        void* (__cdecl *_malloc )( size_t size ),
        void (__cdecl *_free )( void *memblock ),
        size_t (__cdecl *_strlen )( const char *string ),
        int (__stdcall* _MessageBox)(HWND hWnd, LPCTSTR lpText, 
        LPCTSTR lpCaption, UINT uType)
                                    );
    _my_function=(void ( __stdcall *)(int x,
        int y,
        char* str_a,
        char* str_b,
        void* (__cdecl *_memcpy )( void *dest, 
        const void *src, size_t count ),
        int (__cdecl *_sprintf )( char *buffer, const char *format, ... ),
        void* (__cdecl *_malloc )( size_t size ),
        void (__cdecl *_free )( void *memblock ),
        size_t (__cdecl *_strlen )( const char *string ),
        int (__stdcall* _MessageBox)(HWND hWnd, LPCTSTR lpText, 
        LPCTSTR lpCaption, UINT uType)
        )) &p_my_function[0];

    _my_function(x,
                 y,
                 str_a,
                 str_b,
                 _memcpy,
                 _sprintf,
                 _malloc,
                 _free,
                 _strlen,
                 _MessageBox
                 );
}
//

Summary

If you want to conceal crucial information, you shouldn't invoke the MessageBox API function. Certainly, the resistance of this protection is insignificant. However, it may be increased. There are numerous programming tips for this purpose, including dynamic asynchronous decoding, substituting the results of comparison for factors in various expressions, and placing the crucial part of code directly in the key. However self-generating code technology is so important that it has been adopted by Antidebug LIB. The purpose of this article is not to offer ready-to-use protection (which hackers could study), but to prove and show that it is possible theoretically to create self-generating code under the control of Windows. How to make use of this possibility is your task.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)