Skip to content

Commit

Permalink
Merge pull request #1278 from matthiasblaesing/win-x86-unittests
Browse files Browse the repository at this point in the history
Fix unittests for windows 32bit intel
  • Loading branch information
matthiasblaesing committed Dec 3, 2020
2 parents 2089ac1 + 9831288 commit 3b47eff
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 19 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);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public void testReadAlignedCliTool() throws IOException {

public void testWriteAlignedCliTool() throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(new String[] {"xattr", "-w", "JNA", "Java Native Access", testPath});
assertTrue(p.waitFor(10, TimeUnit.SECONDS));
assertTrue(p.waitFor(30, TimeUnit.SECONDS));
String resultString = XAttrUtil.getXAttr(testPath, "JNA");
assertEquals("Java Native Access", resultString);
}
Expand Down
23 changes: 21 additions & 2 deletions contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
import com.sun.jna.ptr.ShortByReference;

import junit.framework.TestCase;
import org.junit.Assume;

public class Kernel32Test extends TestCase {

Expand Down Expand Up @@ -1381,13 +1382,31 @@ public final void testCreateRemoteThreadInvalid() throws IOException {

@Test
public void testCreateRemoteThread() {
Assume.assumeTrue("testCreateRemoteThread is only implemented for x86 + x86-64", Platform.isIntel());

Pointer addr = Kernel32.INSTANCE.VirtualAllocEx(
Kernel32.INSTANCE.GetCurrentProcess(), null, new SIZE_T(4096),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

// mov eax, ecx; ret; int3
Memory localBuffer = new Memory(4096);
localBuffer.setInt(0, 0xccc3c18b);
localBuffer.clear();

if (Platform.is64Bit()) {
// mov eax, ecx; ret; int3
localBuffer.setByte(0, (byte) 0x8b); // MOV
localBuffer.setByte(1, (byte) 0xc1); // ECX -> EAX
localBuffer.setByte(2, (byte) 0xc3); // RET
localBuffer.setByte(3, (byte) 0xcc); // INT3
} else {
// mov eax, esp + 4; ret; int3
localBuffer.setByte(0, (byte) 0x8b); // MOV
localBuffer.setByte(1, (byte) 0x44); // ESP + 4bytes-> EAX
localBuffer.setByte(2, (byte) 0x24); //
localBuffer.setByte(3, (byte) 0x04); //
localBuffer.setByte(4, (byte) 0xc3); // RET
localBuffer.setByte(5, (byte) 0xcc); // INT3
}

IntByReference bytesWritten = new IntByReference();
Kernel32.INSTANCE.WriteProcessMemory(Kernel32.INSTANCE.GetCurrentProcess(),
addr, localBuffer, 4096, bytesWritten);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

import com.sun.jna.CallbackReference;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
Expand Down Expand Up @@ -442,8 +443,14 @@ public LRESULT callback(HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam) {
}

SubClassedWindowProc subclass = new SubClassedWindowProc();
subclass.oldWindowProc = User32.INSTANCE.SetWindowLongPtr(hwndToSubclass, WinUser.GWL_WNDPROC,
CallbackReference.getFunctionPointer(subclass));
if(Platform.is64Bit()) {
subclass.oldWindowProc = User32.INSTANCE.SetWindowLongPtr(hwndToSubclass, WinUser.GWL_WNDPROC,
CallbackReference.getFunctionPointer(subclass));
} else {
// From MSDN: When compiling for 32-bit Windows, SetWindowLongPtr is defined as a call to the SetWindowLong function.
User32.INSTANCE.SetWindowLong(hwndToSubclass, WinUser.GWL_WNDPROC,
(int) Pointer.nativeValue(CallbackReference.getFunctionPointer(subclass)));
}
}

/**
Expand Down

0 comments on commit 3b47eff

Please sign in to comment.