天天看點

動态庫、可執行檔案符号表分析

動态庫内容分析

文章目錄

    • 動态庫内容分析
      • 1. 動态庫編譯
        • 1.1 第一個C檔案:basic.c
        • 1.2第二個C檔案:demo.c
        • 1.3第三個C檔案:main.c
      • 2.動态庫編譯
      • 3.二進制内容分析
        • 3.1 libbasic.so分析
          • 3.1.1 basic.c内容彙總
          • 3.1.2 libbasic.so符号表
          • 3.1.3 小結
        • 3.2 libdemo.so分析
          • 3.2.1 demo.c内容彙總
          • 3.2.2 demo.so符号表
          • 3.2.3 小結
        • 3.3 可執行檔案a.out分析
          • 3.3.1 main.c内容彙總
          • 3.3.2 a.out符号表
          • 3.3.3 小結
      • 4.總結

1. 動态庫編譯

基本思路為:

  • 先編寫兩個C檔案,其中各自實作幾個函數,變量,然後将其分别編譯為動态庫;
  • 再編寫一個實作main函數的C檔案,分别調用上述第一步動态庫中的函數;
  • 分析最後的可執行檔案和動态庫檔案的符号表;

1.1 第一個C檔案:basic.c

這個C檔案隻定義并實作了四個不同形參的函數、五個靜态變量、一個全局變量。由于隻關心符号表或者其他二進制内容,是以不具體實作特定功能。

/*************************************************************************
             > File Name: basic.c
             > Author: Toney Sun
             > Mail: [email protected]
       > Created Time: 2020年04月20日 星期一 09時50分51秒
 ************************************************************************/

#include<stdio.h>

int basic_func=4;
static char *Author="Toney Sun";

void func1()
{
	int tmp_var;
	static char *Mail="[email protected]";
}
void func2(int x)
{
	static char *Mail="[email protected]";
}
int func3(char *a)
{
	static char *Mail="[email protected]";
}
char * func4(int x, int y)
{
	static char *Mail="[email protected]";
}





           

1.2第二個C檔案:demo.c

​ 在demo.c中我定義一個結構體udphdr。然後分别定義了兩個全局變量,實作了三個函數:func5, func6, fun7。

/*************************************************************************
             > File Name: demo.c
             > Author: Toney Sun
             > Mail: [email protected]
       > Created Time: 2020年04月19日 星期日 22時33分39秒
 ************************************************************************/

#include<stdio.h>

struct udphdr{
	short dstport;
	short srcport;
	short checksum;
	short length;
};
enum Date{
	Monday,
	Tuesday,
	Wensday,
	Thursday,
	Friday,
	Saturday,
	Sunday,
};
struct udphdr udp1;

enum Date today = Monday;

int iphdr1=10;

extern void func1();
extern void func2(int x);
extern int func3(char *);
extern char * func4(int x, int y);

int fun5(int a)
{
	struct udphdr udp2;
	func1();
	printf("aaaaaaaaaaa\n");
}
    
int fun6(char *a)
{
	static struct udphdr udp1;
	func2(10);
	printf("aaaaaaaaaaa\n");
}
int fun7(int a, char *b)
{
	func3("test");
	printf("aaaaaaaaaaa\n");
}

           

1.3第三個C檔案:main.c

​ main.c主要用來實作main函數,并調用其他C檔案中實作的函數和全局變量。進而觀察對比不同的函數、變量在符号表中的異同。

/*************************************************************************
             > File Name: main.c
             > Author: Toney Sun
             > Mail: [email protected]
       > Created Time: 2020年04月20日 星期一 09時44分38秒
 ************************************************************************/

#include<stdio.h>
extern void func1();
extern int fun5(int a);   
extern int fun6(char *a);
extern int fun7(int a, char *b);

extern struct udphdr udp;
extern int iphdr;

int myAge=25;
char *mail="[email protected]";

int show()
{
	printf("Author: Toney Sun\n");
}

int main(int argc, char **argv)
{
	int a=10;
	int b=11;
	fun5(a);
	fun6("aaaaa");
	fun7(a, "Toney Sun");
	show();
	
	udp.srcport=4500;
	iphdr=10;
	return 0;
}
           

2.動态庫編譯

  • 使用gcc工具将basic.c編譯為libbasic.so;
  • 使用gcc工具将demo.c編譯為libdemo.so;
  • 使用gcc工具将main.c連結上述兩個動态庫後編譯為a.out

    **注意:**我們不是為了執行該a.out, 而是想檢視上述三個二進制檔案的内容(符号表)。

[email protected]$ gcc -shared -fpic -o libdemo.so demo.c 
[email protected]$ gcc -shared -fpic -o libbasic.so basic.c 
[email protected]$ gcc main.c -L./ -ldemo -lbasic
[email protected]$ ls -l
total 35
-rwxrwxrwx 1 root root 8552 4月  20 10:18 a.out
-rwxrwxrwx 1 root root  454 4月  20 09:52 basic.c
-rwxrwxrwx 1 root root  763 4月  20 09:49 demo.c
-rwxrwxrwx 1 root root 8016 4月  20 09:43 demo.so
-rwxrwxrwx 1 root root 7528 4月  20 10:17 libbasic.so
-rwxrwxrwx 1 root root 8128 4月  20 10:17 libdemo.so
-rwxrwxrwx 1 root root  846 4月  20 10:18 main.c
           

連結怎麼還有個順序問題:(

[email protected]$ gcc main.c -L./ -lbasic -ldemo
.//libdemo.so: undefined reference to `func3'
.//libdemo.so: undefined reference to `func1'
.//libdemo.so: undefined reference to `func2'
collect2: error: ld returned 1 exit status
[email protected]$ gcc main.c -L./ -ldemo -lbasic
[email protected]$
           

3.二進制内容分析

3.1 libbasic.so分析

3.1.1 basic.c内容彙總
序号 函數或變量 性質
1 void func1() 自定義函數
2 void func2(int x) 自定義函數
3 int func3(char *a) 自定義函數
4 char * func4(int x, int y) 自定義函數
5 int basic_func; 自定義全局變量
6 static char *Author; 自定義全局靜态變量
7 static char *Mail; func1内定義局部靜态變量
8 static char *Mail; func2内定義局部靜态變量
9 static char *Mail; func3内定義局部靜态變量
10 static char *Mail; func4内定義局部靜态變量
3.1.2 libbasic.so符号表
  • 使用nm工具檢視符号表内容(當然也可以使用其他工具檢視,例如objdump, readelf, ldd等):
[email protected]$ nm libbasic.so 
0000000000201028 d Author		==================全局靜态變量=================
0000000000201020 D basic_func	====================全局變量==================
0000000000201050 B __bss_start
0000000000201050 b completed.7698
                 w __cxa_finalize
00000000000005a0 t deregister_tm_clones
0000000000000630 t __do_global_dtors_aux
0000000000200e88 t __do_global_dtors_aux_fini_array_entry
0000000000201018 d __dso_handle
0000000000200e90 d _DYNAMIC
0000000000201050 D _edata
0000000000201058 B _end
00000000000006a4 T _fini
0000000000000670 t frame_dummy
0000000000200e80 t __frame_dummy_init_array_entry
00000000000007e8 r __FRAME_END__
000000000000067a T func1		===================實作函數===================
0000000000000681 T func2		===================實作函數===================
000000000000068b T func3		===================實作函數===================
0000000000000696 T func4		===================實作函數===================
0000000000201000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
00000000000006d0 r __GNU_EH_FRAME_HDR
0000000000000568 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000201030 d Mail.2252	================局部靜态變量===================
0000000000201038 d Mail.2256	================局部靜态變量===================
0000000000201040 d Mail.2260	================局部靜态變量===================
0000000000201048 d Mail.2265	================局部靜态變量===================
00000000000005e0 t register_tm_clones
0000000000201050 d __TMC_END__

           
  • 使用nm -Da 檢視本動态庫定義的内容資訊
[email protected]$ nm -Da libbasic.so 
0000000000201020 D basic_func		----------------1----------------
0000000000201050 B __bss_start
                 w __cxa_finalize
0000000000201050 D _edata
0000000000201058 B _end
00000000000006a4 T _fini
000000000000067a T func1			----------------2----------------
0000000000000681 T func2			----------------3----------------
000000000000068b T func3			----------------4----------------
0000000000000696 T func4			----------------5----------------
                 w __gmon_start__
0000000000000568 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable

           
3.1.3 小結
  • 本檔案内定義的全局變量用‘D’來表示;
  • 本檔案内定義的全局靜态變量用‘d’來表示;
  • 本檔案内實作的函數用‘T’來表示;
  • 不同函數内定義的靜态變量在符号表中的符号有所差别,是以不會出現混淆的問題。
  • 從上述内容可以猜測:使用‘d’表示的變量不能被其他檔案引用(上述‘d’辨別的都是靜态變量,這也比較合理)

3.2 libdemo.so分析

3.2.1 demo.c内容彙總
序号 函數或變量 性質
1 struct udphdr udp1; 自定義的全局結構體變量
2 static struct udphdr udp2; 自定義全局靜态變量
3 struct udphdr udp2; 自定義局部變量
4 enum Date today 自定義全局枚舉變量
5 int iphdr; 自定義全局變量
6 extern void func1(); 外部函數
7 extern void func2(int x); 外部函數
8 extern int func3(char *); 外部函數
9 extern char * func4(int x, int y); 外部函數
10 int fun5(int a) 自定義函數
11 int fun6(char *a) 自定義函數
12 int fun7(int a, char *b) 自定義函數
3.2.2 demo.so符号表

同樣的,我們使用nm工具來檢視動态庫符号表資訊:

[email protected]$ nm libdemo.so 
0000000000201044 B __bss_start
0000000000201048 b completed.7698
                 w [email protected]@GLIBC_2.2.5
00000000000006b0 t deregister_tm_clones
0000000000000740 t __do_global_dtors_aux
0000000000200e18 t __do_global_dtors_aux_fini_array_entry
0000000000201038 d __dso_handle
0000000000200e20 d _DYNAMIC
0000000000201044 D _edata
0000000000201068 B _end
0000000000000800 T _fini
0000000000000780 t frame_dummy
0000000000200e10 t __frame_dummy_init_array_entry
0000000000000908 r __FRAME_END__
000000000000078a T fun5							=============================
00000000000007ae T fun6							=============================
00000000000007d3 T fun7							=============================	
                 U func1						=============================
                 U func2						=============================
                 U func3						=============================
0000000000201000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
000000000000081c r __GNU_EH_FRAME_HDR
0000000000000638 T _init
0000000000201040 D iphdr1						=============================
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 U [email protected]@GLIBC_2.2.5
00000000000006f0 t register_tm_clones
0000000000201048 d __TMC_END__
0000000000201050 B today						=============================
0000000000201060 B udp1							=============================
0000000000201058 b udp1.2278					=============================
           
3.2.3 小結
  • 結構體變量(非基本型變量)使用‘B’或‘b’來辨別。
    • 全局結構體變量使用‘B’辨別
    • 局部靜态結構體變量使用‘b’辨別
    • 局部變量不會顯示在符号表中
  • 本檔案内使用的函數使用‘T’辨別
  • 引用其他檔案的函數使用‘U’辨別

3.3 可執行檔案a.out分析

3.3.1 main.c内容彙總
序号 函數或變量 性質
1 extern void func1(); 引用外部函數
2 extern int fun5(int a); 引用外部函數
3 extern int fun6(char *a); 引用外部函數
4 extern int fun7(int a, char *b); 引用外部函數
5 extern struct udphdr udp1; 引用外部結構體變量
6 extern int iphdr1; 引用外部基本類型變量
7 int myAge=25; 本地全局變量
8 char *mail=“[email protected]”; 本地全局靜态變量
3.3.2 a.out符号表

同樣使用nm工具進行檢視:

[email protected]$ nm a.out 
0000000000201020 B __bss_start
0000000000201030 b completed.7698
                 w [email protected]@GLIBC_2.2.5
0000000000201000 D __data_start
0000000000201000 W data_start
00000000000007a0 t deregister_tm_clones
0000000000000830 t __do_global_dtors_aux
0000000000200d88 t __do_global_dtors_aux_fini_array_entry
0000000000201008 D __dso_handle
0000000000200d90 d _DYNAMIC
0000000000201020 D _edata
0000000000201038 B _end
0000000000000974 T _fini
0000000000000870 t frame_dummy
0000000000200d80 t __frame_dummy_init_array_entry
0000000000000b2c r __FRAME_END__
                 U fun5					============1==============
                 U fun6					============2==============
                 U fun7					============3==============
0000000000200fa0 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
00000000000009c0 r __GNU_EH_FRAME_HDR
00000000000006f8 T _init
0000000000200d88 t __init_array_end
0000000000200d80 t __init_array_start
0000000000000980 R _IO_stdin_used
0000000000201020 B iphdr1				============4=============
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000000970 T __libc_csu_fini
0000000000000900 T __libc_csu_init
                 U [email protected]@GLIBC_2.2.5
0000000000201018 d mail					============5==============
000000000000088d T main					============6==============
0000000000201010 D myAge				============7==============
                 U [email protected]@GLIBC_2.2.5
00000000000007e0 t register_tm_clones
000000000000087a T show					============8==============
0000000000000770 T _start
0000000000201020 D __TMC_END__
0000000000201028 B udp1					============9==============

           
3.3.3 小結
  • 引用的外部函數使用‘U’來辨別
  • 全局變量使用‘D’來辨別
  • 全局靜态變量使用‘d’來辨別
  • 引用的外部全局變量(簡單類型和複雜類型)使用‘B’來辨別

4.總結

對符号表中常見的變量、函數辨別總結如下:

序号 辨別 說明
1 T 自定義函數(本檔案内)
2 t 尚未分析
3 D 自定義标準類型全局變量(如int, char, float等)
4 d 自定義标準類型靜态變量(包括全局靜态變量、局部靜态變量)
5 B 自定義擴充類型全局變量(如結構體類型,枚舉型等)、引用的外部全局變量
6 b 自定義靜态擴充類型變量(包括全局靜态、局部靜态類型變量)
7 U 引用的外部函數
8 局部變量在符号表中是不存在的。

繼續閱讀