jdk/src/jdk.attach/windows/native/libattach/WindowsVirtualMachine.c
changeset 26233 d391c2eadc8c
parent 26232 ca9aa0749e5d
parent 26229 b1d885c12096
child 26255 af28748e6b2d
equal deleted inserted replaced
26232:ca9aa0749e5d 26233:d391c2eadc8c
     1 /*
       
     2  * Copyright (c) 2005, 2014, 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 #include <windows.h>
       
    26 #include <string.h>
       
    27 
       
    28 #include "jni.h"
       
    29 #include "jni_util.h"
       
    30 
       
    31 #include "sun_tools_attach_WindowsVirtualMachine.h"
       
    32 
       
    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 /*
       
    91  * Code copied to target process
       
    92  */
       
    93 #pragma check_stack (off)
       
    94 DWORD WINAPI jvm_attach_thread_func(DataBlock *pData)
       
    95 {
       
    96     HINSTANCE h;
       
    97     EnqueueOperationFunc addr;
       
    98 
       
    99     h = pData->_GetModuleHandle(pData->jvmLib);
       
   100     if (h == NULL) {
       
   101         return ERR_OPEN_JVM_FAIL;
       
   102     }
       
   103 
       
   104     addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func1));
       
   105     if (addr == NULL) {
       
   106         addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func2));
       
   107     }
       
   108     if (addr == NULL) {
       
   109         return ERR_GET_ENQUEUE_FUNC_FAIL;
       
   110     }
       
   111 
       
   112     /* "null" command - does nothing in the target VM */
       
   113     if (pData->cmd[0] == '\0') {
       
   114         return 0;
       
   115     } else {
       
   116         return (*addr)(pData->cmd, pData->arg[0], pData->arg[1], pData->arg[2], pData->pipename);
       
   117     }
       
   118 }
       
   119 
       
   120 /* This function marks the end of jvm_attach_thread_func. */
       
   121 void jvm_attach_thread_func_end (void) {
       
   122 }
       
   123 #pragma check_stack
       
   124 
       
   125 
       
   126 /*
       
   127  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   128  * Method:    init
       
   129  * Signature: ()V
       
   130  */
       
   131 JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_init
       
   132   (JNIEnv *env, jclass cls)
       
   133 {
       
   134     // All following APIs exist on Windows XP with SP2/Windows Server 2008
       
   135     _GetModuleHandle = (GetModuleHandleFunc)GetModuleHandle;
       
   136     _GetProcAddress = (GetProcAddressFunc)GetProcAddress;
       
   137     _IsWow64Process = (IsWow64ProcessFunc)IsWow64Process;
       
   138 }
       
   139 
       
   140 
       
   141 /*
       
   142  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   143  * Method:    generateStub
       
   144  * Signature: ()[B
       
   145  */
       
   146 JNIEXPORT jbyteArray JNICALL Java_sun_tools_attach_WindowsVirtualMachine_generateStub
       
   147   (JNIEnv *env, jclass cls)
       
   148 {
       
   149     /*
       
   150      * We should replace this with a real stub generator at some point
       
   151      */
       
   152     DWORD len;
       
   153     jbyteArray array;
       
   154 
       
   155     len = (DWORD)((LPBYTE) jvm_attach_thread_func_end - (LPBYTE) jvm_attach_thread_func);
       
   156     array= (*env)->NewByteArray(env, (jsize)len);
       
   157     if (array != NULL) {
       
   158         (*env)->SetByteArrayRegion(env, array, 0, (jint)len, (jbyte*)&jvm_attach_thread_func);
       
   159     }
       
   160     return array;
       
   161 }
       
   162 
       
   163 /*
       
   164  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   165  * Method:    openProcess
       
   166  * Signature: (I)J
       
   167  */
       
   168 JNIEXPORT jlong JNICALL Java_sun_tools_attach_WindowsVirtualMachine_openProcess
       
   169   (JNIEnv *env, jclass cls, jint pid)
       
   170 {
       
   171     HANDLE hProcess = NULL;
       
   172 
       
   173     if (pid == (jint) GetCurrentProcessId()) {
       
   174         /* process is attaching to itself; get a pseudo handle instead */
       
   175         hProcess = GetCurrentProcess();
       
   176         /* duplicate the pseudo handle so it can be used in more contexts */
       
   177         if (DuplicateHandle(hProcess, hProcess, hProcess, &hProcess,
       
   178                 PROCESS_ALL_ACCESS, FALSE, 0) == 0) {
       
   179             /*
       
   180              * Could not duplicate the handle which isn't a good sign,
       
   181              * but we'll try again with OpenProcess() below.
       
   182              */
       
   183             hProcess = NULL;
       
   184         }
       
   185     }
       
   186 
       
   187     if (hProcess == NULL) {
       
   188         /*
       
   189          * Attempt to open process. If it fails then we try to enable the
       
   190          * SE_DEBUG_NAME privilege and retry.
       
   191          */
       
   192         hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
       
   193         if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) {
       
   194             hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE,
       
   195                            (DWORD)pid);
       
   196         }
       
   197 
       
   198         if (hProcess == NULL) {
       
   199             if (GetLastError() == ERROR_INVALID_PARAMETER) {
       
   200                 JNU_ThrowIOException(env, "no such process");
       
   201             } else {
       
   202                 char err_mesg[255];
       
   203                 /* include the last error in the default detail message */
       
   204                 sprintf(err_mesg, "OpenProcess(pid=%d) failed; LastError=0x%x",
       
   205                     (int)pid, (int)GetLastError());
       
   206                 JNU_ThrowIOExceptionWithLastError(env, err_mesg);
       
   207             }
       
   208             return (jlong)0;
       
   209         }
       
   210     }
       
   211 
       
   212     /*
       
   213      * On Windows 64-bit we need to handle 32-bit tools trying to attach to 64-bit
       
   214      * processes (and visa versa). X-architecture attaching is currently not supported
       
   215      * by this implementation.
       
   216      */
       
   217     if (_IsWow64Process != NULL) {
       
   218         BOOL isCurrent32bit, isTarget32bit;
       
   219         (*_IsWow64Process)(GetCurrentProcess(), &isCurrent32bit);
       
   220         (*_IsWow64Process)(hProcess, &isTarget32bit);
       
   221 
       
   222         if (isCurrent32bit != isTarget32bit) {
       
   223             CloseHandle(hProcess);
       
   224             #ifdef _WIN64
       
   225               JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
       
   226                   "Unable to attach to 32-bit process running under WOW64");
       
   227             #else
       
   228               JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
       
   229                   "Unable to attach to 64-bit process");
       
   230             #endif
       
   231         }
       
   232     }
       
   233 
       
   234     return (jlong)hProcess;
       
   235 }
       
   236 
       
   237 
       
   238 /*
       
   239  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   240  * Method:    closeProcess
       
   241  * Signature: (J)V
       
   242  */
       
   243 JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_closeProcess
       
   244   (JNIEnv *env, jclass cls, jlong hProcess)
       
   245 {
       
   246     CloseHandle((HANDLE)hProcess);
       
   247 }
       
   248 
       
   249 
       
   250 /*
       
   251  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   252  * Method:    createPipe
       
   253  * Signature: (Ljava/lang/String;)J
       
   254  */
       
   255 JNIEXPORT jlong JNICALL Java_sun_tools_attach_WindowsVirtualMachine_createPipe
       
   256   (JNIEnv *env, jclass cls, jstring pipename)
       
   257 {
       
   258     HANDLE hPipe;
       
   259     char name[MAX_PIPE_NAME_LENGTH];
       
   260 
       
   261     jstring_to_cstring(env, pipename, name, MAX_PIPE_NAME_LENGTH);
       
   262 
       
   263     hPipe = CreateNamedPipe(
       
   264           name,                         // pipe name
       
   265           PIPE_ACCESS_INBOUND,          // read access
       
   266           PIPE_TYPE_BYTE |              // byte mode
       
   267             PIPE_READMODE_BYTE |
       
   268             PIPE_WAIT,                  // blocking mode
       
   269           1,                            // max. instances
       
   270           128,                          // output buffer size
       
   271           8192,                         // input buffer size
       
   272           NMPWAIT_USE_DEFAULT_WAIT,     // client time-out
       
   273           NULL);                        // default security attribute
       
   274 
       
   275     if (hPipe == INVALID_HANDLE_VALUE) {
       
   276         char msg[256];
       
   277         _snprintf(msg, sizeof(msg), "CreateNamedPipe failed: %d", GetLastError());
       
   278         JNU_ThrowIOExceptionWithLastError(env, msg);
       
   279     }
       
   280     return (jlong)hPipe;
       
   281 }
       
   282 
       
   283 /*
       
   284  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   285  * Method:    closePipe
       
   286  * Signature: (J)V
       
   287  */
       
   288 JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_closePipe
       
   289   (JNIEnv *env, jclass cls, jlong hPipe)
       
   290 {
       
   291     CloseHandle( (HANDLE)hPipe );
       
   292 }
       
   293 
       
   294 /*
       
   295  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   296  * Method:    connectPipe
       
   297  * Signature: (J)V
       
   298  */
       
   299 JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_connectPipe
       
   300   (JNIEnv *env, jclass cls, jlong hPipe)
       
   301 {
       
   302     BOOL fConnected;
       
   303 
       
   304     fConnected = ConnectNamedPipe((HANDLE)hPipe, NULL) ?
       
   305         TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
       
   306     if (!fConnected) {
       
   307         JNU_ThrowIOExceptionWithLastError(env, "ConnectNamedPipe failed");
       
   308     }
       
   309 }
       
   310 
       
   311 /*
       
   312  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   313  * Method:    readPipe
       
   314  * Signature: (J[BII)I
       
   315  */
       
   316 JNIEXPORT jint JNICALL Java_sun_tools_attach_WindowsVirtualMachine_readPipe
       
   317   (JNIEnv *env, jclass cls, jlong hPipe, jbyteArray ba, jint off, jint baLen)
       
   318 {
       
   319     unsigned char buf[128];
       
   320     DWORD len, nread, remaining;
       
   321     BOOL fSuccess;
       
   322 
       
   323     len = sizeof(buf);
       
   324     remaining = (DWORD)(baLen - off);
       
   325     if (len > remaining) {
       
   326         len = remaining;
       
   327     }
       
   328 
       
   329     fSuccess = ReadFile(
       
   330          (HANDLE)hPipe,         // handle to pipe
       
   331          buf,                   // buffer to receive data
       
   332          len,                   // size of buffer
       
   333          &nread,                // number of bytes read
       
   334          NULL);                 // not overlapped I/O
       
   335 
       
   336     if (!fSuccess) {
       
   337         if (GetLastError() == ERROR_BROKEN_PIPE) {
       
   338             return (jint)-1;
       
   339         } else {
       
   340             JNU_ThrowIOExceptionWithLastError(env, "ReadFile");
       
   341         }
       
   342     } else {
       
   343         if (nread == 0) {
       
   344             return (jint)-1;        // EOF
       
   345         } else {
       
   346             (*env)->SetByteArrayRegion(env, ba, off, (jint)nread, (jbyte *)(buf));
       
   347         }
       
   348     }
       
   349 
       
   350     return (jint)nread;
       
   351 }
       
   352 
       
   353 
       
   354 /*
       
   355  * Class:     sun_tools_attach_WindowsVirtualMachine
       
   356  * Method:    enqueue
       
   357  * Signature: (JZLjava/lang/String;[Ljava/lang/Object;)V
       
   358  */
       
   359 JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_enqueue
       
   360   (JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jstring cmd,
       
   361    jstring pipename, jobjectArray args)
       
   362 {
       
   363     DataBlock data;
       
   364     DataBlock* pData;
       
   365     DWORD* pCode;
       
   366     DWORD stubLen;
       
   367     HANDLE hProcess, hThread;
       
   368     jint argsLen, i;
       
   369     jbyte* stubCode;
       
   370     jboolean isCopy;
       
   371 
       
   372     /*
       
   373      * Setup data to copy to target process
       
   374      */
       
   375     data._GetModuleHandle = _GetModuleHandle;
       
   376     data._GetProcAddress = _GetProcAddress;
       
   377 
       
   378     strcpy(data.jvmLib, "jvm");
       
   379     strcpy(data.func1, "JVM_EnqueueOperation");
       
   380     strcpy(data.func2, "_JVM_EnqueueOperation@20");
       
   381 
       
   382     /*
       
   383      * Command and arguments
       
   384      */
       
   385     jstring_to_cstring(env, cmd, data.cmd, MAX_CMD_LENGTH);
       
   386     argsLen = (*env)->GetArrayLength(env, args);
       
   387 
       
   388     if (argsLen > 0) {
       
   389         if (argsLen > MAX_ARGS) {
       
   390             JNU_ThrowInternalError(env, "Too many arguments");
       
   391             return;
       
   392         }
       
   393         for (i=0; i<argsLen; i++) {
       
   394             jobject obj = (*env)->GetObjectArrayElement(env, args, i);
       
   395             if (obj == NULL) {
       
   396                 data.arg[i][0] = '\0';
       
   397             } else {
       
   398                 jstring_to_cstring(env, obj, data.arg[i], MAX_ARG_LENGTH);
       
   399             }
       
   400             if ((*env)->ExceptionOccurred(env)) return;
       
   401         }
       
   402     }
       
   403     for (i=argsLen; i<MAX_ARGS; i++) {
       
   404         data.arg[i][0] = '\0';
       
   405     }
       
   406 
       
   407     /* pipe name */
       
   408     jstring_to_cstring(env, pipename, data.pipename, MAX_PIPE_NAME_LENGTH);
       
   409 
       
   410     /*
       
   411      * Allocate memory in target process for data and code stub
       
   412      * (assumed aligned and matches architecture of target process)
       
   413      */
       
   414     hProcess = (HANDLE)handle;
       
   415 
       
   416     pData = (DataBlock*) VirtualAllocEx( hProcess, 0, sizeof(DataBlock), MEM_COMMIT, PAGE_READWRITE );
       
   417     if (pData == NULL) {
       
   418         JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
       
   419         return;
       
   420     }
       
   421     WriteProcessMemory( hProcess, (LPVOID)pData, (LPCVOID)&data, (SIZE_T)sizeof(DataBlock), NULL );
       
   422 
       
   423 
       
   424     stubLen = (DWORD)(*env)->GetArrayLength(env, stub);
       
   425     stubCode = (*env)->GetByteArrayElements(env, stub, &isCopy);
       
   426 
       
   427     if ((*env)->ExceptionOccurred(env)) return;
       
   428 
       
   429     pCode = (PDWORD) VirtualAllocEx( hProcess, 0, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
       
   430     if (pCode == NULL) {
       
   431         JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
       
   432         VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
       
   433         return;
       
   434     }
       
   435     WriteProcessMemory( hProcess, (LPVOID)pCode, (LPCVOID)stubCode, (SIZE_T)stubLen, NULL );
       
   436     if (isCopy) {
       
   437         (*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT);
       
   438     }
       
   439 
       
   440     /*
       
   441      * Create thread in target process to execute code
       
   442      */
       
   443     hThread = CreateRemoteThread( hProcess,
       
   444                                   NULL,
       
   445                                   0,
       
   446                                   (LPTHREAD_START_ROUTINE) pCode,
       
   447                                   pData,
       
   448                                   0,
       
   449                                   NULL );
       
   450     if (hThread != NULL) {
       
   451         if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0) {
       
   452             JNU_ThrowIOExceptionWithLastError(env, "WaitForSingleObject failed");
       
   453         } else {
       
   454             DWORD exitCode;
       
   455             GetExitCodeThread(hThread, &exitCode);
       
   456             if (exitCode) {
       
   457                 switch (exitCode) {
       
   458                     case ERR_OPEN_JVM_FAIL :
       
   459                         JNU_ThrowIOException(env,
       
   460                             "jvm.dll not loaded by target process");
       
   461                         break;
       
   462                     case ERR_GET_ENQUEUE_FUNC_FAIL :
       
   463                         JNU_ThrowIOException(env,
       
   464                             "Unable to enqueue operation: the target VM does not support attach mechanism");
       
   465                         break;
       
   466                     default :
       
   467                         JNU_ThrowInternalError(env,
       
   468                             "Remote thread failed for unknown reason");
       
   469                 }
       
   470             }
       
   471         }
       
   472         CloseHandle(hThread);
       
   473     } else {
       
   474         if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
       
   475             //
       
   476             // This error will occur when attaching to a process belonging to
       
   477             // another terminal session. See "Remarks":
       
   478             // http://msdn.microsoft.com/en-us/library/ms682437%28VS.85%29.aspx
       
   479             //
       
   480             JNU_ThrowIOException(env,
       
   481                 "Insufficient memory or insufficient privileges to attach");
       
   482         } else {
       
   483             JNU_ThrowIOExceptionWithLastError(env, "CreateRemoteThread failed");
       
   484         }
       
   485     }
       
   486 
       
   487     VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE);
       
   488     VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
       
   489 }
       
   490 
       
   491 /*
       
   492  * Attempts to enable the SE_DEBUG_NAME privilege and open the given process.
       
   493  */
       
   494 static HANDLE
       
   495 doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) {
       
   496     HANDLE hToken;
       
   497     HANDLE hProcess = NULL;
       
   498     LUID luid;
       
   499     TOKEN_PRIVILEGES tp, tpPrevious;
       
   500     DWORD retLength, error;
       
   501 
       
   502     /*
       
   503      * Get the access token
       
   504      */
       
   505     if (!OpenThreadToken(GetCurrentThread(),
       
   506                          TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
       
   507                          FALSE,
       
   508                          &hToken)) {
       
   509         if (GetLastError() != ERROR_NO_TOKEN) {
       
   510             return (HANDLE)NULL;
       
   511         }
       
   512 
       
   513         /*
       
   514          * No access token for the thread so impersonate the security context
       
   515          * of the process.
       
   516          */
       
   517         if (!ImpersonateSelf(SecurityImpersonation)) {
       
   518             return (HANDLE)NULL;
       
   519         }
       
   520         if (!OpenThreadToken(GetCurrentThread(),
       
   521                              TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
       
   522                              FALSE,
       
   523                              &hToken)) {
       
   524             return (HANDLE)NULL;
       
   525         }
       
   526     }
       
   527 
       
   528     /*
       
   529      * Get LUID for the privilege
       
   530      */
       
   531     if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
       
   532         error = GetLastError();
       
   533         CloseHandle(hToken);
       
   534         SetLastError(error);
       
   535         return (HANDLE)NULL;
       
   536     }
       
   537 
       
   538     /*
       
   539      * Enable the privilege
       
   540      */
       
   541     ZeroMemory(&tp, sizeof(tp));
       
   542     tp.PrivilegeCount = 1;
       
   543     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
       
   544     tp.Privileges[0].Luid = luid;
       
   545 
       
   546     error = 0;
       
   547     if (AdjustTokenPrivileges(hToken,
       
   548                               FALSE,
       
   549                               &tp,
       
   550                               sizeof(TOKEN_PRIVILEGES),
       
   551                               &tpPrevious,
       
   552                               &retLength)) {
       
   553         /*
       
   554          * If we enabled the privilege then attempt to open the
       
   555          * process.
       
   556          */
       
   557         if (GetLastError() == ERROR_SUCCESS) {
       
   558             hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
       
   559             if (hProcess == NULL) {
       
   560                 error = GetLastError();
       
   561             }
       
   562         } else {
       
   563             error = ERROR_ACCESS_DENIED;
       
   564         }
       
   565 
       
   566         /*
       
   567          * Revert to the previous privileges
       
   568          */
       
   569         AdjustTokenPrivileges(hToken,
       
   570                               FALSE,
       
   571                               &tpPrevious,
       
   572                               retLength,
       
   573                               NULL,
       
   574                               NULL);
       
   575     } else {
       
   576         error = GetLastError();
       
   577     }
       
   578 
       
   579 
       
   580     /*
       
   581      * Close token and restore error
       
   582      */
       
   583     CloseHandle(hToken);
       
   584     SetLastError(error);
       
   585 
       
   586     return hProcess;
       
   587 }
       
   588 
       
   589 /* convert jstring to C string */
       
   590 static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len) {
       
   591     jboolean isCopy;
       
   592     const char* str;
       
   593 
       
   594     if (jstr == NULL) {
       
   595         cstr[0] = '\0';
       
   596     } else {
       
   597         str = JNU_GetStringPlatformChars(env, jstr, &isCopy);
       
   598         if ((*env)->ExceptionOccurred(env)) return;
       
   599 
       
   600         strncpy(cstr, str, len);
       
   601         cstr[len-1] = '\0';
       
   602         if (isCopy) {
       
   603             JNU_ReleaseStringPlatformChars(env, jstr, str);
       
   604         }
       
   605     }
       
   606 }