Golang二進位文件混淆保護

Go實在是太棒了。一處編譯,處處運行,沒有依賴,毫無麻煩!

不過麻煩的事情來了。我們寫一個程序,就是想在別人的電腦上運行的。然而,Go語言的默認機制,會泄漏我們的一些信息,雖然不多,但也有點尷尬。本文結合網上的一些常用方法,總結出一套通用的簡單易行的保護措施。

刪除調試符號

默認情況下go編譯出的程序在運行出錯時會輸出自己在哪個線程哪個文件哪個函數哪行出的錯,就像這樣,

圖片來源StackOverflow

DWARF信息對於小黑客們可是如獲至寶,這些關鍵信息不能留下。而且去掉這些東西也非常簡單:

go build -ldflags "-s -w」 [<your/package]n

(需要Go版本大於1.7)

這裡的 -ldflags 參數最終會在 go tool link 的時候傳給它, go tool link -h解釋如下

...n -s disable symbol tablen -w disable DWARF generationn

刪除掉調試符號的另一個好處就是,顯著減小了文件大小(平均20%)

-rwxr-xr-x 1 tim staff 1636736 May 5 11:59 bin/hello <- 標準編譯n-rwxr-xr-x 1 tim staff 1190272 May 5 11:59 hello <- strippedn

再加一個UPX殼,還可以壓縮到原文件大小的五分之一!不知道為啥,go語言的二進位特別好壓!

刪除trace文件信息

在go中觸發 panic 時,上圖的文件目錄也是泄漏信息的一部分。比如上圖就包括了小黑客用的操作系統(Linux),小黑客的名字(nikos),如果你用homebrew版本的Go還會泄漏你的編譯器版本。所以這些當然也要刪掉!

這些信息的來源是編譯器運行時所處環境的環境變數。

上圖中的函數編譯時,環境變數就是這樣。

GOROOT=/opt/gonGOPATH=/home/nikos/projects/gonGOROOT_FINAL=$GOROOTn

這幾個都是可以改的哦。根據參考資料,編譯時GO會從$GOPATH尋找我們自己的代碼,從$GOROOT提取標準庫,在打包時將GOROOT改寫為GOROOT_FINAL並作為trace信息的一部分寫入目標文件。改寫$GOPATH的方式也很簡單,在一個不起眼的目錄里對真實的GOPATH創建一個軟鏈接(快捷方式),編譯器在尋找時就會把快捷方式的目錄名寫到最終文件里,從而達到我們隱藏自己的目的。

話不多說,上代碼。放到自己的.bash_profile或.zshrc中即可

ACTUAL_GOPATH="~/Programming/go"n export GOPATH=/tmp/gon export GOROOT_FINAL=$GOPATHn [ ! -d $GOPATH ] && ln -s "$ACTUAL_GOPATH" "$GOPATH"n [[ ! $PATH =~ $GOPATH ]] && export PATH=$PATH:$GOPATH/binn

我個人把GOROOT_FINAL也寫入為GOPATH,其實這個字元串可以是任意值,但寫成一樣的話,可以讓逆向人員無法分辨,調用的庫是我們自己寫的還是go語言的標準庫。非常猥瑣哦~

這樣一來,生成的二進位文件就相當於其他語言編譯時的Release版本了。再發散一下,自己寫一個庫,將關鍵的字元串做成外部資源並在調用時解密,代碼中不保留明文,再破解就只能人肉跟蹤函數了。滿分!

參考資料

  • How to reduce compiled file size?
  • Shrink your Go binaries with this one weird trick

  • cmd/link: delete source file path info in panic『s stack trace for production releases · Issue #13809 · golang/go

封面圖片:谷歌隨便找的


推薦閱讀:

Golang 的並發與 Erlang、Scala、Node.js 和 Python 的並發模型相比有何特點?
go語言用作廣告dsp開發有什麼優勢和劣勢?
Golang裡面defer的執行順序為什麼是逆序的?
如何看待Phoenix用40核128G內存的機器只能同時保持僅僅200萬WebSocket連接?
go語言以後會不會成為主流web開發語言?

TAG:Go语言 | 逆向工程 |