C++实现 “你被骗了” 自动拦截,反诈神器

rick

“Never Gonna Give You Up” , 已经是历经十五年的名梗了,点开这个视频,就说明 你被骗了。

无论是自己点进了一些奇奇怪怪的链接,还是被自动跳转,你都不希望
展开

0x01 原理&规则

【本程序B站视频链接】快去B站关注我
所以,这个程序就非常有用了,打开后,自动拦截符合规则的rickroll窗口。本程序有两种拦截方式:进程拦截窗口拦截

进程拦截:
每半秒检测一次所有进程的命令行,如果包含特定的rickroll链接(我指定了四个,见下图),则将其击杀。

在这里插入图片描述

窗口拦截:
每半秒检测一次前端窗口,如果标题经过转小写字母、去除空格后包含nevergonnagiveyouup、rickroll或是你被骗了,就按以下顺序进行关闭:

1. Ctrl+W【针对网页等标签页】
2. 发送WM_CLOSE关闭消息【针对窗口】
3. 发送WM_DESTROY销毁消息【针对窗口,暴力】

如果其中一个操作成功剩余操作就不会执行。

每次拦截成功后控制台都会输出拦截信息,以及两种拦截的次数与总次数。


0x02 源代码

编译好的 EXE 这里取 ε = = (づ′▽`)づ 密码:3sve
文件名: AntiRick_rollPopup.cpp
语言标准: 至少 C++20(如果不够,请自行替换实现 std::remove_if 那里删除字符串空格的算法即可)

/***************************************
 *          AntiRick_rollPopup          *
 *         RICKROLL自动拦截器          *
 *         Author: @Wormwaker          *
 *        StartDate: 2024/4/1          *
 ***************************************/
#define UNICODE
#define _UNICODE
//#define ONLY_DEFAULT_BROWSER		
// 如果将上面这个宏启用,进程拦截只检查默认浏览器
// 后来测试了一下,由于默认浏览器的获取可能不准确,还是所有进程进行检查比较好
#include <Windows.h>
//#include <winternl.h>
#include <tlhelp32.h>
#include <io.h>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>

size_t proc_block_cnt {0U}, wnd_block_cnt {0U};

const std::wstring rickroll_list[]
{	// 可以自行添加
	L"www.bilibili.com/video/BV1GJ411x7h7",
	L"www.bilibili.com/video/BV1uT4y1P7CX",
	L"www.bilibili.com/video/BV1hG41147Wx",
	L"www.bilibili.com/video/BV1Pg411r7V5",
};
void SetColor(UINT uFore, UINT uBack) 
{
	
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(handle, uFore + uBack * 0x10);
}

#ifdef ONLY_DEFAULT_BROWSER
std::wstring GetDefaultBrowserPath()
{
	std::wstring defaultBrowserPath;
	HKEY hKey;
	LSTATUS status;
	
	// Check HKEY_LOCAL_MACHINE\SOFTWARE\Classes\http\shell\open\command
	status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Classes\\http\\shell\\open\\command", 0, KEY_READ, &hKey);
	if (status == ERROR_SUCCESS)
	{
		wchar_t browserPath[MAX_PATH];
		DWORD dataSize = sizeof(browserPath);
		status = RegQueryValueEx(hKey, nullptr, nullptr, nullptr, reinterpret_cast<LPBYTE>(browserPath), &dataSize);
		RegCloseKey(hKey);
		if (status == ERROR_SUCCESS)
		{
			defaultBrowserPath = std::wstring(browserPath);
			
			// Extracting the executable path
			size_t pos = defaultBrowserPath.find_first_of(L"\"");
			if (pos != std::wstring::npos)
			{
				defaultBrowserPath = defaultBrowserPath.substr(1, pos - 1);
			}
			
			return defaultBrowserPath;
		}
	}
	
	// Check HKEY_CLASSES_ROOT\http\shell\open\command
	status = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"http\\shell\\open\\command", 0, KEY_READ, &hKey);
	if (status == ERROR_SUCCESS)
	{
		wchar_t browserPath[MAX_PATH];
		DWORD dataSize = sizeof(browserPath);
		status = RegQueryValueEx(hKey, nullptr, nullptr, nullptr, reinterpret_cast<LPBYTE>(browserPath), &dataSize);
		RegCloseKey(hKey);
		if (status == ERROR_SUCCESS)
		{
			defaultBrowserPath = std::wstring(browserPath);
			
			// Extracting the executable path
			size_t pos = defaultBrowserPath.find_first_of(L"\"");
			if (pos != std::wstring::npos)
			{
				defaultBrowserPath = defaultBrowserPath.substr(1, pos - 1);
			}
			
			return defaultBrowserPath;
		}
	}
	
	return L"";
}
#endif

inline bool sequ(const std::wstring& s1, const std::wstring& s2)
{
	return wcsicmp(s1.c_str(), s2.c_str()) == 0;
}

inline bool ExistFile(const std::wstring& strFile) {
	//文件或文件夹都可以
	return !_waccess(strFile.c_str(),S_OK);//S_OK表示只检查是否存在
}

bool IsFile(const std::wstring& path)
{
	DWORD attributes = GetFileAttributes(path.c_str());
	if (attributes != INVALID_FILE_ATTRIBUTES)
	{
		return !(attributes & FILE_ATTRIBUTE_DIRECTORY);
	}
	return false; //失败
}

bool IsProcessNew(HANDLE hProcess, const std::chrono::system_clock::time_point& currentTime, const std::chrono::seconds& threshold)
{	//貌似没用
	FILETIME creationTime, exitTime, kernelTime, userTime;
	if (GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime, &userTime))
	{
		ULARGE_INTEGER creationTimeUI;
		creationTimeUI.LowPart = creationTime.dwLowDateTime;
		creationTimeUI.HighPart = creationTime.dwHighDateTime;
		
		auto processCreationTime = static_cast<std::chrono::system_clock::time_point>(std::chrono::nanoseconds(creationTimeUI.QuadPart * 100));
		
		return currentTime - processCreationTime <= threshold;
	}
	return false;
}

//typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
//	HANDLE ProcessHandle,
//	DWORD ProcessInformationClass,
//	PVOID ProcessInformation,
//	DWORD ProcessInformationLength,
//	PDWORD ReturnLength
//	);
//std::wstring GetProcessCommandLine(HANDLE hProcess)
//{
//	UNICODE_STRING commandLine;
//	std::wstring commandLineContents {L""};
//	_NtQueryInformationProcess NtQuery = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
//	if (NtQuery)
//	{
//		PROCESS_BASIC_INFORMATION pbi;
//		NTSTATUS isok = NtQuery(hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL);        
//		if (NT_SUCCESS(isok))
//		{
//			PEB peb;
//			RTL_USER_PROCESS_PARAMETERS upps;
//			PVOID rtlUserProcParamsAddress;
//			if (ReadProcessMemory(hProcess, &(((_PEB*) pbi.PebBaseAddress)->ProcessParameters), &rtlUserProcParamsAddress, sizeof(PVOID), NULL))
//			{
//				if (ReadProcessMemory(hProcess,
//					&(((_RTL_USER_PROCESS_PARAMETERS*) rtlUserProcParamsAddress)->CommandLine),
//					&commandLine, sizeof(commandLine), NULL))
//				{
					commandLineContents = (TCHAR *)malloc(commandLine.Length + sizeof(TCHAR));
					memset(commandLineContents, 0, commandLine.Length + sizeof(TCHAR));
					ReadProcessMemory(hProcess, commandLine.Buffer,
						commandLineContents, commandLine.Length, NULL);
//					
//					WCHAR* buffer = new WCHAR[commandLine.Length / sizeof(WCHAR) + 1];
//					if (ReadProcessMemory(hProcess, commandLine.Buffer, buffer, commandLine.Length, NULL))
//					{
//						buffer[commandLine.Length / sizeof(WCHAR)] = L'\0';
//						commandLineContents = buffer;
//					}
//					delete[] buffer;
//				}
//			}
//		}
//	}
//	
//	return commandLineContents;
//}// original code from https://blog.csdn.net/u013676868/article/details/103275407

// 以下获取进程命令行参数代码来自于:https://www.cnblogs.com/2018shawn/p/15557662.html
// NtQueryInformationProcess for pure 32 and 64-bit processes
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
	IN HANDLE ProcessHandle,
	ULONG ProcessInformationClass,
	OUT PVOID ProcessInformation,
	IN ULONG ProcessInformationLength,
	OUT PULONG ReturnLength OPTIONAL
	);

typedef NTSTATUS (NTAPI *_NtReadVirtualMemory)(
	IN HANDLE ProcessHandle,
	IN PVOID BaseAddress,
	OUT PVOID Buffer,
	IN SIZE_T Size,
	OUT PSIZE_T NumberOfBytesRead);

// NtQueryInformationProcess for 32-bit process on WOW64
typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)(
	IN HANDLE ProcessHandle,
	IN PVOID64 BaseAddress,
	OUT PVOID Buffer,
	IN ULONG64 Size,
	OUT PULONG64 NumberOfBytesRead);

// PROCESS_BASIC_INFORMATION for pure 32 and 64-bit processes
typedef struct _PROCESS_BASIC_INFORMATION {
	PVOID Reserved1;
	PVOID PebBaseAddress;
	PVOID Reserved2[2];
	ULONG_PTR UniqueProcessId;
	PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;

// PROCESS_BASIC_INFORMATION for 32-bit process on WOW64
// The definition is quite funky, as we just lazily doubled sizes to match offsets...
typedef struct _PROCESS_BASIC_INFORMATION_WOW64 {
	PVOID Reserved1[2];
	PVOID64 PebBaseAddress;
	PVOID Reserved2[4];
	ULONG_PTR UniqueProcessId[2];
	PVOID Reserved3[2];
} PROCESS_BASIC_INFORMATION_WOW64;

typedef struct _UNICODE_STRING {
	USHORT Length;
	USHORT MaximumLength;
	PWSTR  Buffer;
} UNICODE_STRING;

typedef struct _UNICODE_STRING_WOW64 {
	USHORT Length;
	USHORT MaximumLength;
	PVOID64 Buffer;
} UNICODE_STRING_WOW64;

std::wstring GetProcessCommandLine(HANDLE hProcess)
{
	if(!hProcess || hProcess == INVALID_HANDLE_VALUE)
	{
		SetColor(12, 0);
		printf("Invalid Process Handle!\n");
		return L"";
	}
	DWORD err {0L};
	// determine if 64 or 32-bit processor
	SYSTEM_INFO si;
	GetNativeSystemInfo(&si);
	
	// determine if this process is running on WOW64
	BOOL wow;
	IsWow64Process(GetCurrentProcess(), &wow);
	
	// use WinDbg "dt ntdll!_PEB" command and search for ProcessParameters offset to find the truth out
	DWORD ProcessParametersOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0x20 : 0x10;
	DWORD CommandLineOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0x70 : 0x40;
	
	// read basic info to get ProcessParameters address, we only need the beginning of PEB
	DWORD pebSize = ProcessParametersOffset + 8;
	PBYTE peb = (PBYTE)malloc(pebSize);
	ZeroMemory(peb, pebSize);
	
	// read basic info to get CommandLine address, we only need the beginning of ProcessParameters
	DWORD ppSize = CommandLineOffset + 16;
	PBYTE pp = (PBYTE)malloc(ppSize);
	ZeroMemory(pp, ppSize);
	
	PWSTR cmdLine;
	
	if (wow)
	{
		// we're running as a 32-bit process in a 64-bit OS
		PROCESS_BASIC_INFORMATION_WOW64 pbi;
		ZeroMemory(&pbi, sizeof(pbi));
		
		// get process information from 64-bit world
		_NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64QueryInformationProcess64");
		err = query(hProcess, 0, &pbi, sizeof(pbi), NULL);
		if (err != 0)
		{
			SetColor(12, 0);
			printf("NtWow64QueryInformationProcess64 failed\n");
			CloseHandle(hProcess);
			return L"";
		}
		
		// read PEB from 64-bit address space
		_NtWow64ReadVirtualMemory64 read = (_NtWow64ReadVirtualMemory64)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64");
		err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL);
		if (err != 0)
		{
			SetColor(12, 0);
			printf("NtWow64ReadVirtualMemory64 PEB failed\n");
			CloseHandle(hProcess);
			return L"";
		}
		
		// read ProcessParameters from 64-bit address space
		// PBYTE* parameters = (PBYTE*)*(LPVOID*)(peb + ProcessParametersOffset); // address in remote process address space
		PVOID64 parameters = (PVOID64) * ((PVOID64*)(peb + ProcessParametersOffset)); // corrected 64-bit address, see comments
		err = read(hProcess, parameters, pp, ppSize, NULL);
		if (err != 0)
		{
			SetColor(12, 0);
			printf("NtWow64ReadVirtualMemory64 Parameters failed\n");
			CloseHandle(hProcess);
			return L"";
		}
		
		// read CommandLine
		UNICODE_STRING_WOW64* pCommandLine = (UNICODE_STRING_WOW64*)(pp + CommandLineOffset);
		cmdLine = (PWSTR)malloc(pCommandLine->MaximumLength);
		err = read(hProcess, pCommandLine->Buffer, cmdLine, pCommandLine->MaximumLength, NULL);
		if (err != 0)
		{
			SetColor(12, 0);
			printf("NtWow64ReadVirtualMemory64 Parameters failed\n");
			CloseHandle(hProcess);
			return L"";
		}
	}
	else
	{
		// we're running as a 32-bit process in a 32-bit OS, or as a 64-bit process in a 64-bit OS
		PROCESS_BASIC_INFORMATION pbi;
		ZeroMemory(&pbi, sizeof(pbi));
		
		// get process information
		_NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
		err = query(hProcess, 0, &pbi, sizeof(pbi), NULL);
		if (err != 0)
		{
			SetColor(12, 0);
			printf("NtQueryInformationProcess failed %ld\n", GetLastError());
			CloseHandle(hProcess);
			return L"";
		}
		
		// read PEB
		if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL))
		{
			SetColor(12, 0);
			printf("ReadProcessMemory PEB failed\n");
			CloseHandle(hProcess);
			return L"";
		}
		
		// read ProcessParameters
		PBYTE* parameters = (PBYTE*)*(LPVOID*)(peb + ProcessParametersOffset); // address in remote process adress space
		if (!ReadProcessMemory(hProcess, parameters, pp, ppSize, NULL))
		{
			SetColor(12, 0);
			printf("ReadProcessMemory Parameters failed\n");
			CloseHandle(hProcess);
			return L"";
		}
		
		// read CommandLine
		UNICODE_STRING* pCommandLine = (UNICODE_STRING*)(pp + CommandLineOffset);
		cmdLine = (PWSTR)malloc(pCommandLine->MaximumLength);
		if (!ReadProcessMemory(hProcess, pCommandLine->Buffer, cmdLine, pCommandLine->MaximumLength, NULL))
		{
			SetColor(12, 0);
			printf("ReadProcessMemory Parameters failed\n");
			CloseHandle(hProcess);
			return L"";
		}
	}
	return std::wstring{cmdLine};
}

void TerminateProcessWhoWannaRickroll(const std::wstring& exeName)
{
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnapshot == INVALID_HANDLE_VALUE)
	{
		SetColor(12, 0);
		std::cerr << "Failed to create process snapshot." << std::endl;
		return;
	}
	
	PROCESSENTRY32 pe32;
	pe32.dwSize = sizeof(PROCESSENTRY32);
	
//	std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
	std::chrono::seconds threshold(5);
	
	if (Process32First(hSnapshot, &pe32))
	{
		do
		{
			if (exeName.empty() || wcsicmp(pe32.szExeFile, exeName.c_str()) == 0)	//名称匹配
			{
				//std::wcout << pe32.szExeFile << '\n';
				//打开进程句柄
				HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, pe32.th32ProcessID);
				if (hProcess != NULL)
				{
					//是否为新进程
					//if (IsProcessNew(hProcess, currentTime, threshold))
					{
//						//获取命令行参数
//						wchar_t commandLine[MAX_PATH];
//						DWORD dwSize = sizeof(commandLine);
						std::wstring commandLine {GetProcessCommandLine(hProcess)};
//						if (QueryFullProcessImageName(hProcess, 0, commandLine, &dwSize))
						if (!commandLine.empty())
						{
							//std::wcout << L"CommandLine:" << commandLine << L"\n\n";
							//你被骗了
							for(const auto& url : rickroll_list)
								if (wcsstr(commandLine.c_str(), url.c_str()) != nullptr)
								{
									proc_block_cnt++;
									//终结其生命
									SetColor(14, 0);
									std::wcout << L"\r***************************                               \n";
									SetColor(10, 0);
									std::wcout << L"  SOMEONE WANNA RICKROLL! \n";
									SetColor(13, 0);
									std::wcout << L"Rickroll URL: ";
									SetColor(2, 0);
									std::wcout << url << L'\n';
									SetColor(13, 0);
									std::wcout << L"Process Name: ";
									SetColor(14, 0);
									std::wcout << pe32.szExeFile << L'\n';
									SetColor(13, 0);
									std::wcout << L"Process ID: ";
									SetColor(15, 0);
									std::wcout << pe32.th32ProcessID << L'\n';
									SetColor(11, 0);
									std::wcout << L"Terminating process..." << std::endl;
									TerminateProcess(hProcess, 0);
									SetColor(14, 0);
									std::wcout << L"***************************\n\n";
								}
						}else{
							std::wcout << L"QueryFullProcessImageName Failed! - " << GetLastError() << L'\n';
						}
					}
					CloseHandle(hProcess);
				}
			}
		} while (Process32NextW(hSnapshot, &pe32));
	}
	
	CloseHandle(hSnapshot);
}

void CloseWindowWhoWannaRickroll()
{
	HWND hwnd = GetForegroundWindow();
	WCHAR title[1024]{0};
	GetWindowTextW(hwnd, title, 1024);
	std::wstring no_space_lower_title{wcslwr(title)};
	no_space_lower_title.erase(
		std::remove_if(
			no_space_lower_title.begin(), no_space_lower_title.end(), 
				[](wchar_t ch) { return std::iswspace(ch); }), 		//删除空格
		no_space_lower_title.end());
	
	if(wcsstr(no_space_lower_title.c_str(), L"nevergonnagiveyouup")
	|| wcsstr(no_space_lower_title.c_str(), L"rickroll")
	|| wcsstr(no_space_lower_title.c_str(), L"你被骗了"))
	{
		DWORD pid{0L};
		GetWindowThreadProcessId(hwnd, &pid);
		wnd_block_cnt++;
		SetColor(14, 0);
		std::wcout << L"\r**************************                                   \n";
		SetColor(10, 0);
		std::wcout << L" SOMEONE WANNA RICKROLL!\n";
		SetColor(13, 0);
		std::wcout << L"\nWindow Caption: ";
//		std::wcout << (wcslen(title) == 0 ? (L"(null)") : std::wstring(title).c_str());
		SetColor(7, 0);
		printf("%S", title);
		std::wcout << L'\n';
		SetColor(13, 0);
		std::wcout << L"Process ID:" << pid << L'\n';
		SetColor(1, 0);
		std::wcout << L"Closing it (Ctrl+W)...\n";
		keybd_event(VK_LCONTROL, 0, 0, 0);
		keybd_event('W', 0, 0, 0);
		Sleep(10);
		keybd_event('W', 0, 2, 0);
		keybd_event(VK_LCONTROL, 0, 2, 0);
		Sleep(500);
		if(nullptr != FindWindowW(nullptr, title))
		{
			SetColor(12, 0);
			std::wcout << L"Failed, send close message to it...\n";
			SendMessage(hwnd, WM_CLOSE, 0, 0);
			Sleep(500);
			if(nullptr != FindWindowW(nullptr, title))
			{
				SetColor(12, 0);
				std::wcout << L"Failed, Try to destroy it...\n";
				SendMessage(hwnd, WM_DESTROY, 0, 0);
			}
		}
		SetColor(14, 0);
		std::wcout << L"**************************\n\n";	
	}
}

int main()
{
	_wsystem(L"title Anti-Rick-Roll-Popup v1.0 - @Wormwaker");
#ifdef ONLY_DEFAULT_BROWSER
	std::wstring defaultBrowser = GetDefaultBrowserPath();
	std::wstring realPath {L""};
	
	std::wcout.imbue(std::locale(""));  //设置语言环境
	SetColor(8, 0);
	std::wcout << L"Reg value = ";
	std::wcout << defaultBrowser << std::endl;
	
	for(int i{0}; i < defaultBrowser.size() - 3; ++i)
	{
		if(sequ(defaultBrowser.substr(i, 4), L".exe"))
		{
			realPath = defaultBrowser.substr(0, i+4);
			if(ExistFile(realPath) && IsFile(realPath))
			{
				break;
			}
		}
	}
	SetColor(14, 0);
	std::wcout << L"Real path = ";
	SetColor(6, 0);
	std::wcout << realPath << std::endl;
	
	std::wstring exename{realPath};
	for(int i {realPath.size()-1}; i >= 0; --i)
	{
		if(realPath.at(i) == '\\')
		{
			exename = realPath.substr(i + 1, realPath.size() - i - 1);
			break;
		}
	}
	SetColor(14, 0);
	std::wcout << L"EXE Name = " << exename << std::endl;
#else
	std::wstring exename{L""};
#endif
	
	SetColor(15, 0);
	std::wcout << L"Anti-Rickroll-Popup Started!  \n\n\n\n";
	while(1)
	{
		TerminateProcessWhoWannaRickroll(exename);
		CloseWindowWhoWannaRickroll();
		std::this_thread::sleep_for(std::chrono::milliseconds(500));
		SetColor(15, 0);
		std::wcout << "\r[BLOCKED RICKROLL TOTAL: " << (proc_block_cnt+wnd_block_cnt) << " (Process: " << proc_block_cnt << " , Window: " << wnd_block_cnt << " ) ]     ";
	}
	return 0;
}

0x03 代码注意事项

  1. 本来进程拦截只会对默认浏览器进行监控(先查看HKEY_LOCAL_MACHINE Classes 里的http,再去看HKEY_CLASSES_ROOT里的http),但是由于Windows不断更新可能获取不准确,于是放弃。如果你想重新打开以提高性能,只需在开头把宏ONLY_DEFAULT_BROWSER开启即可。
  2. 宽字符串版本,以便更好支持 Unicode
  3. 有些浏览器(例如Edge)在打开一次后,关闭窗口进程也不会退出,因此进程拦截只会在首次打开时成功拦截,后面只能触发反应稍慢的窗口拦截。
  4. 进程拦截因为无需等待窗口加载,因此比窗口拦截更迅速更精确。

0x04 程序注意事项

1.注意,只要标题含那三种就会拦截,包括本程序及源代码(所以加了下划线)、PPT、文件资源管理器(例如搜索“你被骗了”),所以谨慎一点,以免产生损失。
2.有时 Ctrl+W 急了可能会导致Ctrl键未释放,按键可能会出现奇怪的现象,这时候再按一下左Ctrl即可恢复原样。
3. 有些窗口因为反应迟缓到达第三步“销毁”才消失,然后窗口又不会重新Create,就会导致无法正常打开非Rickroll窗口,此时请考虑重启该应用。

0x05 参考文献

由衷感谢你们!

Windows C++ 遍历所有进程的命令行
OpenAI
通过C++语言在应用层获取任意进程命令行参数

2024.4

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/515579.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

layui框架实战案例(26):layui-carousel轮播组件添加多个Echarts图标的效果

在Layui中&#xff0c;使用layui-carousel轮播组件嵌套Echarts图表来实现多个图表的展示。 css层叠样式表 调整轮播图背景色为白色&#xff1b;调整当个Echarts图表显示loading…状态&#xff1b;同一个DIV轮播项目添加多个Echarts的 .layui-carousel {background-color: #f…

【图论】有向无环图中一个节点的所有祖先 - 邻接表(DFS)

文章目录 题目&#xff1a;有向无环图中一个节点的所有祖先题目描述代码与解题思路 题目&#xff1a;有向无环图中一个节点的所有祖先 2192. 有向无环图中一个节点的所有祖先 题目描述 代码与解题思路 func getAncestors(n int, edges [][]int) [][]int {g : make([][]int, …

C#清空窗体的背景图片

目录 一、涉及到的知识点 1.设置窗体的背景图 2.加载窗体背景图 3.清空窗体的背景图 二、 示例 一、涉及到的知识点 1.设置窗体的背景图 详见本文作者的其他文章&#xff1a;C#手动改变自制窗体的大小-CSDN博客 https://wenchm.blog.csdn.net/article/details/137027140…

链路追踪原理

分布式系统为什么需要链路追踪&#xff1f; 随着互联网业务快速扩展&#xff0c;软件架构也日益变得复杂&#xff0c;为了适应海量用户高并发请求&#xff0c;系统中越来越多的组件开始走向分布式化&#xff0c;如单体架构拆分为微服务、服务内缓存变为分布式缓存、服务组件通…

IDEA2023.1.1中文插件

1.启动IDEA 选中Customize 2.选择All settings 3.选中Plugins,再搜索栏里输入Chinese,找到 "Chinese (Simplified) Language"插件&#xff0c;点击 Install 进行安装。 4. 安装完成后&#xff0c;重启IntelliJ IDEA&#xff0c;即可看到界面语言已经变为中文。

HashMap为啥线程不安全?

1. HashMap1.7在多线程并发下扩容时&#xff0c;头插法会出现环。 /*** Rehashes the contents of this map into a new array with a* larger capacity. This method is called automatically when the* number of keys in this map reaches its threshold.** If current cap…

回溯算法|491.递增子序列

力扣题目链接 class Solution { private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {if (path.size() > 1) {result.push_back(path);// 注意这里不要加return&#xff0c;要取树上…

[计算机知识] TCP/IP网络模型、MySQL的结构

TCP/IP网络模型 应用层 给用户提供应用功能&#xff0c;如HTTP, DNS 应用层处于用户态&#xff0c;传输层及以下处于内核态 传输层 给应用层提供网络支持&#xff0c;如TCP, UDP TCP提供稳定、面向连接的网络传输协议 应用层的数据可能会太大&#xff0c;就需要进行拆分…

【GAMES101】Lecture08 09 Shading 3 (Texture Mapping cont.) 纹理映射 续集

目录 0 引言1 如何在三角形内进行插值&#xff1a;重心坐标1.1 为什么要在三角形内插值1.2 重心坐标1.3 使用重心坐标做三角形内颜色插值 2 应用纹理2.1 简单的纹理映射&#xff1a;漫反射2.2 问题&#xff1a;纹理放大&#xff08;采用插值解决&#xff09;2.2 点查询和范围查…

Qt主窗口 之:停靠/悬浮窗口(QDockWidget)

一、QDockWidget概述 QDockWidget 是 Qt 中的一个窗口部件&#xff0c;用于创建可停靠的窗口&#xff0c;通常用于构建多文档接口&#xff08;MDI&#xff09;或可定制的用户界面。QDockWidget 允许用户将窗口停靠在应用程序的主窗口周围&#xff0c;或将其拖动到独立的浮动窗…

STM32

GPIO通用输入输出口 GPIO:8种输入输出模式 浮空输入可读取引脚电平&#xff0c;若引脚悬空&#xff0c;电平不确定上拉输入可读取引脚电平&#xff0c;内部接上拉电阻&#xff0c;悬空时默认为高电平下拉输入可读取引脚电平&#xff0c;内部接下拉电阻&#xff0c;悬空时默认…

视频编辑的瑞士军刀,MoviePy库的详解与应用示例

左手编程&#xff0c;右手年华。大家好&#xff0c;我是一点&#xff0c;关注我&#xff0c;带你走入编程的世界。 公众号&#xff1a;一点sir&#xff0c;关注领取python编程资料 在数字媒体的时代&#xff0c;视频内容的创作和编辑变得越来越重要。无论是社交媒体上的短视频&…

【数据结构】初识数据结构与复杂度总结

前言 C语言这块算是总结完了&#xff0c;那从本篇开始就是步入一个新的大章——数据结构&#xff0c;这篇我们先来认识一下数据结构有关知识&#xff0c;以及复杂度的相关知识 个人主页&#xff1a;小张同学zkf 若有问题 评论区见 感兴趣就关注一下吧 目录 1.什么是数据结构 2.…

原创【matcap材质在ue4中的实现办法】

matcap材质在ue4中的实现办法 2023-08-29 15:34 https://www.bilibili.com/video/BV1GR4y1b76n/?spm_id_from333.337.search-card.all.click&vd_sourced76b773892c830a157c0ccc97ba78411 评论(0)

PS从入门到精通视频各类教程整理全集,包含素材、作业等(8)复发

PS从入门到精通视频各类教程整理全集&#xff0c;包含素材、作业等 最新PS以及插件合集&#xff0c;可在我以往文章中找到 由于阿里云盘有分享次受限制和文件大小限制&#xff0c;今天先分享到这里&#xff0c;后续持续更新 B站-PS异闻录&#xff1a;萌新系统入门课课程视频 …

Golang学习系列1-pprof性能调优

1. pprof 简述 一位亦师亦友的话让我记忆犹新&#xff0c;他说“学习一个新事务&#xff0c;应该从三个方面入手what,why,how;且三者的重要程度应该是递减”。所以在本文的第一部分先叙述下pprof的what & why。 1.1 What&#xff1f; pprof是golang自身提供的一种性能分…

基于顺序表的学生成绩管理系统

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…

【Flink技术原理构造及特性】

1、Flink简介 Flink是一个批处理和流处理结合的统一计算框架&#xff0c;其核心是一个提供了数据分发以及并行化计算的流数据处理引擎。它的最大亮点是流处理&#xff0c;是业界最顶级的开源流处理引擎。 Flink最适合的应用场景是低时延的数据处理&#xff08;Data Processin…

算法练习—day1

title: 算法练习—day1 date: 2024-04-03 21:49:55 tags: 算法 categories:LeetCode typora-root-url: 算法练习—day1 网址&#xff1a;https://red568.github.io 704. 二分查找 题目&#xff1a; 题目分析&#xff1a; 左右指针分别为[left,right]&#xff0c;每次都取中…

练习 19 Web [BJDCTF2020]Easy MD5

如果你是第一批做这个题的&#xff0c;这道题一点也不easy 打开在前端代码里面看到&#xff0c;输入框输入的内容实际是’password’ 随意输入内容&#xff0c;查看响应header中的内容有一句SQL代码&#xff0c;可知我们要让password在md5后返回值为true 然后尬住&#xff…