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

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值