摘 要详细阐述了如何使用DLL远程注入技术对Windows 记事本进行换肤,讲解了DLL远程注入的概念和步骤。 关键词DLL远程注入,换肤 一、概述 1. DLL远程注入原理 DLL远程注入就是使用远程线程来插入DLL,就是要求目标进程中的线程调用LoadLibrary函数来加载必要的DLL。由于除了自己进程中的线程外,我们无法方便地控制其它进程中的线程,因此这种解决方案要求我们在目标进程中创建一个新线程。由于是自己创建这个线程,因此我们能够控制它执行什么代码。 Windows提供了一个称为CreaeRemoteThread的函数,使我们能够非常容易地在另一个进程中创建线程: HANDLE CreateRemoteThread(HANDLE hProcess,PSECURITY_ARRTRIBUTES psa,DWORD dwStackSize, PTHREAD_START_ROUTINE pfnStartAddr,PVOID pvParam,DWORD fdwCreate,PDOWRD pdwThreadId); 如何才能让该线程加载我们的DLL呢?那就需要该线程调用LoadLibrary函数: HINSTANCE LoadLibraryA (LPCSTR pszLibFileName); //ANSI 版本 HINSTANCE LoadLibraryW (LPCWSTR pszLibFileName); //Unicode版本 我们现在要做的事情是创建一个新线程,并使线程函数的地址成为LoadLibraryA或LoadLibraryW函数的地址。 PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle(TEXT(“kernel32”)),”LoadLibraryA”); HANDLE hThread = CreateRemoteThread(hProcessRemote,NULL,0,pfnThreadRtn,”C:""MyLib.dll”,0,NULL); 细心的读者应该注意到一个问题:就是字符串”C:""MyLib.dll”是在调用进程的地址空间中,会导致远程进程的线程可能引发访问违规。所以我们必须将DLL的路径名字符串放入远程进程的地址空间中。
这时,DLL已经被插入远程的地址空间中,同时DLL的DllMain函数接收到一个DLL_PROCESS_ATTACH通知,并且能够执行需要的代码。 需要提醒的是,这种插入DLL的方法存在唯一一个不足是,Windows98并不支持这样的函数。只能用在Window2000及以上版本。 2. 对记事本换肤 要对记事本换肤,需要解决2个问题: 第一、找到能对程序进行换肤DLL文件,这里我们采用Skin++ (www.uipower.com)作为换肤DLL; 第二、能将DLL远程注入到记事本的方法,该方法我们在上面已经做了介绍。
二、换肤的关键部分代码 TCHAR szLibFileName[_MAX_PATH]; GetModuleFileName(NULL, szLibFileName,_MAX_PATH); CString strLibFileName(szLibFileName); strLibFileName = strLibFileName.Left(strLibFileName.ReverseFind(_T('""')) + 1); strLibFileName += _T("SkinPlusPlus.dll"); _tcscpy(szLibFileName,strLibFileName); HWND hNotepad = ::FindWindow(_T("Notepad"),NULL); if (hNotepad == NULL) return; DWORD dwRemoteProcessId; ::GetWindowThreadProcessId( hNotepad, (DWORD*)&dwRemoteProcessId ); HANDLE hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE,dwRemoteProcessId); //计算DLL路径名需要的内存空间 int cb = (1 + _tcslen(szLibFileName)) * sizeof(TCHAR); //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区 BYTE* pszLibFileRemote = (BYTE*) VirtualAllocEx( hRemoteProcess, NULL, cb,MEM_COMMIT, PAGE_EXECUTE_READWRITE); //使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间 int iReturnCode = WriteProcessMemory(hRemoteProcess,pszLibFileRemote, (PVOID)szLibFileName,cb, NULL); //计算LoadLibraryW的入口地址 PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA"); //启动远程线程LoadLibraryW,通过远程线程调用用户的DLL文件 HANDLE hThread = CreateRemoteThread( hRemoteProcess, NULL, 0,pfnStartAddr, pszLibFileRemote, 0, NULL); WaitForSingleObject( hThread, INFINITE ); DWORD dwHandle; GetExitCodeThread( hThread, &dwHandle ); VirtualFreeEx( hRemoteProcess, pszLibFileRemote, cb, MEM_DECOMMIT ); CloseHandle( hThread ); ::SetForegroundWindow(hNotepad); 三、结束语 DLL的远程注入技术和软件换肤是目前Windows上非常流行的2项技术,您可以在很多场合同时看到这2者的身影,比如MSNShell。有兴趣的读者可以到http://www.msnshell.com/上下载使用。 |