

DLL文件 DLL是Dynamic Link Library的缩写,意为动态链接库。DLL文件一般被存放在C:WindowsSystem目录下。DLL是一个包含可由多个程序同时使用的代码和数据的库。
DLL文件简介 在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可有多个DLL文件,一个DLL文件也可能被几个应用程序所共用,这样的DLL文件被称为共享DLL文件。例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数。因此,每个程序都可以使用该 DLL 中包含的功能来实现“打开”对话框。这有助于促进代码重用和内存的有效使用。
通过使用 DLL,程序可以实现模块化,由相对独立的组件组成。例如,一个计帐程序可以按模块来销售。可以在运行时将各个模块加载到主程序中(如果安装了相应模块)。因为模块是彼此独立的,所以程序的加载速度更快,而且模块只在相应的功能被请求时才加载。
此外,可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。例如,您可能具有一个工资计算程序,而税率每年都会更改。当这些更改被隔离到 DLL 中以后,您无需重新生成或安装整个程序就可以应用更新。
Windows 操作系统中的一些作为 DLL 实现的文件
·ActiveX 控件 (.ocx) 文件
ActiveX 控件的一个示例是日历控件,它使您可以从日历中选择日期。
·控制面板 (.cpl) 文件
.cpl 文件的一个示例是位于控制面板中的项。每个项都是一个专用 DLL。
·设备驱动程序 (.drv) 文件
设备驱动程序的一个示例是控制打印到打印机的打印机驱动程序。
DLL 的优点
[编辑本段]
程序使用 DLL 的优点 ·
使用较少的资源
当多个程序使用同一个函数库时,DLL 可以减少在磁盘和物理内存中加载的代码的重复量。这不仅可以大大影响在前台运行的程序,而且可以大大影响其他在 Windows 操作系统上运行的程序。
·
推广模块式体系结构
DLL 有助于促进模块式程序的开发。这可以帮助您开发要求提供多个语言版本的大型程序或要求具有模块式体系结构的程序。模块式程序的一个示例是具有多个可以在运行时动态加载的模块的计帐程序。
·
简化部署和安装
当 DLL 中的函数需要更新或修复时,部署和安装 DLL 不要求重新建立程序与该 DLL 的链接。此外,如果多个程序使用同一个 DLL,那么多个程序都将从该更新或修复中获益。当您使用定期更新或修复的第三方 DLL 时,此问题可能会更频繁地出现。
1、如何了解某应用程序使用哪些DLL文件
右键单击该应用程序并选择快捷菜单中的“快速查看”命令,在随后出现的“快速查看”窗口的“引入表”一栏中你将看到其使用DLL文件的情况。
2、如何知道DLL文件被几个程序使用
运行Regedit,进入HKEY_LOCAL_MACHINESoftwareMicrosrftWindowsCurrentVersionSharedDlls子键查看,其右边窗口中就显示了所有DLL文件及其相关数据,其中数据右边小括号内的数字就说明了被几个程序使用,(2)表示被两个程序使用,(0)则表示无程序使用,可以将其删除。
3、如何解决DLL文件丢失的情况
有时在卸载文件时会提醒你删除某个DLL文件可能会影响其他应用程序的运行。所以当你卸载软件时,就有可能误删共享的DLL文件。一旦出现了丢失DLL文件的情况,如果你能确定其名称,可以在Sysbckup(系统备份文件夹)中找到该DLL文件,将其复制到System文件夹中。如果这样不行,在电脑启动时又总是出现“***dll文件丢失……”的提示框,你可以在“开始/运行”中运行Msconfig,进入系统配置实用程序对话框以后,单击选择“System.ini”标签,找出提示丢失的DLL文件,使其不被选中,这样开机时就不会出现错误提示了。
rundll的功能是以命令列的方式呼叫Windows的动态链结库。
Rundll32.exe与Rundll.exe的区别就在于前者是呼叫32位的链结库,后者是用于16位的链结库。rundll32.exe是专门用来调用dll文件的程序。
如果用的是Win98,rundll32.exe一般存在于Windows目录下;
如果用的WinXP,rundll32.exe一般存在于WindowsSystem32目录下。
若是在其它目录,就可能是一个木马程序,它会伪装成rundll32.exe。
DLL 故障排除工具
可以使用多个工具来帮助您解决 DLL 问题。以下是其中的部分工具。
Dependency Walker
Dependency Walker 工具可以递归扫描以寻找程序所使用的所有依赖 DLL。当您在 Dependency Walker 中打开程序时,Dependency Walker 会执行下列检查:
·Dependency Walker 检查是否丢失 DLL。
·Dependency Walker 检查是否存在无效的程序文件或 DLL。
·Dependency Walker 检查导入函数和导出函数是否匹配。
·Dependency Walker 检查是否存在循环依赖性错误。
·Dependency Walker 检查是否存在由于针对另一不同操作系统而无效的模块。
通过使用 Dependency Walker,您可以记录程序使用的所有 DLL。这可能有助于避免和更正将来可能发生的 DLL 问题。当您安装 Microsoft Visual Studio 6.0 时,Dependency Walker 将位于以下目录中:
drive\Program Files\Microsoft Visual Studio\Common\Tools
DLL Universal Problem Solver
DLL Universal Problem Solver (DUPS) 工具用于审核、比较、记录和显示 DLL 信息。下表说明了组成 DUPS 工具的实用工具:
·Dlister.exe:该实用工具枚举计算机中的所有 DLL,并且将此信息记录到一个文本文件或数据库文件中。
·Dcomp.exe:该实用工具比较在两个文本文件中列出的 DLL,并产生包含差异的第三个文本文件。
·Dtxt2DB.exe:该实用工具将通过使用 Dlister.exe 实用工具和 Dcomp.exe 实用工具创建的文本文件加载到 dllHell 数据库中。
·DlgDtxt2DB.exe:该实用工具提供 Dtxt2DB.exe 实用工具的图形用户界面 (GUI) 版本。
DLL 的类型
当您在应用程序中加载 DLL 时,可以使用两种链接方法来调用导出的 DLL 函数。这两种链接方法是加载时动态链接和运行时动态链接。
1、加载时动态链接
在加载时动态链接中,应用程序像调用本地函数一样对导出的 DLL 函数进行显式调用。要使用加载时动态链接,请在编译和链接应用程序时提供头文件 (.h) 和导入库文件 (.lib)。当您这样做时,链接器将向系统提供加载 DLL 所需的信息,并在加载时解析导出的 DLL 函数的位置。
2、运行时动态链接
在运行时动态链接中,应用程序调用 LoadLibrary 函数或 LoadLibraryEx 函数以在运行时加载 DLL。成功加载 DLL 后,可以使用 GetProcAddress 函数获得要调用的导出的 DLL 函数的地址。在使用运行时动态链接时,无需使用导入库文件。
Win32 DLL的特点
Win32 DLL与 Win16 DLL有很大的区别,这主要是由操作系统的设计思想决定的。一方面,在Win16 DLL中程序入口点函数和出口点函数(LibMain和WEP)是分别实现的;而在Win32 DLL中却由同一函数DLLMain来实现。无论何时,当一个进程或线程载入和卸载DLL时,都要调用该函数,它的原型是
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved);
其中,第一个参数表示DLL的实例句柄;第三个参数系统保留;这里主要介绍一下第二个参数,它有四个可能的值:DLL_PROCESS_ATTACH(进程载入),DLL_THREAD_ATTACH(线程载入),DLL_THREAD_DETACH(线程卸载),DLL_PROCESS_DETACH(进程卸载),在DLLMain函数中可以对传递进来的这个参数的值进行判别,并根据不同的参数值对DLL进行必要的初始化或清理工作。举个例子来说,当有一个进程载入一个DLL时,系统分派给DLL的第二个参数为DLL_PROCESS_ATTACH,这时,你可以根据这个参数初始化特定的数据。另一方面,在Win16环境下,所有应用程序都在同一地址空间;而在Win32环境下,所有应用程序都有自己的私有空间,每个进程的空间都是相互独立的,这减少了应用程序间的相互影响,但同时也增加了编程的难度。大家知道,在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的;而在Win32环境中,情况却发生了变化,当进程在载入DLL时,系统自动把DLL地址映射到该进程的私有空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间,也就是说每个进程所拥有的相同的DLL的全局数据其值却并不一定是相同的。因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。亦即把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。
黑线 2006-11-07 19:49
DLL木马的原理
什么是 DLL?
DLL 是一个包含可由多个程序同时使用的代码和数据的库。例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数。因此,每个程序都可以使用该 DLL 中包含的功能来实现“打开”对话框。这有助于促进代码重用和内存的有效使用。
通过使用 DLL,程序可以实现模块化,由相对独立的组件组成。例如,一个计帐程序可以按模块来销售。可以在运行时将各个模块加载到主程序中(如果安装了相应模块)。因为模块是彼此独立的,所以程序的加载速度更快,而且模块只在相应的功能被请求时才加载。
此外,可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。例如,您可能具有一个工资计算程序,而税率每年都会更改。当这些更改被隔离到 DLL 中以后,您无需重新生成或安装整个程序就可以应用更新。
下表说明了 Windows 操作系统中的一些作为 DLL 实现的文件:• ActiveX 控件 (.ocx) 文件
ActiveX 控件的一个示例是日历控件,它使您可以从日历中选择日期。
• 控制面板 (.cpl) 文件
.cpl 文件的一个示例是位于控制面板中的项。每个项都是一个专用 DLL。
• 设备驱动程序 (.drv) 文件
设备驱动程序的一个示例是控制打印到打印机的打印机驱动程序。
DLL木马的实现原理是编程者在DLL中包含木马程序代码,随后在目标主机中选择特定目标进程,以某种方式强行指定该进程调用包含木马程序的DLL,最终达到侵袭目标系统的目的。
正是DLL程序自身的特点决定了以这种形式加载木马不仅可行,而且具有良好的隐藏性:
(1)DLL程序被映射到宿主进程的地址空间中,它能够共享宿主进程的资源,并根据宿主进程在目标主机的级别非法访问相应的系统资源;
(2)DLL程序没有独立的进程地址空间,从而可以避免在目标主机中留下"蛛丝马迹",达到隐蔽自身的目的。
DLL木马实现了"真隐藏",我们在任务管理器中看不到木马"进程",它完全溶进了系统的内核。与"真隐藏"对应的是"假隐藏","假隐藏"木马把自己注册成为一个服务。虽然在任务管理器中也看不到这个进程,但是"假隐藏"木马本质上还具备独立的进程空间。"假隐藏"只适用于Windows9x的系统,对于基于WINNT的操作系统,通过服务管理器,我们可以发现系统中注册过的服务。
DLL木马注入其它进程的方法为远程线程插入。
远程线程插入技术指的是通过在另一个进程中创建远程线程的方法进入那个进程的内存地址空间。将木马程序以DLL的形式实现后,需要使用插入到目标进程中的远程线程将该木马DLL插入到目标进程的地址空间,即利用该线程通过调用Windows API LoadLibrary函数来加载木马DLL,从而实现木马对系统的侵害。
DLL木马注入程序
这里涉及到一个非常重要的Windows API――CreateRemoteThread。与之相比,我们所习惯使用的CreateThread API函数只能在进程自身内部产生一个新的线程,而且被创建的新线程与主线程共享地址空间和其他资源。而CreateRemoteThread则不同,它可以在另外的进程中产生线程!CreateRemoteThread有如下特点:
(1)CreateRemoteThread较CreateThread多一个参数hProcess,该参数用于指定要创建线程的远程进程,其函数原型为:
HANDLE CreateRemoteThread(
HANDLE hProcess, //远程进程句柄
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
(2)线程函数的代码不能位于我们用来注入DLL木马的进程所在的地址空间中。也就是说,我们不能想当然地自己写一个函数,并把这个函数作为远程线程的入口函数;
(3)不能把本进程的指针作为CreateRemoteThread的参数,因为本进程的内存空间与远程进程的不一样。
以下程序由作者Shotgun的DLL木马注入程序简化而得(单击此处下载,在经典书籍《Windows核心编程》中我们也可以看到类似的例子),它将d盘根目录下的troydll.dll插入到ID为4000的进程中:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
void CheckError ( int, int, char *); //出错处理函数
PDWORD pdwThreadId;
HANDLE hRemoteThread, hRemoteProcess;
DWORD fdwCreate, dwStackSize, dwRemoteProcessId;
PWSTR pszLibFileRemote=NULL;
void main(int argc,char **argv)
{
int iReturnCode;
char lpDllFullPathName[MAX_PATH];
WCHAR pszLibFileName[MAX_PATH]={0};
dwRemoteProcessId = 4000;
strcpy(lpDllFullPathName, "d:\\troydll.dll");
//将DLL文件全路径的ANSI码转换成UNICODE码
iReturnCode = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
lpDllFullPathName, strlen(lpDllFullPathName),
pszLibFileName, MAX_PATH);
CheckError(iReturnCode, 0, "MultByteToWideChar");
//打开远程进程
hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | //允许创建线程
PROCESS_VM_OPERATION | //允许VM操作
PROCESS_VM_WRITE, //允许VM写
FALSE, dwRemoteProcessId );
CheckError( (int) hRemoteProcess, NULL, "Remote Process not Exist or Access Denied!");
//计算DLL路径名需要的内存空间
int cb = (1 + lstrlenW(pszLibFileName)) * sizeof(WCHAR);
pszLibFileRemote = (PWSTR) VirtualAllocEx( hRemoteProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
CheckError((int)pszLibFileRemote, NULL, "VirtualAllocEx");
//将DLL的路径名复制到远程进程的内存空间
iReturnCode = WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (PVOID) pszLibFileName, cb, NULL);
CheckError(iReturnCode, false, "WriteProcessMemory");
//计算LoadLibraryW的入口地址
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
CheckError((int)pfnStartAddr, NULL, "GetProcAddress");
//启动远程线程,通过远程线程调用用户的DLL文件
hRemoteThread = CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL);
CheckError((int)hRemoteThread, NULL, "Create Remote Thread");
//等待远程线程退出
WaitForSingleObject(hRemoteThread, INFINITE);
//清场处理
if (pszLibFileRemote != NULL)
{
VirtualFreeEx(hRemoteProcess, pszLibFileRemote, 0, MEM_RELEASE);
}
if (hRemoteThread != NULL)
{
CloseHandle(hRemoteThread );
}
if (hRemoteProcess!= NULL)
{
CloseHandle(hRemoteProcess);
}
}
//错误处理函数CheckError()
void CheckError(int iReturnCode, int iErrorCode, char *pErrorMsg)
{
if(iReturnCode==iErrorCode)
{
printf("%s Error:%d\n\n", pErrorMsg, GetLastError());
//清场处理
if (pszLibFileRemote != NULL)
{
VirtualFreeEx(hRemoteProcess, pszLibFileRemote, 0, MEM_RELEASE);
}
if (hRemoteThread != NULL)
{
CloseHandle(hRemoteThread );
}
if (hRemoteProcess!= NULL)
{
CloseHandle(hRemoteProcess);
}
exit(0);
}
}
从DLL木马注入程序的源代码中我们可以分析出DLL木马注入的一般步骤为:
(1)取得宿主进程(即要注入木马的进程)的进程ID dwRemoteProcessId;
(2)取得DLL的完全路径,并将其转换为宽字符模式pszLibFileName;
(3)利用Windows API OpenProcess打开宿主进程,应该开启下列选项:
a.PROCESS_CREATE_THREAD:允许在宿主进程中创建线程;
b.PROCESS_VM_OPERATION:允许对宿主进程中进行VM操作;
c.PROCESS_VM_WRITE:允许对宿主进程进行VM写。
(4)利用Windows API VirtualAllocEx函数在远程线程的VM中分配DLL完整路径宽字符所需的存储空间,并利用Windows API WriteProcessMemory函数将完整路径写入该存储空间;
(5)利用Windows API GetProcAddress取得Kernel32模块中LoadLibraryW函数的地址,这个函数将作为随后将启动的远程线程的入口函数;
(6)利用Windows API CreateRemoteThread启动远程线程,将LoadLibraryW的地址作为远程线程的入口函数地址,将宿主进程里被分配空间中存储的完整DLL路径作为线程入口函数的参数以另其启动指定的DLL;
(7)清理现场。
DLL木马的防治
从DLL木马的原理和一个简单的DLL木马程序中我们学到了DLL木马的工作方式,这可以帮助我们更好地理解DLL木马病毒的防治手段。
一般的木马被植入后要打开一网络端口与攻击程序通信,所以防火墙是抵御木马攻击的最好方法。防火墙可以进行数据包过滤检查,我们可以让防火墙对通讯端口进行限制,只允许系统接受几个特定端口的数据请求。这样,即使木马植入成功,攻击者也无法进入到受侵系统,防火墙把攻击者和木马分隔开来了。
对于DLL木马,一种简单的观察方法也许可以帮助用户发现之。我们查看运行进程所依赖的DLL,如果其中有一些莫名其妙的DLL,则可以断言这个进程是宿主进程,系统被植入了DLL木马。"道高一尺,魔高一丈",现如今,DLL木马也发展到了更高的境界,它们看起来也不再"莫名其妙"。在最新的一些木马里面,开始采用了先进的DLL陷阱技术,编程者用特洛伊DLL替换已知的系统DLL。特洛伊DLL对所有的函数调用进行过滤,对于正常的调用,使用函数转发器直接转发给被替换的系统DLL;对于一些事先约定好的特殊情况,DLL会执行一些相应的操作。
[查看全文]