MS.Net CLR 擴(kuò)展PE結(jié)構(gòu)分析2
2024-07-10 13:02:14
供稿:網(wǎng)友
本文來源于網(wǎng)頁設(shè)計(jì)愛好者web開發(fā)社區(qū)http://www.html.org.cn收集整理,歡迎訪問。flier lu <[email protected]>
注意:本系列文章在水木清華bbs(smth.org)之.net版首發(fā),
轉(zhuǎn)載請保留以上信息,發(fā)表請與作者聯(lián)系
metadata 篇
第一章 metadata 概述
1.1 什么是 metadata
metadata翻譯成中文是“元數(shù)據(jù)”,可以理解為type of type,
說白了就是描述類型的類型數(shù)據(jù)。從最初級的語言層面支持的rtti
(“近代”的編程語言基本上都提供了足夠的支持,如c++,delphi等,
部分較“落伍”的語言也通過不同形式如擴(kuò)展庫提供了模擬支持,
“現(xiàn)代”的編程語言則提供了強(qiáng)力的支持,如java和c#<本質(zhì)是clr>),
到后來二進(jìn)制級的com的idl和類型庫(類型庫是idl編譯后的二進(jìn)制形式),
到現(xiàn)在的metadata,其實(shí)是遵循著相同的設(shè)計(jì)思路。只是出于不同的需求
設(shè)計(jì)、實(shí)現(xiàn),有這各自的優(yōu)點(diǎn)缺點(diǎn)罷了。但隨著語言的發(fā)展,更多的需求集中在
靈活性方面,因而語言發(fā)展的趨勢是元數(shù)據(jù)的使用越來越多、支持越來越強(qiáng)。
舉個(gè)最簡單的例子,在ide中,動(dòng)態(tài)顯示當(dāng)前對象的方法、屬性名列表的功能
(ms叫intellisense,borland叫codeinsight),就得宜于類型信息
以前在vc里實(shí)現(xiàn),比較麻煩,得生成專門的符號庫;在vb里強(qiáng)一點(diǎn),可以通過
com的idispatch,itypeinfo,itypelib等接口動(dòng)態(tài)獲取,但編程麻煩要死;
到clr,庫一級直接提供支持,可以通過system.reflection完全控制
甚至比com類型庫更高一級地支持動(dòng)態(tài)創(chuàng)建。
對用戶來說,可以完全了解當(dāng)前程序接口,有哪些module,哪些class,
哪些method等等,這給開發(fā)者提供了巨大的創(chuàng)造空間。如dunit(dotnet下
的xunit單元測試平臺(tái))就大量使用reflection機(jī)制,我們等會(huì)談使用時(shí)再說。
1.2 metadata在clr中的作用
對于clr架構(gòu)來說,metadata可以算是核心操作對象,幾乎絕大多數(shù)功能
都需要參考其數(shù)據(jù)。從靜態(tài)的il代碼構(gòu)成(二進(jìn)制編碼中直接使用metadata里的token)
到動(dòng)態(tài)jit編譯器(使用metadata定位il代碼及其關(guān)系);從簡單的代碼載入執(zhí)行
(class loader通過metadata定位代碼入口、編譯執(zhí)行)到復(fù)雜的不同語言互操作
(如vb.net繼承c#的類,實(shí)際上是直接繼承clr中metadata中的類);等等……
幾乎所有地方都能看到metadata的身影。
因?yàn)楸疚牡闹饕康氖墙榻B底層結(jié)構(gòu),這里就不再羅嗦metadata的好處了,
反正以后文章中大家會(huì)次次看到他,各種優(yōu)點(diǎn)自己慢慢體會(huì)吧 :)
1.3 如何訪問和使用 metadata
做了一通廣告,大家一定很關(guān)心如何使用metadata,聽我慢慢道來
在clr里使用metadata,可以在三個(gè)層面進(jìn)行操作。
最簡單的方法是直接通過類庫提供的system.reflection命名空間中的
若干類進(jìn)行訪問,例如
using system.reflection;
using system;
public class simple
{
public static void main ()
{
module mod = assembly.getexecutingassembly().getmodules () [0];
console.writeline ("module name is " + mod.name);
console.writeline ("module fullyqualifiedname is " +
mod.fullyqualifiedname);
console.writeline ("module scopename is " + mod.scopename);
}
}
這種訪問方式使用起來最簡單,功能也足夠強(qiáng)大,能夠完成我們絕大多數(shù)的需要,
特別是在system.reflection.emit命名空間中,更提供了動(dòng)態(tài)生成、修改的支持
功能強(qiáng)大得我都想不出能有什么改進(jìn)了 :) (寫.net病毒就靠他了,hoho)
不過這種方式必須有clr環(huán)境的支持,受到庫功能的限制(后面我們會(huì)看到很多
在reflection一級里不提供的信息:),因此ms為工具軟件開發(fā)商提供了另一套
較底層的開發(fā)庫,metadata unmanaged api。這套庫通過一系列com接口,
提供了直接訪問metadata的強(qiáng)大支持,system.reflection應(yīng)該就是使用它實(shí)現(xiàn)的。
有興趣的朋友可以參看frameworksdk/tool developers guide/docs
目錄下的metadata unmanaged api.doc文檔,里面有詳細(xì)的說明。
如同其名字所示,它必須用unmanaged代碼來使用,如傳統(tǒng)的vc,delphi等。
可以說99%的工作,都可以通過上面兩套庫來完成,不過總有些象我這樣的人,
喜歡對技術(shù)追根究底,想把隱藏在美好面紗下的底層架構(gòu)糾出來暴露一把,呵呵
因此有了第三個(gè)層面,二進(jìn)制層面的逆向工程分析。
好在ms為了讓其cli(clr的子集)標(biāo)準(zhǔn)化,公開了大量文檔,總算沒要我用上
softice之類的牛刀,partition ii metadata.doc文檔中對metadata的
二進(jìn)制格式實(shí)現(xiàn)給出了比較詳盡的說明,加上gnome的mono項(xiàng)目已經(jīng)做了很多工作
因而對metadata的二進(jìn)制層面分析不是那么困難。
接下去的文章中,我會(huì)逐漸將metadata在pe中的組織結(jié)構(gòu)逐漸剝離開來,
讓大家能夠了解這個(gè)神秘的clr核心到底是什么,里面隱藏了些什么,我們能夠通過
他做什么,為什么要這樣設(shè)計(jì),等等……
1.4 metadata在pe中的組織結(jié)構(gòu)
說了一通廢話后,回到正體上來,談?wù)刴etadata在pe中的組織結(jié)構(gòu)。
注意:這一章里面我只把metadata結(jié)構(gòu)的大概情況介紹一下,下一章會(huì)專門
針對二進(jìn)制模式分析進(jìn)行詳細(xì)講解。如果你只想了解底層結(jié)構(gòu),可以跳過
下一章。以后的文章也會(huì)遵循這種方式組織,講一些結(jié)構(gòu)、原理,跟著講
一些實(shí)際數(shù)據(jù)分析方法。
上次我們提到clr的頭信息里面專門有一個(gè)字段指向metadata數(shù)據(jù)塊,
實(shí)際上這個(gè)數(shù)據(jù)塊只是metadata的一個(gè)頭結(jié)構(gòu),保存有metadata的信息,
而metadata的實(shí)際數(shù)據(jù),是通過若干不同的heap或者說stream保存的。
這里我統(tǒng)一使用stream“流“作為他的名字,但很多文檔中以heap”堆“作為
其稱呼,我們可以理解他是一個(gè)二進(jìn)制流,其中數(shù)據(jù)以堆的結(jié)構(gòu)進(jìn)行組織。
metadata里最常見的有五種流,#string, #blob, #guid,
#us(user string)和#~流("#"是流名字的前綴)
string流就是一個(gè)字符串堆,metadata內(nèi)部用到的所有字符串如類或方法
的名字等等都以utf8編碼保存在此堆內(nèi)。而用戶的字符串如字符串常量,
則以unicode編碼保存在us(user string)堆內(nèi)。值得注意的是,
us流和string流在二進(jìn)制結(jié)構(gòu)組織上不同,我們后面將分析時(shí)會(huì)詳細(xì)提及。
guid流是保存程序中使用到的guid的數(shù)組,如assembly中module的mvid。
blob流是一個(gè)通用存儲(chǔ)空間,除了guid和字符串以外基本上所有
亂七八糟的東西都放在里面,呵呵,如publickey,常量的值等等。
最重要的是#~流,這是metadata實(shí)際信息存放的地方。#~流結(jié)構(gòu)上以
若干張表(table)的形式組織,每張表存儲(chǔ)某一方面的metadata信息,
如methoddef表存儲(chǔ)所有方法的信息。每張表又由若干的行(row)組成
每行有n個(gè)列(column),每列代表一種信息,如methoddef表中每一行
都有一個(gè)方法的rva,類型標(biāo)志,名字,signature等等信息。在其中通過
各種索引來相互關(guān)聯(lián),整個(gè)組織結(jié)構(gòu)和關(guān)系數(shù)據(jù)庫很相似。
比較特殊的是,這里所有的表通過一個(gè)64bit的有效位圖來表示其存在與否
每種類型的表有一個(gè)編號,如methoddef表的編號是6,則第(1<<(6-1))位置1
因而每個(gè)表的每一行,可以使用一個(gè)唯一的token表示。此token是一個(gè)32bit
無符號整型數(shù),最高一個(gè)字節(jié)表示表的編號,低三個(gè)字節(jié)表示表中的索引號。
如0x06000003表示0x06表(methoddef)中第3行(如myapp::add)
這個(gè)token概念在clr中頻繁使用,如il代碼調(diào)用函數(shù)、使用變量都是使用token。
與之類似的還有coded index,下次講二進(jìn)制實(shí)現(xiàn)時(shí)再說。