可執(zhí)行程序进宝,是怎么“動”起來的

  • ldd只能對共享對象瞭亮,也就是動態(tài)可執(zhí)行文件使用痹换。

ldd prints the shared objects (shared libraries) required by each program or shared object specified on the command line.

  • 對/bin/sh程序使用ldd,查看其依賴的庫
  • 對自己寫的程序使用ldd精置,可以看到计寇,每次執(zhí)行l(wèi)dd的時(shí)候,每個(gè)依賴庫所映射的地址都不一樣脂倦,這可能和我們馬上要探索的可程序“動起來”的過程有關(guān)饲常。和安全也有一定的關(guān)系。
  • ldd man page中的解釋如下:

In the usual case, **ldd **invokes the standard dynamic linker (see ld.so(8)) with the **LD_TRACE_LOADED_OBJECTS **environment variable set to 1. This causes the dynamic linker to inspect the program's dynamic dependencies, and find (according to the rules described in ld.so(8)) and load the objects that satisfy those dependencies. For each dependency, **ldd **displays the location of the matching object and the (hexadecimal) address at which it is loaded. (The linux-vdso and ld-linux shared dependencies are special; see vdso(7) and ld.so(8).)

  • 簡單來說狼讨,ldd實(shí)際是調(diào)用標(biāo)準(zhǔn)鏈接器來得到依賴關(guān)系。ldd會顯示以來的共享庫以及加載時(shí)在可執(zhí)行程序的虛擬地址空間中柒竞。

  • 在ld.so的man page中政供,可以看到,實(shí)際上朽基,除了我們使用ldd這種方式來調(diào)用動態(tài)鏈接器外布隔,也可以直接用下面這樣的方式來獲取我們需要的信息:

LD_TRACE_LOADED_OBJECTS If set (to any value), causes the program to list its dynamic dependencies, as if run by ldd(1), instead of running normally.

  • 動態(tài)鏈接器還會在動態(tài)可執(zhí)行程序被執(zhí)行的時(shí)候自動被調(diào)用,動態(tài)鏈接器保存在ELF文件中的.interp section中稼虎。
  • 當(dāng)然了衅檀,我們主要關(guān)注的還是ELF中的動態(tài)鏈接是如何進(jìn)行的。

看看hello的結(jié)構(gòu):
ELF Header

thorn@ubuntu:~/LinuxKernel/menu$ readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048736
  Start of program headers:          52 (bytes into file)
  Start of section headers:          724012 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         6
  Size of section headers:           40 (bytes)
  Number of section headers:         31
  Section header string table index: 28

section headers

thorn@ubuntu:~/LinuxKernel/menu$ readelf -S hello
There are 31 section headers, starting at offset 0xb0c2c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.ABI-tag     NOTE            080480f4 0000f4 000020 00   A  0   0  4
  [ 2] .note.gnu.build-i NOTE            08048114 000114 000024 00   A  0   0  4
  [ 3] .rel.plt          REL             08048138 000138 000070 08  AI  0  23  4
  [ 4] .init             PROGBITS        080481a8 0001a8 000023 00  AX  0   0  4
  [ 5] .plt              PROGBITS        080481d0 0001d0 0000e0 00  AX  0   0 16
  [ 6] .text             PROGBITS        080482b0 0002b0 07201c 00  AX  0   0 16
  [ 7] __libc_freeres_fn PROGBITS        080ba2d0 0722d0 000a6d 00  AX  0   0 16
  [ 8] __libc_thread_fre PROGBITS        080bad40 072d40 00009e 00  AX  0   0 16
  [ 9] .fini             PROGBITS        080bade0 072de0 000014 00  AX  0   0  4
  [10] .rodata           PROGBITS        080bae00 072e00 01a88c 00   A  0   0 32
  [11] __libc_subfreeres PROGBITS        080d568c 08d68c 000028 00   A  0   0  4
  [12] __libc_atexit     PROGBITS        080d56b4 08d6b4 000004 00   A  0   0  4
  [13] __libc_thread_sub PROGBITS        080d56b8 08d6b8 000004 00   A  0   0  4
  [14] .eh_frame         PROGBITS        080d56bc 08d6bc 0129d0 00   A  0   0  4
  [15] .gcc_except_table PROGBITS        080e808c 0a008c 0000b1 00   A  0   0  1
  [16] .tdata            PROGBITS        080e9f5c 0a0f5c 000010 00 WAT  0   0  4
  [17] .tbss             NOBITS          080e9f6c 0a0f6c 000018 00 WAT  0   0  4
  [18] .init_array       INIT_ARRAY      080e9f6c 0a0f6c 000008 00  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      080e9f74 0a0f74 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        080e9f7c 0a0f7c 000004 00  WA  0   0  4
  [21] .data.rel.ro      PROGBITS        080e9f80 0a0f80 000070 00  WA  0   0 32
  [22] .got              PROGBITS        080e9ff0 0a0ff0 000008 04  WA  0   0  4
  [23] .got.plt          PROGBITS        080ea000 0a1000 000044 04  WA  0   0  4
  [24] .data             PROGBITS        080ea060 0a1060 000f20 00  WA  0   0 32
  [25] .bss              NOBITS          080eaf80 0a1f80 000e0c 00  WA  0   0 32
  [26] __libc_freeres_pt NOBITS          080ebd8c 0a1f80 000018 00  WA  0   0  4
  [27] .comment          PROGBITS        00000000 0a1f80 000034 01  MS  0   0  1
  [28] .shstrtab         STRTAB          00000000 0b0ae0 00014c 00      0   0  1
  [29] .symtab           SYMTAB          00000000 0a1fb4 007e50 10     30 848  4
  [30] .strtab           STRTAB          00000000 0a9e04 006cdc 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

當(dāng)然還有很多其他的如符號表霎俩、字符串表等等信息哀军。

開始挖ELF的加載過程,怎么動起來的打却。
exec代碼如下:

int Exec(int argc, char *argv[])
{
        int pid;
        /* fork another process */
        pid = fork();
        if (pid < 0)
        {
                /* error occurred */
                fprintf(stderr,"Fork Failed!");
                exit(-1);
        }
        else if (pid == 0)
        {
                /*       child process  */
        printf("This is Child Process!\n");
                execlp("/hello","hello",NULL);
        }
        else
        {
                /*      parent process   */
        printf("This is Parent Process!\n");
                /* parent will wait for the child to complete*/
                wait(NULL);
                printf("Child Complete!\n");
        }
}
  • 可以看到杉适,代碼中使用了exec這個(gè)系統(tǒng)調(diào)用,而且是在子進(jìn)程中使用的柳击。exec這個(gè)系統(tǒng)調(diào)用很有意思猿推,和fork相反,exec調(diào)用一次捌肴,從不返回蹬叭,因?yàn)樗采w了調(diào)用進(jìn)程。

搭建好執(zhí)行環(huán)境:


設(shè)置了以下斷點(diǎn):


執(zhí)行exec状知,和我們之前的系統(tǒng)調(diào)用一樣秽五,停在了sys_execve

  • 停在了getname處,可以看到饥悴,在查找/hello這個(gè)應(yīng)用筝蚕,而在我們簡單的文件系統(tǒng)(我們的文件系統(tǒng)只有一個(gè)/根目錄)下這個(gè)hello是存在的卦碾。

-- 注:有必要研究下這個(gè)系內(nèi)核的文件系統(tǒng)是怎么實(shí)現(xiàn)的,在QEMU下用-initrd roofs.img的原理

  • 繼續(xù)追蹤下去起宽,可以看到洲胖,執(zhí)行了do_execv_common。停在了load_elf_binary處坯沪,這個(gè)函數(shù)很是關(guān)鍵绿映,可以說,這個(gè)函數(shù)的實(shí)現(xiàn)部分和ELF的文件標(biāo)準(zhǔn)內(nèi)的各種section腐晾、header等打交道叉弦,要想搞明白這個(gè),還是先把elf文件的規(guī)約讀懂藻糖。

  • 其實(shí)一句話說完淹冰,這段代碼主要是圍繞著elf文件的格式,來準(zhǔn)備裝載一個(gè)可執(zhí)行程序所需要的各種環(huán)境巨柒。怎么說呢樱拴,應(yīng)該說是這就是和ELF相呼應(yīng)的地方。不過洋满,若想搞明白晶乔,到底是怎樣,兩方面都要搞清楚牺勾。


  • 完了到了start_thread正罢,我理解的是,start_kernel并沒有真正的start驻民,而是對內(nèi)核的相關(guān)寄存器做了修改翻具。

真正start的時(shí)候,還是在調(diào)度的時(shí)候回还,也即是把新的進(jìn)程準(zhǔn)備好呛占,放到調(diào)度隊(duì)列之后伍俘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肴茄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子仙粱,更是在濱河造成了極大的恐慌仅叫,老刑警劉巖帜篇,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诫咱,居然都是意外死亡笙隙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門坎缭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來竟痰,“玉大人签钩,你說我怎么就攤上這事』悼欤” “怎么了铅檩?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長莽鸿。 經(jīng)常有香客問我昧旨,道長,這世上最難降的妖魔是什么祥得? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任兔沃,我火速辦了婚禮,結(jié)果婚禮上级及,老公的妹妹穿的比我還像新娘乒疏。我一直安慰自己,他們只是感情好饮焦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布怕吴。 她就那樣靜靜地躺著,像睡著了一般追驴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疏之,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天殿雪,我揣著相機(jī)與錄音,去河邊找鬼锋爪。 笑死丙曙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的其骄。 我是一名探鬼主播亏镰,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拯爽!你這毒婦竟也來了索抓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤毯炮,失蹤者是張志新(化名)和其女友劉穎逼肯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桃煎,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡篮幢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了为迈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片三椿。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缺菌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出搜锰,到底是詐尸還是另有隱情伴郁,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布纽乱,位于F島的核電站蛾绎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鸦列。R本人自食惡果不足惜租冠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望薯嗤。 院中可真熱鬧顽爹,春花似錦、人聲如沸骆姐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玻褪。三九已至肉渴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間带射,已是汗流浹背同规。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窟社,地道東北人券勺。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像灿里,于是被迫代替她去往敵國和親关炼。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容