• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            road420

            導(dǎo)航

            <2013年7月>
            30123456
            78910111213
            14151617181920
            21222324252627
            28293031123
            45678910

            統(tǒng)計(jì)

            常用鏈接

            留言簿(2)

            隨筆檔案

            文章檔案

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            DLL 線程本地存儲(chǔ)

            DLL, 線程本地存儲(chǔ)

            1.概覽
            .構(gòu)造DLL  
               (1)僅導(dǎo)出函數(shù)
                  DLL可以導(dǎo)出全局變量和類,但我們不建議這么做,建議導(dǎo)出函數(shù)。
               (2).lib
                  每個(gè)DLL都有與之相對(duì)應(yīng)的.lib文件,該文件中列出了DLL中導(dǎo)出的函數(shù)和變量的符號(hào)名
               (3)指定要導(dǎo)出的函數(shù)名
                   因?yàn)椴煌幾g器的Name mangle規(guī)則不同,這就導(dǎo)致DLL不能跨編譯器使用。
                   有以下兩種方法可以解決這個(gè)問題:
                        1..def文件中指定要導(dǎo)出的函數(shù)名
                        2.在編譯指中指定要導(dǎo)出的函數(shù)名:
                            #pragma comment(linker, "/export:MyFunc=_MyFunc@8")
            .DLL加載路徑
                當(dāng)需要加載一個(gè)DLL時(shí),系統(tǒng)會(huì)依照下面的順序去尋找所需DLL直到找到為止,然后加載,否則加載失敗。
                          (1)當(dāng)前可執(zhí)行文件路徑
                          (2)GetWindowsDirectory返回的Windows系統(tǒng)路徑
                          (3)16位系統(tǒng)的路徑 windows"system
                          (4)GetSystemDirectory返回的Windows系統(tǒng)路徑
                          (5)當(dāng)前進(jìn)程所在路徑
                          (6)PATH環(huán)境中所指定的路徑
            ­
            .創(chuàng)建\使用動(dòng)態(tài)鏈接庫
            首先必須創(chuàng)建一個(gè)包含需要導(dǎo)出的符號(hào)的頭文件,以便其他程序鏈接到該dll上:
            // dllexample.h
            #ifdef DLLEXAMPLE_EXPORTS // 在編譯命令中已定義,所以實(shí)際用的是 __declspec(dllexport)
            #define DLLEXAMPLE_API __declspec(dllexport)
            #else
            #define DLLEXAMPLE_API __declspec(dllimport)
            #endif
            DLLEXAMPLE_API int fnDllexample(void);
            當(dāng)其他應(yīng)用包含該頭文件,意圖使用該dll的導(dǎo)出符號(hào)時(shí),因?yàn)闆]有定義DLLEXAMPLE_EXPORTS,所以使用的是__declspec(dllimport),這樣編譯器編譯時(shí)便知道這是從外部引入的函數(shù)。在鏈接時(shí),鏈接程序?qū)⑸蓪?dǎo)入表(ImportAddressTable),該表羅列了所有調(diào)用到的函數(shù),以及一個(gè)空白的對(duì)應(yīng)地址。在程序執(zhí)行時(shí),加載器將動(dòng)態(tài)的填入每個(gè)函數(shù)符號(hào)在本進(jìn)程中的地址,使得程序能正確的調(diào)用到dll中的函數(shù)上。
            這種通過dll提供的.h和.lib文件進(jìn)行鏈接dll的使用方式,稱為隱式鏈接。用vc開發(fā)程序時(shí),幾乎所有的系統(tǒng)API調(diào)用都用了隱式鏈接。
            .顯式鏈接
            在exe創(chuàng)建時(shí)不引用.lib文件中的符號(hào),當(dāng)然也不必包含.h頭文件,而是由程序調(diào)用LoadLibrary(Ex)以及GetProcAddress函數(shù)來獲取每個(gè)需要使用的函數(shù)地址,從而進(jìn)行dll中的函數(shù)調(diào)用,這種dll使用方法稱為顯式鏈接。顯式鏈接時(shí)不生成對(duì)應(yīng)dll的IAT.
            當(dāng)決定不再使用該dll時(shí),通過調(diào)用FreeLibrary來卸載。需要注意的是,同一個(gè)進(jìn)程中共計(jì)調(diào)用LoadLibrary的次數(shù)要和調(diào)用FreeLibrary的次數(shù)相等,因?yàn)橄到y(tǒng)維護(hù)了一個(gè)使用計(jì)數(shù),當(dāng)計(jì)數(shù)為0時(shí),才會(huì)真正的卸載該dll.
            如果想確認(rèn)一個(gè)dll是否已經(jīng)被映射到進(jìn)程空間中,盡量使用GetModuleHandle,最好不要冒然使用LoadLibrary(Ex).
            GetProcAddress可以傳遞函數(shù)名或者序號(hào)(通過MAKEINTRESOURCE(2)來"制作"序號(hào)).
            ­
            1.1動(dòng)態(tài)加載DLL文件 LoadLibraryEx
            HMODULE LoadLibraryEx( //返回DLL加載到進(jìn)程空間原首地址。
            PCTSTR pszDLLPathName,
            HANDLE hFile,
            DWORD dwFlags);
            dwFlags 可以有以下幾個(gè)值
                          (1) DONT_RESOLVE_DLL_REFERENCES
                                                建議永遠(yuǎn)不要使有這個(gè)值,它的存在僅僅是為了向后兼容、
                              更多內(nèi)容請(qǐng)?jiān)L問:http://blogs.msdn.com/oldnewthing/archive/2005/02/14/372266.aspx
                          (2) LOAD_LIBRARY_AS_DATAFILE
                              把要加載的DLL文件以數(shù)據(jù)文件的形式加載到進(jìn)程中。
                              GetModuleHandleGetProcAddress返回NULL
                          (3) LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
                              與前者相同,不同的時(shí)獨(dú)占打開,禁止其它進(jìn)程訪問和修改該DLL中的內(nèi)容。
                          (4) LOAD_LIBRARY_AS_IMAGE_RESOURCE
                              不修改DLL中的RVA,以image的形式加載到進(jìn)程中。常與LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE一起使用。
                          (5) LOAD_WITH_ALTERED_SEARCH_PATH
                               修改DLL的加載路徑
            1.2 DLL的加載與卸載
                (1)加載
                   不要在同一進(jìn)程中,同時(shí)使用LoadLIbraryLoadLibraryEx加載同一DLL文件。
                   DLL的引用計(jì)數(shù)是以進(jìn)程為單位的。LoadLibrary會(huì)把DLL文件加載到內(nèi)存,然后映射到進(jìn)程空間中。
                   多次加載同一DLL只會(huì)增加引用計(jì)數(shù)而不會(huì)多次映射。當(dāng)所有進(jìn)程對(duì)DLL的引用計(jì)數(shù)都為0時(shí),系統(tǒng)會(huì)在內(nèi)存中釋放該DLL
                (2)卸載
                     FreeLibrary,FreeLibraryAndExitThread對(duì)當(dāng)前進(jìn)程的DLL的引用計(jì)數(shù)減1
                (3) GetProcAddress
                     取得函數(shù)地址。它只接受ANSI字符串。
            2.DLL的入口函數(shù)
                  2.1 DllMain
                          BOOL WINAPI DllMain(
                          HINSTANCE hInstDll, ""加載后在進(jìn)程中的虛擬地址
                          DWORD fdwReason, ""系統(tǒng)因何而調(diào)用該函數(shù)
                          PVOID fImpLoad ""查看是隱工還是動(dòng)態(tài)加載該DLL
                DLLsDllMain方法來初始化他們自已。DllMain中的代碼應(yīng)盡量簡單,只做一些簡單的初始化工作。
                不要在DllMain中調(diào)用LoadLibrary,FreeLibraryShell, ODBC, COM, RPC, socket 函數(shù),從而避免不可預(yù)期的錯(cuò)誤。
              2.2 fdwReason的值
                (1)DLL_PROCESS_ATTACH
                  系統(tǒng)在為每個(gè)進(jìn)程第一次加載該DLL時(shí)會(huì),執(zhí)行DLL_PROCESS_ATTACH后面的語句來初始化DLL,DllMain的返回值僅由它決定。
                 系統(tǒng)會(huì)忽略DLL_THREAD_ATTACH等執(zhí)行后DllMain的返回值。
                 如果DllMain返回FALSE,系統(tǒng)會(huì)自動(dòng)調(diào)用DLL_PROCESS_DETACH的代碼并解除DLL文件中進(jìn)程中的內(nèi)存映射。        
                (2)DLL_PROCESS_DETACH
                    如果DLL是因進(jìn)程終止而卸載其在進(jìn)程中的映射,那么負(fù)責(zé)調(diào)用ExitProcess的線程會(huì)調(diào)用DllMainDLL_PROCESS_DETACH所對(duì)應(yīng)的代碼。
                    如果DLL是因FreeLibraryFreeLibraryAndExitThread,而卸載其在進(jìn)程中的映射, 那么FreeLibraryFreeLibraryAndExitThread會(huì)負(fù)責(zé)調(diào)用DllMainDLL_PROCESS_DETACH所對(duì)應(yīng)的代碼。
                    如果DLL是因TerminateProcess而卸載其在進(jìn)程中的映射,系統(tǒng)不會(huì)調(diào)用DllMainDLL_PROCESS_DETACH所對(duì)應(yīng)的代碼。
                (3) DLL_THREAD_ATTACH
                    若進(jìn)程是先加載的DLL,后創(chuàng)建的線程
                    那么在進(jìn)程中創(chuàng)建新線程時(shí)(主線程除外),系統(tǒng)會(huì)執(zhí)行該進(jìn)程已載的所有DLLDllMainDLL_THREAD_ATTACH對(duì)應(yīng)的代碼。
                     若進(jìn)程是先創(chuàng)建的線程,后加載的DLL
                     那么系統(tǒng)不會(huì)調(diào)用DLLDllMain中的代碼。
                 (4) DLL_THREAD_DETACH
                     進(jìn)程中的線程退出時(shí),會(huì)先執(zhí)行所有已加載DLLDllMainDLL_THREAD_DETACH所對(duì)應(yīng)的代碼。若該代碼中有死循環(huán),線程不會(huì)退出。              
            2.3 同步化DllMain的調(diào)用
                  同一時(shí)間只能有一個(gè)線程調(diào)用DllMain中的代碼,所以下面的代碼會(huì)導(dǎo)致死循環(huán)
            BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, PVOID fImpLoad) {
               HANDLE hThread;
               DWORD dwThreadId;
               switch (fdwReason) {
               case DLL_PROCESS_ATTACH:
                  // The DLL is being mapped into the process' address space.
                  // Create a thread to do some stuff.
                  hThread = CreateThread(NULL, 0, SomeFunction, NULL,
                     0, &dwThreadId);// CreateThread會(huì)DLL_THREAD_ATTACH中的代碼,但是由于當(dāng)前線程并未執(zhí)行完畢,
                  //所以DLL_THREAD_ATTACH 中的代碼不會(huì)被執(zhí)行,且CreateThread永無不會(huì)返回。
                  // Suspend our thread until the new thread terminates.
                  WaitForSingleObject(hThread, INFINITE);
            ­
                  // We no longer need access to the new thread.
                  CloseHandle(hThread);
                  break;
            ­
               case DLL_THREAD_ATTACH:
                  // A thread is being created.
                  break;
            ­
               case DLL_THREAD_DETACH:
                  // A thread is exiting cleanly.
                  break;
            ­
               case DLL_PROCESS_DETACH:
                  // The DLL is being unmapped from the process' address space.
                  break;
               }
               return(TRUE);
            }
            ­
            3.延時(shí)加載DLL
            (1)延時(shí)加載DLL的限制
                     延遲加載的D L L是個(gè)隱含鏈接的D L L,它實(shí)際上要等到你的代碼試圖引用D L L中包含的一個(gè)符號(hào)時(shí)才進(jìn)行加載,它與動(dòng)態(tài)加載不同。
                    http://msdn2.microsoft.com/en-us/library/yx1x886y(VS.80).aspx
            4.已知的DLL (Known DLLs)
                位置:HKEY_LOCAL_MACHINE"SYSTEM"CurrentControlSet"Control"Session Manager"KnownDLLs
                LoadLibrary在查找DLL會(huì)先去該位置查找有無相應(yīng)的鍵值與DLL要對(duì)應(yīng),若有則根據(jù)鏈值去%SystemRoot%"System32加載鍵值對(duì)應(yīng)的DLL
                若無則根據(jù)默認(rèn)規(guī)去尋找DLL
            5.Bind and Rebase Module
                它可以程序啟動(dòng)的速度。ReBaseImage
            ­
            DLL 注入和API(DLL Injection and API Hooking)
            1.概覽
              每個(gè)進(jìn)程都有自已獨(dú)立的地址空間,一個(gè)進(jìn)程不可能創(chuàng)建一個(gè)指向其它進(jìn)程地址空間的指針。
               然而如果我們把自已的DLL注射到另一個(gè)進(jìn)程的地址空間去,我們就可以在那個(gè)被注入的進(jìn)程里為所欲為了。
               Subclass同一進(jìn)程中的窗體:http://msdn2.microsoft.com/en-us/library/ms649784.aspx.
            2.用注冊(cè)表注入DLL
                 該方法適用于給GUI的程序注入DLL
                 所有的GUI應(yīng)用程序在啟動(dòng)時(shí)都會(huì)加載User32.dll,而在User32.dllDLL_PROCESS_ATTACH代碼根據(jù)注冊(cè)表中的信息
            來注入用戶指定的DLL
            注冊(cè)表項(xiàng) HKEY_LOCAL_MACHINE"Software"Microsoft"Windows NT"CurrentVersion"Windows"
            中有兩個(gè)值:
                LoadAppInit_Dlls:鍵值中指定要注入的DLL 如:c:"inject.dll
            AppInit_Dlls:若其鍵值為1,則注入LoadAppInit_Dlls中指定的DLL,否則若為0則不注入。
                :
            (1)LoadAppInit_Dlls中的值是以空格或分號(hào)分隔的,所以DLL的路徑中最好不要有空格,最后不指定路徑,直接將DLL放到windows系統(tǒng)目錄中。
            (2) 用注冊(cè)表注入DLL的方式有很大的局限性,Kernel32.dllNtdll.dll中有的函數(shù)才能調(diào)用
            一.注入dll
            1.通過注冊(cè)表項(xiàng) HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs 來指定你的dll的路徑,那么當(dāng)一個(gè)GUI程序啟動(dòng)時(shí)就要加載User32.dll,而User32.dll將會(huì)檢查這個(gè)值,如果有的話就LoadLibrary該Dll。這個(gè)方法不好,因?yàn)榇蠖鄶?shù)情況我們只需要針對(duì)性的注入,并且沒辦法注入到不使用User32.dll的進(jìn)程中;
            ­
            2.用SetWindowsHookEx函數(shù),并傳遞目標(biāo)線程ID、需要掛載的Dll在本進(jìn)程中的映射地址(hInstance)、替換函數(shù)在本進(jìn)程中的地址。這樣,當(dāng)被掛載進(jìn)程的這個(gè)線程要執(zhí)行相應(yīng)的操作時(shí)(GETMESSAGE、鍵盤消息之類的),就會(huì)發(fā)現(xiàn)已經(jīng)安裝了WH_XX,The system checks to see whether the DLL containing the GetMsgProc function is mapped into Process B's address space,如果還未映射該Dll,則強(qiáng)制LoadLibrary。然后系統(tǒng)調(diào)用hThisInstance + (GetMsgProc - hInstance),從而實(shí)現(xiàn)了事件的通知。這種方法的好處是可以針對(duì)某個(gè)進(jìn)程安裝Hook,缺點(diǎn)是容易被目標(biāo)進(jìn)程發(fā)現(xiàn)、同樣只適用于GUI進(jìn)程。如果不再想使用掛鉤了,那么需要調(diào)用UnhookWindowsHookEx,卸載Hook。
            ­
            3.使用遠(yuǎn)程線程注入Dll(Injecting a DLL Using Remote Threads)
            這個(gè)方法比較好。流程是這樣的:
            ?調(diào)用VirtualAllocEx,在目標(biāo)進(jìn)程保留一塊內(nèi)存,并提交,其長度是你要注入Dll的全路徑長度nLen + 1,返回地址pv;
            ?調(diào)用WriteProcessMemory,在目標(biāo)進(jìn)程的pv處寫入Dll的全路徑,注意要添加\0結(jié)束符;
            ?獲取本進(jìn)程的LoadLibrary函數(shù)的地址,方法是調(diào)用pfn = GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA")——之所以獲取本進(jìn)程的地址,是因?yàn)閗ernel32.dll在每個(gè)進(jìn)程的映射地址都相同,倘若不同,那么此方法則無效;
            ?調(diào)用HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0,  pfn, pv, 0, NULL)來創(chuàng)建遠(yuǎn)程線程,其實(shí)這個(gè)線程函數(shù)就是LoadLibrary函數(shù),因此將執(zhí)行映射Dll到目標(biāo)進(jìn)程的操作;
            ?調(diào)用VirtuallFreeEx(hProcessRemote, pv)釋放提交的內(nèi)存;
            這便完成了dll注入。
            缺點(diǎn)是不能用在windows98上。但是對(duì)于xp都要被微軟拋棄的年代,windows98地影響不大了。
            ­
            4.披著羊皮的狼:使用特洛伊Dll來注入Dll(Injecting a DLL with a Trojan DLL)
            其實(shí)就是替換某個(gè)目標(biāo)進(jìn)程要加載的a.dll,并把a(bǔ).dll的所有引出函數(shù)用函數(shù)轉(zhuǎn)發(fā)器在自己的dll引出。
            ­
            5.用調(diào)試函數(shù)插入Dll
            ReadProcessMemory和WriteProcessMemory是windows提供的調(diào)試函數(shù)。如果在方法3中調(diào)用WriteProcessMemory寫入的不是字串而是精心編排好的機(jī)器指令,并且寫在目標(biāo)進(jìn)程特定的地址空間,那么這段機(jī)器指令就有機(jī)會(huì)執(zhí)行——而這段機(jī)器指令恰好完成了LoadLibrary功能;
            ­
            6.其他方法(略)
            ­
            二.掛接API(API Hooking)
            其實(shí),這是許多注入的Dll都愿意做的事情。
            所謂掛接API就是在目標(biāo)進(jìn)程調(diào)用windows API之前,先執(zhí)行我們的仿API函數(shù),從而控制系統(tǒng)API的行為,達(dá)到特殊的目的。
            我們的仿造函數(shù)必須與要替換的系統(tǒng)API有相同的型參表以及相同的返回值類型.
            ­
            1.改寫系統(tǒng)API代碼的前幾個(gè)字節(jié),通過寫入jmp指令來跳轉(zhuǎn)到我們的函數(shù)。在我們的函數(shù)里執(zhí)行操作,可以直接返回一個(gè)值,也可以將系統(tǒng)API的前幾個(gè)字節(jié)復(fù)原,調(diào)用系統(tǒng)API,并返回系統(tǒng)API的值——隨便你想怎么做。
            此方法的缺點(diǎn)是對(duì)于搶占式多線程的系統(tǒng)不太管用。
            ­
            2.通過改寫目標(biāo)進(jìn)程IAT中要調(diào)用的函數(shù)地址來達(dá)到目的。具體操作見書中示例
            ­
            ­
            ­
            線程本地存儲(chǔ)(Thread-Local Storage)
            例子C / C + +運(yùn)行期庫要使用線程本地存儲(chǔ)器( T L S)。由于運(yùn)行期庫是在多線程應(yīng)用程序出現(xiàn)前的許多年設(shè)計(jì)的,因此運(yùn)行期庫中的大多數(shù)函數(shù)是用于單線程應(yīng)用程序的。函數(shù)s t r t o k就是個(gè)很好的例子。
            盡可能避免使用全局變量和靜態(tài)變量
            1.動(dòng)態(tài)TLS
            圖21-1 用于管理T L S的內(nèi)部數(shù)據(jù)結(jié)構(gòu)
            ­
            在創(chuàng)建線程時(shí),進(jìn)程會(huì)為當(dāng)前創(chuàng)建的線程分配一個(gè)void *的數(shù)組作為TLS用。它用于存儲(chǔ)只限當(dāng)前線程可見的全局變量。
            從而使進(jìn)程中的每個(gè)線程都可以有自已的(不能其它線程訪問的)全局變量。
            TlsAlloc在返回時(shí)會(huì)先把槽中的值置為0。每個(gè)線程至少有64個(gè)槽。
            2.靜態(tài)TLS
                          __declspec(thread)關(guān)鍵字用于聲明,線程本地的全局變量。
                          要求聲明的變量必須是全局變量或靜態(tài)變量。
            3.Common API:
                          TlsAlloc   TlsFree
                          TlsSetValue   TlsGetValue
                          __declspec(thread)

            posted on 2009-10-26 18:33 深邃者 閱讀(1050) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久久久亚洲AV成人片| 99久久免费国产精精品| 亚洲欧美伊人久久综合一区二区| 久久精品国产亚洲AV嫖农村妇女| 久久99国产亚洲高清观看首页| 久久国产成人午夜aⅴ影院| 久久99热这里只频精品6| 国产人久久人人人人爽| 欧美久久一区二区三区| 日本强好片久久久久久AAA| 久久国产热这里只有精品| 色欲久久久天天天综合网 | 日韩精品久久久肉伦网站| 国产精品成人久久久久久久| 精品综合久久久久久98| 精品久久久久国产免费 | 中文精品久久久久人妻不卡| 91精品国产综合久久香蕉 | 99久久婷婷国产综合亚洲| 香蕉久久AⅤ一区二区三区| 久久综合九色综合精品| 国产午夜精品久久久久免费视| 亚洲级αV无码毛片久久精品 | 久久人人爽人人爽人人片AV不| 久久久久亚洲精品天堂久久久久久 | 一本色道久久88综合日韩精品| 777久久精品一区二区三区无码| 麻豆成人久久精品二区三区免费| 伊人色综合久久天天人守人婷| 国产亚州精品女人久久久久久 | 久久精品国产色蜜蜜麻豆| 久久无码人妻精品一区二区三区| 久久精品国产影库免费看 | 国产欧美一区二区久久| 久久人人爽人人爽人人片AV不 | 国产成人久久精品激情| 久久久久亚洲av无码专区喷水| 久久亚洲精品中文字幕| 久久青青草原亚洲av无码app| 久久精品麻豆日日躁夜夜躁| 精品久久久久久久久午夜福利|