inline

定義各類內聯函數的關鍵字

inline關鍵字用來定義一個類的內聯函數,引入它的主要原因是用它替代C中表達式形式的宏定義。inline hook如同修改內頁內容,寫上(由此處跳轉到XXX頁),位置在開始的叫淺層inline hook,靠後的則為深層inline hook。以上方法是通用、有效的,可放心使用,不必擔心在頭文件包含CPP文件會導致編譯錯誤。

從字面上來理解,inline hook即內置hook,內部跳轉hook,從內部聯結到其它函數的hook。在程序的不同層面有不同的函數地址清單,如應用層的IAT表,驅動層的SSDT和IDT表,此即在上述函數地址清單中修改函數地址。

定義格式


、鍵義類聯函,引替達式形式宏義。
達式形式宏義:
#define ExpressionName(Var1,Var2) ((Var1)+(Var2))*((Var1)-(Var2))
取代這種形式的原因如下:
1.C中使用define這種形式宏定義的原因是因為,C語言是一個效率很高的語言,這種宏定義在形式及使用上像一個函數,但它使用預處理器實現,沒有了參數壓棧,代碼生成等一系列的操作。因此,效率很高,這是它在C中被使用的一個主要原因。
2.這種宏定義在形式上類似於一個函數,但在使用它時,僅僅只是做預處理器符號表中的簡單替換,因此它不能進行參數有效性的檢測,也就不能享受C++編譯器嚴格類型檢查的好處,另外它的返回值也不能被強制轉換為可轉換的合適的類型。這樣,它的使用就存在著一系列的隱患和局限性。
3.在C++中引入了類及類的訪問控制,這樣,如果一個操作或者說一個表達式涉及到類的保護成員或私有成員,你就不可能使用這種宏定義來實現(因為無法將this指針放在合適的位置)。
4.inline推出的目的,也正是為了取代這種表達式形式的宏定義,它消除了宏定義的缺點,同時又很好地繼承了宏定義的優點。
預定義
對應於上面的1-3點,闡述如下:
1.inline定義的類的內聯函數,函數的代碼被放入符號表中,在使用時直接進行替換(像宏一樣展開),沒有了調用的開銷,效率也很高。
2.很明顯,類的內聯函數也是一個真正的函數,編譯器在調用一個內聯函數時,會首先檢查它的參數的類型,保證調用正確。然後進行一系列的相關檢查,就像對待任何一個真正的函數一樣。這樣就消除了它的隱患和局限性。
3.inline可以作為某個類的成員函數,當然就可以在其中使用所在類的保護成員及私有成員。
在何時使用inline函數:
首先,你可以使用inline函數完全取代表達式形式的宏定義。
另外要注意,內聯函數一般只會用在函數內容非常簡單的時候。這是因為,內聯函數的代碼會在任何調用它的地方展開,如果函數太複雜,代碼膨脹帶來的惡果很可能會大於效率的提高帶來的益處。內聯函數最重要的使用地方是用於類的存取函數。

功能注意事項


(1)內聯函數的作用
●對於內聯函數,C++有可能直接用函數體代碼來替代對函數的調用,這一過程稱為函數體的內聯展開。
●對於只有幾條語句的小函數來說,與函數的調用、返回有關的準備和收尾工作的代碼往往比函數體本身的代碼要大得多。因此,對於這類簡單的、使用頻繁的小函數,將之說明為內聯函數可提高運行效率。
(2)慎用內聯函數
內聯是以代碼膨脹複製為代價,僅僅省去了函數調用的開銷,從而提高函數的執行效率。如果執行函數體內代碼的時間,相比於函數調用的開銷較大,那麼效率的收穫會很少。另一方面,每一處內聯函數的調用都要複製代碼, 將使程序的總代碼量增大,消耗更多的內存空間。以下情況不宜使用內聯:
1)如果函數體內的代碼比較長,使用內聯將導致內存消耗代價較高。
2)如果函數體內出現循環,那麼執行函數體內代碼的時間要比函數調用的開銷大。

函數區別


1)內聯含函數比一般函數在前面多一個inline修飾符。
2)內聯函數是直接複製“鑲嵌”到主函數中去的,就是將內聯函數的代碼直接放在內聯函數的位置上,這與一般函數不同,主函數在調用一般函數的時候,是指令跳轉到被調用函數的入口地址,執行完被調用函數后,指令再跳轉回主函數上繼續執行後面的代碼;而由於內聯函數是將函數的代碼直接放在了函數的位置上,所以沒有指令跳轉,指令按順序執行。
3)一般函數的代碼段只有一份,放在內存中的某個位置上,當程序調用它是,指令就跳轉過來;當下一次程序調用它是,指令又跳轉過來;而內聯函數是程序中調用幾次內聯函數,內聯函數的代碼就會複製幾份放在對應的位置上
4)內聯函數一般在頭文件中定義,而一般函數在頭文件中聲明,在cpp中定義。

InLine hook


原理
Inline-Hook通過修改函數的流程, 跳轉至自定義的流程,再跳回原函數,以保證系統不崩潰,實現代碼邏輯的篡改。
首先將目標指令替換為跳轉指令,跳轉地址為一段我們自己編寫的彙編代碼,這段彙編代碼先是執行用戶指定的代碼,如修改寄存器的值,然後執行被替換掉的原指令2,最後再跳轉回原指令3處,恢復程序的正常運行。
流程
(1)構造跳轉指令。
(2)在內存中找到欲HOOK函數地址,並保存欲HOOK位置處的前5個位元組。
(3)將構造的跳轉指令寫入需HOOK的位置處。
(4)當被HOOK位置被執行時會轉到我們的流程執行。
(5)如果要執行原來的流程,那麼取消HOOK,也就是還原被修改的位元組。
(6)執行原來的流程。
(7)繼續HOOK住原來的位置。
inline
inline

使用方法


簡單提一下inline 的使用吧:
1.在類中定義這種函數:
class ClassName{
.....
....
INT GetWidth(){return m_lPicWidth;}; // 如果在類中直接定義,不需要用inline修飾,編譯器自動化為內聯函數
.... //此說法在《C++ Primer》中提及
....
}
2.在類外定義前加inline關鍵字:
class Account {
public:
Account(double initial_balance) { balance = initial_balance; } //與1相同
double GetBalance(); //在類中聲明
double Deposit( double Amount );
double Withdraw( double Amount );
double balance;
};
inline double Account::GetBalance() { return balance; } //在類外定義時添加inline關鍵字
inline double Account::Deposit( double Amount ) { return ( balance += Amount ); }
inline double Account::Withdraw( double Amount ) { return ( balance -= Amount ); }
此外還有一些規則需注意:
1、inline說明對編譯器來說只是一種建議,編譯器可以選擇忽略這個建議。比如,你將一個長達1000多行的函數指定為inline,編譯器就會忽略這個inline,將這個函數還原成普通函數。
2、在調用內聯函數時,要保證內聯函數的定義讓編譯器"看"到,也就是說內聯函數的定義要在頭文件中,這與通常的函數定義不一樣。但如果你習慣將函數定義放在CPP文件中,或者想讓頭文件更簡潔一點,可這樣做:
//SomeInline.h中
#ifndef SOMEINLINE_H
#define SOMEINLINE_H
inline Type Example(void);
//........其他函數的聲明
#include“SomeInlie.cpp” //源文件後綴名隨編譯器而定
#endif
//SomeInline.cpp中
#include"SomeInline.h"
Type Example(void)
{
//..........
}
//...............其他函數的定義
以上方法是通用、有效的,可放心使用,不必擔心在頭文件包含CPP文件會導致編譯錯誤。

CSS

display:inline
它可以讓行內顯示為塊的元素,變為行內顯示,例如
DIV1
DIV2
這裡DIV1和DIV2分別佔一行,但是你給他們加上屬性后變了
DIV1 DIV2
DIV1和DIV2這時候顯示在同一行了,試試看吧
和 display:inline 對應的是 display:block,block 會讓應用了該 CSS 屬性的 HTML 標記變成塊級別元素,例如 SPAN 是行內顯示的,但是你加了 display:block 屬性就不一樣了
[font style= "display:block "] SPAN1 [/font]
[font style= "display:block "] SPAN2 [/font]
block一般一個塊佔一行,除非float
inline是自動排為一行,就象段內的文字一樣,可成為多行。
display:inline比較經典的用法是用在
● 下的
● 中display:inline 對應不顯示為 display:nonedisplay:block 對應不顯示為 hidden說通俗點 樣式為none的元素不佔位置,而樣式為hidden的元素雖然不顯示但還是佔地方InLinehook字面含義從字面上來理解,inline hook即內置hook,內部跳轉hook,從內部聯結到其它函數的hook。指直接修改目標函數的指令,用一個跳轉或者其他指令來達到掛鉤(執行自寫的其他函數)的目的。這是相對一般的函數地址hook來說,一般的hook方法是指是在調用函數處修改函數地址,而不是在原來的函數體裡面做修改。如:CALL 0x10000001 改成 CALL 0x10000002還有就是函數地址列表hook。函數在應用層的IAT表地址如同函數的含糊地址,如X小區,驅動層的如詳細地址,如X棟X室,驅動的保護就如同小區保安起到保護作用。SSDT hook、IDT hook和IAT hook如同修改目錄中章節的地址,把XXX節 xxx頁改為yyy頁。比較一般來說,改地址的hook,其使用時比較穩定。 inline hook 更加高級一點,一般也跟難以被發現。附inline:內置,在線的,聯機的