維尼的蜂巢

Archive for 六月 2008

動態連結函式庫(Dynamic Linking Libraries,DLLs)

Posted by: kevinlin on: 六月 18, 2008

我覺得做DLL這東西很有趣,程式執行到一半我們可以呼叫某個DLL裡面的某個function,我想寫個小範例在這邊。
DLL的載入大致上分兩種
1 、 隱式連結(Implicitly Link)(也叫載入期動態連結 Load-Time Dynamic Linking)
這種是屬於靜態載入,就是指,程式編譯時會預留函式的空間。所以當程式被Windows的loader載入到記憶體中後,loader會自動檢查執行檔中所有的import function的定義,把所有需要的DLLs都載入到記憶體裡面。
優點:
1、 使用DLL裡面的Function的方法,就像是包含在自己程式裡面的function一樣可以使用。
2 、 動作較為簡單,載入的方法跟尋找DLL的動作由作業系統負責處理,應用程式不用調整也無法去干涉。
缺點:
1 、 當找不到DLL時,程式就不能開啟(就是常見的找不到xxx.dll)。
2 、 編譯時需要先include DLL的宣告檔(通常是.h)。
3 、 隨著載入的DLLs增加,載入應用程式的速度會便慢。
4 、 若遇到不同品牌 的C++編譯器時靜態載入可就沒有這麼簡單處理了,因為當函式經過Calling Conventions的處理後,若要使用其他品牌編譯器所致造出的DLL須得大動干戈才行。
2 、 顯式連結(Explicit Linking)
跟他的名字一樣,就是在程式執行的過程中動態載入DLL,用完了就馬上釋放DLL
優點:
1 、DLL只要需要時才會載入到記憶體中,可以更有效的使用記憶體。
2 、 應用程式開始的時候不用先載入DLL,所以載入速度比上面的方法快。
3 、 編譯時不須額外include DLL函式的宣告檔。
4 、 讓我們可以更清楚DLL的載入流程。
缺點:
要多花一些程式碼來處理載入的過程!
我要介紹的是Explicit Linking
下面是test.cpp,他會產生一個test.dll

#include <iostream>
#include <Windows.h>
using namespace std;

__declspec( dllexport ) int AddFunction(int a, int b)
{ return a+b; }
__declspec( dllexport ) int SubFunction(int a, [...]

__stdcall ,__cdecl的區別 再次探討

Posted by: kevinlin on: 六月 17, 2008

前面寫了這篇,感覺很亂,再來深入探討一次
看了這篇後,我覺得用組合語言來敘述差異似乎更加的清楚明白
__cdecl 之前說 由呼叫者來調整堆疊

//函式 foo(int arg1, int arg2, int arg3)
push    arg3
push    arg2
push    arg1
call      foo
add      sp, 12         //相當於 pop; pop; pop

__stdcall 之前說 由被呼叫者調整堆疊,這樣的做法可以節省程式的大小

//函式 foo(int arg1, int arg2, int arg3)
push arg3
push arg2
push arg1
call foo
//stack 的清除工作會在 foo 函式內完成

上面兩個差異MSDN有告訴我們:
The __cdecl calling convention creates larger executables [...]

warning C4996-VS2005遭受的問題

Posted by: kevinlin on: 六月 12, 2008

我的程式裡warning C4996大概有400多個,回想以前在VS2003時,一個warning都沒有,真是個美好的時代。
發生的warning像下面這樣
warning C4996: ’sprintf’: This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS
這個錯誤是VS2005後,為了安全性而發生的錯誤,當然可以直接無視,不過大概是有三種方法
第一種就是直接無視他

#pragma warning(disable:4996)

#define _CRT_SECURE_NO_DEPRECATE 1

上面這個方法就可以很簡單的無視,不過注意要放在pre-compile header file “stdafx.h”最前面,要在還沒有include任何檔案之前。
第二種就是
直接使用Security CRT functions。(在後面會詳述)
第三種就是用
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
這個定義會自動幫你使用 Security CRT functions,但是warning一樣會出現,所以可以1、3混搭
方法一自然是不建議啊!!人家都說有security issure了,你還無視他的存在,那你當機是應該的。
VS2005為了讓我們建構更安全的應用程式,針對一些像是gets、sprintf、strcpy…等等C Run-time Library的操作,提供了比較安全一點的函式。大家稱他為Security Enhancements in the CRT
為什麼要這樣呢? 來看一個簡單的範例
MSDN上說C Run-time Library裡最不可靠的函式就是 gets,舉個例:

char buffer[10] = { 0 };
gets(buffer);

第一行宣告Buffer並將他初始化為0。(建議將所有變數初始化為明確的值,可以避免不必要的意外)。
接著gets會獨進一行你輸入的東西,這方法有甚麼問題呢??問題在,C-style陣列傳入到function中,是傳遞第一個element的指標。所以gets這個function會把char[]當成char*,因此他就沒有一個資訊來知道這個buffer大小了。
這都不是很重要,重要的來了,gets裡他假設這個buffer是無大小限制的(就是UINT_MAX),他只會把你輸入的東西丟進去buffer裡面,想做「緩衝區溢滿」攻擊的人就開始高興了。
所以,很多原始的C Run-time Library都有一樣的問題,缺乏一個驗證的數字,所以到了VS2005,它說「現在他們已經不適用了,該用我的好東西了。」
因為這些function是在以前效能主導的時代所寫的,我們現在已經是安全主導的年代了,這些老舊的東西微軟提供了一些新函式來取代,很簡單他在後面加了 _s ,例如 gets ==> [...]