ELF檔案動態重定向
本文分析ELF檔案在執行時動態重定向的實現。
以下面的兩個程式為例:
$ cat mlib.c
int boo()
{
return 0;
}
int foo()
{
void *fn = boo;
boo();
return 0;
}
$ cat ./main.c
int boo();
int main()
{
void *fn = boo;$ cat ./main.c
int boo();
int main()
{
void *fn = boo;
boo();
}
boo();
}
$ gcc -o libmlib.so -shared -fPIC ./mlib.c $ gcc -o main -lmlib -L. ./main.c
main函式中引用的函式boo定義在shared library中。
loader如何實現對shared library中的函式呼叫進行重定向
初始時,main函式中對boo的呼叫實際call的是[email protected],地址為0x400560,位置處於section .plt中(參見表一)。(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400660 <+0>: push %rbp
0x0000000000400661 <+1>: mov %rsp,%rbp
=> 0x0000000000400664 <+4>: sub $0x10,%rsp
0x0000000000400668 <+8>: movq $0x400560,-0x8(%rbp)
0x0000000000400670 <+16>: mov $0x0,%eax
0x0000000000400675 <+21>: callq 0x400560 <
0x000000000040067a <+26>: leaveq
0x000000000040067b <+27>: retq
End of assembler dump.
對[email protected]進行反彙編,可以看出第一條jmp語句跳到了下一行0x400566。0x2被push到了堆疊。0x2應該代表.rela.plt中的第三項(0為第一項),該資訊將被傳遞給loader。
(gdb) disassemble 0x400560
Dump of assembler code for function [email protected]
0x0000000000400560 <+0>: jmpq *0x2004f2(%rip) # 0x600a58 <[email protected]>
0x0000000000400566 <+6>: pushq $0x2
0x000000000040056b <+11>: jmpq 0x400530
(gdb) x /xg 0x600a58
0x600a58 <[email protected]>: 0x0000000000400566
push操作後,jmp到了0x400530,接著又把0x600a38中的資料push到了堆疊。注意0x600a38是.got.plt 中的第二個entry(每個entry的size是8)。最後又jmp到了0x00007ffff7def2d0(地址0x600a40中的資料)。
(gdb) x /5i 0x400530
0x400530: pushq 0x200502(%rip) # 0x600a38
0x400536: jmpq *0x200504(%rip) # 0x600a40
0x40053c: nopl 0x0(%rax)
0x400540 <[email protected]>: jmpq *0x200502(%rip) # 0x600a48 <[email protected]>
0x400546 <[email protected]+6>: pushq $0x0
(gdb) x /xg 0x600a38
0x600a38: 0x00007ffff7ffe190
(gdb) x /xg 0x600a40
0x600a40: 0x00007ffff7def2d0
從shared library map中可以看出,0x00007ffff7def2d0對應到/lib64/ld-linux-x86-64.so.2中。loader將利用之前push的兩個引數0x2和0x00007ffff7ffe190對[email protected](即0x600a58)中的資料進行更新,修改成函式boo的實際地址。
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x00007ffff7ddbba0 0x00007ffff7df4baa Yes (*) /lib64/ld-linux-x86-64.so.2
No linux-vdso.so.1
0x00007ffff7bda5b0 0x00007ffff7bda6c8 Yes (*) ./libmlib.so
0x00007ffff784c470 0x00007ffff7978aa0 Yes (*) /usr/lib/libc.so.6
(*): Shared library is missing debugging information.
將程式執行到斷點0x000000000040067a,檢查0x600a58的數值,可以看出已經變成了函式boo的地址。
(gdb) x /xg 0x600a58
0x600a58 <[email protected]>: 0x00007ffff7bda698
(gdb) p boo
$1 = {<text variable, no debug info>} 0x7ffff7bda698 <boo>
loader如何實現對shared library中變數的重定向
在main函式中對boo的地址進行了引用。可以看出boo的地址就是0x400560,即<[email protected]>,而非boo的真正地址。後面可以看出,即使在libmlib.so中對boo的引用同樣也指向0x400560。××這樣做的目的應當是確保在main和library當中對同一函式的地址引用是相等的××。0x0000000000400668 <+8>: movq $0x400560,-0x8(%rbp)
在shared library中的foo函式中對boo也做了引用,可以看出boo的地址被用0x200978中的資料間接代替了,而且0x200978中的數值是0,顯然不對。
gdb ./libmlib.so
(gdb) disassemble foo
Dump of assembler code for function foo:
0x00000000000006a3 <+0>: push %rbp
0x00000000000006a4 <+1>: mov %rsp,%rbp
0x00000000000006a7 <+4>: sub $0x10,%rsp
0x00000000000006ab <+8>: mov 0x2002c6(%rip),%rax # 0x200978
0x00000000000006b2 <+15>: mov %rax,-0x8(%rbp)
0x00000000000006b6 <+19>: mov $0x0,%eax
0x00000000000006bb <+24>: callq 0x590 <[email protected]>
0x00000000000006c0 <+29>: mov $0x0,%eax
0x00000000000006c5 <+34>: leaveq
0x00000000000006c6 <+35>: retq
(gdb) x /xg 0x200978
0x200978: 0x0000000000000000
這是因為在.rela.dyn中有一個boo的重定向項。當libmlib.so被load進main中時,loader將會根據相應symbol的地址修正所有R_X86_64_GLOB_DAT重定向項的值。這些重定向項所指向的需要修改的地址都位於section .got中(參見表三)。
$ readelf -r ./libmlib.so
Relocation section '.rela.dyn' at offset 0x430 contains 9 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000200780 000000000008 R_X86_64_RELATIVE 660
000000200788 000000000008 R_X86_64_RELATIVE 620
0000002009b8 000000000008 R_X86_64_RELATIVE 2009b8
000000200958 000200000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0
000000200960 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000200968 000400000006 R_X86_64_GLOB_DAT 0000000000000000 _Jv_RegisterClasses + 0
000000200970 000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0
000000200978 000a00000006 R_X86_64_GLOB_DAT 0000000000000698 boo + 0
000000200980 000600000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize + 0
Relocation section '.rela.plt' at offset 0x508 contains 3 entries:
Offset Info Type Sym. Value Sym. Name + Addend
0000002009a0 000300000007 R_X86_64_JUMP_SLO 0000000000000000 __gmon_start__ + 0
0000002009a8 000a00000007 R_X86_64_JUMP_SLO 0000000000000698 boo + 0
0000002009b0 000600000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_finalize + 0
下面可以看出,在load之後foo中所引用的boo的地址更新成了0x400560,即<[email protected]>。
gdb ./main
(gdb) disassemble foo
Dump of assembler code for function foo:
0x00007ffff7bda6a3 <+0>: push %rbp
0x00007ffff7bda6a4 <+1>: mov %rsp,%rbp
0x00007ffff7bda6a7 <+4>: sub $0x10,%rsp
0x00007ffff7bda6ab <+8>: mov 0x2002c6(%rip),%rax # 0x7ffff7dda978
0x00007ffff7bda6b2 <+15>: mov %rax,-0x8(%rbp)
0x00007ffff7bda6b6 <+19>: mov $0x0,%eax
0x00007ffff7bda6bb <+24>: callq 0x7ffff7bda590 <[email protected]>
0x00007ffff7bda6c0 <+29>: mov $0x0,%eax
0x00007ffff7bda6c5 <+34>: leaveq
0x00007ffff7bda6c6 <+35>: retq
End of assembler dump.
(gdb) x /xg 0x7ffff7dda978
0x7ffff7dda978: 0x0000000000400560
與重定向相關的section
.plt重定向的入口程式碼。對於每一個需要重定向的函式,都會類似下面的程式碼。其中push的數值應該代表.rela.plt中的對應entry。
(gdb) disassemble 0x400560
Dump of assembler code for function [email protected]:
0x0000000000400560 <+0>: jmpq *0x2004f2(%rip) # 0x600a58 <[email protected]>
0x0000000000400566 <+6>: pushq $0x2
0x000000000040056b <+11>: jmpq 0x400530
.got
R_X86_64_GLOB_DAT重定向項所指向的需要修改的地址。用於重定向對於變數的引用。
.got.plt
每一項佔8個位元組。
第一項的數值是0x0000000000600848,即dynamic section的起始地址。
第二項的數值是0x00007ffff7ffe190,據說代表link_map的起始地址?loader用它進行relocation.
第三項的數值是0x00007ffff7def2d0,是loader的_dl_runtime_resolve函式起始地址。
(gdb) disassemble 0x00007ffff7def2d0
Dump of assembler code for function _dl_runtime_resolve:
之後的每一項對應一個函式的重定向地址。初始時,如[email protected]所示,該值指向下一條彙編指令。重定向完成後,該值指向真正的函式地址。
(gdb) x /8xg 0x600a30
0x600a30: 0x0000000000600848 0x00007ffff7ffe190
0x600a40: 0x00007ffff7def2d0 0x00007ffff784e920
附表
表一,main的sectionSection Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000400200 00000200
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 000000000040021c 0000021c
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.build-i NOTE 000000000040023c 0000023c
0000000000000024 0000000000000000 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000400260 00000260
000000000000003c 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 00000000004002a0 000002a0
0000000000000120 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 00000000004003c0 000003c0
00000000000000b5 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 0000000000400476 00000476
0000000000000018 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000400490 00000490
0000000000000020 0000000000000000 A 6 1 8
[ 9] .rela.dyn RELA 00000000004004b0 000004b0
0000000000000018 0000000000000018 A 5 0 8
[10] .rela.plt RELA 00000000004004c8 000004c8
0000000000000048 0000000000000018 A 5 12 8
[11] .init PROGBITS 0000000000400510 00000510
000000000000001a 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 0000000000400530 00000530
0000000000000040 0000000000000010 AX 0 0 16
[13] .text PROGBITS 0000000000400570 00000570
0000000000000184 0000000000000000 AX 0 0 16
[14] .fini PROGBITS 00000000004006f4 000006f4
0000000000000009 0000000000000000 AX 0 0 4
[15] .rodata PROGBITS 0000000000400700 00000700
0000000000000004 0000000000000004 AM 0 0 4
[16] .eh_frame_hdr PROGBITS 0000000000400704 00000704
0000000000000034 0000000000000000 A 0 0 4
[17] .eh_frame PROGBITS 0000000000400738 00000738
00000000000000f4 0000000000000000 A 0 0 8
[18] .init_array INIT_ARRAY 0000000000600830 00000830
0000000000000008 0000000000000000 WA 0 0 8
[19] .fini_array FINI_ARRAY 0000000000600838 00000838
0000000000000008 0000000000000000 WA 0 0 8
[20] .jcr PROGBITS 0000000000600840 00000840
0000000000000008 0000000000000000 WA 0 0 8
[21] .dynamic DYNAMIC 0000000000600848 00000848
00000000000001e0 0000000000000010 WA 6 0 8
[22] .got PROGBITS 0000000000600a28 00000a28
0000000000000008 0000000000000008 WA 0 0 8
[23] .got.plt PROGBITS 0000000000600a30 00000a30
0000000000000030 0000000000000008 WA 0 0 8
[24] .data PROGBITS 0000000000600a60 00000a60
0000000000000010 0000000000000000 WA 0 0 8
[25] .bss NOBITS 0000000000600a70 00000a70
0000000000000008 0000000000000000 WA 0 0 4
[26] .comment PROGBITS 0000000000000000 00000a70
000000000000004e 0000000000000001 MS 0 0 1
[27] .shstrtab STRTAB 0000000000000000 00000abe
0000000000000108 0000000000000000 0 0 1
[28] .symtab SYMTAB 0000000000000000 00001348
0000000000000648 0000000000000018 29 47 8
[29] .strtab STRTAB 0000000000000000 00001990
000000000000022f 0000000000000000 0 0 1
表二,main的重定向資訊
注意.rela.plt中的第三行boo的重定向資訊,其中offset是000000600a58,剛好在section .got.plt中。
$ readelf -r ./main
Relocation section '.rela.dyn' at offset 0x4b0 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000600a28 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
Relocation section '.rela.plt' at offset 0x4c8 contains 3 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000600a48 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0
000000600a50 000300000007 R_X86_64_JUMP_SLO 0000000000000000 __gmon_start__ + 0
000000600a58 000800000007 R_X86_64_JUMP_SLO 0000000000400560 boo + 0
表三,libmlib.so的section(部分)
$ readelf -S ./libmlib.so
There are 27 section headers, starting at offset 0xad8:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.gnu.build-i NOTE 0000000000000190 00000190
0000000000000024 0000000000000000 A 0 0 4
[ 2] .gnu.hash GNU_HASH 00000000000001b8 000001b8
0000000000000040 0000000000000000 A 3 0 8
..........
[19] .got PROGBITS 0000000000200958 00000958
0000000000000030 0000000000000008 WA 0 0 8
相關推薦
ELF檔案動態重定向
本文分析ELF檔案在執行時動態重定向的實現。 以下面的兩個程式為例: $ cat mlib.c int boo() { return 0; } int foo() { void *fn = boo; boo(); return 0; }
apache(.htaccess檔案)路由重定向配置步驟
1.在專案根目錄資料夾下面新建.htaccess檔案(apache重寫); .htaccess檔案內容如下: <IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f Rewri
url下載檔案(重定向+cookie設定)
很多時候,下載檔案時會重定向,並且要求攜帶cookie才允許下載,這種情況下,如果讓下載支援重定向,並且設定cookie呢?下面的程式碼可以供大家參考。 public static voi
過濾驅動 檔案訪問重定向方法
在pre callback 中,使用IoReplaceFileObjectName 修改 Data->Iopb->TargetFileObject 檔案路徑, 然後: Data->IoStatus.Status = ST
Linux:基礎IO(檔案描述符分配規則)(重定向)(inode)(軟硬連結)(動態庫靜態庫)
目錄 檔案描述符的分配規則 重定向原理 FILE 總結 理解檔案系統 inode是什麼 inode內容 硬連結 軟連結 軟硬連結區別: 動態庫和靜態庫 如何生成自己的動態庫和靜態庫 如何連結一個庫生成可執行程式 檔案描述符的分配規則 最
Python檔案&IO處理技巧(1): 讀寫、重定向、間隔符、路徑、存在性與檔案列表
1. 文字資料的讀寫 open() & write() : rt模式的重新整理模式 當我們需要讀寫各種不同編碼的文字資料(如ASCII,UTF-8或UTF-16編碼等), 可以直接使用帶rt模式的open()內建函式。如果需要將文字內容寫入到一個檔案中,就要使用帶有 w
IDA動態遠端除錯elf檔案的最簡單設定(姿勢)
0x01: 將IDA安裝目錄下的dbgsrv資料夾整個都拷貝到linux下(我都拷貝到了ubuntu桌面) 0x02: 將所要除錯的檔案直接放在dbgsrv目錄下 0x03: IDA設定如下: 0x04: 這裡根據你的elf檔案型別
ELF檔案載入與動態連結(二)
GOT應該儲存的是puts函式的絕對虛地址,這裡為什麼儲存的卻是[email protected]的第二條指令呢? 原來“直譯器”將動態庫載入記憶體後,並沒有直接將函式地址更新到GOT表中,而是在函式第一次被呼叫時,才會進行函式地址的重定位,這樣做的好處是可以加快程式載入速度,尤其對大型程式來說。有
ELF檔案載入與動態連結(一)
關於ELF檔案的詳細介紹,推薦閱讀: ELF檔案格式分析 —— 滕啟明。ELF檔案由ELF頭部、程式頭部表、節區頭部表以及節區4部分組成。 通過objdump工具和readelf工具,可以觀察ELF檔案詳細資訊。 ELF檔案載入過程分析 從編譯、連結和執行的角度,應用程
轉載:C#關閉檔案重定向,實現操作System32資料夾
我們已經知道: ①:本機模式64位程式執行在純模式下,並且訪問鍵和儲存在以下注冊表子鍵中的值:HKEY_LOCAL_MACHINE \ Software ②:32位程式執行在WOW64模式下,並且訪問鍵和值儲存在以下注冊表子項中:HKEY_LOCAL_MACHINE \ So
[譯]如何將docker日誌重定向到單個檔案裡
原文來源: how-to-redirect-docker-logs-to-a-single-file 問題: 我想把某一個docker的log全部匯出到一個檔案裡進行分析,我該怎麼做? 其實不用那樣操作,Docker預設把所有的日誌存在一個log檔案裡面。你可以通過以下命令檢視docker對應log的地址:
SpringMVC篇:轉發與重定向、圖片檔案上傳、Json(jackson)
注意: 專案:war 和 專案:war exploded 兩者並不同,idea 執行 專案:war exploded <dependency> <groupId>org.
重定向標準輸入到檔案
#!/bin/bash echo '' > redis.txt for((i=1;i<=3;i++)) do echo 'get te
SprinMVC轉發、重定向、收集date資料、自定義轉換器、檔案上傳、json資料轉換
1.專案模組圖 2.完成SpringMVC的基本搭建 pom.xml(下載jar包的檔案) <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.
Linux基礎-檔案管理和重定向
Linux基礎-檔案管理和重定向 2018/7/27 15:00:07 1. 每一個分割槽都是一個獨立存在的檔案系統 2. 目錄:路徑對映符 3. 檔案 檔案有兩種資料 元資料:描述資料的資料屬性 metadata 資料:data FHS:
tee---將資料重定向到檔案,
tee命令用於將資料重定向到檔案,另一方面還可以提供一份重定向資料的副本作為後續命令的stdin。簡單的說就是把資料重定向到給定檔案和螢幕上。 存在快取機制,每1024個位元組將輸出一次。若從管道接收輸入資料,應該是緩衝區滿,才將資料轉存到指定的檔案中。若檔案內容不到1024個位元組,則接收完
動態連結中資料的重定向例子
程式的大致框架: 主程式: #include <stdio.h> extern void hello(void); extern int a; int main(void) { printf("in main.c a=%d\n", a); printf("i
Nginx下訪問原始碼.html檔案重定向到相對目錄下.php檔案
請求報錯404故障 故障描述: LNMP環境下發布商城原始碼,通過web請求訪問.html檔案報404錯誤請求檔案不存在,在原始碼裡只存在.php檔案 例子圖
動態sql 和重定向
<select id="findByTiaoJian" parameterType="cn.zzsxt.furniture.vo.TiaojianVo" resultType="cn.zzsxt.furniture.vo.MoneyUserVo"> SELEC
【C language】測試自動程式碼生成過程的重定向到檔案
測試自動程式碼生成過程的重定向 #include <stdio.h> #include <string.h> #include <stdbool.h> #include <stdio.h> #include <stdar