再探.NET的PE文件結構(安全篇)

轉自 https://www.cnblogs.com/dwlsxj/p/PE.htmlhtml

1、開篇編輯器

  首先寫在前面,這篇文章源於我的的研究和探索,因爲.NET有本身的反射機制,能夠清楚的將源碼反射出來,這樣你的軟件就很容易被破解,固然這篇文章不會說怎麼樣保護你的軟件不被破解,相反是借用一個軟件來說述是怎麼被攻破的,也會有人說這是一篇破文,我其實這篇文章已經寫了很長時間了,不知道以什麼形式發出來,由於畢竟是有些破解類的東西。可是我以爲從這篇文章相反的是可以帶來一些啓發。你們應該都知道Reflector這個反編譯軟件還有一個插件是專門用來改IL的插件叫Reflexil,這裏咱們也要用到前面那個工具Reflector,後面的插件咱們這裏咱們不用,接下來分析的東西可讓你們可以更深刻.NET的PE,深刻內幕來看看,好,閒話少說….直接上分析。工具

2、詳細分析過程

  若是不懂.NET的PE文件結構的帥哥美女,能夠看一下上一篇文章http://www.cnblogs.com/dwlsxj/p/4052871.html,這裏要用到PE的知識,首先咱們來看一下這個程序的限制,這個程序有顯示限制也就是顯示的列表只能顯示三行。以下圖所示:flex

  咱們如今要用Reflector工具將咱們要破解的程序反編譯一下看一下哪裏沒有跳轉到MessagBox彈出對話框了!反編譯成C#代碼後咱們能夠看到這個程序就一個主界面,看到了Form名字就說明這個是一個Windows的窗體:spa

  點開以後,就發現ProgressChanged方法裏面有內容,裏面包含了彈出消息框的所有代碼,好的咱們這裏就肯定了是這個方法讓這個消息框彈出來的!的確他就是罪魁禍首,先記錄備案。插件

  如今已經知道是哪一個方法彈出消息框來了,那麼咱們就能夠再元數據表中進行查找該方法所在的RVA,這裏我要講一個元數據表中的表這個表就是MethodDef表,這個表很重要也很好玩,這個表裏不但指出了該方法的IL代碼的位置,還限定了方法的屬性。下面來看一下表結構:code

偏移orm

大小htm

名稱blog

說明

0

4

RVA

該方法體的RVA(方法體包括:方法頭、IL代碼、異常處理定義)

4

2

ImplFlags

限定了方法的執行方法(如abstract、P/Invoke)

6

2

Flags

先頂了方法的調用屬性和其餘的一些性質

8

2(4)

Name

指向#String的偏移,表示該方法的名稱

 

2(4)

Signature

指向#Blob的偏移,Signature定義了方法的調用方式(如返回值類型等)

 

2

ParamList

指向Param表的索引,指出了方法的參數

  看到上面這個表不由讓我開心,由於我能找到這個方法存放的位置,也就是我須要的是這個RVA的地址,那麼這個方法的RVA是多少呢?帶着疑問思考,咱們會想到用到一個工具來幫助咱們查找這個方法到底在Method的第幾個,這裏不講直接打開CFF也能夠看到這個方法。我要曲折的找一下。打開ILDASM,既然.NET裏面有元數據這個一號人物,咱們就來小窺一下元數據表,該方法的元數據確定在裏面。

  果真不出咱們所料,確實在元數據裏面有描述,由於元數據是描述數據的數據,那麼咱們就拿到了這個Token標示:0600001F,能夠翻回到上一篇文章找一下這個對應的表是MethodDef正仍是咱們想要的,在這個表下的第31的位置就是咱們要找的內容,懷着疑問打開CFF軟件,來證明一下咱們找的沒有錯!!!

  通過證明是我要找的ProgressChanged方法在元數據表中的描述,如今就能夠取出關鍵信息ProgressChanged方法的RVA:0x3184

  經過CFF查看一下區塊的內容:

  能夠正確的觀察到該方法的RVA存放在.text區塊中,由於該區塊的範圍是:2000~14A00,而3184正好落在了這段地址當中,好,接下來就能夠算出該代碼在物理地址了:3184-2000+200=1384,好的,0x1384就是咱們要在文件中查找的的物理地址。這時候打開16進制編輯器,將程序載入到16進制編輯器中。CTRL+G搜索0x1384這個地址,下面是咱們搜到的地址:

  大家會疑問我怎麼知道這麼一段就是這個方法的代碼呢?讓我來揭曉這個謎底。OK,RVA咱們算的確定沒錯,也就是開始位置1384這個確定是沒錯的,可是代碼的長度不是很肯定對吧?好,打開ILDASM找到這個方法就知道這個方法的長度,或者是在這個方法的頭部咱們就能夠肯定這個方法的長度。

  驗證結果的時候到了經過ILDASM來驗證下:

  經過上述結論咱們能夠證明確實是存放的IL的代碼,咱們能夠看到上面有一個開始指令,是我標記的這個開始指令的IL代碼是ldarg.2加載方法參數2到堆棧上。這裏不看他的個什麼東東!咱們只要知道他的Opcode是多少就行了這個指令的Opcode是04,那麼咱們就在上面的16進制編輯器中進行搜索:

  意思就是04這個指令的前面都是在作初始化堆棧和初始化參數的操做,而從04開始纔是真正執行代碼。好的開始的指令已經找好了,咱們就要看一下咱們要修改那段代碼了,先觀察這段比較num--==0這裏,注意這裏修改代碼的時候不能破壞代碼的長度和代碼的堆棧平衡原理。咱們想如何能讓這個條件永遠不成立,OK,我想到了一個方法就是不讓這個參數進行減法操做,讓他一直進行加法操做!首先先小窺一下的他的IL代碼咱們開講一下總體IL的實現,這裏只講num--==0處的代碼:

 

代碼詳細講解以下:

  IL_002f:  ldloc.3           //加載3到堆棧上。

  IL_0030:  dup               //複製棧頂數據

  IL_0031:  ldc.i4.1          //加載1到堆棧上

  IL_0032:  sub               //3-1的操做。

  IL_0033:  stloc.3           //保存到局部變量3中這是由原來的3變成了2

  IL_0034:  ldc.i4.0          //加載變量0到堆棧

  IL_0035:  ceq               //於O比較後的結果放在堆棧上(返回0或1)    IL_0037:  ldc.i4.0           //由於咱們比較後的結果爲0或1因此在壓入一個0後面進行比較false(ceq從堆棧彈出兩個參數)

  IL_0038:  ceq

  IL_003a:  brfalse    IL_0113//條件成立跳到消息框

  OK分析到這裏,這段指令的sub指令是咱們的關鍵,咱們要將這個指令改成Add就能夠實現了,對應的Sub的Opcode是59,而對應AddOpcode是58這樣咱們把59變成58再把16進制另存一份就能夠實現全部功能了。

  改好後咱們來看一下效果如何吧!!!

  其實咱們看似Reflexil簡簡單單的修改了一個指令的值,其實背後作了大內容,好比要對區塊的RVA進行修正,就當前的方法的RVA的修改以及全部方法的修改等操做。這塊就很少說了有興趣的本身研究下!

相關文章
相關標籤/搜索