以下六個程式片段皆能輸出 Hello, World,卻將原始碼混淆至極致。前五個可在 GCC 編譯通過,最後一個需 G++(C++ 編譯器)。這不僅是技巧展示,更能加深對預處理器、指標運算、位運算與控制流的理解。
#define _________ }
#define ________ putchar
#define _______ main
#define _(a) ________(a);
#define ______ _______(){
#define __ ______ _(0x48)_(0x65)_(0x6C)_(0x6C)
#define ___ _(0x6F)_(0x2C)_(0x20)_(0x77)_(0x6F)
#define ____ _(0x72)_(0x6C)_(0x64)_(0x21)
#define _____ __ ___ ____ _________
#include<stdio.h>
_____
利用巨集遞迴展開,將 main(){ putchar(...); } 拆解為單字元輸出,十六進位碼對應 ASCII:0x48=H、0x65=e... 最後 _____ 展開為完整函數。
#include<stdio.h>
main(){
int x=0,y[14],*z=&y;*(z++)=0x48;*(z++)=y[x++]+0x1D;
*(z++)=y[x++]+0x07;*(z++)=y[x++]+0x00;*(z++)=y[x++]+0x03;
*(z++)=y[x++]-0x43;*(z++)=y[x++]-0x0C;*(z++)=y[x++]+0x57;
*(z++)=y[x++]-0x08;*(z++)=y[x++]+0x03;*(z++)=y[x++]-0x06;
*(z++)=y[x++]-0x08;*(z++)=y[x++]-0x43;*(z++)=y[x]-0x21;
x=*(--z);while(y[x]!=NULL)putchar(y[x++]);
}
透過指標 z 遍歷陣列 y,利用位移量編碼字元,最後反向輸出。展示指標運算的靈活與危險。
#include<stdio.h>
#define __(a) goto a;
#define ___(a) putchar(a);
#define _(a,b) ___(a) __(b);
main()
{ _:__(t)a:_('r',g)b:_('$',p)
c:_('l',f)d:_(' ',s)e:_('a',s)
f:_('o',q)g:_('l',h)h:_('d',n)
i:_('e',w)j:_('e',x)k:_('\n',z)
l:_('H',l)m:_('X',i)n:_('!',k)
o:_('z',q)p:_('q',b)q:_(',',d)
r:_('i',l)s:_('w',v)t:_('H',j)
u:_('a',a)v:_('o',a)w:_(')',k)
x:_('l',c)y:_('\t',g)z:___(0x0)}
將輸出流程拆解為標籤跳轉,每個標籤輸出一字元並跳往下一標籤,構成隱式有限狀態機。
int n[]={0x48,0x65,0x6C,0x6C,0x6F,0x2C,0x20,0x77,0x6F,0x72,0x6C,0x64,0x21,0x0A,0x00},*m=n;
main(n){putchar(*m)!='\0'?main(m++):exit(n++);}
利用 main 遞迴呼叫自身,配合指標遞增遍歷字元陣列,遇結束符 \0 則退出。展示遞迴替代迴圈的技巧。
main(){int i,n[]={(((1<<1)<<(1<<1)<<(1<<1)<<(1<<(1>>1)))+((1<<1)<<(1<<1))), ... }; for(i=(1>>1);i<(((1<<1)<<(1<<1))+((1<<1)<<(1<<(1>>1)))+(1<<1));i++) printf("%c",n[i]);}
所有字元碼(ASCII)均由 1 的左移、右移、加減運算組合而成,零硬編碼數值。極致展示位運算的表達能力。
#include <stdio.h>
#define _(_) putchar(_);
int main(void){int i = 0;_(++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++i)_(++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++i)_(++++++++++++++++++++++++++++++++++++++++++++++++++++++++i)_(--++i)_(++++++i)_(------...i)_(----------------i)_(++++++i)_(------------i)_(--------i)_(----------------------------i)_(------------------i)return i;}
利用大量 ++/-- 運算子疊加產生目標 ASCII 碼,僅 C++ 允許此類運算子連續作用於同一變數(C 標準未定義行為)。
這些寫法雖展示語言特性邊界,但實務中應極力避免。良好的代碼應清晰表達意圖,而非炫技。理解它們有助於看懂混淆代碼、逆向分析與編譯器原理,但請勿在生產環境模仿。