/* * Copyright (C) 2017 Laurens Weyn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package hooker; import com.sun.java.swing.plaf.windows.resources.windows; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.platform.win32.WinDef; import com.sun.jna.ptr.IntByReference; import com.sun.jna.win32.W32APIOptions; import language.dictionary.Japanese; import java.awt.*; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; /** * Created by Laurens on 2/18/2017. */ public class KernelController { private static Kernel32 kernel32; private static User32 user32; //I/O permissions public static int PROCESS_VM_READ = 0x0010; public static int PROCESS_VM_WRITE = 0x0020; public static int PROCESS_VM_OPERATION = 0x0008; private static boolean attemptedLoad = false; /** * Internal function. Ensures kernel libraries are loaded if possible. */ private static void attemptLoad() { if(attemptedLoad)return; try { kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, W32APIOptions.UNICODE_OPTIONS); user32 = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.UNICODE_OPTIONS); }catch(UnsatisfiedLinkError ignored) { System.out.println("Native libraries not available"); } attemptedLoad = true; } /** * Checks if this system supports kernel-level operations (I.E. it's a Windows machine) * @return true if kernel32 and user32 exist and are loaded */ public static boolean isKernelAvailable() { attemptLoad(); return kernel32 != null && user32 != null; } public static Kernel32 getKernel32() { attemptLoad(); return kernel32; } public static User32 getUser32() { attemptLoad(); return user32; } /** * Finds all windows * @param onlyJapanese limit window search to ones containing Japanese text * @return a map of all titles and their window pointers. */ public static Map<String, Pointer> findAllWindows(boolean onlyJapanese) { if(!isKernelAvailable())return null; HashMap<String, Pointer> windows = new HashMap<>(); user32.EnumWindows((hWnd, data) -> { //hWnd is the window pointer, data is usually return data (unused) String text = getWindowName(hWnd); if(text != null && (!onlyJapanese || Japanese.isJapaneseWriting(text))) { windows.put(text, hWnd); } return true; }, null); return windows; } /** * Gets process ID from a window pointer * @param hWnd the window pointer * @return the process ID */ public static int getPID(Pointer hWnd) { if(!isKernelAvailable())return -1; IntByReference pid = new IntByReference(); user32.GetWindowThreadProcessId(hWnd, pid); return pid.getValue(); } /** * Gets the currently focused window * @return pointer to the focused window, or null if not possible */ public static Pointer getFocusedWindow() { if(!isKernelAvailable())return null; return user32.GetForegroundWindow(); } private static char[] windowText = new char[256]; /** * Gets the (possibly unicode) name of a window * @param hWnd the window pointer * @return the name of the window, null if it has no name */ public static String getWindowName(Pointer hWnd) { if(!isKernelAvailable() || hWnd == null)return null; int len = user32.GetWindowTextW(hWnd, windowText, 256); if(len == 0)return null;//unnamed window return new String(windowText, 0, len);//Charset.forName("UTF-8").decode(bb).toString(); } public static Rectangle getWindowArea(Pointer hWnd) { if(!isKernelAvailable() || hWnd == null)return null; WinDef.RECT rect = new WinDef.RECT(); user32.GetWindowRect(hWnd, rect); return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); } /** * Sends key to advance dialogue to a window, even if that window is not focused. * @param hWnd the window to send the key to. */ public static void sendAdvanceKey(Pointer hWnd) { if(!isKernelAvailable() || hWnd == null)return; int WM_KEYDOWN = 0x0100; int WM_KEYUP = 0x0101; //keycodes: https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx int VK_RETURN = 0x0D; user32.PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0); user32.PostMessage(hWnd, WM_KEYUP, VK_RETURN, 0); } private static Boolean is64Bit = null; public static boolean is64Bit() { if(is64Bit == null) { switch(System.getProperty("sun.arch.data.model")) { case "32": is64Bit = false; break; case "64": is64Bit = true; break; } System.out.println("64 bit: " + is64Bit); } return is64Bit; } }