源代码下载

   详细阐述了如何使用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版本

         我们现在要做的事情是创建一个新线程,并使线程函数的地址成为LoadLibraryALoadLibraryW函数的地址。

         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名称
DWORD dwSize, dwWritten;
dwSize = lstrlenA( lpszDll ) + 1;
LPVOID lpBuf = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE );
WriteProcessMemory( hProcess, lpBuf, (LPVOID)lpszDll, dwSize, &dwWritten )

HANDLE hThread = CreateRemoteThread(hProcessRemote,NULL,0,pfnThreadRtn, lpBuf, 0,NULL);

// 等待LoadLibrary加载完毕,对字符串空间进行回收

VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );

    这时,DLL已经被插入远程的地址空间中,同时DLLDllMain函数接收到一个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/上下载使用。