Skip to content

Commit

Permalink
Fix getProcessFilePath for querying 64 bit processes from 32bit JVMs
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiasblaesing committed Dec 3, 2020
1 parent f743b56 commit 6a6be08
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Bug Fixes
* [#1252](https://github.com/java-native-access/jna/issues/1252): - Fix bindings of `CTL_ENTRY#getRgAttribute`, `CTL_INFO#getRgCTLEntry`, `CTL_INFO#getRgExtension`, `CERT_EXTENSIONS#getRgExtension`, `CERT_INFO#getRgExtension`, `CRL_INFO#getRgCRLEntry`, `CRL_INFO#getRgExtension`, `CRL_ENTRY#getRgExtension`. Add bindings for `CertEnumCertificatesInStore`, `CertEnumCTLsInStore`, `CertEnumCRLsInStore` and `CryptQueryObject` in `c.s.j.p.win32.Crypt32`.<br> *WARNING:* The signatures for `CTL_INFO#getRgCTLEntry` and `CTL_INFO#getRgExtension` were changed - as the original signatures were obviously wrong and read the wrong attributes, it is not considered an API break - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#1275](https://github.com/java-native-access/jna/issues/1275): Fix `CFStringRef#stringValue` for empty Strings - [@dyorgio](https://github.com/dyorgio).
* [#1279](https://github.com/java-native-access/jna/issues/1279): Remove `DLLCallback` import from `CallbackReference` - [@dyorgio](https://github.com/dyorgio).
* [#1278](https://github.com/java-native-access/jna/pull/1278): Improve compatibility of `c.s.j.p.WindowUtils#getProcessFilePath` and fix unittests for windows 32bit intel - [@matthiasblaesing](https://github.com/matthiasblaesing).

Release 5.6.0
=============
Expand Down
80 changes: 66 additions & 14 deletions contrib/platform/src/com/sun/jna/platform/WindowUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,12 @@
import com.sun.jna.platform.unix.X11.Xrender.XRenderPictFormat;
import com.sun.jna.platform.win32.GDI32;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Kernel32Util;
import com.sun.jna.platform.win32.Psapi;
import com.sun.jna.platform.win32.PsapiUtil;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinDef.DWORDByReference;
import com.sun.jna.platform.win32.WinDef.HBITMAP;
import com.sun.jna.platform.win32.WinDef.HDC;
Expand All @@ -99,6 +102,7 @@
import com.sun.jna.platform.win32.WinDef.POINT;
import com.sun.jna.platform.win32.WinDef.RECT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinError;
import com.sun.jna.platform.win32.WinGDI;
import com.sun.jna.platform.win32.WinGDI.BITMAP;
import com.sun.jna.platform.win32.WinGDI.BITMAPINFO;
Expand Down Expand Up @@ -1278,33 +1282,81 @@ public String getWindowTitle(final HWND hwnd) {

@Override
public String getProcessFilePath(final HWND hwnd) {
final char[] filePath = new char[2048];
final IntByReference pid = new IntByReference();
User32.INSTANCE.GetWindowThreadProcessId(hwnd, pid);

final HANDLE process = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION | WinNT.PROCESS_VM_READ,
false, pid.getValue());
// GetProcessImageFileName requires PROCESS_QUERY_INFORMATION on
// older windows versions so try that first. If we fail to get
// access to that information fallback to
// PROCESS_QUERY_LIMITED_INFORMATION. This allows reading image
// paths from processes running with elevated privileges (at least
// worked successfully for a setup program started from a network
// share)
HANDLE process = Kernel32.INSTANCE.OpenProcess(
WinNT.PROCESS_QUERY_INFORMATION,
false,
pid.getValue());

if (process == null) {
if(Kernel32.INSTANCE.GetLastError() != WinNT.ERROR_ACCESS_DENIED) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
} else {
// Ignore windows, that can't be accessed
return "";
process = Kernel32.INSTANCE.OpenProcess(
WinNT.PROCESS_QUERY_LIMITED_INFORMATION,
false,
pid.getValue());

if (process == null) {
if (Kernel32.INSTANCE.GetLastError() != WinNT.ERROR_ACCESS_DENIED) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
} else {
// Ignore windows, that can't be accessed
return "";
}
}
}
}

try {
final int length = Psapi.INSTANCE.GetModuleFileNameExW(process,
null, filePath, filePath.length);
if (length == 0) {
if(Kernel32.INSTANCE.GetLastError() != WinNT.ERROR_INVALID_HANDLE) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
} else {
// ignore invalid handles
return "";
String processImagePath = PsapiUtil.GetProcessImageFileName(process);

// GetProcessImageFileName returns the file name as a device
// filename in the form \Device\Harddisk5\. To make this more
// familiar and keep compatibility with QueryModuleName try to
// map back to known path (DOS path or UNC path)

// Map Mup to UNC path
if(processImagePath.startsWith("\\Device\\Mup\\")) {
return "\\" + processImagePath.substring(11);
}

// Format of FindFirstVolume is
// \\?\Volume{00000000-0000-0000-0000-000000000000}\
char[] volumeUUID = new char[50];
HANDLE h = Kernel32.INSTANCE.FindFirstVolume(volumeUUID, 50);
if (h == null || h.equals(WinBase.INVALID_HANDLE_VALUE)) {
throw new Win32Exception(Native.getLastError());
}
try {
do {
String volumePath = Native.toString(volumeUUID);
for (String s : Kernel32Util.getVolumePathNamesForVolumeName(volumePath)) {
if (s.matches("[a-zA-Z]:\\\\")) {
for (String path : Kernel32Util.queryDosDevice(s.substring(0, 2), 1024)) {
if(processImagePath.startsWith(path)) {
return s + processImagePath.substring(path.length() + 1);
}
}
}
}
} while (Kernel32.INSTANCE.FindNextVolume(h, volumeUUID, 50));
if (Native.getLastError() != WinError.ERROR_NO_MORE_FILES) {
throw new Win32Exception(Native.getLastError());
}
} finally {
Kernel32.INSTANCE.FindVolumeClose(h);
}
return Native.toString(filePath).trim();
return processImagePath;
} finally {
Kernel32.INSTANCE.CloseHandle(process);
}
Expand Down
2 changes: 2 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Psapi.java
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ public interface Psapi extends StdCallLibrary {
boolean GetModuleInformation(HANDLE hProcess, HMODULE hModule, MODULEINFO lpmodinfo, int cb);

/**
* Retrieves the name of the executable file for the specified process.
*
* @param hProcess
* A handle to the process. The handle must have the
* PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION
Expand Down
33 changes: 33 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/PsapiUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
*/
package com.sun.jna.platform.win32;

import com.sun.jna.Native;
import java.util.Arrays;

import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;

/**
Expand Down Expand Up @@ -54,4 +56,35 @@ public static int[] enumProcesses() {

return Arrays.copyOf(lpidProcess, lpcbNeeded.getValue() / DWORD.SIZE);
}

/**
* Retrieves the name of the executable file for the specified process.
*
* @param hProcess
* A handle to the process. The handle must have the
* PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION
* access right. For more information, see Process Security and
* Access Rights. <br>
* Windows Server 2003 and Windows XP: The handle must have the
* PROCESS_QUERY_INFORMATION access right.
* @return ame of the executable file for the specified process.
* @throws Win32Exception in case an error occurs
* @see <a href="http://msdn.microsoft.com/en-us/library/ms683217(VS.85).aspx">MSDN</a>
*/
public static String GetProcessImageFileName(HANDLE process) {
int size = 2048;
while (true) {
final char[] filePath = new char[size];
int length = Psapi.INSTANCE.GetProcessImageFileName(process,
filePath, filePath.length);
if(length == 0) {
if(Native.getLastError() != WinError.ERROR_INSUFFICIENT_BUFFER) {
throw new Win32Exception(Native.getLastError());
}
size += 2048;
} else {
return Native.toString(filePath);
}
}
}
}

0 comments on commit 6a6be08

Please sign in to comment.