Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

480 lines
14 KiB

  1. #ifndef WIN32_LEAN_AND_MEAN
  2. #define WIN32_LEAN_AND_MEAN
  3. #endif
  4. #ifndef STRICT
  5. #define STRICT
  6. #endif
  7. #ifndef _WIN32_WINNT
  8. #define _WIN32_WINNT 0x0500
  9. #endif
  10. #include <windows.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <stdarg.h>
  14. #include "detours.h"
  15. //
  16. // Registry information used by RWSpy
  17. //
  18. WCHAR RWSpyKey[] = L"Software\\Microsoft\\RWSpy";
  19. WCHAR DeviceValueName[] = L"FileToSpyOn";
  20. WCHAR DeviceNameToSpyOn[MAX_PATH] = L"";
  21. WCHAR LogFileValueName[] = L"Log File";
  22. WCHAR DefaultLogFileName[] = L"%SystemRoot%\\rwspy.log";
  23. WCHAR LogFileName[MAX_PATH] = L"\0";
  24. //
  25. // Globals
  26. //
  27. HANDLE g_hDeviceToSpyOn = INVALID_HANDLE_VALUE;
  28. HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
  29. //
  30. // Detours trampolines
  31. //
  32. DETOUR_TRAMPOLINE(HANDLE WINAPI Real_CreateFileW(LPCWSTR a0, DWORD a1, DWORD a2,
  33. LPSECURITY_ATTRIBUTES a3, DWORD a4, DWORD a5, HANDLE a6), CreateFileW);
  34. DETOUR_TRAMPOLINE(BOOL WINAPI Real_WriteFile(HANDLE hFile, LPCVOID lpBuffer,
  35. DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped), WriteFile);
  36. DETOUR_TRAMPOLINE(BOOL WINAPI Real_WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite,
  37. LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletion), WriteFileEx);
  38. DETOUR_TRAMPOLINE(BOOL WINAPI Real_ReadFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToRead,
  39. LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped), ReadFile);
  40. DETOUR_TRAMPOLINE(BOOL WINAPI Real_ReadFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD dwNumberOfBytesToRead,
  41. LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletion), ReadFileEx);
  42. DETOUR_TRAMPOLINE(BOOL WINAPI Real_DeviceIoControl(HANDLE hFile, DWORD code, LPVOID inBuffer, DWORD cbIn,
  43. LPVOID outBuffer, DWORD cbOutSize, LPDWORD cbOutActual, LPOVERLAPPED lpOverlapped), DeviceIoControl);
  44. DETOUR_TRAMPOLINE(BOOL WINAPI Real_CloseHandle(HANDLE hObject), CloseHandle);
  45. // closes log and makes further writing impossible until log reopened
  46. void CloseLog(void)
  47. {
  48. if(g_hLogFile != INVALID_HANDLE_VALUE) {
  49. Real_CloseHandle(g_hLogFile);
  50. g_hLogFile = INVALID_HANDLE_VALUE;
  51. }
  52. }
  53. // Attempts to open log file. Assumes that LogFileName[] is already set
  54. // elsewhere.
  55. BOOL OpenLog(void)
  56. {
  57. BOOL success = FALSE;
  58. CloseLog();
  59. g_hLogFile = Real_CreateFileW(LogFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL,
  60. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  61. if(g_hLogFile != INVALID_HANDLE_VALUE) {
  62. success = TRUE;
  63. }
  64. return success;
  65. }
  66. // Writes specified number of characters to the log file
  67. BOOL WriteToLog(CHAR *bytes, DWORD len)
  68. {
  69. BOOL success = FALSE;
  70. if(g_hLogFile != INVALID_HANDLE_VALUE && len && bytes) {
  71. DWORD cbWritten;
  72. if(Real_WriteFile(g_hLogFile, bytes, len, &cbWritten, NULL) && len == cbWritten) {
  73. success = TRUE;
  74. } else {
  75. CloseLog();
  76. }
  77. }
  78. return success;
  79. }
  80. // writes printf-style string to the log file
  81. void Log(LPCSTR fmt, ...)
  82. {
  83. va_list marker;
  84. CHAR buffer[1024];
  85. DWORD cbToWrite;
  86. if(g_hLogFile == INVALID_HANDLE_VALUE || fmt == NULL)
  87. return;
  88. va_start(marker, fmt);
  89. _vsnprintf(buffer, sizeof(buffer), fmt, marker);
  90. cbToWrite = lstrlenA(buffer);
  91. WriteToLog(buffer, cbToWrite);
  92. }
  93. // writes db-style bytes to the log file
  94. void LogBytes(BYTE *pBytes, DWORD dwBytes)
  95. {
  96. DWORD nBytes = min(dwBytes, 8192L);
  97. const static CHAR hex[] = "0123456789ABCDEF";
  98. CHAR buffer[80];
  99. DWORD cbToWrite = 75;
  100. DWORD byte = 0;
  101. int pos;
  102. if(g_hLogFile == INVALID_HANDLE_VALUE || pBytes == NULL || nBytes == 0)
  103. return;
  104. while(byte < nBytes) {
  105. if((byte % 16) == 0) {
  106. if(byte != 0) {
  107. // write previous line into file
  108. if(!WriteToLog(buffer, cbToWrite))
  109. break;
  110. }
  111. memset(buffer, ' ', cbToWrite - 1);
  112. buffer[cbToWrite - 1] = '\n';
  113. buffer[0] = hex[(byte >> 12) & 0xF];
  114. buffer[1] = hex[(byte >> 8) & 0xF];
  115. buffer[2] = hex[(byte >> 4) & 0xF];
  116. buffer[3] = hex[byte & 0xF];
  117. }
  118. pos = (byte % 16 < 8 ? 5 : 6)+ (byte % 16) * 3;
  119. buffer[pos] = hex[(pBytes[byte] >> 4) & 0xF];
  120. buffer[pos + 1] = hex[pBytes[byte] & 0xF];
  121. pos = 5 + 16 * 3 + 2 + (byte % 16);
  122. buffer[pos] = pBytes[byte] >= ' ' && pBytes[byte] <= 127 ? pBytes[byte] : '.';
  123. byte++;
  124. }
  125. // write one final line
  126. WriteToLog(buffer, cbToWrite);
  127. }
  128. HANDLE WINAPI
  129. My_CreateFileW(LPCWSTR a0,
  130. DWORD a1,
  131. DWORD a2,
  132. LPSECURITY_ATTRIBUTES a3,
  133. DWORD a4,
  134. DWORD a5,
  135. HANDLE a6)
  136. {
  137. HANDLE hResult;
  138. __try {
  139. hResult = Real_CreateFileW(a0, a1, a2, a3, a4, a5, a6);
  140. }
  141. __finally {
  142. // if we have a file to spy on
  143. if(DeviceNameToSpyOn[0]) {
  144. WCHAR *pw = DeviceNameToSpyOn;
  145. LPCWSTR p = a0;
  146. while(*p && *pw) {
  147. WCHAR w = *p;
  148. if(w != *pw)
  149. break;
  150. p++;
  151. pw++;
  152. }
  153. if(*p == L'\0' && *pw == L'\0') {
  154. // we got our file
  155. if(hResult == INVALID_HANDLE_VALUE) {
  156. Log("Tried creating '%S', LastError() = : %d\n", a0 ? a0 : L"NULL", GetLastError());
  157. } else {
  158. Log("Created '%S', handle: %x\n", a0 ? a0 : L"NULL", hResult);
  159. }
  160. if(hResult != INVALID_HANDLE_VALUE) {
  161. // successsfully created
  162. if(g_hDeviceToSpyOn != INVALID_HANDLE_VALUE && hResult != g_hDeviceToSpyOn) {
  163. // hmm... it was already open. Let user know
  164. // this happened:
  165. Log("Note: we were already spying on this device with handle %x. Changing to %x\n",
  166. g_hDeviceToSpyOn, hResult);
  167. }
  168. g_hDeviceToSpyOn = hResult;
  169. }
  170. }
  171. } else {
  172. // simply record the file name into output file
  173. Log("Creating file: '%S', result: %x\n", a0 ? a0 : L"NULL", hResult);
  174. }
  175. }
  176. return hResult;
  177. }
  178. BOOL WINAPI
  179. My_WriteFile(HANDLE hFile,
  180. LPCVOID lpBuffer,
  181. DWORD nNumberOfBytesToWrite,
  182. LPDWORD lpNumberOfBytesWritten,
  183. LPOVERLAPPED lpOverlapped)
  184. {
  185. BOOL bresult;
  186. DWORD bytesWritten;
  187. __try {
  188. bresult = Real_WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
  189. }
  190. __finally {
  191. if(g_hDeviceToSpyOn != INVALID_HANDLE_VALUE && hFile == g_hDeviceToSpyOn) {
  192. bytesWritten = lpNumberOfBytesWritten ? *lpNumberOfBytesWritten :
  193. nNumberOfBytesToWrite;
  194. if(bresult) {
  195. Log("Wrote %d bytes:\n", bytesWritten);
  196. } else {
  197. Log("Failure writing %d bytes, LastError() = %d:\n",
  198. nNumberOfBytesToWrite, GetLastError());
  199. }
  200. LogBytes((BYTE *)lpBuffer, bytesWritten);
  201. }
  202. }
  203. return bresult;
  204. }
  205. BOOL WINAPI
  206. My_WriteFileEx(HANDLE hFile,
  207. LPCVOID lpBuffer,
  208. DWORD nNumberOfBytesToWrite,
  209. LPOVERLAPPED lpOverlapped,
  210. LPOVERLAPPED_COMPLETION_ROUTINE lpOverlappedCompletion)
  211. {
  212. BOOL bresult;
  213. __try {
  214. bresult = Real_WriteFileEx(hFile, lpBuffer, nNumberOfBytesToWrite, lpOverlapped, lpOverlappedCompletion);
  215. }
  216. __finally {
  217. if(g_hDeviceToSpyOn != INVALID_HANDLE_VALUE && hFile == g_hDeviceToSpyOn) {
  218. if(bresult) {
  219. Log("Submitted %d bytes to WriteEx:\n", nNumberOfBytesToWrite);
  220. } else {
  221. Log("Failed to submit %d bytes to WriteEx, LastError() = %d:\n",
  222. nNumberOfBytesToWrite, GetLastError());
  223. }
  224. LogBytes((BYTE *)lpBuffer, nNumberOfBytesToWrite);
  225. }
  226. }
  227. return bresult;
  228. }
  229. BOOL WINAPI
  230. My_ReadFile(HANDLE hFile,
  231. LPCVOID lpBuffer,
  232. DWORD nNumberOfBytesToRead,
  233. LPDWORD lpNumberOfBytesRead,
  234. LPOVERLAPPED lpOverlapped)
  235. {
  236. BOOL bresult;
  237. DWORD bytesRead;
  238. __try {
  239. bresult = Real_ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
  240. }
  241. __finally {
  242. if(g_hDeviceToSpyOn != INVALID_HANDLE_VALUE && hFile == g_hDeviceToSpyOn) {
  243. bytesRead = lpNumberOfBytesRead ? *lpNumberOfBytesRead :
  244. nNumberOfBytesToRead;
  245. if(bresult) {
  246. Log("Read %d bytes:\n", bytesRead);
  247. LogBytes((BYTE *)lpBuffer, bytesRead);
  248. } else {
  249. Log("Failure to read %d bytes, LastError() = %d:\n",
  250. nNumberOfBytesToRead, GetLastError());
  251. }
  252. }
  253. }
  254. return bresult;
  255. }
  256. //
  257. // Please, note that to see ReadEx bytes one needs to detour
  258. // the completion routine (we don't do it here).
  259. //
  260. BOOL WINAPI
  261. My_ReadFileEx(HANDLE hFile,
  262. LPCVOID lpBuffer,
  263. DWORD nNumberOfBytesToRead,
  264. LPOVERLAPPED lpOverlapped,
  265. LPOVERLAPPED_COMPLETION_ROUTINE lpOverlappedCompletion)
  266. {
  267. BOOL bresult;
  268. __try {
  269. bresult = Real_ReadFileEx(hFile, lpBuffer, nNumberOfBytesToRead, lpOverlapped, lpOverlappedCompletion);
  270. }
  271. __finally {
  272. if(g_hDeviceToSpyOn != INVALID_HANDLE_VALUE && hFile == g_hDeviceToSpyOn) {
  273. if(bresult) {
  274. Log("Submitted ReadEx for %d bytes:\n", nNumberOfBytesToRead);
  275. } else {
  276. Log("Failed to sumbit ReadEx for %d bytes, LastError() = %d:\n",
  277. nNumberOfBytesToRead, GetLastError());
  278. }
  279. }
  280. }
  281. return bresult;
  282. }
  283. BOOL WINAPI
  284. My_DeviceIoControl(HANDLE hFile, DWORD code, LPVOID inBuffer, DWORD cbIn,
  285. LPVOID outBuffer, DWORD cbOutSize, LPDWORD pcbOutActual, LPOVERLAPPED lpOverlapped)
  286. {
  287. BOOL result;
  288. DWORD outBytes;
  289. DWORD Function;
  290. __try {
  291. result = Real_DeviceIoControl(hFile, code, inBuffer, cbIn, outBuffer, cbOutSize, pcbOutActual, lpOverlapped);
  292. }
  293. __finally {
  294. if(g_hDeviceToSpyOn != INVALID_HANDLE_VALUE && hFile == g_hDeviceToSpyOn) {
  295. outBytes = pcbOutActual ? *pcbOutActual : cbOutSize;
  296. Function = (code >> 2) & 0xFFF;
  297. Log("DeviceIoControl code = %x, Function = %x, %d bytes in:\n",
  298. code, Function, cbIn);
  299. LogBytes((BYTE *)inBuffer, cbIn);
  300. if(outBytes) {
  301. Log(" %d bytes out:\n", outBytes);
  302. LogBytes((BYTE *)outBuffer, outBytes);
  303. }
  304. }
  305. }
  306. return result;
  307. }
  308. BOOL WINAPI
  309. My_CloseHandle(HANDLE hObject)
  310. {
  311. BOOL bresult;
  312. __try {
  313. bresult = Real_CloseHandle(hObject);
  314. }
  315. __finally {
  316. if(g_hDeviceToSpyOn != INVALID_HANDLE_VALUE && hObject == g_hDeviceToSpyOn) {
  317. Log("Closed handle %x\n", hObject);
  318. g_hDeviceToSpyOn = INVALID_HANDLE_VALUE;
  319. }
  320. }
  321. return bresult;
  322. }
  323. void PrepareLogger()
  324. {
  325. HKEY hKey;
  326. WCHAR buffer[MAX_PATH];
  327. // retrieve our configuration from the registry
  328. if(ERROR_SUCCESS == RegCreateKeyExW(HKEY_LOCAL_MACHINE, RWSpyKey,
  329. 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL))
  330. {
  331. DWORD dwType, cbData = sizeof(buffer);
  332. cbData = sizeof(buffer);
  333. if(ERROR_SUCCESS == RegQueryValueExW(hKey, LogFileValueName, 0, &dwType, (BYTE *) buffer, &cbData) &&
  334. cbData)
  335. {
  336. ExpandEnvironmentStringsW(buffer, LogFileName, MAX_PATH);
  337. } else {
  338. // no log file name value found, create it so that users
  339. // would know what its name is
  340. cbData = lstrlenW(DefaultLogFileName) * sizeof(DefaultLogFileName[0]);
  341. RegSetValueExW(hKey, LogFileValueName, 0, REG_EXPAND_SZ, (BYTE *) DefaultLogFileName, cbData);
  342. }
  343. DeviceNameToSpyOn[0] = L'\0';
  344. cbData = sizeof(DeviceNameToSpyOn);
  345. if(ERROR_SUCCESS != RegQueryValueExW(hKey, DeviceValueName, NULL, &dwType, (LPBYTE) DeviceNameToSpyOn, &cbData)
  346. || !DeviceNameToSpyOn[0])
  347. {
  348. // no "FileToSpyOn" value found, create it so that users
  349. // would know what the value name is
  350. RegSetValueExW(hKey, DeviceValueName, 0, REG_SZ, (BYTE *)DeviceNameToSpyOn, sizeof(WCHAR));
  351. }
  352. RegCloseKey(hKey);
  353. }
  354. // if we still don't have file name, use the default one
  355. if(!LogFileName[0]) {
  356. ExpandEnvironmentStringsW(DefaultLogFileName, LogFileName, MAX_PATH);
  357. }
  358. OpenLog();
  359. DetourFunctionWithTrampoline((PBYTE) Real_CreateFileW, (PBYTE) My_CreateFileW);
  360. DetourFunctionWithTrampoline((PBYTE) Real_WriteFile, (PBYTE) My_WriteFile);
  361. DetourFunctionWithTrampoline((PBYTE) Real_WriteFileEx, (PBYTE) My_WriteFileEx);
  362. DetourFunctionWithTrampoline((PBYTE) Real_ReadFile, (PBYTE) My_ReadFile);
  363. DetourFunctionWithTrampoline((PBYTE) Real_ReadFileEx, (PBYTE) My_ReadFileEx);
  364. DetourFunctionWithTrampoline((PBYTE) Real_DeviceIoControl, (PBYTE) My_DeviceIoControl);
  365. DetourFunctionWithTrampoline((PBYTE) Real_CloseHandle, (PBYTE) My_CloseHandle);
  366. }
  367. BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, PVOID lpReserved)
  368. {
  369. switch (dwReason) {
  370. case DLL_PROCESS_ATTACH:
  371. PrepareLogger();
  372. break;
  373. case DLL_PROCESS_DETACH:
  374. CloseLog();
  375. break;
  376. case DLL_THREAD_ATTACH:
  377. case DLL_THREAD_DETACH:
  378. break;
  379. }
  380. return TRUE;
  381. }
  382. // This is necessary for detours static injection code (see detours
  383. // code if you need to understand why)
  384. void NullExport()
  385. {
  386. }