修改ELF檔案統計記憶體洩露

2021-10-23 04:24:46 字數 4012 閱讀 1909

本篇不走尋常路,想要正常的記憶體除錯手段請查閱核心相關的記憶體debug功能.

程式開發了很長時間,參與開發的人也很多,今天我想用實驗統計來證明我們寫的核心module沒有產生記憶體洩露,通常的做法是封裝記憶體的api,中間加上統計邏輯,但是我不想改他們的**,有什麼辦法嗎?

我翻了一下code,裡面有上百處申請記憶體的位置,主要使用了兩種api,一種是kmalloc,另外一種是建立自己的kmem_cache的方式.後一種自帶記憶體洩露檢查,當module解除安裝時嘗試destroy kmem_cache,如果還有slab物件沒有歸還時會自動報warning,這也是一種方式,建立自己的kmem_cache,通過slabinfo檢視使用情況,唯一不好的是建立一大堆kmem_cache.

而kmalloc/kzalloc有什麼方法嗎?剛開始我考慮借助gcc巨集的方式,可以考慮下面這種實現是否可以成功:

.#define hook_kmalloc kmalloc

hook_kmalloc()

這種當然是不成功的,它最終展開的邏輯想要展示成下面這樣,當然在巨集展開後會發生重複定義的錯誤:

func1()
沒有辦法在乙個module中不修改**的情況將直接進行func呼叫的情況變成進行func->hook_func->func的操作.

最後採用乙個折中的方法:

1.寫個除錯module1,封裝kmalloc成hook_kmalloc,kfree->hook_kfree,加上除錯邏輯

2.module中把不必要的都去掉,然後放到唯一的乙個標頭檔案中,大部分都不關心標頭檔案,只要不報警應該沒問題.

之後在這個標頭檔案中做文章,想除錯時不呼叫核心原生的而是呼叫module1中的介面.

#ifndef hook_slab_h

#define hook_slab_h

#ifdef debug

#define hook_kmalloc kmalloc

#define hook_kfree kfree

#else

# include #endif

#endif

有沒有辦法一點**都不修改的情況下進行替換呢?二進位制編輯替換

這種hack方式是進行二進位制格式的替換,只需要掌握一點elf格式的基礎就可以,so easy!!!

kmalloc預設是inline的,它實際呼叫__kmalloc,我們可以根據module的.rela.text的資訊進行替換,所有呼叫__kmalloc的地方變成hook_kmalloc,我當然不會傻傻的修改重定位段,只需要簡單的修改一下字串就可以完成替換.下面只是提供原型,將__kmalloc替換成1_kmalloc,不寫程式直接用工具編輯二進位制檔案.

module原始的資訊:

readelf -r test.ko |grep _kmalloc

000000006203 051300000002 r_x86_64_pc32 0000000000000000 __kmalloc - 4

......

0000000278f2 051300000002 r_x86_64_pc32 0000000000000000 __kmalloc - 4

總共有n個使用__kmalloc的位置,下面是重定位段的資訊:

readelf -s test.ko 

there are 54 section headers, starting at offset 0x1109688:

section headers:

[nr] name type address offset

size entsize flags link info align

... [ 3] .rela.text rela 0000000000000000 00978450

00000000000282c0 0000000000000018 i 51 2 8

[51] .symtab symtab 0000000000000000 0096ab28

0000000000007c98 0000000000000018 52 366 8

[52] .strtab strtab 0000000000000000 009727c0

0000000000005c90 0000000000000000 0 0 1

# nm test.ko |grep kmalloc

u __kmalloc

u kmalloc_caches

u kmalloc_order_trace

重定位段的link記錄符號表的index,info記錄重定位段應用在哪個section上.

簡單捋一捋整個過程:在insmod的過程中會應用重定位段,其中查詢需要的符號位置也就是符號表中的項,符號並沒有直接儲存函式名稱而是儲存了相關的字串表的索引和偏移,我們只需要簡單對應的字串的內容就可以完成.

在這裡需要對使用__kmalloc的位置進行重定位,修改字串表中__kmalloc為1_kmalloc之後,安裝時module就不再依賴__kmalloc而是1_kmalloc,我們就成功通過修改二進位制程式來完成hook.

#readelf -r test.ko |grep _kmalloc

000000006203 051300000002 r_x86_64_pc32 0000000000000000 1_kmalloc - 4

......

0000000278f2 051300000002 r_x86_64_pc32 0000000000000000 1_kmalloc - 4

#nm zsdefend.ko |grep kmalloc

u 1_kmalloc

#dmesg:

[175853.839949] test: unknown symbol 1_kmalloc (err 0)

限制:

1.修改二進位制module在開啟簽名之後因為修改內容,也就是數字簽名必然會不一致,所以在開啟強安全功能的系統上就不能這樣搞了

2.修改的函式名還是有限制的,修改後的函式名長度》原始的函式名長度,否則就越界了.

當然也可以取任意長度的hook名稱,但是需要做一些額外的工作,過程如下:

2.1.在module的.strtab中追加想要的hook名稱,函式名就是乙個普通的字串,以0結尾.

objcopy --dump-section .strtab=strtab.sec test.ko

echo -ne "hook_kmalloc\x00" >>strtab.sec

objcopy --update-section .strtab=strtab.sec test.ko

2.2.修改.symtab中的指標,指向追加的hook名稱

objcopy --dump-section .symtab=symtab.sec test.ko

我們從這裡看符號的偏移051300000002>>32=0x513,之後編輯這個偏移的符號表的st_name

readelf -r test.ko |grep _kmalloc

000000006203 051300000002 r_x86_64_pc32 0000000000000000 1_kmalloc - 4

vim -b symtab.sec # %!xxd %!xxd -r

更新符號表

objcopy --update-section .symtab=symtab.sec test.ko

Android記憶體洩露利器(RSS記憶體統計篇)

前言 rss resident set size 表示實際使用物理記憶體 包含共享庫占用的記憶體 因為它包含了共享記憶體,所以他的意義不及pss。所以現在檢視記憶體使用情況一般參照pss。因此現在一般不使用getprocessstate.bat,而是使用getmemorystate.bat andr...

記憶體模型與elf檔案

bss段 bss segment 用於存放程式中未經初始化的全域性變數和靜態區域性變數。在目標檔案中,這個段並不佔據實際空間,它僅僅只是乙個佔位符。bss段屬於靜態記憶體分配。資料段 data segment 通常是指用來存放程式中已初始化的全域性變數和靜態區域性變數的一塊記憶體區域,讀寫屬性。資料...

Linux下記憶體統計和記憶體洩露類問題的定位方法

在產品的開發中,通過對當前系統消耗記憶體總量的統計,可以對產品所需記憶體總量進行精確的評估,從而選擇合適的記憶體晶元與大小,降低產品的成本。在遇到記憶體洩露類問題時,經常會對此束手無策,本文通過對proc下程序相關的檔案進行分析,精確評估系統消耗記憶體的大小,還可以對記憶體洩露類問題的解決提供一種定...