目標檔案函式隱藏初探

2022-03-15 08:54:53 字數 4319 閱讀 6415

場景如下,需要以.o形式(靜態庫形式),發布乙個庫,給其他**整合。生成庫mylib.o之後,使用nm檢視,可以檢視到很多函式符號。但其實這個庫跟外界,應該是只通過一組指定的函式介面進行互動,其他的函式不應該暴露給外界,更不應該供外界直接呼叫。

為此,可以進行一些處理。

一種可行的方式是,將內部使用的函式,原始碼中標記為static。

但這麼修改之後,庫本身的其他原始檔,也無法使用該函式了,因為c語言中的static是將函式的作用域限定在了函式所在的原始檔。

生成庫之後,可使用工具鏈中的 objcopy 工具,修改符號表,將內部函式都修改為本地函式,這樣外部**無法直接鏈結到這些函式,只能使用指定的函式。

檢視幫助可知,objcopy 支援將除 -g 引數指定的符號外,其他符號全部修改成本地符號。

objcopy --help

-g --keep-global-symbol localize all symbols except

於是使用如下命令,

mv mylib.o mylib_origin.o

objcopy -g api_1 -g api_2 mylib_origin.o mylib.o

生成庫之後,可使用工具鏈中的 strip 工具,裁剪符號表,將不打算給外界使用的函式,直接從符號表中刪除。

檢視幫助可知,strip可用 -s 引數刪除所有符號,使用 -k 引數指定要保留的符號,使用 -n 指定要strip掉的符號。

strip --help

-s --strip-all remove all symbol and relocation information

-n --strip-symbol=do not copy symbol -k --keep-symbol=do not strip symbol --keep-file-symbols do not strip file symbol(s)

於是使用如下命令,可刪除所有符號,只保留api_1和api_2

cp mylib.o mylib_origin.o

strip -s -k api_1 -k api_2 mylib.o

使用如下命令,則是只刪除inner_fun1和inner_fun2

cp mylib.o mylib_origin.o

strip -n inner_fun1 -n inner_fun2 mylib.o

假設庫mylib.c 中有四個函式,inner_fun1,inner_fun2是內部使用的函式,api_1,api_2時給外部使用的介面。

#include void inner_fun1() 

void inner_fun2()

void api_1()

void api_2() ;

編譯生產目標檔案

gcc -o mylib.o -c mylib.c
檢視符號表

nm mylib.o

0000000000000026 t api_1

0000000000000039 t api_2

u _global_offset_table_

0000000000000000 t inner_fun1

0000000000000013 t inner_fun2

u puts

四個函式都可以看到,且都是 t ,即可被外部鏈結。

注:對於每乙個符號來說,其型別如果是小寫的,則表明該符號是 local 的;大寫則表明該符號是 global(external) 的。

寫個main.c鏈結下試試

int main()

編譯鏈結

gcc main.c mylib.o -o main
執行main,可以看到成功呼叫了api,也成功呼叫了inner的函式。

./main 

api 1

api 2

inner 1

inner 2

那麼先試試 static 定義,將mylib.c中的inner函式加上static

#include static void inner_fun1() 

static void inner_fun2()

void api_1()

void api_2() ;

重新生成庫,再檢視符號表

nm mylib.o

0000000000000026 t api_1

0000000000000039 t api_2

u _global_offset_table_

0000000000000000 t inner_fun1

0000000000000013 t inner_fun2

u puts

可以看到,inner_fun1和inner_fun2的標記,已經不是 t,而是 t 了。

此時,外部函式嘗試鏈結使用,會報錯

gcc main.c mylib.o -o main

/tmp/cccun3al.o:在函式『main』中:

main.c:(.text+0x1e):對『inner_fun1』未定義的引用

main.c:(.text+0x28):對『inner_fun2』未定義的引用

collect2: error: ld returned 1 exit status

不修改原始檔,直接使用objcopy修改mylib.o

mv mylib.o mylib_origin.o

objcopy -g api_1 -g api_2 mylib_origin.o mylib.o

修改前後

nm mylib_origin.o mylib.o

mylib_origin.o:

0000000000000026 t api_1

0000000000000039 t api_2

u _global_offset_table_

0000000000000000 t inner_fun1

0000000000000013 t inner_fun2

u puts

mylib.o:

0000000000000026 t api_1

0000000000000039 t api_2

u _global_offset_table_

0000000000000000 t inner_fun1

0000000000000013 t inner_fun2

u puts

此時,main.c 就只能使用api_1, api_2,無法使用inner_fun1, inner_fun2了。因為inner_fun1, inner_fun2是內部符號了。

不修改原始檔,直接使用strip修改mylib.o

cp mylib.o mylib_origin.o

strip -n inner_fun1 -n inner_fun2 mylib.o

修改前後

nm mylib_origin.o mylib.o 

mylib_origin.o:

0000000000000026 t api_1

0000000000000039 t api_2

u _global_offset_table_

0000000000000000 t inner_fun1

0000000000000013 t inner_fun2

u puts

mylib.o:

0000000000000026 t api_1

0000000000000039 t api_2

u _global_offset_table_

u puts

此時,main.c 就只能使用api_1, api_2,無法使用inner_fun1, inner_fun2了。因為inner_fun1, inner_fun2不存在符號表中了。

本文主要介紹了,static標記函式,objcopy和strip三種方式,避免庫內部函式被外部程式使用。但即使strip刪除了符號表,也還是可以從二進位制檔案中分析到內外部函式名稱的。所以如果想隱藏內部函式名稱,以避免暴露內部邏輯,那就還需要使用一些其他的手段。

初探python官網,展望學成目標

在初學者指引中可以找到python標準庫的相關網頁,從中可以完整地了解到這門語言的基本內容,在學習一門語言中這是十分重要的。在稍微找一下還能發現各種網路文件的鏈結,在需要查閱時,從官方給出文件中找是最好不過的了。除此之外,python的應用這一塊也是很引人注目,官網上列出了一些常見的使用場景如網頁開...

AfxBeginThread函式初探

在進行多執行緒程式設計的時候,我們經常用到afxbeginthread函式來啟動一條執行緒 該函式使用起來非常的簡單方便,其定義如下 cwinthread afxbeginthread afx threadproc pfnthreadproc,執行緒函式位址 lpvoid pparam,執行緒引數 ...

python函式初探

任何一門程式語言都會有函式,函式通常也被稱作方法,初學者聽到函式或方法可能根本不知道是什麼意思,我打個簡單的比方,電熱水壺可以把冷水燒開,那麼在這裡電熱水壺就可以被理解成乙個函式,它的主要功能是負責把冷水燒成熱水。在 python 中函式也就是指能完成乙個固定的功能的方法,並且是可重複使用的,函式最...