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.
I try to resolve these questions, and get some experience as follows:
The function code must be relocatable code:
- Only use local variable, don't use global variable, static variable, and constant string variable.
- 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.
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)
{
_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,str_a,MB_OK);
}
else
{
_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,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.
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;
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;
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:
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:
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," 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.
#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.
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)
{
case 1:
for(p=0;p<_founc_len(00001);p++) pcode[hp+p]=_founc(00001)[p];
hp=hp+p;
break;
default:
break;
}
}
for(int i=0;i<code_len;i++) p_my_function[i]=pcode[i]^99;
}
At last, execute My_function
in the STACK.
void Run_my_function()
{
int x=1; 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.