В программной инженерии обфускация – это намеренное действие по созданию исходного или машинного кода, который людям трудно понять. Несколько преимуществ обфускации кода включают безопасность и оптимизацию, но в основном программисты обладают особым чувством юмора, которое удовлетворяет обфускация. Существует такой интерес к обфускации кода, что существует Международный конкурс запутанного кода C, который представляет собой ежегодное соревнование по компьютерному программированию специально для творений, созданных с использованием запутанного кода C. Победитель IOCCC 1986 года Джим Хейг порадовал нас этой красотой:

#define DIT (
#define DAH )
#define __DAH   ++
#define DITDAH  *
#define DAHDIT  for
#define DIT_DAH malloc
#define DAH_DIT gets
#define _DAHDIT char
_DAHDIT _DAH_[]="ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:"
;main           DIT         DAH{_DAHDIT
DITDAH          _DIT,DITDAH     DAH_,DITDAH DIT_,
DITDAH          _DIT_,DITDAH        DIT_DAH DIT
DAH,DITDAH      DAH_DIT DIT     DAH;DAHDIT
DIT _DIT=DIT_DAH    DIT 81          DAH,DIT_=_DIT
__DAH;_DIT==DAH_DIT DIT _DIT        DAH;__DIT
DIT'\n'DAH DAH      DAHDIT DIT      DAH_=_DIT;DITDAH
DAH_;__DIT      DIT         DITDAH
_DIT_?_DAH DIT      DITDAH          DIT_ DAH:'?'DAH,__DIT
DIT' 'DAH,DAH_ __DAH    DAH DAHDIT      DIT
DITDAH          DIT_=2,_DIT_=_DAH_; DITDAH _DIT_&&DIT
DITDAH _DIT_!=DIT   DITDAH DAH_>='a'?   DITDAH
DAH_&223:DITDAH     DAH_ DAH DAH;       DIT
DITDAH          DIT_ DAH __DAH,_DIT_    __DAH DAH
DITDAH DIT_+=       DIT DITDAH _DIT_>='a'?  DITDAH _DIT_-'a':0
DAH;}_DAH DIT DIT_  DAH{            __DIT DIT
DIT_>3?_DAH     DIT          DIT_>>1 DAH:'\0'DAH;return
DIT_&1?'-':'.';}__DIT DIT           DIT_ DAH _DAHDIT
DIT_;{DIT void DAH write DIT            1,&DIT_,1 DAH;}

Что происходит, когда вышеперечисленное скомпилировано с использованием gcc? Что ж, взгляните:

#define DIT (
#define DAH )
#define __DAH   ++
#define DITDAH  *
#define DAHDIT  for
#define DIT_DAH malloc
#define DAH_DIT gets
#define _DAHDIT char
_DAHDIT _DAH_[]="ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:"
;main           DIT         DAH{_DAHDIT
DITDAH          _DIT,DITDAH     DAH_,DITDAH DIT_,
DITDAH          _DIT_,DITDAH        DIT_DAH DIT
DAH,DITDAH      DAH_DIT DIT     DAH;DAHDIT
DIT _DIT=DIT_DAH    DIT 81          DAH,DIT_=_DIT
__DAH;_DIT==DAH_DIT DIT _DIT        DAH;__DIT
DIT'\n'DAH DAH      DAHDIT DIT      DAH_=_DIT;DITDAH
DAH_;__DIT      DIT         DITDAH
_DIT_?_DAH DIT      DITDAH          DIT_ DAH:'?'DAH,__DIT
DIT' 'DAH,DAH_ __DAH    DAH DAHDIT      DIT
DITDAH          DIT_=2,_DIT_=_DAH_; DITDAH _DIT_&&DIT
DITDAH _DIT_!=DIT   DITDAH DAH_>='a'?   DITDAH
DAH_&223:DITDAH     DAH_ DAH DAH;       DIT
DITDAH          DIT_ DAH __DAH,_DIT_    __DAH DAH
DITDAH DIT_+=       DIT DITDAH _DIT_>='a'?  DITDAH _DIT_-'a':0
DAH;}_DAH DIT DIT_  DAH{            __DIT DIT
DIT_>3?_DAH     DIT          DIT_>>1 DAH:'\0'DAH;return
DIT_&1?'-':'.';}__DIT DIT           DIT_ DAH _DAHDIT
DIT_;{DIT void DAH write DIT            1,&DIT_,1 DAH;}
julien@ubuntu:~/c/ioccc$ gcc hague.c -o h
hague.c:10:2: warning: return type defaults to ‘int’ [-Wimplicit-int]
 ;main   DIT   DAH{_DAHDIT
  ^
hague.c: In function ‘main’:
hague.c:6:17: warning: conflicting types for built-in function ‘malloc’
 #define DIT_DAH malloc
                 ^
hague.c:12:24: note: in expansion of macro ‘DIT_DAH’
 DITDAH   _DIT_,DITDAH  DIT_DAH DIT
                        ^
hague.c:15:35: warning: implicit declaration of function ‘__DIT’ [-Wimplicit-function-declaration]
 __DAH;_DIT==DAH_DIT DIT _DIT  DAH;__DIT
                                   ^
hague.c:18:7: warning: implicit declaration of function ‘_DAH’ [-Wimplicit-function-declaration]
 _DIT_?_DAH DIT  DITDAH   DIT_ DAH:'?'DAH,__DIT
       ^
hague.c: At top level:
hague.c:25:6: warning: return type defaults to ‘int’ [-Wimplicit-int]
 DAH;}_DAH DIT DIT_ DAH{   __DIT DIT
      ^
hague.c: In function ‘_DAH’:
hague.c:25:6: warning: type of ‘DIT_’ defaults to ‘int’ [-Wimplicit-int]
hague.c: At top level:
hague.c:27:17: warning: return type defaults to ‘int’ [-Wimplicit-int]
 DIT_&1?'-':'.';}__DIT DIT   DIT_ DAH _DAHDIT
                 ^
hague.c: In function ‘__DIT’:
hague.c:28:20: warning: implicit declaration of function ‘write’ [-Wimplicit-function-declaration]
 DIT_;{DIT void DAH write DIT   1,&DIT_,1 DAH;}
                    ^
/tmp/ccG1Yh1A.o: In function `main':
hague.c:(.text+0x14a): warning: the `gets' function is dangerous and should not be used.

Мы получаем кучу довольно загадочных предупреждений, но программа все равно скомпилируется и запустится. И что делает эта программа? Он переводит слова на английском языке в азбуку Морзе. Как? Через макросы! По сути, макросы — это одна из директив препроцессора, доступных в C. Подстановка макросов — это процесс, в котором идентификатор в программе заменяется предопределенной строкой. Почему программисты используют макросы? Потому что программисты ленивы. Замена чего-то более длинного на что-то более короткое имеет смысл для ленивых.

Определение макроса имеет следующий вид:

#define идентификаторстрока

Пока макросы определены в соответствии с приведенным выше синтаксисом, компилятор сможет перевести наш исходный код на машинный язык.

Теперь давайте «деобфусцируем» наш код. Наиболее важные макросы, на которые стоит обратить внимание:

  • _DIT станет строкой
  • DAH_ станет c
  • DAHDIT станет для

Теперь, когда у нас есть представление о том, что такое макросы и как они используются, давайте посмотрим, что выводит программа Джеймса Хейга:

$ ./h 
Hello, World
.... . .-.. .-.. --- --..-- / .-- --- .-. .-.. -..

довольно аккуратный