以下六個程式片段皆能在 GCC 編譯通過(最後一個需 g++),完成相同任務:輸出 Hello, World,同時將原始碼混淆至極致。展示 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(0x48); putchar(0x65); ... }。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++]);
}
原理:利用 y 陣列初始值為 0,透過相加/相減 ASCII 差值構建字元碼存入 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)
}
原理:每個標籤輸出一字元並 goto 下一標籤,構成有限狀態機。z 輸出 \0 結束。
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 遞迴呼叫自身,參數 n 實為指標 m 遞增,putchar 輸出當前字元直到 \0。
main(){
int i, n[]={(((1<<1)<<(1<<1)<<(1<<1)<<(1<<(1>>1)))+((1<<1)<<(1<<1))),
(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<<(1<<1)<<(1<<1))+((1<<1)<<(1<<(1>>1)))+(1<<(1>>1))),
... // 共 14 個元素,全由 1、位移、加減構成
};
for(i=0; i<14; ++i) printf("%c", n[i]);
}
原理:完全不使用數字字面常數,僅用 1、位移、加減運算計算出每個字元的 ASCII 碼。
#include <stdio.h>
#define _(_) putchar(_);
int main(void){
int i = 0;
_(++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++i)
_(++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++i)
_(++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++i)
_(--++i)_(++++++i)_(------------------------------------------------i)
_(----------------i)_(++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++i)
_(----------------i)_(++++++i)_(------------i)_(--------i)_(-------------------------------i)
_(----------------------i)_(-------------------------------i) return i;
}
原理:利用大量 ++/-- 對 i 累加/遞減至目標 ASCII 碼,putchar 輸出。需 C++ 編譯器支援連續 ++(C 標準不允許對同一變數連續副作用)。