日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

动态加载技术

發(fā)布時(shí)間:2025/6/17 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态加载技术 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 一:動(dòng)態(tài)庫(kù)技術(shù)
      • 1.DLL靜態(tài)調(diào)用
      • 2.DLL動(dòng)態(tài)調(diào)用
    • 二:動(dòng)態(tài)加載技術(shù)
      • 1.導(dǎo)出函數(shù)起始地址
      • 2.在編程中使用動(dòng)態(tài)加載技術(shù)
        • 1.查找kernel32.dll的基地址
        • 2.獲取GetProcAddress地址
        • 3.在代碼中使用獲取的函數(shù)地址編程

動(dòng)態(tài)加載技術(shù)可以讓程序設(shè)計(jì)者脫離復(fù)雜的導(dǎo)入表結(jié)構(gòu),在程序空間中構(gòu)造類似于導(dǎo)入表的調(diào)用引入函數(shù)機(jī)制。

在了解這一知識(shí)前最好先了解windows虛擬內(nèi)存管理,詳情見我博客

一:動(dòng)態(tài)庫(kù)技術(shù)

1.DLL靜態(tài)調(diào)用

又稱隱式調(diào)用。隱式加載就是在程序編譯的時(shí)候就將dll編譯到可執(zhí)行文件中。調(diào)用一個(gè)動(dòng)態(tài)鏈接庫(kù)的函數(shù)通常采取的方式是:把產(chǎn)生動(dòng)態(tài)鏈接庫(kù)時(shí)產(chǎn)生的".lib"庫(kù)文件和".inc"包含的文件加入到應(yīng)用程序的工程中,想使用DLL中的函數(shù)時(shí),直接使用函數(shù)的名字即可,例如,加入user32.lib user32.inc調(diào)用MessageBox函數(shù)

2.DLL動(dòng)態(tài)調(diào)用

又稱顯式調(diào)用。通過API函數(shù)加載和卸載DLL來(lái)達(dá)到調(diào)用DLL函數(shù)的目的。與動(dòng)態(tài)庫(kù)調(diào)用有關(guān)的函數(shù)主要包括:

  • LoadLibrary(或MFC的AfxLoadLibrary),裝載動(dòng)態(tài)鏈接庫(kù)
  • GetProcAddress,獲取要引入函數(shù)的VA(虛擬內(nèi)存地址),將符號(hào)名或標(biāo)識(shí)號(hào)轉(zhuǎn)換為DLL內(nèi)部地址
  • FreeLibrary(或MFC的AfxFreeLibrary),釋放動(dòng)態(tài)鏈接庫(kù)
  • //1.加載動(dòng)態(tài)庫(kù)HINSTANCE m_hDll = LoadLibrary(_T("MFCDLL1.dll"));//2.根據(jù)函數(shù)名獲取函數(shù)地址typedef IHpDllWin* (*hpDllFun)();hpDllFun pShowDlg = (hpDllFun)GetProcAddress(m_hDll, "ShowDialog");//3.獲取導(dǎo)出類對(duì)象指針,調(diào)用導(dǎo)出函數(shù)IHpDllWin* m_hpwin = pShowDlg();//4.卸載dllFreeLibrary(hDll);

    二:動(dòng)態(tài)加載技術(shù)

    1.導(dǎo)出函數(shù)起始地址

    程序引進(jìn)動(dòng)態(tài)鏈接庫(kù)的最終目的是要調(diào)用動(dòng)態(tài)鏈接庫(kù)里的函數(shù)代碼,所以,獲取動(dòng)態(tài)連接庫(kù)里的導(dǎo)出函數(shù)起始地址是動(dòng)態(tài)加載技術(shù)的關(guān)鍵。

    現(xiàn)在假設(shè)user32.dll被動(dòng)態(tài)裝載到內(nèi)存的0x77DF0000處,那么MessageBoxA的入口地址VA就是:
    0x77DF000 + 0x00026544 = 0x7E16544

    如果一個(gè)函數(shù)在進(jìn)程空間中的VA 確定以后,最簡(jiǎn)單拿的調(diào)用方式就是通過一下硬編碼方式來(lái)調(diào)用

    push xx ;顯示往棧里壓入該函數(shù)的參數(shù),個(gè)數(shù)由調(diào)用的函數(shù)決定 ...... mov eax,77E16544; call eax

    2.在編程中使用動(dòng)態(tài)加載技術(shù)

    分三步:
    1.獲取kernel32.dll的基地址
    2.獲取GetProcAddress函數(shù)的地址(然后通過此函數(shù)獲取LoadLibrary函數(shù)的地址)
    3.在代碼中使用獲取的函數(shù)地址編程

    1.查找kernel32.dll的基地址

    .386.model flat,stdcalloption casemap:noneinclude windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib;數(shù)據(jù)段.data szText db 'kernel32.dll在本程序地址空間的基地址為:%08x',0dh,0ah,0 kernel32Base dd ? szBuffer db 256 dup(0);代碼段.code _getKernelBase proc _dwKernelRetAddresslocal @dwRetpushadmov @dwRet,0mov edi,_dwKernelRetAddressand edi,0ffff0000h ;查找指令所在頁(yè)的邊界,以1000h對(duì)齊.repeat.if word ptr [edi]==IMAGE_DOS_SIGNATURE ;找到kernel32.dll的dos頭mov esi,ediadd esi,[esi+003ch].if word ptr [esi]==IMAGE_NT_SIGNATURE ;找到kernel32.dll的PE頭標(biāo)識(shí)mov @dwRet,edi.break.endif.endifsub edi,010000h.break .if edi<070000000h.until FALSEpopadmov eax,@dwRetret _getKernelBase endp start:mov eax,dword ptr [esp]invoke _getKernelBase,eaxinvoke wsprintf,addr szBuffer,addr szText,eaxinvoke MessageBox,NULL,addr szBuffer,NULL,MB_OKretend start

    2.獲取GetProcAddress地址

    通過_getApi,得到某個(gè)動(dòng)態(tài)鏈接庫(kù)的基地址,并知道調(diào)用函數(shù)名稱的情況下,可以通過調(diào)用該函數(shù)得到調(diào)用函數(shù)地址

    ;------------------------------------------------ ; 從內(nèi)存中模塊的導(dǎo)出表中獲取某個(gè) API 的入口地址 ;------------------------------------------------ _getApi proc _hModule,_lpszApilocal @dwReturn,@dwStringLenpushadmov @dwReturn,0call @F @@:pop ebxsub ebx,offset @B;創(chuàng)建用于錯(cuò)誤處理的SEH結(jié)構(gòu)assume fs:nothingpush ebplea eax,[ebx+offset _ret]push eaxlea eax,[ebx+offset _SEHHandler]push eaxpush fs:[0]mov fs:[0],esp;計(jì)算API字符串的長(zhǎng)度(注意帶尾部的0)mov edi,_lpszApimov ecx,-1xor al,alcldrepnz scasbmov ecx,edisub ecx,_lpszApimov @dwStringLen,ecx;從DLL文件頭的數(shù)據(jù)目錄中獲取導(dǎo)出表的位置mov esi,_hModuleadd esi,[esi+3ch]assume esi:ptr IMAGE_NT_HEADERSmov esi,[esi].OptionalHeader.DataDirectory.VirtualAddressadd esi,_hModuleassume esi:ptr IMAGE_EXPORT_DIRECTORYmov ebx,[esi].AddressOfNamesadd ebx,_hModulexor edx,edx.repeatpush esimov edi,[ebx]add edi,_hModulemov esi,_lpszApimov ecx,@dwStringLenrepz cmpsb.if ZERO?pop esijmp @F.endifpop esiadd ebx,4inc edx.until edx>=[esi].NumberOfNamesjmp _ret @@:;API名稱索引->序號(hào)索引->地址索引sub ebx,[esi].AddressOfNamessub ebx,_hModuleshr ebx,1add ebx,[esi].AddressOfNameOrdinalsadd ebx,_hModulemovzx eax,word ptr [ebx]shl eax,2add eax,[esi].AddressOfFunctionsadd eax,_hModule;從地址表得到導(dǎo)出函數(shù)地址mov eax,[eax]add eax,_hModulemov @dwReturn,eax _ret:pop fs:[0]add esp,0chassume esi:nothingpopadmov eax,@dwReturnret _getApi endpstart:invoke _getApi,hDllKernel32,addr szGetProcAddress ;獲取GetProcAddress函數(shù)的內(nèi)存地址mov _GetProcAddress,eax...retend start

    3.在代碼中使用獲取的函數(shù)地址編程

    ;聲明函數(shù)_QLMessageBoxA typedef proto :dword,:dword,:dword,:dword;聲明函數(shù)引用_ApiMessageBoxA typedef ptr _QLMessageBoxA...;定義函數(shù)_messageBox _ApiMessageBoxA ?;動(dòng)態(tài)獲取_messageBox的地址...;調(diào)用函數(shù)invoke _messageBox,NULL,offset szText,NULL,MB_OK

    總結(jié)

    以上是生活随笔為你收集整理的动态加载技术的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。