1 /*
2  * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include "jni_util.h"
27 
28 #include <windows.h>
29 #include <Sddl.h>
30 #include <string.h>
31 
32 #include "sun_tools_attach_VirtualMachineImpl.h"
33 
34 /* kernel32 */
35 typedef HINSTANCE (WINAPI* GetModuleHandleFunc) (LPCTSTR);
36 typedef FARPROC (WINAPI* GetProcAddressFunc)(HMODULE, LPCSTR);
37 
38 /* only on Windows 64-bit or 32-bit application running under WOW64 */
39 typedef BOOL (WINAPI *IsWow64ProcessFunc) (HANDLE, PBOOL);
40 
41 static GetModuleHandleFunc _GetModuleHandle;
42 static GetProcAddressFunc _GetProcAddress;
43 static IsWow64ProcessFunc _IsWow64Process;
44 
45 /* psapi */
46 typedef BOOL  (WINAPI *EnumProcessModulesFunc)  (HANDLE, HMODULE *, DWORD, LPDWORD );
47 typedef DWORD (WINAPI *GetModuleFileNameExFunc) ( HANDLE, HMODULE, LPTSTR, DWORD );
48 
49 /* exported function in target VM */
50 typedef jint (WINAPI* EnqueueOperationFunc)
51     (const char* cmd, const char* arg1, const char* arg2, const char* arg3, const char* pipename);
52 
53 /* OpenProcess with SE_DEBUG_NAME privilege */
54 static HANDLE
55 doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
56 
57 /* convert jstring to C string */
58 static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len);
59 
60 
61 /*
62  * Data copied to target process
63  */
64 
65 #define MAX_LIBNAME_LENGTH      16
66 #define MAX_FUNC_LENGTH         32
67 #define MAX_CMD_LENGTH          16
68 #define MAX_ARG_LENGTH          1024
69 #define MAX_ARGS                3
70 #define MAX_PIPE_NAME_LENGTH    256
71 
72 typedef struct {
73    GetModuleHandleFunc _GetModuleHandle;
74    GetProcAddressFunc _GetProcAddress;
75    char jvmLib[MAX_LIBNAME_LENGTH];         /* "jvm.dll" */
76    char func1[MAX_FUNC_LENGTH];
77    char func2[MAX_FUNC_LENGTH];
78    char cmd[MAX_CMD_LENGTH];                /* "load", "dump", ...      */
79    char arg[MAX_ARGS][MAX_ARG_LENGTH];      /* arguments to command     */
80    char pipename[MAX_PIPE_NAME_LENGTH];
81 } DataBlock;
82 
83 /*
84  * Return codes from enqueue function executed in target VM
85  */
86 #define ERR_OPEN_JVM_FAIL           200
87 #define ERR_GET_ENQUEUE_FUNC_FAIL   201
88 
89 /*
90  * Declare library specific JNI_Onload entry if static build
91  */
92 DEF_STATIC_JNI_OnLoad
93 
94 /*
95  * Code copied to target process
96  */
97 #pragma check_stack (off)
98 /* Switch off all runtime checks (checks caused by /RTC<x>). They cause the
99  * generated code to contain relative jumps to check functions which make
100  * the code position dependent. */
101 #pragma runtime_checks ("scu", off)
jvm_attach_thread_func(DataBlock * pData)102 DWORD WINAPI jvm_attach_thread_func(DataBlock *pData)
103 {
104     HINSTANCE h;
105     EnqueueOperationFunc addr;
106 
107     h = pData->_GetModuleHandle(pData->jvmLib);
108     if (h == NULL) {
109         return ERR_OPEN_JVM_FAIL;
110     }
111 
112     addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func1));
113     if (addr == NULL) {
114         addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func2));
115     }
116     if (addr == NULL) {
117         return ERR_GET_ENQUEUE_FUNC_FAIL;
118     }
119 
120     /* "null" command - does nothing in the target VM */
121     if (pData->cmd[0] == '\0') {
122         return 0;
123     } else {
124         return (*addr)(pData->cmd, pData->arg[0], pData->arg[1], pData->arg[2], pData->pipename);
125     }
126 }
127 
128 /* This function marks the end of jvm_attach_thread_func. */
jvm_attach_thread_func_end(void)129 void jvm_attach_thread_func_end (void) {
130 }
131 #pragma check_stack
132 #pragma runtime_checks ("scu", restore)
133 
134 /*
135  * Class:     sun_tools_attach_VirtualMachineImpl
136  * Method:    init
137  * Signature: ()V
138  */
Java_sun_tools_attach_VirtualMachineImpl_init(JNIEnv * env,jclass cls)139 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_init
140   (JNIEnv *env, jclass cls)
141 {
142     // All following APIs exist on Windows XP with SP2/Windows Server 2008
143     _GetModuleHandle = (GetModuleHandleFunc)GetModuleHandle;
144     _GetProcAddress = (GetProcAddressFunc)GetProcAddress;
145     _IsWow64Process = (IsWow64ProcessFunc)IsWow64Process;
146 }
147 
148 
149 /*
150  * Class:     sun_tools_attach_VirtualMachineImpl
151  * Method:    generateStub
152  * Signature: ()[B
153  */
Java_sun_tools_attach_VirtualMachineImpl_generateStub(JNIEnv * env,jclass cls)154 JNIEXPORT jbyteArray JNICALL Java_sun_tools_attach_VirtualMachineImpl_generateStub
155   (JNIEnv *env, jclass cls)
156 {
157     /*
158      * We should replace this with a real stub generator at some point
159      */
160     DWORD len;
161     jbyteArray array;
162 
163     len = (DWORD)((LPBYTE) jvm_attach_thread_func_end - (LPBYTE) jvm_attach_thread_func);
164     array= (*env)->NewByteArray(env, (jsize)len);
165     if (array != NULL) {
166         (*env)->SetByteArrayRegion(env, array, 0, (jint)len, (jbyte*)&jvm_attach_thread_func);
167     }
168     return array;
169 }
170 
171 /*
172  * Class:     sun_tools_attach_VirtualMachineImpl
173  * Method:    openProcess
174  * Signature: (I)J
175  */
Java_sun_tools_attach_VirtualMachineImpl_openProcess(JNIEnv * env,jclass cls,jint pid)176 JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_openProcess
177   (JNIEnv *env, jclass cls, jint pid)
178 {
179     HANDLE hProcess = NULL;
180 
181     if (pid == (jint) GetCurrentProcessId()) {
182         /* process is attaching to itself; get a pseudo handle instead */
183         hProcess = GetCurrentProcess();
184         /* duplicate the pseudo handle so it can be used in more contexts */
185         if (DuplicateHandle(hProcess, hProcess, hProcess, &hProcess,
186                 PROCESS_ALL_ACCESS, FALSE, 0) == 0) {
187             /*
188              * Could not duplicate the handle which isn't a good sign,
189              * but we'll try again with OpenProcess() below.
190              */
191             hProcess = NULL;
192         }
193     }
194 
195     if (hProcess == NULL) {
196         /*
197          * Attempt to open process. If it fails then we try to enable the
198          * SE_DEBUG_NAME privilege and retry.
199          */
200         hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
201         if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) {
202             hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE,
203                            (DWORD)pid);
204         }
205 
206         if (hProcess == NULL) {
207             if (GetLastError() == ERROR_INVALID_PARAMETER) {
208                 JNU_ThrowIOException(env, "no such process");
209             } else {
210                 char err_mesg[255];
211                 /* include the last error in the default detail message */
212                 sprintf(err_mesg, "OpenProcess(pid=%d) failed; LastError=0x%x",
213                     (int)pid, (int)GetLastError());
214                 JNU_ThrowIOExceptionWithLastError(env, err_mesg);
215             }
216             return (jlong)0;
217         }
218     }
219 
220     /*
221      * On Windows 64-bit we need to handle 32-bit tools trying to attach to 64-bit
222      * processes (and visa versa). X-architecture attaching is currently not supported
223      * by this implementation.
224      */
225     if (_IsWow64Process != NULL) {
226         BOOL isCurrent32bit, isTarget32bit;
227         (*_IsWow64Process)(GetCurrentProcess(), &isCurrent32bit);
228         (*_IsWow64Process)(hProcess, &isTarget32bit);
229 
230         if (isCurrent32bit != isTarget32bit) {
231             CloseHandle(hProcess);
232             #ifdef _WIN64
233               JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
234                   "Unable to attach to 32-bit process running under WOW64");
235             #else
236               JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
237                   "Unable to attach to 64-bit process");
238             #endif
239         }
240     }
241 
242     return (jlong)hProcess;
243 }
244 
245 
246 /*
247  * Class:     sun_tools_attach_VirtualMachineImpl
248  * Method:    closeProcess
249  * Signature: (J)V
250  */
Java_sun_tools_attach_VirtualMachineImpl_closeProcess(JNIEnv * env,jclass cls,jlong hProcess)251 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_closeProcess
252   (JNIEnv *env, jclass cls, jlong hProcess)
253 {
254     CloseHandle((HANDLE)hProcess);
255 }
256 
257 
258 /*
259  * Class:     sun_tools_attach_VirtualMachineImpl
260  * Method:    createPipe
261  * Signature: (Ljava/lang/String;)J
262  */
Java_sun_tools_attach_VirtualMachineImpl_createPipe(JNIEnv * env,jclass cls,jstring pipename)263 JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_createPipe
264   (JNIEnv *env, jclass cls, jstring pipename)
265 {
266     HANDLE hPipe;
267     char name[MAX_PIPE_NAME_LENGTH];
268 
269     SECURITY_ATTRIBUTES sa;
270     LPSECURITY_ATTRIBUTES lpSA = NULL;
271     // Custom Security Descriptor is required here to "get" Medium Integrity Level.
272     // In order to allow Medium Integrity Level clients to open
273     // and use a NamedPipe created by an High Integrity Level process.
274     TCHAR *szSD = TEXT("D:")                  // Discretionary ACL
275                   TEXT("(A;OICI;GRGW;;;WD)")  // Allow read/write to Everybody
276                   TEXT("(A;OICI;GA;;;SY)")    // Allow full control to System
277                   TEXT("(A;OICI;GA;;;BA)");   // Allow full control to Administrators
278 
279     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
280     sa.bInheritHandle = FALSE;
281     sa.lpSecurityDescriptor = NULL;
282 
283     if (ConvertStringSecurityDescriptorToSecurityDescriptor
284           (szSD, SDDL_REVISION_1, &(sa.lpSecurityDescriptor), NULL)) {
285         lpSA = &sa;
286     }
287 
288     jstring_to_cstring(env, pipename, name, MAX_PIPE_NAME_LENGTH);
289 
290     hPipe = CreateNamedPipe(
291           name,                         // pipe name
292           PIPE_ACCESS_INBOUND,          // read access
293           PIPE_TYPE_BYTE |              // byte mode
294             PIPE_READMODE_BYTE |
295             PIPE_WAIT,                  // blocking mode
296           1,                            // max. instances
297           128,                          // output buffer size
298           8192,                         // input buffer size
299           NMPWAIT_USE_DEFAULT_WAIT,     // client time-out
300           lpSA);        // security attributes
301 
302     LocalFree(sa.lpSecurityDescriptor);
303 
304     if (hPipe == INVALID_HANDLE_VALUE) {
305         JNU_ThrowIOExceptionWithLastError(env, "CreateNamedPipe failed");
306     }
307     return (jlong)hPipe;
308 }
309 
310 /*
311  * Class:     sun_tools_attach_VirtualMachineImpl
312  * Method:    closePipe
313  * Signature: (J)V
314  */
Java_sun_tools_attach_VirtualMachineImpl_closePipe(JNIEnv * env,jclass cls,jlong hPipe)315 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_closePipe
316   (JNIEnv *env, jclass cls, jlong hPipe)
317 {
318     CloseHandle((HANDLE)hPipe);
319 }
320 
321 /*
322  * Class:     sun_tools_attach_VirtualMachineImpl
323  * Method:    connectPipe
324  * Signature: (J)V
325  */
Java_sun_tools_attach_VirtualMachineImpl_connectPipe(JNIEnv * env,jclass cls,jlong hPipe)326 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connectPipe
327   (JNIEnv *env, jclass cls, jlong hPipe)
328 {
329     BOOL fConnected;
330 
331     fConnected = ConnectNamedPipe((HANDLE)hPipe, NULL) ?
332         TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
333     if (!fConnected) {
334         JNU_ThrowIOExceptionWithLastError(env, "ConnectNamedPipe failed");
335     }
336 }
337 
338 /*
339  * Class:     sun_tools_attach_VirtualMachineImpl
340  * Method:    readPipe
341  * Signature: (J[BII)I
342  */
Java_sun_tools_attach_VirtualMachineImpl_readPipe(JNIEnv * env,jclass cls,jlong hPipe,jbyteArray ba,jint off,jint baLen)343 JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_readPipe
344   (JNIEnv *env, jclass cls, jlong hPipe, jbyteArray ba, jint off, jint baLen)
345 {
346     unsigned char buf[128];
347     DWORD len, nread, remaining;
348     BOOL fSuccess;
349 
350     len = sizeof(buf);
351     remaining = (DWORD)(baLen - off);
352     if (len > remaining) {
353         len = remaining;
354     }
355 
356     fSuccess = ReadFile(
357          (HANDLE)hPipe,         // handle to pipe
358          buf,                   // buffer to receive data
359          len,                   // size of buffer
360          &nread,                // number of bytes read
361          NULL);                 // not overlapped I/O
362 
363     if (!fSuccess) {
364         if (GetLastError() == ERROR_BROKEN_PIPE) {
365             return (jint)-1;
366         } else {
367             JNU_ThrowIOExceptionWithLastError(env, "ReadFile");
368         }
369     } else {
370         if (nread == 0) {
371             return (jint)-1;        // EOF
372         } else {
373             (*env)->SetByteArrayRegion(env, ba, off, (jint)nread, (jbyte *)(buf));
374         }
375     }
376 
377     return (jint)nread;
378 }
379 
380 
381 /*
382  * Class:     sun_tools_attach_VirtualMachineImpl
383  * Method:    enqueue
384  * Signature: (JZLjava/lang/String;[Ljava/lang/Object;)V
385  */
Java_sun_tools_attach_VirtualMachineImpl_enqueue(JNIEnv * env,jclass cls,jlong handle,jbyteArray stub,jstring cmd,jstring pipename,jobjectArray args)386 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue
387   (JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jstring cmd,
388    jstring pipename, jobjectArray args)
389 {
390     DataBlock data;
391     DataBlock* pData;
392     DWORD* pCode;
393     DWORD stubLen;
394     HANDLE hProcess, hThread;
395     jint argsLen, i;
396     jbyte* stubCode;
397     jboolean isCopy;
398 
399     /*
400      * Setup data to copy to target process
401      */
402     data._GetModuleHandle = _GetModuleHandle;
403     data._GetProcAddress = _GetProcAddress;
404 
405     strcpy(data.jvmLib, "jvm");
406     strcpy(data.func1, "JVM_EnqueueOperation");
407     strcpy(data.func2, "_JVM_EnqueueOperation@20");
408 
409     /*
410      * Command and arguments
411      */
412     jstring_to_cstring(env, cmd, data.cmd, MAX_CMD_LENGTH);
413     argsLen = (*env)->GetArrayLength(env, args);
414 
415     if (argsLen > 0) {
416         if (argsLen > MAX_ARGS) {
417             JNU_ThrowInternalError(env, "Too many arguments");
418             return;
419         }
420         for (i=0; i<argsLen; i++) {
421             jobject obj = (*env)->GetObjectArrayElement(env, args, i);
422             if (obj == NULL) {
423                 data.arg[i][0] = '\0';
424             } else {
425                 jstring_to_cstring(env, obj, data.arg[i], MAX_ARG_LENGTH);
426             }
427             if ((*env)->ExceptionOccurred(env)) return;
428         }
429     }
430     for (i = argsLen; i < MAX_ARGS; i++) {
431         data.arg[i][0] = '\0';
432     }
433 
434     /* pipe name */
435     jstring_to_cstring(env, pipename, data.pipename, MAX_PIPE_NAME_LENGTH);
436 
437     /*
438      * Allocate memory in target process for data and code stub
439      * (assumed aligned and matches architecture of target process)
440      */
441     hProcess = (HANDLE)handle;
442 
443     pData = (DataBlock*) VirtualAllocEx( hProcess, 0, sizeof(DataBlock), MEM_COMMIT, PAGE_READWRITE );
444     if (pData == NULL) {
445         JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
446         return;
447     }
448     WriteProcessMemory( hProcess, (LPVOID)pData, (LPCVOID)&data, (SIZE_T)sizeof(DataBlock), NULL );
449 
450 
451     stubLen = (DWORD)(*env)->GetArrayLength(env, stub);
452     stubCode = (*env)->GetByteArrayElements(env, stub, &isCopy);
453 
454     if ((*env)->ExceptionOccurred(env)) return;
455 
456     pCode = (PDWORD) VirtualAllocEx( hProcess, 0, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
457     if (pCode == NULL) {
458         JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
459         VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
460         return;
461     }
462     WriteProcessMemory( hProcess, (LPVOID)pCode, (LPCVOID)stubCode, (SIZE_T)stubLen, NULL );
463     if (isCopy) {
464         (*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT);
465     }
466 
467     /*
468      * Create thread in target process to execute code
469      */
470     hThread = CreateRemoteThread( hProcess,
471                                   NULL,
472                                   0,
473                                   (LPTHREAD_START_ROUTINE) pCode,
474                                   pData,
475                                   0,
476                                   NULL );
477     if (hThread != NULL) {
478         if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0) {
479             JNU_ThrowIOExceptionWithLastError(env, "WaitForSingleObject failed");
480         } else {
481             DWORD exitCode;
482             GetExitCodeThread(hThread, &exitCode);
483             if (exitCode) {
484                 switch (exitCode) {
485                     case ERR_OPEN_JVM_FAIL :
486                         JNU_ThrowIOException(env,
487                             "jvm.dll not loaded by target process");
488                         break;
489                     case ERR_GET_ENQUEUE_FUNC_FAIL :
490                         JNU_ThrowIOException(env,
491                             "Unable to enqueue operation: the target VM does not support attach mechanism");
492                         break;
493                     default : {
494                         char errmsg[128];
495                         sprintf(errmsg, "Remote thread failed for unknown reason (%d)", exitCode);
496                         JNU_ThrowInternalError(env, errmsg);
497                     }
498                 }
499             }
500         }
501         CloseHandle(hThread);
502     } else {
503         if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
504             //
505             // This error will occur when attaching to a process belonging to
506             // another terminal session. See "Remarks":
507             // http://msdn.microsoft.com/en-us/library/ms682437%28VS.85%29.aspx
508             //
509             JNU_ThrowIOException(env,
510                 "Insufficient memory or insufficient privileges to attach");
511         } else {
512             JNU_ThrowIOExceptionWithLastError(env, "CreateRemoteThread failed");
513         }
514     }
515 
516     VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE);
517     VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
518 }
519 
520 /*
521  * Attempts to enable the SE_DEBUG_NAME privilege and open the given process.
522  */
523 static HANDLE
doPrivilegedOpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId)524 doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) {
525     HANDLE hToken;
526     HANDLE hProcess = NULL;
527     LUID luid;
528     TOKEN_PRIVILEGES tp, tpPrevious;
529     DWORD retLength, error;
530 
531     /*
532      * Get the access token
533      */
534     if (!OpenThreadToken(GetCurrentThread(),
535                          TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
536                          FALSE,
537                          &hToken)) {
538         if (GetLastError() != ERROR_NO_TOKEN) {
539             return (HANDLE)NULL;
540         }
541 
542         /*
543          * No access token for the thread so impersonate the security context
544          * of the process.
545          */
546         if (!ImpersonateSelf(SecurityImpersonation)) {
547             return (HANDLE)NULL;
548         }
549         if (!OpenThreadToken(GetCurrentThread(),
550                              TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
551                              FALSE,
552                              &hToken)) {
553             return (HANDLE)NULL;
554         }
555     }
556 
557     /*
558      * Get LUID for the privilege
559      */
560     if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
561         error = GetLastError();
562         CloseHandle(hToken);
563         SetLastError(error);
564         return (HANDLE)NULL;
565     }
566 
567     /*
568      * Enable the privilege
569      */
570     ZeroMemory(&tp, sizeof(tp));
571     tp.PrivilegeCount = 1;
572     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
573     tp.Privileges[0].Luid = luid;
574 
575     error = 0;
576     if (AdjustTokenPrivileges(hToken,
577                               FALSE,
578                               &tp,
579                               sizeof(TOKEN_PRIVILEGES),
580                               &tpPrevious,
581                               &retLength)) {
582         /*
583          * If we enabled the privilege then attempt to open the
584          * process.
585          */
586         if (GetLastError() == ERROR_SUCCESS) {
587             hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
588             if (hProcess == NULL) {
589                 error = GetLastError();
590             }
591         } else {
592             error = ERROR_ACCESS_DENIED;
593         }
594 
595         /*
596          * Revert to the previous privileges
597          */
598         AdjustTokenPrivileges(hToken,
599                               FALSE,
600                               &tpPrevious,
601                               retLength,
602                               NULL,
603                               NULL);
604     } else {
605         error = GetLastError();
606     }
607 
608 
609     /*
610      * Close token and restore error
611      */
612     CloseHandle(hToken);
613     SetLastError(error);
614 
615     return hProcess;
616 }
617 
618 /* convert jstring to C string */
jstring_to_cstring(JNIEnv * env,jstring jstr,char * cstr,int len)619 static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len) {
620     jboolean isCopy;
621     const char* str;
622 
623     if (jstr == NULL) {
624         cstr[0] = '\0';
625     } else {
626         str = JNU_GetStringPlatformChars(env, jstr, &isCopy);
627         if ((*env)->ExceptionOccurred(env)) return;
628 
629         strncpy(cstr, str, len);
630         cstr[len-1] = '\0';
631         if (isCopy) {
632             JNU_ReleaseStringPlatformChars(env, jstr, str);
633         }
634     }
635 }
636