• <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

            導航

            <2009年10月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統(tǒng)計

            常用鏈接

            留言簿(2)

            隨筆檔案

            文章檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            DLL 線程本地存儲

            DLL, 線程本地存儲

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

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

            亚洲国产成人精品久久久国产成人一区二区三区综 | 久久亚洲国产精品五月天婷| 久久伊人色| 久久精品水蜜桃av综合天堂 | 久久精品国产亚洲麻豆| 久久精品国产亚洲一区二区三区| 亚洲精品成人久久久| 久久精品国产清高在天天线| 精品无码久久久久久久久久| 狠狠色婷婷久久综合频道日韩 | avtt天堂网久久精品| 欧洲国产伦久久久久久久 | 热re99久久精品国产99热| 久久久高清免费视频| 久久九九青青国产精品| 精品综合久久久久久97| 国内精品久久久久久久涩爱| 91精品国产高清久久久久久io| 亚洲一级Av无码毛片久久精品| 老司机国内精品久久久久| 一本色道久久综合亚洲精品| 久久久国产精品| 午夜精品久久久久久99热| 亚洲精品无码专区久久同性男| 日韩亚洲欧美久久久www综合网| 亚洲欧美成人综合久久久| 欧美一区二区久久精品| 狠狠色伊人久久精品综合网 | 韩国免费A级毛片久久| 亚洲午夜无码久久久久| 伊人久久大香线蕉av一区| 中文字幕精品久久久久人妻| 亚洲国产香蕉人人爽成AV片久久| 久久久久国色AV免费观看 | 亚洲国产精品无码久久一线 | 日本精品久久久久中文字幕8| 2022年国产精品久久久久| 国产成年无码久久久久毛片| 香蕉99久久国产综合精品宅男自| 久久国产精品一国产精品金尊| 欧美午夜A∨大片久久 |