在Linux的實際開發中,與庫相關的命令工具有很多,這些工具在前面也介紹了一部分,現在做一個相對全面的介紹,掌握了這些命令工具,會在實際開發中大大減少解決問題的思路,提高開發的效率。在查找和定位問題時,起到事半功倍的效果。
二、查看和分析工具1、file
這個命令可以用來查看幾乎所有類型的文件的詳細信息
file [ -bchikLnNprsvz ] [ -f namefile ] [ -F separator ] [ -m magicfiles ] file ...
-b
只顯示執行結果,不顯示文件名
-c
這個是顯示執行過程,在Linux命令中基本差不多
-f
顯示文件中文件名的文件類型
-F
指定分隔符號替換輸出文件名後的默認的「:」分隔符。
-i
輸出mime類型的字符串
-L
顯示相關軟連結對應文件的文件類型
-z
嘗試顯示壓縮文件的內容
看一下執行效果:
machine:~/dlltest$ file -b testdll.cpp
C source, ASCII text
machine:~/dlltest$ file testdll.cpp
testdll.cpp: C source, ASCII text
machine:~/dlltest$ file -c testdll.cpp
cont offset type opcode mask value desc
machine:~/dlltest$ file -f testdll.cpp
#include <iostream>: cannot open `#include <iostream>' (No such file or directory)
: cannot open `' (No such file or directory)
int Compare(int a,int b);: cannot open `int Compare(int a,int b);' (No such file or directory)
: cannot open `' (No such file or directory)
int main(): cannot open `int main()' (No such file or directory)
{: cannot open `{' (No such file or directory)
int a = 100;: cannot open `\011int a = 100;' (No such file or directory)
int b = 200;: cannot open `\011int b = 200;' (No such file or directory)
: cannot open `' (No such file or directory)
int max = Compare(a,b);: cannot open `\011int max = Compare(a,b);' (No such file or directory)
std::cout<<"max is :"<< max<< std::endl;: cannot open `\011std::cout<<"max is :"<< max<< std::endl;' (No such file or directory)
: cannot open `' (No such file or directory)
return 0;: cannot open `\011return 0;' (No such file or directory)
}: cannot open `}' (No such file or directory)
2、size
可以用來查看輸入文件的段大小和總大小:
size [parms] [file]
參數:
size [-A|-B|--format=compatibility] 控制輸出格式
[--help]
[-d|-o|-x|--radix=number] 輸出的數據進位
[--common] 列印common symbols大小
[-t|--totals] 列出所有文件的總大小
[--target=bfdname] [-V|--version]
[objfile...]
默認是以十進位顯示數據的。看一下執行命令:
machine:~/dlltest$ size dtest
text data bss dec hex filename
2483 704 280 3467 d8b dtest
machine:~/dlltest$ size -x dtest
text data bss dec hex filename
0x9b3 0x2c0 0x118 3467 d8b dtest
machine:~/dlltest$ size dc dtest
text data bss dec hex filename
3323 712 280 4315 10db dc
2483 704 280 3467 d8b dtest
3、strings
這個命令用來在二進位文件中查找可列印的字符串:
strings [ -a ] [ - ] [ -o ] [ -t Format ] [ -n Number ] [ -Number ] [file ... ]
-a --all:掃描整個文件
-f –print-file-name:顯示文件名
-n –bytes=[number]:找到並輸出終止符
- :設置顯示字節數,默認4個
-t --radix={o,d,x} :輸出字符的位置,基於八進位,十進位或者十六進位
-o :八進位 等於--radix=o
-T --target= :指定目標文件格式
最常用的是如果庫的版本不對,會報編譯錯誤缺少XXX函數,那麼就可以用這個命令來試一下目前庫是否版本低
machine:/usr/local/lib64$ strings libstdc++.so |grep GLIBCXX*
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBCXX_3.4.21
GLIBCXX_3.4.22
GLIBCXX_3.4.23
GLIBCXX_3.4.24
GLIBCXX_3.4.25
GLIBCXX_3.4.26
4、ldd
這個命令是用來查看文件依賴的,如果缺少庫,可以用他來看:
ldd [option] [parms]
參數:
--version:顯示版本
-v:顯示詳細信息
-u:顯示未應用用直接依賴
-d:執行重定位並顯示不存在的依賴
-r:執行數據對象和函數的重定位,並顯示不存在的依賴
執行一下:
machine:~/dlltest$ ldd dtest
linux-vdso.so.1 (0x00007ffdb39f7000)
libdisplay.so => not found
libcompare.so => not found
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fea0eb7d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fea0e7df000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fea0e5c7000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fea0e1d6000)
/lib64/ld-linux-x86-64.so.2 (0x00007fea0ef0b000)
不過ldd命令無法識別通過動態加載的動態庫,最重要的是,這個命令可能會引起安全問題,因為一些版本的ldd可能會嘗試執行程序來獲得依賴信息,這就給病毒木馬提供了機會,所以可以使用以下的兩個命令來替換:
machine:~/dlltest$ objdump -p dtest|grep NEEDED
NEEDED libdisplay.so
NEEDED libcompare.so
NEEDED libstdc++.so.6
NEEDED libm.so.6
NEEDED libgcc_s.so.1
NEEDED libc.so.6
machine:~/dlltest$ readelf -d dtest|grep NEEDED
0x0000000000000001 (NEEDED) 共享庫:[libdisplay.so]
0x0000000000000001 (NEEDED) 共享庫:[libcompare.so]
0x0000000000000001 (NEEDED) 共享庫:[libstdc++.so.6]
0x0000000000000001 (NEEDED) 共享庫:[libm.so.6]
0x0000000000000001 (NEEDED) 共享庫:[libgcc_s.so.1]
0x0000000000000001 (NEEDED) 共享庫:[libc.so.6]
5、nm
顯示目標文件的符號表:
nm [option] [parms]
-A:顯示文件名
-D:顯示動態符號
-g:只顯示外部符號
-r:逆序顯示符號表
執行一下命令:
machine:~/dlltest$ nm -g libcompare.so
0000000000201038 B __bss_start
U __cxa_atexit@@GLIBC_2.2.5
w __cxa_finalize@@GLIBC_2.2.5
U Display
0000000000201038 D _edata
0000000000201040 B _end
00000000000007d8 T _fini
w __gmon_start__
0000000000000620 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000000745 T _Z7Compareii
U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
6、objdump
這個命令非常強大,強大到可以在WIN和LINUX上同時使用。它不但支持ELF,更是支持幾十種其它格式的文件,提供了大量的針對二進位文件的分析信息。
其下命令最後都要跟目標文件地址和名稱。
objdump -f:獲得頭信息
objdump -h:列出所有節
objdump -t(T) :列出所有符號(動態符號)
objdump -p:列查看動態節
objdump -R:查看重定位
objdump -s -j(節名稱):查看節的數據
objdump -d -M intel:以intel方式查看彙編,前提是編譯期提供了-g選項。
前邊講過這個,不再舉例
7、readelf
這個命令只能看ELF文件。主要的用法有以下幾個:
其下命令最後都要跟目標文件地址和名稱。
readelf -h :用於獲取目標頭文件信息,比如上面的頭就是用這個命令得到的。
readelf -S:是大寫的S,是獲得節的信息
readelf --symbols:用於得到文件內的符號。注意這裡是兩個-
readelf --dyn-syms:列出動態符號
readelf -d:只看動態節信息
readelf -r:查看重定位信息
readelf -x:查看指定節的信息
其它更多的可以用man命令或者查找相關資料。看一下執行查看指定節的命令。
1、chrpath
這個工具可以改變rpath的路徑,也就是可以修改依賴庫的路徑,好東西啊。
chrpath [-v|-d|-c|-r <path>] <program> [<program> ...]
參數:
-v|--version 顯示版本號
-d|--delete 刪除當前rpath/runpath設置
-c|--convert 覆蓋上述設置
-r <path>|--replace <path> 用給定的路徑覆蓋上述路徑
-l|--list 顯示上述路徑
看一下執行情況:
machine:~/dlltest$ ldd dtest
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8996e19000)
machine:~/dlltest$ chrpath -r "/usr/local/lib/" dtest
machine:~/dlltest$ ldd dtest
libstdc++.so.6 => /usr/local/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8996e19000)
如果沒有這個命令,需要安裝一下。
2、patchelf
這個功能和上面的類似也是修改runpath的路徑。
patchelf --set-rpath [one or more paths] [executable]
執行命令:
machine:~/dlltest$ patchelf --set-rpath /usr/local/lib/ dtest
machine:~/dlltest$ readelf -d dtest
Dynamic section at offset 0x270 contains 31 entries:
標記 類型 名稱/值
0x000000000000001d (RUNPATH) Library runpath: [/usr/local/lib/]
0x0000000000000001 (NEEDED) 共享庫:[libdisplay.so]
0x0000000000000001 (NEEDED) 共享庫:[libcompare.so]
0x0000000000000001 (NEEDED) 共享庫:[libstdc++.so.6]
3、ldconfig
這個命令的重要性在於,如果在/etc/ld.so.conf中包含的目錄中修改了依賴庫文件,可以使用這個命令將其更新到/etc/ld.so.cache文件中,從而使路徑生效。但是這個命令需要root權限。
1、strace
追蹤進程調用
strace [option] [file]
參數:
-tt 在每行輸出的前面,顯示毫秒級別的時間
-T 顯示每次系統調用所花費的時間
-v 對於某些相關調用,把完整的環境變量,文件stat結構等打出來。
-f 跟蹤目標進程,以及目標進程創建的所有子進程
-e 控制要跟蹤的事件和跟蹤行為,比如指定要跟蹤的系統調用名稱
-o 把strace的輸出單獨寫到指定的文件
-s 當系統調用的某個參數是字符串時,最多輸出指定長度的內容,默認是32個字節
-p 指定要跟蹤的進程pid, 要同時跟蹤多個pid, 重複多次-p選項即可。
執行一下:
machine:~/dlltest$ strace -tt ./dtest -o 1.log
18:20:27.732059 writev(2, [{iov_base="./dtest", iov_len=7}, {iov_base=": ", iov_len=2}, {iov_base="error while loading shared libra"..., iov_len=36}, {iov_base=": ", iov_len=2}, {iov_base="libdisplay.so", iov_len=13}, {iov_base=": ", iov_len=2}, {iov_base="cannot open shared object file", iov_len=30}, {iov_base=": ", iov_len=2}, {iov_base="No such file or directory", iov_len=25}, {iov_base="\n", iov_len=1}], 10./dtest: error while loading shared libraries: libdisplay.so: cannot open shared object file: No such file or directory
) = 120
18:20:27.732185 exit_group(127) = ?
18:20:27.732317 +++ exited with 127 +++
//如果跟蹤某個進程可以:
strace -tt -T -v -f -e trace=file -o ./data.log -s 1024 -p 9879
跟蹤某個執行文件啟動調用:
strace -tt -T -f -e trace=file -o ./data.log -s 1024 ./exefilename
2、addr2line
這個可以通過崩潰的地址來回退到指定文件的位置,不過前提是要加上調試符號 -g.
addr2line [-b bfdname|--target=bfdname] [-C|--demangle[=style]] [-e filename|--exe=filename] [-f|--functions] [-s|--basename] [-i|--inlines] [-j|--section=name] [-H|--help] [-V|--version] [addr addr ...]
參數:
-b
指定目標文件的目標代碼格式為bfdname。
-C
將低級符號名稱解碼(demangle)為用戶級名稱。去除c++改名機制產生的代碼。
-e
指定應為其轉換地址的可執行文件的名稱。默認文件是a.out。
-f
顯示函數名以及文件和行號信息。
-s
只顯示每個文件名而不顯示相關路徑
-i
如果地址屬於內聯函數,則列印全部代碼
-j
讀取相對於指定節而不是絕對地址的偏移量。
假如taddr.cpp第6行做一個除0的動作,編譯後執行,崩潰轉儲,使用gdb exe core得到地址就可以使用如下命令來操作:
machine:~/dlltest$ addr2line -C -f -e taddr 0x00000000004007c7
main
/dlltest/taddr.cpp:6
3、gdb
這個工具實在是太強大,請移步專門的分析篇章。
使用上面的命令,看一個個體的例子的分析過程(例子使用前面創建的dtest):
1、確定文件類型
machine:~/dlltest$ file dtest
dtest: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, not stripped
machine:~/dlltest$ readelf -h dtest |grep 類型
類型: EXEC (可執行文件)
2、確定可執行文件入口
machine:~/dlltest$ objdump -f dtest|grep 起始
起始地址 0x0000000000400850
machine:~/dlltest$ readelf -h dtest |grep 入口
入口點地址: 0x400850
3、列出符號表
machine:~/dlltest$ readelf --dyn-syms dtest 動態連結符號
Symbol table '.dynsym' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Z7Compareii
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@GLIBC_2.2.5 (3)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE@GLIBCXX_3.4 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E@GLIBCXX_3.4 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSolsEi@GLIBCXX_3.4 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (3)
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
9: 0000000000601068 0 NOTYPE GLOBAL DEFAULT 23 _edata
10: 0000000000601198 0 NOTYPE GLOBAL DEFAULT 24 _end
11: 00000000004007d0 0 FUNC GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait@GLIBCXX_3.4 (2)
12: 00000000004007a8 0 FUNC GLOBAL DEFAULT 12 _init
13: 0000000000601068 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
14: 0000000000400a54 0 FUNC GLOBAL DEFAULT 15 _fini
15: 0000000000601080 272 OBJECT GLOBAL DEFAULT 24 _ZSt4cout@GLIBCXX_3.4 (2)
16: 0000000000400840 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (2)
machine:~/dlltest$ objdump -t dtest 獲取外部可見符號
dtest: 文件格式 elf64-x86-64
SYMBOL TABLE:
00000000003ff888 l d .interp 0000000000000000 .interp
00000000003ff8a8 l d .note.ABI-tag 0000000000000000 .note.ABI-tag
00000000003ff830 l d .hash 0000000000000000 .hash
00000000003ff7e8 l d .gnu.hash 0000000000000000 .gnu.hash
00000000003ff650 l d .dynsym 0000000000000000 .dynsym
00000000003ff4b0 l d .dynstr 0000000000000000 .dynstr
000000000040063e l d .gnu.version 0000000000000000 .gnu.version
0000000000400660 l d .gnu.version_r 0000000000000000 .gnu.version_r
00000000004006a0 l d .rela.dyn 0000000000000000 .rela.dyn
00000000004006e8 l d .rela.plt 0000000000000000 .rela.plt
00000000004007a8 l d .init 0000000000000000 .init
00000000004007c0 l d .plt 0000000000000000 .plt
0000000000400850 l d .text 0000000000000000 .text
0000000000400a54 l d .fini 0000000000000000 .fini
0000000000400a60 l d .rodata 0000000000000000 .rodata
0000000000400a70 l d .eh_frame_hdr 0000000000000000 .eh_frame_hdr
0000000000400ac0 l d .eh_frame 0000000000000000 .eh_frame
0000000000600da8 l d .init_array 0000000000000000 .init_array
0000000000600db8 l d .fini_array 0000000000000000 .fini_array
00000000003ff270 l d .dynamic 0000000000000000 .dynamic
0000000000600ff0 l d .got 0000000000000000 .got
0000000000601000 l d .got.plt 0000000000000000 .got.plt
0000000000601058 l d .data 0000000000000000 .data
0000000000601080 l d .bss 0000000000000000 .bss
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000400890 l F .text 0000000000000000 deregister_tm_clones
00000000004008c0 l F .text 0000000000000000 register_tm_clones
0000000000400900 l F .text 0000000000000000 __do_global_dtors_aux
0000000000601190 l O .bss 0000000000000001 completed.7409
0000000000600db8 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry
0000000000400930 l F .text 0000000000000000 frame_dummy
0000000000600da8 l O .init_array 0000000000000000 __frame_dummy_init_array_entry
0000000000000000 l df *ABS* 0000000000000000 testdll.cpp
0000000000400a64 l O .rodata 0000000000000001 _ZStL19piecewise_construct
0000000000601191 l O .bss 0000000000000001 _ZStL8__ioinit
000000000040098d l F .text 000000000000003e _Z41__static_initialization_and_destruction_0ii
00000000004009cb l F .text 0000000000000015 _GLOBAL__sub_I_main
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000400bfc l O .eh_frame 0000000000000000 __FRAME_END__
0000000000000000 l df *ABS* 0000000000000000
0000000000400a70 l .eh_frame_hdr 0000000000000000 __GNU_EH_FRAME_HDR
0000000000600dc0 l O .dynamic 0000000000000000 _DYNAMIC
0000000000600db8 l .init_array 0000000000000000 __init_array_end
0000000000600da8 l .init_array 0000000000000000 __init_array_start
0000000000601000 l O .got.plt 0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000601068 g .data 0000000000000000 _edata
0000000000601058 w .data 0000000000000000 data_start
0000000000400a60 g O .rodata 0000000000000004 _IO_stdin_used
0000000000400932 g F .text 000000000000005b main
00000000004007d0 F *UND* 0000000000000000 _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.4
0000000000601060 g O .data 0000000000000000 .hidden __dso_handle
0000000000400a54 g F .fini 0000000000000000 _fini
0000000000400880 g F .text 0000000000000002 .hidden _dl_relocate_static_pie
0000000000000000 F *UND* 0000000000000000 _Z7Compareii
0000000000000000 F *UND* 0000000000000000 __cxa_atexit@@GLIBC_2.2.5
0000000000400850 g F .text 000000000000002b _start
0000000000000000 F *UND* 0000000000000000 _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4
0000000000000000 F *UND* 0000000000000000 _ZNSolsEPFRSoS_E@@GLIBCXX_3.4
00000000004007a8 g F .init 0000000000000000 _init
0000000000601068 g O .data 0000000000000000 .hidden __TMC_END__
0000000000601080 g O .bss 0000000000000110 _ZSt4cout@@GLIBCXX_3.4
0000000000601058 g .data 0000000000000000 __data_start
0000000000601198 g .bss 0000000000000000 _end
0000000000601068 g .bss 0000000000000000 __bss_start
0000000000000000 F *UND* 0000000000000000 _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
00000000004009e0 g F .text 0000000000000065 __libc_csu_init
0000000000000000 F *UND* 0000000000000000 _ZNSolsEi@@GLIBCXX_3.4
0000000000400a50 g F .text 0000000000000002 __libc_csu_fini
0000000000000000 F *UND* 0000000000000000 __libc_start_main@@GLIBC_2.2.5
0000000000000000 w *UND* 0000000000000000 __gmon_start__
0000000000400840 F *UND* 0000000000000000 _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
4、查看節的信息
machine:~/dlltest$ readelf -s dtest
Symbol table '.dynsym' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Z7Compareii
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@GLIBC_2.2.5 (3)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE@GLIBCXX_3.4 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E@GLIBCXX_3.4 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSolsEi@GLIBCXX_3.4 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (3)
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
9: 0000000000601068 0 NOTYPE GLOBAL DEFAULT 23 _edata
10: 0000000000601198 0 NOTYPE GLOBAL DEFAULT 24 _end
11: 00000000004007d0 0 FUNC GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait@GLIBCXX_3.4 (2)
12: 00000000004007a8 0 FUNC GLOBAL DEFAULT 12 _init
13: 0000000000601068 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
14: 0000000000400a54 0 FUNC GLOBAL DEFAULT 15 _fini
15: 0000000000601080 272 OBJECT GLOBAL DEFAULT 24 _ZSt4cout@GLIBCXX_3.4 (2)
16: 0000000000400840 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (2)
Symbol table '.symtab' contains 73 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000003ff888 0 SECTION LOCAL DEFAULT 6
2: 00000000003ff8a8 0 SECTION LOCAL DEFAULT 7
3: 00000000003ff830 0 SECTION LOCAL DEFAULT 5
5、查看段的信息
machine:~/dlltest$ objdump -p dtest
dtest: 文件格式 elf64-x86-64
程序頭:
PHDR off 0x0000000000000040 vaddr 0x00000000003ff040 paddr 0x00000000003ff040 align 2**3
filesz 0x0000000000000230 memsz 0x0000000000000230 flags r--
STACK off 0x0000000000001000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
LOAD off 0x0000000000000000 vaddr 0x00000000003ff000 paddr 0x00000000003ff000 align 2**12
filesz 0x0000000000001000 memsz 0x0000000000001000 flags rw-
DYNAMIC off 0x0000000000000270 vaddr 0x00000000003ff270 paddr 0x00000000003ff270 align 2**3
filesz 0x0000000000000240 memsz 0x0000000000000240 flags rw-
INTERP off 0x0000000000000888 vaddr 0x00000000003ff888 paddr 0x00000000003ff888 align 2**0
filesz 0x000000000000001c memsz 0x000000000000001c flags r--
LOAD off 0x0000000000001000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**12
filesz 0x0000000000000c00 memsz 0x0000000000000c00 flags r-x
NOTE off 0x0000000000001254 vaddr 0x0000000000400254 paddr 0x0000000000400254 align 2**2
filesz 0x0000000000000020 memsz 0x0000000000000020 flags r--
EH_FRAME off 0x0000000000001a70 vaddr 0x0000000000400a70 paddr 0x0000000000400a70 align 2**2
filesz 0x000000000000004c memsz 0x000000000000004c flags r--
LOAD off 0x0000000000001da8 vaddr 0x0000000000600da8 paddr 0x0000000000600da8 align 2**12
filesz 0x00000000000002c0 memsz 0x00000000000003f0 flags rw-
RELRO off 0x0000000000001da8 vaddr 0x0000000000600da8 paddr 0x0000000000600da8 align 2**0
filesz 0x0000000000000258 memsz 0x0000000000000258 flags r--
動態節:
RUNPATH /usr/local/lib/
NEEDED libdisplay.so
NEEDED libcompare.so
NEEDED libstdc++.so.6
NEEDED libm.so.6
NEEDED libgcc_s.so.1
NEEDED libc.so.6
INIT 0x00000000004007a8
FINI 0x0000000000400a54
INIT_ARRAY 0x0000000000600da8
INIT_ARRAYSZ 0x0000000000000010
FINI_ARRAY 0x0000000000600db8
FINI_ARRAYSZ 0x0000000000000008
HASH 0x00000000003ff830
GNU_HASH 0x00000000003ff7e8
STRTAB 0x00000000003ff4b0
SYMTAB 0x00000000003ff650
STRSZ 0x000000000000019d
SYMENT 0x0000000000000018
DEBUG 0x0000000000000000
PLTGOT 0x0000000000601000
PLTRELSZ 0x00000000000000c0
PLTREL 0x0000000000000007
JMPREL 0x00000000004006e8
RELA 0x00000000004006a0
RELASZ 0x0000000000000048
RELAENT 0x0000000000000018
VERNEED 0x0000000000400660
VERNEEDNUM 0x0000000000000002
VERSYM 0x000000000040063e
版本引用:
required from libc.so.6:
0x09691a75 0x00 03 GLIBC_2.2.5
required from libstdc++.so.6:
0x08922974 0x00 02 GLIBCXX_3.4
6、反彙編
machine:~/dlltest$ objdump -d -M intel dtest
dtest: 文件格式 elf64-x86-64
Disassembly of section .init:
00000000004007a8 <_init>:
4007a8: 48 83 ec 08 sub rsp,0x8
4007ac: 48 8b 05 45 08 20 00 mov rax,QWORD PTR [rip+0x200845] # 600ff8 <__gmon_start__>
4007b3: 48 85 c0 test rax,rax
4007b6: 74 02 je 4007ba <_init+0x12>
4007b8: ff d0 call rax
4007ba: 48 83 c4 08 add rsp,0x8
4007be: c3 ret
Disassembly of section .plt:
00000000004007c0 <.plt>:
4007c0: ff 35 42 08 20 00 push QWORD PTR [rip+0x200842] # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
4007c6: ff 25 44 08 20 00 jmp QWORD PTR [rip+0x200844] # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
4007cc: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
00000000004007d0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@plt>:
4007d0: ff 25 42 08 20 00 jmp QWORD PTR [rip+0x200842] # 601018 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
4007d6: 68 00 00 00 00 push 0x0
4007db: e9 e0 ff ff ff jmp 4007c0 <.plt>
00000000004007e0 <_Z7Compareii@plt>:
4007e0: ff 25 3a 08 20 00 jmp QWORD PTR [rip+0x20083a] # 601020 <_Z7Compareii>
4007e6: 68 01 00 00 00 push 0x1
4007eb: e9 d0 ff ff ff jmp 4007c0 <.plt>
00000000004007f0 <__cxa_atexit@plt>:
4007f0: ff 25 32 08 20 00 jmp QWORD PTR [rip+0x200832] # 601028 <__cxa_atexit@GLIBC_2.2.5>
4007f6: 68 02 00 00 00 push 0x2
4007fb: e9 c0 ff ff ff jmp 4007c0 <.plt>
0000000000400800 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>:
400800: ff 25 2a 08 20 00 jmp QWORD PTR [rip+0x20082a] # 601030 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@GLIBCXX_3.4>
400806: 68 03 00 00 00 push 0x3
40080b: e9 b0 ff ff ff jmp 4007c0 <.plt>
0000000000400810 <_ZNSolsEPFRSoS_E@plt>:
400810: ff 25 22 08 20 00 jmp QWORD PTR [rip+0x200822] # 601038 <_ZNSolsEPFRSoS_E@GLIBCXX_3.4>
400816: 68 04 00 00 00 push 0x4
40081b: e9 a0 ff ff ff jmp 4007c0 <.plt>
7 、判斷是否Debug
machine:~/dlltest$ readelf --debug-dump=line taddr
.debug_line 節的調試內容轉儲:
偏移: 0x0
長度: 1061
DWARF 版本: 2
導言長度: 993
最小指令長度: 1
「is_stmt」的初始值: 1
行基數: -5
行範圍: 14
操作碼基數: 13
操作碼:
Opcode 1 has 0 args
Opcode 2 has 1 arg
Opcode 3 has 1 arg
Opcode 4 has 1 arg
Opcode 5 has 1 arg
Opcode 6 has 0 args
Opcode 7 has 0 args
Opcode 8 has 0 args
Opcode 9 has 1 arg
Opcode 10 has 0 args
Opcode 11 has 0 args
Opcode 12 has 1 arg
目錄表 (偏移 0x1b):
1 /usr/local/include/c++/9.1.0
2 /usr/local/include/c++/9.1.0/bits
3 /usr/local/include/c++/9.1.0/x86_64-pc-linux-gnu/bits
4 /usr/local/include/c++/9.1.0/debug
5 /usr/local/include/c++/9.1.0/ext
6 /usr/local/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include
7 /usr/include/x86_64-linux-gnu/bits/types
8 /usr/include/x86_64-linux-gnu/bits
9 /usr/include
文件名表 (偏移 0x163):
條目 目錄 時間 大小 名稱
1 0 0 0 taddr.cpp
2 1 0 0 iostream
8 、查看應用依賴項
machine:~/dlltest$ ldd dtest
linux-vdso.so.1 (0x00007ffd18f90000)
libdisplay.so => not found
libcompare.so => not found
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8941397000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8940ff9000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f8940de1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f89409f0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8941725000)
或者特定的加載庫
machine:~/dlltest$ ldconfig -p|grep display
//此處沒有找到
9、使用strace追蹤加載的動態庫
這個已經介紹並運行了實例,此處不再贅述。
10、lsof顯示當前打開的文件
//顯示某個進程使用的文件
# lsof -c MeetingServer
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
MeetingSe 9032 root cwd DIR 253,1 4096 1186984 /root/projects/MeetingServer/build
MeetingSe 9032 root rtd DIR 253,1 4096 2 /
MeetingSe 9032 root txt REG 253,1 2446712 1187072 /root/projects/MeetingServer/build/MeetingServer
MeetingSe 9032 root mem REG 253,1 2151672 265443 /usr/lib64/libc-2.17.so
MeetingSe 9032 root mem REG 253,1 141968 265470 /usr/lib64/libpthread-2.17.so
MeetingSe 9032 root mem REG 253,1 88720 266411 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
MeetingSe 9032 root mem REG 253,1 1137024 265452 /usr/lib64/libm-2.17.so
MeetingSe 9032 root mem REG 253,1 995840 266421 /usr/lib64/libstdc++.so.6.0.19
MeetingSe 9032 root mem REG 253,1 163400 265153 /usr/lib64/ld-2.17.so
MeetingSe 9032 root 0w CHR 1,3 0t0 1028 /dev/null
MeetingSe 9032 root 1w REG 253,1 1285955 1187006 /root/projects/MeetingServer/build/1.log
MeetingSe 9032 root 2w REG 253,1 1285955 1187006 /root/projects/MeetingServer/build/1.log
MeetingSe 9032 root 3u IPv4 222350 0t0 TCP *:38888 (LISTEN)
MeetingSe 9032 root 4u a_inode 0,10 0 6487 [eventpoll]
MeetingSe 9032 root 5u a_inode 0,10 0 6487 [timerfd]
[root@iZj6c8dmrj7zr49bx5dnooZ ~]# lsof -c -p 9032
lsof: missing -c option value
lsof 4.87
latest revision: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
latest FAQ: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
latest man page: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof_man
usage: [-?abhKlnNoOPRtUvVX] [+|-c c] [+|-d s] [+D D] [+|-f[gG]] [+|-e s]
[-F [f]] [-g [s]] [-i [i]] [+|-L [l]] [+m [m]] [+|-M] [-o [o]] [-p s]
[+|-r [t]] [-s [p:s]] [-S [t]] [-T [t]] [-u s] [+|-w] [-x [fl]] [--] [names]
Use the ``-h'' option to get more help information.
[root@iZj6c8dmrj7zr49bx5dnooZ ~]# lsof -p 9032
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
MeetingSe 9032 root cwd DIR 253,1 4096 1186984 /root/projects/MeetingServer/build
MeetingSe 9032 root rtd DIR 253,1 4096 2 /
MeetingSe 9032 root txt REG 253,1 2446712 1187072 /root/projects/MeetingServer/build/MeetingServer
MeetingSe 9032 root mem REG 253,1 2151672 265443 /usr/lib64/libc-2.17.so
MeetingSe 9032 root mem REG 253,1 141968 265470 /usr/lib64/libpthread-2.17.so
MeetingSe 9032 root mem REG 253,1 88720 266411 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
MeetingSe 9032 root mem REG 253,1 1137024 265452 /usr/lib64/libm-2.17.so
MeetingSe 9032 root mem REG 253,1 995840 266421 /usr/lib64/libstdc++.so.6.0.19
MeetingSe 9032 root mem REG 253,1 163400 265153 /usr/lib64/ld-2.17.so
MeetingSe 9032 root 0w CHR 1,3 0t0 1028 /dev/null
MeetingSe 9032 root 1w REG 253,1 1285955 1187006 /root/projects/MeetingServer/build/1.log
MeetingSe 9032 root 2w REG 253,1 1285955 1187006 /root/projects/MeetingServer/build/1.log
MeetingSe 9032 root 3u IPv4 222350 0t0 TCP *:38888 (LISTEN)
MeetingSe 9032 root 4u a_inode 0,10 0 6487 [eventpoll]
MeetingSe 9032 root 5u a_inode 0,10 0 6487 [timerfd]
lsof還可以恢復刪除的文件,這裡不介紹。此命令非常強大,可以查詢相關資料。
六、總結基本到這裡,對庫的學習和使用就基本告一段落了,整個過程使用的工程簡單明了,只要掌握了這些基本的方法,就可以進行複雜的開發,因為所謂複雜,並不是庫使用本身的複雜,而是業務邏輯的複雜,導出一個函數和導出一百個函數,沒有什麼區別。同樣,使用一個動態庫和使用一百個動態庫同樣沒有區別,如果說非要有區別,就是要認真考慮庫的設計和導出的ABI兼容問題,考慮一個不同的庫之間的調用如果解耦和儘量設計使用單向調用的原則。
假使真的沒有辦法,遇到了非常複雜的循環調用,動態庫和靜態庫來回調用,深入數層甚至上十層,只要掌握了分析工具和命令,一點點的琢磨,終究還是能夠解決問題的。
一定要學會的是編程的思想和設計的原則,一定會把複雜的邏輯抽象成一個簡單的模型,這樣,對於解決看上去非常複雜的問題有著重要的幫助。而這,就需要同學們仔細反覆的深入學習和實踐了。