问题
I am adding User32Ext methods to JNI. In particular, I extended the original UserExt class:
package sirius.core;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.win32.W32APIOptions;
public abstract interface Kernel32Ext
extends Kernel32
{
public static final Kernel32Ext INSTANCE = (Kernel32Ext)Native.loadLibrary("kernel32.dll", Kernel32Ext.class, W32APIOptions.DEFAULT_OPTIONS);
public abstract Pointer VirtualAllocEx(WinNT.HANDLE paramHANDLE, Pointer paramPointer, int paramInt, WinDef.DWORD paramDWORD1, WinDef.DWORD paramDWORD2);
public abstract boolean VirtualFreeEx(WinNT.HANDLE paramHANDLE, Pointer paramPointer, int paramInt, WinDef.DWORD paramDWORD);
}
I want to add the GetModuleFileNameEx function.
I'd write it like this:
public abstract DWORD getModuleFileName(WinNT.HANDLE hProcess, WinNT.HMODULE hModule, WinNT.LPTSTR pathString, WinNT.DWORD pathStringLength);
But WinNT.LPTSTR
is not defined. It's apparently supposed to be a pointer (to char I guess?). So, how do I finish this?
回答1:
First of all, I am sorry for my incorrect answer for you
So, I've tested your code right after receiving your question again. I have to make my own class for this issue.
Let's look at the prototype of the GetModuleFileName
DWORD WINAPI GetModuleFileName(
_In_opt_ HMODULE hModule,
_Out_ LPTSTR lpFilename,
_In_ DWORD nSize
);
Your prototype is for the GetModuleFileNameEx not for the GetModuleFileName. link
The main point i missed is the lpFilename argument that must be muttable object.
It can be any muttable objects like array of char or array of bytes as a prameter.
I think we can not use the String class as a parameter because it's an immutable class.
I figured that the GetModuleFileName is recommended than the GetModuleFileNameEx from the msdn site.
You can find at the middle of the article they say,
To retrieve the name of a module in the current process, use the GetModuleFileName function. This is more efficient and more reliable than calling GetModuleFileNameEx with a handle to the current process
There are two conditions here. First, My OS is Windows 7 Ultimate 64-bit Second, you and i have a different developer environment.
I downloaded the latest jna.jar and jna-platform.jar from the original site.
I have tested four different methods..one of them is failed.
My entry point is as following
public static void main(String[] args) {
testCopyFile();
printProcesses();
testAllocFree(PROCESSID);
testAllocFree2(PROCESSID);
testModuleFileName(PROCESSID);
testModuleFileName2(PROCESSID);
}
The testCopyFile method just copy some text file with a different approach to yours.
private static void testCopyFile() {
Function copyFunc = Function.getFunction("kernel32", "CopyFileA");
Object[] params = new Object[3];
params[0] = "C:\\DEV\\temp\\_info.txt";
params[1] = "C:\\DEV\\temp\\_info2.txt";
params[2] = false;
copyFunc.invoke(params);
}
The Function class, Object as parameters and invoke method of the Function class are needed by implementing the same function.
Next one is to find process id for the test.
private static void printProcesses()
{
Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference();
HANDLE snapshot = Kernel32Me.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS,
new DWORD(0));
try {
while (Kernel32Me.INSTANCE.Process32Next(snapshot, processEntry)) {
System.out.println(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile));
}
} finally {
Kernel32Me.INSTANCE.CloseHandle(snapshot);
}
}
Just pick the one of them displayed on the screen. For convenient reason, I first tested two methods with common functions, VirtualAllocEx and VirtualFreeEx.
I tested it successfully done..
The following two different methods, testAllocFree and testAllocFree2 functions result the same output.
private static void testAllocFree(final int processId) {
SIZE_T dwSize = new SIZE_T(1024);
DWORD flAllocationType = new DWORD(Kernel32Me.MEM_RESERVE | Kernel32Me.MEM_COMMIT);
DWORD flProtect = new DWORD(Kernel32Me.PAGE_READWRITE);
Pointer allocPoint = null;
boolean ret = false;
DWORD options
= new DWORD(
Kernel32Me.PROCESS_VM_OPERATION |
Kernel32Me.PROCESS_VM_WRITE |
Kernel32Me.PROCESS_VM_READ |
Kernel32Me.PROCESS_CREATE_THREAD |
Kernel32Me.PROCESS_QUERY_INFORMATION);
DWORD procs = new DWORD(processId);
HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs);
if(null == hProcess)
{
System.err.println("Can't have a handle for you..sorry");
return;
}
try
{
allocPoint = Kernel32Me.INSTANCE.VirtualAllocEx(hProcess, null, dwSize, flAllocationType, flProtect);
if(allocPoint==null)
{
System.err.println("Can't get a memory resource for you..sorry");
int c = Kernel32Me.INSTANCE.GetLastError();
System.out.println("\t>>" + c);
//c = Native.getLastError();
//System.out.println("\t" + c);
}
if (allocPoint != null) {
dwSize = new SIZE_T(0);
DWORD freeType = new DWORD(Kernel32Me.MEM_RELEASE);
System.err.println("allocPoint >>==> " + allocPoint.toString());
ret = Kernel32Me.INSTANCE.VirtualFreeEx(hProcess, allocPoint, dwSize, freeType);
if(!ret)
{
int c = Kernel32Me.INSTANCE.GetLastError();
System.out.println("\t" + c);
c = Native.getLastError();
System.out.println("\t" + c);
}
else
{
System.out.println("\t Free success");
}
}
}
finally
{
Kernel32Me.INSTANCE.CloseHandle(hProcess);
}
}
And,
private static void testAllocFree2(final int processId) {
Function allocFunc = Function.getFunction("kernel32", "VirtualAllocEx");
Function freeFunc = Function.getFunction("kernel32", "VirtualFreeEx");
DWORD flAllocationType = new DWORD(Kernel32Me.MEM_RESERVE | Kernel32Me.MEM_COMMIT);
DWORD flProtect = new DWORD(Kernel32Me.PAGE_READWRITE);
SIZE_T dwSize = new SIZE_T(1024);
DWORD freeType = new DWORD(Kernel32Me.MEM_RELEASE);
DWORD options
= new DWORD(
Kernel32Me.PROCESS_VM_OPERATION |
Kernel32Me.PROCESS_VM_WRITE |
Kernel32Me.PROCESS_VM_READ |
Kernel32Me.PROCESS_CREATE_THREAD |
Kernel32Me.PROCESS_QUERY_INFORMATION);
DWORD procs = new DWORD(processId);
Pointer allocPoint = null;
HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs);
if(null == hProcess)
{
System.err.println("Can't have a handle for you..sorry");
return;
}
Object[] inArgs = new Object[5];
inArgs[0] = hProcess;
inArgs[1] = null;
inArgs[2] = dwSize;
inArgs[3] = flAllocationType;
inArgs[4] = flProtect;
allocPoint = (Pointer) allocFunc.invoke(Pointer.class, inArgs);
try
{
if(allocPoint==null)
{
System.err.println("Can't get a memory resource for you..sorry");
int c = Kernel32Me.INSTANCE.GetLastError();
System.out.println("\t>>" + c);
//c = Native.getLastError();
//System.out.println("\t" + c);
}
if (allocPoint != null) {
Object[] inArgs2 = new Object[4];
inArgs2[0] = hProcess;
inArgs2[1] = allocPoint;
inArgs2[2] = new SIZE_T(0);
inArgs2[3] = freeType;
System.err.println("allocPoint ==> " + allocPoint.toString());
freeFunc.invoke(inArgs2);
}
}
finally
{
Kernel32Me.INSTANCE.CloseHandle(hProcess);
}
}
Finally, the GetModuleFileName and GetModuleFileNameA function tested below
private static void testModuleFileName(final int processId)
{
DWORD nSize = new DWORD(256);
char lpFilename[] = new char[256];
byte bFilename[] = new byte[256];
String strFileName = new String();
DWORD options = new DWORD(Kernel32Me.PROCESS_VM_READ | Kernel32Me.PROCESS_QUERY_INFORMATION);
DWORD procs = new DWORD(processId);
HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options,false, procs);
if(null == hProcess)
{
System.err.println("Can't have a handle for you..sorry");
return;
}
try
{
Kernel32Me.INSTANCE.GetModuleFileName(null, lpFilename, nSize);
System.err.println("module path is " + new String(lpFilename));
Kernel32Me.INSTANCE.GetModuleFileName(null, bFilename, nSize);
System.err.println("module path is " + new String(bFilename));
Kernel32Me.INSTANCE.GetModuleFileNameEx(hProcess, null, strFileName, nSize);
System.err.println("module path is " + strFileName);
}
finally
{
Kernel32Me.INSTANCE.CloseHandle(hProcess);
}
}
I have two prototypes, one is array bytes and another is array of chars used in the code.
DWORD GetModuleFileName(HMODULE hModule, char[] lpFilename, DWORD nSize);
DWORD GetModuleFileName(HMODULE hModule, byte[] lpFilename, DWORD nSize);
The third one didn't working as i mentioned at the start which told me the UnsatisfiedLinkError.. I don't know why..
DWORD GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, String lpFilename, DWORD nSize);
Another implementation is also the same..look at the code
private static void testModuleFileName2(final int processId)
{
Function allocFunc = Function.getFunction("kernel32", "GetModuleFileName");
DWORD nSize = new DWORD(256);
char[] lpFilename = new char[256];
DWORD procs = new DWORD(processId);
DWORD options
= new DWORD(
Kernel32Me.PROCESS_VM_READ |
Kernel32Me.PROCESS_QUERY_INFORMATION);
HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs);
if(null == hProcess)
{
System.err.println("Can't have a handle for you..sorry");
return;
}
try
{
Object[] inArgs = new Object[3];
inArgs[0] = null;
inArgs[1] = lpFilename;
inArgs[2] = nSize;
allocFunc.invoke(inArgs);
System.err.println("module path is " + new String(lpFilename));
}
finally
{
Kernel32Me.INSTANCE.CloseHandle(hProcess);
}
}
I found both methods not working finally.
Function allocFunc = Function.getFunction("kernel32", "GetModuleFileName");
Function allocFunc = Function.getFunction("kernel32", "GetModuleFileNameEx");
show me the not found procedure message...
java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileName' java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileNameEx'
I have to dig it more about these errors at some time near future.
Last one...Here is a main prototype class
public interface Kernel32Me extends StdCallLibrary {
final Kernel32Me INSTANCE
= (Kernel32Me) Native.loadLibrary("kernel32.dll", Kernel32Me.class, W32APIOptions.DEFAULT_OPTIONS);
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa366890(v=vs.85).aspx
int PROCESS_CREATE_THREAD = 0x0002;
int PAGE_EXECUTE_READWRITE = 0x40;
int PROCESS_QUERY_INFORMATION = 0x0400;
int PROCESS_VM_OPERATION = 0x0008;
int PROCESS_VM_WRITE = 0x0020;
int PROCESS_VM_READ = 0x0010;
int PAGE_READWRITE = 0x04;
int MEM_RESERVE = 0x00002000;
int MEM_COMMIT = 0x00001000;
int MEM_RESET = 0x00080000;
int MEM_DECOMMIT = 0x4000;
int MEM_RELEASE = 0x8000;
Pointer VirtualAllocEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
boolean VirtualFreeEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, DWORD dwFreeType);
DWORD GetModuleFileName(HMODULE hModule, char[] lpFilename, DWORD nSize);
DWORD GetModuleFileName(HMODULE hModule, byte[] lpFilename, DWORD nSize);
DWORD GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, String lpFilename, DWORD nSize);
HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID);
boolean Process32First(HANDLE hSnapshot, PROCESSENTRY32 lppe);
boolean Process32Next(HANDLE hSnapshot, PROCESSENTRY32 lppe);
HANDLE OpenProcess(DWORD dwDesiredAccess, boolean bInheritHandle, DWORD dwProcessId);
boolean CloseHandle(HANDLE hObject);
int GetLastError();
}
The output might look like below
0 [System Process]
4 System
280 smss.exe
444 csrss.exe
536 wininit.exe
544 csrss.exe
7860 chrome.exe
8132 chrome.exe
7808 chrome.exe
7516 chrome.exe
6176 chrome.exe
8156 chrome.exe
7120 chrome.exe
7476 chrome.exe
8016 chrome.exe
5616 devmonsrv.exe
1644 chrome.exe
6548 chrome.exe
5960 chrome.exe
5636 chrome.exe
8260 chrome.exe
3440 notepad.exe
8844 chrome.exe
9416 chrome.exe
6744 chrome.exe
6032 chrome.exe
9724 javaw.exe
Free success
allocPoint >>==> native@0x34d0000
allocPoint ==> native@0x34d0000
module path is C:\DEV\COMP\Java\jdk1.7\bin\javaw.exe
module path is C.... <== The output is strange...
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileNameEx':
You need to use array of char than array of byte avoiding character encoding problem.
My import statements are,
import com.sun.jna.Function;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.Tlhelp32.PROCESSENTRY32;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
You can use the methods below in turn.
printProcesses(); testModuleFileName(PROCESSID);
private static final int PROCESSID = 3440; // the process id from printProcesses();
public static void main(String[] args) {
printProcesses();
testModuleFileName(PROCESSID);
}
I hope this may help you
P.S
Finally, I've got my own answer for this issue... It can be done with Psapi interface... Here is my final test method...
private static void testModuleFileName2(final int processId) {
DWORD nSize = new DWORD(260);
char lpFilename[] = new char[260];
byte bFilename[] = new byte[260];
DWORD options = new DWORD(Kernel32Me.PROCESS_VM_READ | Kernel32Me.PROCESS_QUERY_INFORMATION);
DWORD procs = new DWORD(processId);
HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs);
if (null == hProcess) {
System.err.println("Can't have a handle for you..sorry");
return;
}
HMODULE handle = Kernel32.INSTANCE.GetModuleHandle("kernel32.dll");
if (null == handle) {
System.err.println("Can't have a handle for you..sorry");
return;
}
try {
Kernel32Me.INSTANCE.GetModuleFileName(handle, lpFilename, nSize);
System.err.println("2> module path is " + new String(lpFilename));
Psapi.INSTANCE.GetModuleFileNameExA(hProcess, handle, bFilename, 260);
System.err.println("2> module path is " + new String(bFilename));
Psapi.INSTANCE.GetModuleFileNameExW(hProcess, null, lpFilename, 260);
System.err.println("2> module path is " + new String(lpFilename));
} finally {
Kernel32Me.INSTANCE.CloseHandle(hProcess);
}
}
I opened a notepad.exe and got a its process id
Then, I called this method.
来源:https://stackoverflow.com/questions/43822087/what-to-use-instead-of-lptstr-in-java-jna