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.

261 lines
7.2KB

  1. /**
  2. * This is an unfinished experiment.
  3. * It's a windows only command line program that
  4. * find the Rack process in memory, and sets its
  5. * priority class to realtime.
  6. */
  7. #include <stdio.h>
  8. #include <windows.h>
  9. #include <psapi.h>
  10. #include <string>
  11. class ProcessNameAndHandle
  12. {
  13. public:
  14. std::string name;
  15. HANDLE handle = INVALID_HANDLE_VALUE;
  16. };
  17. ProcessNameAndHandle getProcessNameAndHandle(DWORD pid);
  18. bool setRealtimePriority(HANDLE pHandle);
  19. bool enablePrivilege(HANDLE hProcess, const char * privilege);
  20. std::string GetLastErrorAsString();
  21. int main(int argc, char** argv)
  22. {
  23. HANDLE realHandle = GetCurrentProcess();
  24. bool b = enablePrivilege(realHandle, SE_DEBUG_NAME);
  25. printf("try set debug on us: %d\n", b);
  26. if (!b) {
  27. // TODO: we should re-run here
  28. printf("can't get debug right from system. Try running as admin\n");
  29. fflush(stdout);
  30. // Spawn a copy of ourselves, via ShellExecuteEx().
  31. // The "runas" verb is important because that's what
  32. // internally triggers Windows to open up a UAC prompt.
  33. // HANDLE child = ShellExecuteEx(argc, argv, "runas");
  34. SHELLEXECUTEINFO sinfo;
  35. memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO));
  36. sinfo.cbSize = sizeof(SHELLEXECUTEINFO);
  37. sinfo.fMask = SEE_MASK_FLAG_DDEWAIT |
  38. SEE_MASK_NOCLOSEPROCESS;
  39. sinfo.hwnd = NULL;
  40. sinfo.lpFile = argv[0];
  41. sinfo.lpParameters = "";
  42. sinfo.lpVerb = "runas"; // <<-- this is what makes a UAC prompt show up
  43. sinfo.nShow = SW_SHOWMAXIMIZED;
  44. // The only way to get a UAC prompt to show up
  45. // is by calling ShellExecuteEx() with the correct
  46. // SHELLEXECUTEINFO struct. Non privlidged applications
  47. // cannot open/start a UAC prompt by simply spawning
  48. // a process that has the correct XML manifest.
  49. BOOL result = ShellExecuteEx(&sinfo);
  50. if (!result) {
  51. printf("re-exec as admin failed\n");
  52. return -1;
  53. }
  54. // HINSTANCE appInstance = sinfo.hInstApp;
  55. printf("exec worked. hp=%x\n", sinfo.hProcess);
  56. fflush(stdout);
  57. // User accepted UAC prompt (gave permission).
  58. // The unprivileged parent should wait for
  59. // the privileged child to finish.
  60. WaitForSingleObject(sinfo.hProcess, INFINITE);
  61. printf("orig proc finished waiting\n");
  62. DWORD exitCode=666;
  63. GetExitCodeProcess(sinfo.hProcess, &exitCode);
  64. printf("EXIT CODE %d\n", exitCode);
  65. CloseHandle(sinfo.hProcess);
  66. }
  67. // here were able to set debug
  68. DWORD aProcesses[1024], cbNeeded, cProcesses;
  69. unsigned int i;
  70. if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
  71. printf("enum proc failed\n");
  72. return 1;
  73. }
  74. // Calculate how many process identifiers were returned.
  75. cProcesses = cbNeeded / sizeof(DWORD);
  76. // find the pid for Rack.
  77. HANDLE rackProcessHandle = INVALID_HANDLE_VALUE;
  78. std::string rackName("Rack.exe");
  79. for (i = 0; i < cProcesses; i++) {
  80. if (aProcesses[i] != 0) {
  81. //PrintProcessNameAndID( aProcesses[i] );
  82. ProcessNameAndHandle proc = getProcessNameAndHandle(aProcesses[i]);
  83. if (proc.name == rackName) {
  84. rackProcessHandle = proc.handle;
  85. } else {
  86. CloseHandle(proc.handle);
  87. }
  88. }
  89. }
  90. printf("rack pid = %d\n", rackProcessHandle);
  91. if (rackProcessHandle == INVALID_HANDLE_VALUE) {
  92. printf("could not find rack process\n");
  93. return -1;
  94. }
  95. bool bSet = setRealtimePriority(rackProcessHandle);
  96. CloseHandle(rackProcessHandle);
  97. }
  98. /**
  99. *
  100. */
  101. ProcessNameAndHandle getProcessNameAndHandle(DWORD processID)
  102. {
  103. TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
  104. // Get a handle to the process.
  105. HANDLE hProcess = OpenProcess(PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
  106. FALSE, processID);
  107. // Get the process name
  108. if (NULL != hProcess) {
  109. HMODULE hMod;
  110. DWORD cbNeeded;
  111. if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),
  112. &cbNeeded)) {
  113. GetModuleBaseName(hProcess, hMod, szProcessName,
  114. sizeof(szProcessName) / sizeof(TCHAR));
  115. } else printf("could not enum proc\n");
  116. } else {
  117. return {};
  118. }
  119. // Release the handle to the process.
  120. // CloseHandle(hProcess);
  121. return {szProcessName, hProcess};
  122. }
  123. #if 0
  124. // Returns the last Win32 error, in string format. Returns an empty string if there is no error.//Returns
  125. std::string GetLastErrorAsString()
  126. {
  127. //Get the error message, if any.
  128. DWORD errorMessageID = ::GetLastError();
  129. if (errorMessageID == 0)
  130. return std::string(); //No error message has been recorded
  131. LPSTR messageBuffer = nullptr;
  132. size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  133. NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &messageBuffer, 0, NULL);
  134. std::string message(messageBuffer, size);
  135. //Free the buffer.
  136. LocalFree(messageBuffer);
  137. return message;
  138. }
  139. #endif
  140. bool setClassRealtime(HANDLE h)
  141. {
  142. auto x = GetPriorityClass(h);
  143. auto b = SetPriorityClass(h, REALTIME_PRIORITY_CLASS);
  144. auto c = GetPriorityClass(h);
  145. #if 0
  146. printf("setrealtime(%d) %d, %d, %d\n", REALTIME_PRIORITY_CLASS, x, b, c);
  147. if (!b) {
  148. printf("SetP call failed with %d (%s)\n", GetLastError(), GetLastErrorAsString().c_str());
  149. }
  150. #endif
  151. return c == REALTIME_PRIORITY_CLASS;
  152. }
  153. bool enablePrivilege(HANDLE hProcess, const char * privilege)
  154. {
  155. printf("called ep with %s\n", privilege);
  156. struct
  157. {
  158. DWORD Count;
  159. LUID_AND_ATTRIBUTES Privilege[1];
  160. } Info;
  161. HANDLE Token;
  162. BOOL Result;
  163. // Open the token.
  164. Result = OpenProcessToken(hProcess,
  165. TOKEN_ADJUST_PRIVILEGES,
  166. &Token);
  167. if (Result != TRUE) {
  168. printf("ep Cannot open process token.\n");
  169. return FALSE;
  170. }
  171. Info.Count = 1;
  172. Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
  173. // Get the LUID.
  174. Result = LookupPrivilegeValue(NULL,
  175. privilege,
  176. &(Info.Privilege[0].Luid));
  177. if (Result != TRUE) {
  178. printf("ep Cannot get privilege for %s.\n", privilege);
  179. return FALSE;
  180. }
  181. // Adjust the privilege.
  182. Result = AdjustTokenPrivileges(Token, FALSE,
  183. (PTOKEN_PRIVILEGES) &Info,
  184. 0, NULL, NULL);
  185. CloseHandle(Token);
  186. // Check the result.
  187. if (Result != TRUE) {
  188. printf("ep Cannot adjust token privileges (%u)\n", GetLastError());
  189. return FALSE;
  190. } else {
  191. if (GetLastError() != ERROR_SUCCESS) {
  192. // printf("getlasterror = %d, %s\n", GetLastError(), GetLastErrorAsString().c_str());
  193. printf("Cannot enable the %s privilege; ", privilege
  194. );
  195. printf("please check the local policy.\n");
  196. return FALSE;
  197. }
  198. }
  199. return TRUE;
  200. }
  201. /**
  202. *
  203. */
  204. bool setRealtimePriority(HANDLE hRackProcess)
  205. {
  206. auto set = setClassRealtime(hRackProcess);
  207. printf("set pri class at start ret %d\n", set);
  208. return set;
  209. }