由于在書里沒有找到具體的托管資源數(shù)據(jù)結(jié)構(gòu),這個過程主要通過dnlib源碼進(jìn)行分析崩泡。
以上是本次研究使用的樣本禁荒,目的是能夠順利讀取到托管數(shù)據(jù)中的PE文件,即“資源正文”(便于理解)角撞。
源碼開始就做了一個4字節(jié)的判定呛伴,因此在不明含義的時候勃痴,先把他當(dāng)作一個四字節(jié)的固定標(biāo)識來看。
接著是一個checkreader函數(shù):
也就是標(biāo)識符热康,后面4個字節(jié)(4-8)為numReader沛申,8-12就是readersdSize,后面是resourceReaderFullName和resourceSetFullName兩個字符串姐军。
接下來铁材,是三個整型,分別為version奕锌,numResources, numUserTypes:
可以看到著觉,版本2,資源數(shù)目為2個:
驗(yàn)證一下:
順便拿來另一個資源數(shù)據(jù)來看歇攻,版本2固惯,資源數(shù)目12個。
后面就是基于numUserTypes讀取了一波字符串缴守,然后不當(dāng)人的弄了一個reader的position賦值葬毫,~在C#里是按位取反運(yùn)算符是一元運(yùn)算符,具有"翻轉(zhuǎn)"位效果屡穗,即0變成1贴捡,1變成0,所以 0000 0111 變成1111 1000:
復(fù)習(xí)了一下補(bǔ)碼反碼的知識:
負(fù)數(shù) = 負(fù)數(shù)的絕對值按位取反+1
負(fù)數(shù)按位取反+1 =負(fù)數(shù)的絕對值
因此1111 1000值為-8
那也就是說村砂,當(dāng)前的位置(當(dāng)前應(yīng)該指向第0x0111個字節(jié))會變成 (當(dāng)前偏移+7)& 11111000烂斋,為0x0118。
之后基于numResources會連續(xù)獲取兩組整型數(shù)础废,offsets后面對的尋址有用汛骂。
獲取到dataBaseOffset才算是真正即將開始資源正文,然后獲取資源名稱评腺,和資源偏移加載資源:
至此帘瞭,通過dataBase加上resourceOffset就能夠準(zhǔn)確地找到資源的正文了,前5字節(jié)為7bit編碼整型數(shù)蒿讥,表示資源類型蝶念。算法如下:
之后為正文內(nèi)容,分析結(jié)束芋绸。