定弘法师2017年视频:电脑里的动态连接库是什么意思?如果打开文件经常与它连接不上是什么回事该怎么办?

来源:百度文库 编辑:高考问答 时间:2024/04/28 17:56:49

DLL文件即动态链接库文件,是一种可执行文件,它允许程序共享执行特殊任务所必需的代码和其他资源。Windows提供的DLL文件中包含了允许基于Windows的程序在Windows环境下操作的许多函数和资源。

DLL多数情况下是带有DLL扩展名的文件,但也可能是EXE或其他扩展名。它们向运行于Windows操作系统下的程序提供代码、数据或函数。程序可根据DLL文件中的指令打开、启用、查询、禁用和关闭驱动程序。

DLL的全称是Dynamic Link Library, 中文叫做“动态链接文件”。在Windows操作系统中, DLL对于程序执行是非常重要的, 因为程序在执行的时候, 必须链接到DLL文件, 才能够正确地运行。而有些DLL文件可以被许多程序共用。因此, 程序设计人员可以利用DLL文件, 使程序不至于太过巨大。但是当安装的程序越来越多, DLL文件也就会越来越多, 如果当你删除程序的时候, 没有用的DLL文件没有被删除的话, 久而久之就造成系统的负担了。

DLL是动态连接库。使用动态连接库的一些好处是:
1.多个应用程序共享代码和数据:比如Office软件的各个组成部分有相似的外观和功能,这就是通过共享动态连接库实现的。
2.在钩子程序过滤系统消息时必须使用动态连接库。
3.动态连接库以一种自然的方式将一个大的应用程序划分为几个小的模块,有利于小组内部成员的分工与合作。而且,各个模块可以独立升级。如果小组中的一个成员开发了一组实用例程,他就可以把这些例程放在一个动态连接库中,让小组的其他成员使用。
4.为了实现应用程序的国际化,往往需要使用动态连接库。使用动态连接库可以将针对某一国家、语言的信息存放在其中。对于不同的版本,使用不同的动态连接库。在使用AppWizard生成应用程序时,我们可以指定资源文件使用的语言,这就是通过提供不同的动态连接库实现的。
VC++、C++ Builder、Delphi都可以编写DLL文件。Visual Basic 5.0以上版本也可以编写一种特殊的DLL,即ActiveX DLL。

DLL不是独立运行的程序,它是某个程序的一个部分,它只能由所属的程序调用。用户不能,也不需要打开它。

一. 什么是动态连接库
动态连接库使用标准的PE文件格式,在动态连接库里可以定义资源并使用各种资源,并且可以导入并使用其它动态连接库里定义的函数(动态连接库嵌套)。它提供函数给其它程序在运行的时候调用。通常动态连接库文件的扩展名是.dll,但是系统中某些exe文件,字体文件.fon,一些驱动程序.drv,各种控件.ocx和输入法模块ime等都是动态连接库。
二. 动态连接库框架
;--------------------------------------------------------------------------------------
;DLLSkeleton.asm
;--------------------------------------------------------------------------------------
.386
.modelflat,stdcall
optioncasemap:none
include\masm32\include\windows.inc
include\masm32\include\user32.inc
include\masm32\include\kernel32.inc
includelib\masm32\lib\user32.lib
includelib\masm32\lib\kernel32.lib
.data
.code
DllEntryprochInstDLL:HINSTANCE,reasonWORD,reserved1WORD
moveax,TRUE
ret
DllEntryEndp
;---------------------------------------------------------------------------------------------------
;下面是一个空函数,您可以象下面一样插入您的函数。
;----------------------------------------------------------------------------------------------------
TestFunctionproc
ret
TestFunctionendp
EndDllEntry
;-------------------------------------------------------------------------------------
;DLLSkeleton.def
;-------------------------------------------------------------------------------------
LIBRARYDLLSkeleton
EXPORTSTestFunction

1入口点和初始化代码
DllEntryprochInstDLL:HINSTANCE,reasonWORD,reserved1WORD
moveax,TRUE
ret
DllEntryEndp
每一个动态连接库必须有一个入口函数,以方便操作系统使用。(注意入口函数对调用的应用程序是透明的)函数的名称是什么没有特定的要求,但是格式是有规定的。看看什么情况下要用到入口函数:
■当动态链接库被加载时
■当动态链接库卸载时
■同一进程的线程生成时
■同一进程的线程退出时
hInstDLL是该动态链接库模块的句柄。它和进程的实例句柄不一样。如果您以后要用,可以保存它,因为以后再要获得它不容易。
根据不同的时机,reason传入的值可能是下面的四个值中的一个:
DLL_PROCESS_ATTACH动态链接库第一次插入进程的地址空间时。当传入的参数是该值时,可以做一些初始化的工作。
DLL_PROCESS_DETACH动态链接库从进程的地址空间卸出时。可以在此做一些清理的工作。譬如:释放内存等。
DLL_THREAD_ATTACH新线程生成。
DLL_THREAD_DETACH线程销毁。
如果想要库中的代码继续执行,返回TRUE,否则返回FALSE,那样动态链接库就不会加载了。譬如:想分配一块内存,如果不成功的话就退出,这时就可以返回FALSE。那样动态链接库就不会加载了。可以加入的函数,它们的位置并不重要,把它们放在入口点函数的前面或后面都可以。只是如果您想要它们能被其它的程序调用的话,就必须把它们的名字放到模块定义文件(.def)中去。
动态链接库在它们自己的编译过程就需要,而不只是提供给其它要引用它的程序参考。它们如下:
LIBRARYDLLSkeleton
EXPORTSTestFunction
第一行是必须的。LIBRARY定义了DLL的模块名称。它必须和动态链接库的名称相同。
EXPORTS关键字告诉链接器该DLL的引出函数,也就是其它程序可以调用的函数。举个例子:其它的程序想要调用函数TestFunction,我们就把它放到EXPORTS中。
2链接选项
链接器的选项中必须放入开关项:/DLL和/DEF,就像下面这样:
link/DLL/SUBSYSTEM:WINDOWS/DEFLLSkeleton.def/LIBPATH:c:\masm32\libDLLSkeleton.obj
编译器的开关选项是一样的,即:/c/coff/Cp。在链接好后,链接器会生成.lib和.dll文件。前者是引入库,当其它的程序要调用自己的动态链接库中的函数时就需要该引入库,以便把必要的信息加入到其可执行文件中去。
三. 动态连接库的调用方法
1在include文件定义的时候包含动态连接库的.rc和.lib库文件,在程序中直接调用动态连接库里的函数
2动态加载所需的DLL。
那我们该如何解决这个问题呢?
在Windows中提供了两个函数LoadLibrary和GetProcAddress,LoadLibrary函数用来动态加载DLL,而GetProcAddress函数用来从某个DLL中获取指定函数的地址。这两个函数的用法如下:
HINSTANCELoadLibrary(
LPCTSTRlpLibFileName//addressoffilenameofexecutablemodule
);
FARPROCGetProcAddress(
HMODULEhModule,//handletoDLLmodule
LPCSTRlpProcName//nameoffunction
);
LoadLibarary函数用来加载一个DLL模块,如果成功,则返回该模块的句柄。这个句柄可以用于GetProcAddress函数。而GetProcAddress函数则从DLL模块中查找特定函数名的函数的地址。例如下面两句代码就是从kernel32.dll中取得CreateProcess函数的地址:
HMODULE hModule=LoadLibrary(“kernel32.dll”);
FARPROC *fn=GetProcAddress(hModule,”CreatePrcess”)
但现在又出现了一个问题,函数LoadLibrary和GetProcAddress的地址又从哪得到呢?这就像一个现有鸡还是先有蛋的问题一样。
在WinNT中,进程的环境块(PEB)地址总是在0x7FFDF000处。而在PEB中由该进程加载的每个DLL的地址,当然包括Kernel32.dll的地址。找到Kernel32.dll的地址之后,就可以通过Kernel32.dll的PE文件头找到其导出函数表,再查找该导出函数表就可以找到函数“GetProcAddress”的地址,之后就可以通过GetProcAddress函数得到“LoadLibrary”的地址了。
完成这个功能的Win32汇编代码给出。
;**************************************************************************
;*下面这部分汇编需要对PEB结构非常的了解
;**************************************************************************
mov eax,7FFDF00Ch
;7FFDF000的位置是PEB的位置,其偏移0x0C(即7FFDF00Ch)是PEB_LDR_DATA结构
mov eax,dwordptr[eax]
mov esi,dwordptr[eax+1Ch]
;在PEB_LDR_DATA+0x1c地方就是一些动态连接库的地址了,如第一个指向ntdll.dll
;第二个就是我们需要的kernel32.dll的地址,第三个是msvcrt.dll,一个指针链表
lodsd
mov eax,dwordptr[eax+8]
;此时得到了Kernel32.dll的位置,eax等于77E60000
mov [ebx+hModule],eax
;此时hModule等于kernel32.dll的位置,即77E60000

;********************************************************************
;从PE文件头的数据目录获取导出表地址
;********************************************************************
mov esi,[ebx+hModule]
add esi,[esi+3ch]
assume esitrIMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,[ebx+hModule]
assume esitrIMAGE_EXPORT_DIRECTORY
;esi指向kernel。dll的导出表
;********************************************************************
;查找符合名称的导出函数名
;********************************************************************
mov eax,[esi].AddressOfNames
add eax,[ebx+hModule]
xor edx,edx
.repeat
push esi
mov edi,[eax]
add edi,[ebx+hModule]
lea esi,[ebx+offset_szGetProcAddress]
mov ecx,14
repz cmpsb
.if ZERO?
pop esi
jmp @F
.endif
pop esi
add eax,4
inc edx
.until edx>= [esi].NumberOfNames
jmp return
@@:
;********************************************************************
;API名称索引-->序号索引-->地址索引
;********************************************************************
sub eax,[esi].AddressOfNames
sub eax,[ebx+hModule]
shr eax,1
add eax,[esi].AddressOfNameOrdinals
add eax,[ebx+hModule]
movzx edx,wordptr[eax]
shl edx,2
add edx,[esi].AddressOfFunctions
add edx,[ebx+hModule]
;********************************************************************
;从地址表得到导出函数地址
;********************************************************************
mov eax,[edx]
add eax,[ebx+hModule]
;取得GetProcAddress函数的地址
mov [ebx+_lpGetProcAddress],eax
;取得LoadLibrary函数的地址
lea esi,[ebx+offset_szLoadLibrary]
_invoke [ebx+_lpGetProcAddress],[ebx+hModule],esi
mov [ebx+_lpLoadLibrary],eax
assume esi:nothing