整个系统的配置都保存在注册表中,我们可以通过调整其中的设置来改变系统的行为。
该方式依赖User32.dll,也就是说,需要可执行程序调用到这个系统动态库,我们注入的dll才会被执行到。基本上所有基于GUI的应用程序都使用了User32.dll。
注册表位置:
- // AppInit_Dlls(64位程序读取)
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows [AppInit_DLLs]
-
- //AppInit_Dlls(32位程序读取)
- HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows [AppInit_DLLs]
-
- //32位系统
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows [AppInit_DLLs]
查看注册表:windows+R键,输入regedit。

AppInit_DLLs:需要包含一个DLL的文件名或一组DLL的文件名(通过空格或逗号分隔),例如:D:\testDll.dll。
LoadAppInit_Dlls:将它的值设为1。
原理:当User32.dll被映射到一个新的进程时,会收到DLL_PROCESS_ATTACH通知,会取得上述注册表AppInit_DLLs键的值,并调用LoadLibrary来载入这个字符串中指定的每个DLL。当系统载入每个DLL的时候,会调用它们的DLLMain函数并将参数fdwReason的值设为DLL_PROCESS_ATTACH,这样每个DLL就能够对自己进行初始化。
2.1首先编译一个自定义的DLL,我使用的vs2019,创建一个动态链接库,如下图所示。

2.2在dllmain.cpp中编写如下代码,主要是创建了一个新的进程,然后使用google浏览器打开百度页面。当系统载入每个DLL的时候,会调用它们的DLLMain函数并将参数fdwReason(这里命名为ul_reason_for_call)的值设为DLL_PROCESS_ATTACH,这样每个DLL就能够对自己进行初始化。
- // dllmain.cpp : 定义 DLL 应用程序的入口点。
- #include "pch.h"
-
- #define CMD L"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
- #define URL L"http://www.baidu.com"
-
-
- BOOL APIENTRY DllMain( HMODULE hModule,
- DWORD ul_reason_for_call,
- LPVOID lpReserved
- )
- {
- TCHAR cmd[MAX_PATH] = { 0 };
-
- STARTUPINFO si = { 0 };
- PROCESS_INFORMATION pi = { 0 };
- si.cb = sizeof(STARTUPINFO);
- si.dwFlags = STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_SHOWNORMAL;
-
- switch (ul_reason_for_call)
- {
- case DLL_PROCESS_ATTACH:
- wsprintf(cmd, L"%s %s", CMD, URL);
- // 创建一个新进程及其主线程;
- if (!CreateProcess(NULL, (LPTSTR)(LPCSTR)cmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
- break;
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- if (pi.hProcess != NULL)
- CloseHandle(pi.hProcess);
- break;
- }
- return TRUE;
- }
-
2.3编译然后生成库。
将生成好的库放到一个简洁的路径下,这里放到D:/testDll.dll。

2.4使用代码将键值写入到注册表。
新建一个控制台应用程序,代码如下:
- #define DSTKEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\"
-
- BOOL RegInject(WCHAR* DllFullPath)
- {
- BOOL bOk = FALSE;
- HKEY hKey = NULL;
- BYTE DllPath[MAX_PATH] = { 0 };
-
- //打开注册表
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, DSTKEY, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
- {
- printf("RegOpenKeyEx Error!");
- return FALSE;
- }
-
- memcpy((void*)DllPath, DllFullPath, _tcslen(DllFullPath) * 2 + 1);
-
- //设置键值
- if (RegSetValueEx(hKey, L"AppInit_DLLs", 0, REG_SZ, DllPath, (_tcslen(DllFullPath) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS)
- {
- printf("RegSetKeyValue Error!");
- return FALSE;
- }
-
- DWORD dwValue = 1;
- //设置键值
- if (RegSetValueEx(hKey, L"LoadAppInit_DLLs", 0, REG_DWORD, (BYTE*)&dwValue, sizeof(dwValue)) != ERROR_SUCCESS)
- {
- printf("RegSetKeyValue Error! ");
- return FALSE;
- }
-
- //RegDeleteValue(hKey, L"AppInit_DLLs");
- //RegDeleteValue(hKey, L"LoadAppInit_DLLs");
-
- bOk = TRUE;
-
-
- if (hKey)
- RegCloseKey(hKey);
- return bOk;
- }
-
-
- // TODO: 在此处放置代码
- WCHAR DllFullPath[MAX_PATH] = L"D:\\testDll.dll";
- BOOL bOk = RegInject(DllFullPath);
- if (bOk)
- {
- printf("Registry inject success! ");
- }
- else
- {
- printf("Registry inject fail! ");
- }
注意:程序要使用管理员权限执行,修改如下图所示。

设置好注册表之后,任意GUI程序运行,都会打开浏览器,会弹出无数个网页。慎用!!!
2.5删除注册表键值
需要调用以下方法,删除对应的键值,这样才能将网页无限弹窗停止。
- RegDeleteValue(hKey, L"AppInit_DLLs");
- RegDeleteValue(hKey, L"LoadAppInit_DLLs");