今天和同事聊到「真搞不懂為什麼某些人那麼容易中毒?」這個話題時,剛好心血來潮,順手示範了一個從前曾拿來整人用的老把戲。

這個把戲就是用 linker 把某個二進制資料嵌入到執行檔中,變成其中一個區段。當然,其中沒什麼高深的學問,只是因為很多人沒有仔細玩過 binutils,不曉得 ld 有這樣的功能。

懶得打字,直接貼程式碼。首先是 Makefile,為了和 MinGW 行為相容,以下所有的執行檔都刻意加上 exe 副檔名,對 Linux 沒影響。(提醒一下,如果要複製去玩的話,別忘了把空白改 tab)

all: wrapper.exe

wrapper.exe: payload.exe wrapper.c
    gcc -c -o wrapper.o wrapper.c
    ld -Ur -o payload.exe.o -b binary payload.exe
    gcc -o wrapper.exe wrapper.o payload.exe.o

payload.exe: payload.c
    gcc -o payload.exe -O2 -s payload.c

clean:
    rm *.o *.exe

payload.exe 是什麼並不重要,可以放個最簡單的 Hello World,或者乾脆抽換成圖檔、音樂檔等等。

重點在於 wrapper.c

#include <stdio.h>

extern const char _binary_payload_exe_start[];
extern const char _binary_payload_exe_end[];
extern const char _binary_payload_exe_size[];

int main()
{
    const size_t payloadSize = (size_t) ((void*)_binary_payload_exe_size);
    const char* payload = _binary_payload_exe_start;
    printf("size=%u \n", payloadSize);

    FILE* outfile = fopen("qwerty.exe", "wb");
    fwrite(payload, sizeof(char), payloadSize, outfile);
    fclose(outfile);
}

剛剛嵌入的二進制檔案,在程式碼中可以透過 _binary_<檔名>_start 等變數存取,檔名中的特殊字元好像會被換成底線。另一點需要注意的是,隨者 toolchain 版本的不同,變數名稱開頭也可能沒有底線,建議先用 objdump 看看實際的 symbol 變成什麼。

上面的 wrapper 程式會把被內嵌的 payload 原封不動寫出成檔案 qwerty.exe,只要具有執行權限就能執行。

應用的情境之一: 用圖檔當成 payload,把 wrapper 換成圖檔的圖示。當使用者執行 wrapper 時,將圖檔解到 temp 資料夾下然後用預設圖片瀏覽器開啟,使用者會誤以為自己確實點選了圖檔,此時 wrapper 可以在背後做其他事.....

題外話,我一直搞不懂這件事:Windows 明明就是用副檔名辨識執行檔,可是為什麼系統偏偏預設隱藏副檔名。真是自己拿石頭砸腳的設計。

應用的情境之二: 將 script 檔和直譯引擎包成單一個執行檔,直譯器可以直接從 char 陣列讀取 script。

當然,還有很多不同的玩法,大家可以發揮創意。至於要拿來整人,還有些細節要處理,這裡就不多說了。

novus 發表在 痞客邦 PIXNET 留言(0) 人氣()