mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 18:40:45 +00:00
611 lines
24 KiB
Java
611 lines
24 KiB
Java
/*
|
|
* Copyright (C) 2010-2024 JPEXS
|
|
*
|
|
* 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 com.jpexs.process.win32;
|
|
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.Advapi32;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.BITMAP;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.BaseTSD;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.Gdi32;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.ICONINFO;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.Kernel32;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.MEMORY_BASIC_INFORMATION;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.PROCESSENTRY32;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.Psapi;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.SHFILEINFO;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.Shell32;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.User32;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.WinBase;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.WinDef;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.WinNT;
|
|
import com.jpexs.decompiler.flash.gui.jna.platform.win32.WinNT.HANDLE;
|
|
import com.jpexs.helpers.ProgressListener;
|
|
import com.jpexs.process.ProcessTools;
|
|
import com.sun.jna.Memory;
|
|
import com.sun.jna.NativeLong;
|
|
import com.sun.jna.Pointer;
|
|
import com.sun.jna.ptr.IntByReference;
|
|
import com.sun.jna.ptr.NativeLongByReference;
|
|
import com.sun.jna.ptr.PointerByReference;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
/**
|
|
* @author JPEXS
|
|
*/
|
|
public class Win32ProcessTools extends ProcessTools {
|
|
|
|
private static long pointerToAddress(Pointer p) {
|
|
return Pointer.nativeValue(p);
|
|
}
|
|
|
|
public static List<MEMORY_BASIC_INFORMATION> getPageRanges(WinNT.HANDLE hOtherProcess) {
|
|
List<MEMORY_BASIC_INFORMATION> ret = new ArrayList<>();
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
WinBase.SYSTEM_INFO si = new WinBase.SYSTEM_INFO();
|
|
Kernel32.INSTANCE.GetSystemInfo(si);
|
|
Pointer lpMem = si.lpMinimumApplicationAddress;
|
|
while (pointerToAddress(lpMem) < pointerToAddress(si.lpMaximumApplicationAddress)) {
|
|
mbi = new MEMORY_BASIC_INFORMATION();
|
|
BaseTSD.SIZE_T t = Kernel32.INSTANCE.VirtualQueryEx(hOtherProcess, lpMem, mbi, new BaseTSD.SIZE_T(mbi.size()));
|
|
if (t.longValue() == 0) {
|
|
//Logger.getLogger(Win32ProcessTools.class.getName()).log(Level.SEVERE, "Cannot get page ranges. Last error:{0}", Kernel32.INSTANCE.GetLastError());
|
|
break;
|
|
}
|
|
ret.add(mbi);
|
|
lpMem = new Pointer(pointerToAddress(mbi.baseAddress) + mbi.regionSize.longValue());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public static void printMemInfo(MEMORY_BASIC_INFORMATION mbi) {
|
|
System.out.println("Region size:" + mbi.regionSize);
|
|
String stateStr = "";
|
|
if ((mbi.state.intValue() & Kernel32.MEM_COMMIT) == Kernel32.MEM_COMMIT) {
|
|
stateStr += " commit";
|
|
}
|
|
if ((mbi.state.intValue() & Kernel32.MEM_FREE) == Kernel32.MEM_FREE) {
|
|
stateStr += " free";
|
|
}
|
|
if ((mbi.state.intValue() & Kernel32.MEM_RESERVE) == Kernel32.MEM_RESERVE) {
|
|
stateStr += " reserve";
|
|
}
|
|
stateStr = stateStr.trim();
|
|
|
|
String typeStr = "";
|
|
if ((mbi.type.intValue() & Kernel32.MEM_IMAGE) == Kernel32.MEM_IMAGE) {
|
|
typeStr += " image";
|
|
}
|
|
if ((mbi.type.intValue() & Kernel32.MEM_MAPPED) == Kernel32.MEM_MAPPED) {
|
|
typeStr += " mapped";
|
|
}
|
|
if ((mbi.type.intValue() & Kernel32.MEM_PRIVATE) == Kernel32.MEM_PRIVATE) {
|
|
typeStr += " private";
|
|
}
|
|
typeStr = typeStr.trim();
|
|
|
|
String protStr = "";
|
|
if ((mbi.allocationProtect.intValue() & WinNT.PAGE_EXECUTE) == Kernel32.PAGE_EXECUTE) {
|
|
protStr += " execute";
|
|
}
|
|
if ((mbi.allocationProtect.intValue() & WinNT.PAGE_EXECUTE_READ) == Kernel32.PAGE_EXECUTE_READ) {
|
|
protStr += " execute_read";
|
|
}
|
|
if ((mbi.allocationProtect.intValue() & WinNT.PAGE_EXECUTE_READWRITE) == Kernel32.PAGE_EXECUTE_READWRITE) {
|
|
protStr += " execute_readwrite";
|
|
}
|
|
if ((mbi.allocationProtect.intValue() & WinNT.PAGE_READONLY) == Kernel32.PAGE_READONLY) {
|
|
protStr += " readonly";
|
|
}
|
|
if ((mbi.allocationProtect.intValue() & WinNT.PAGE_READWRITE) == Kernel32.PAGE_READWRITE) {
|
|
protStr += " readwrite";
|
|
}
|
|
if ((mbi.allocationProtect.intValue() & WinNT.PAGE_WRITECOPY) == Kernel32.PAGE_WRITECOPY) {
|
|
protStr += " writecopy";
|
|
}
|
|
|
|
protStr = protStr.trim();
|
|
System.out.println("State:" + stateStr);
|
|
System.out.println("Type:" + typeStr);
|
|
System.out.println("Protect:" + protStr);
|
|
System.out.println("baseAddress:" + mbi.baseAddress);
|
|
System.out.println("========================");
|
|
}
|
|
|
|
private static byte[] mergeArrays(byte[] one, byte[] two) {
|
|
byte[] combined = new byte[one.length + two.length];
|
|
|
|
System.arraycopy(one, 0, combined, 0, one.length);
|
|
System.arraycopy(two, 0, combined, one.length, two.length);
|
|
return combined;
|
|
}
|
|
|
|
public static Map<String, Character> getDriveMappings() {
|
|
Map<String, Character> ret = new HashMap<>();
|
|
for (char d = 'A'; d <= 'Z'; d++) {
|
|
char[] buf = new char[1024];
|
|
int len = Kernel32.INSTANCE.QueryDosDevice(d + ":", buf, buf.length).intValue();
|
|
String tar = new String(buf, 0, len);
|
|
tar = tar.trim();
|
|
if (!"".equals(tar)) {
|
|
ret.put(tar, d);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public static String ntPathToWin32(String path) {
|
|
for (String dp : driveMappings.keySet()) {
|
|
if (path.startsWith(dp)) {
|
|
return driveMappings.get(dp) + ":" + path.substring(dp.length());
|
|
}
|
|
}
|
|
return path;
|
|
}
|
|
|
|
private static final Map<String, Character> driveMappings = getDriveMappings();
|
|
|
|
public static boolean drawIcon(BufferedImage ret, WinDef.HICON hIcon, int diFlags) {
|
|
|
|
WinDef.HDC hdcScreen = User32.INSTANCE.GetDC(null);
|
|
WinDef.HDC hdcMem = Gdi32.INSTANCE.CreateCompatibleDC(hdcScreen);
|
|
|
|
WinDef.HBITMAP bitmap = Gdi32.INSTANCE.CreateCompatibleBitmap(hdcScreen, ret.getWidth(), ret.getHeight());
|
|
|
|
WinNT.HANDLE hbmOld = Gdi32.INSTANCE.SelectObject(hdcMem, bitmap);
|
|
|
|
WinNT.HANDLE hBrush = Gdi32.INSTANCE.CreateSolidBrush(new WinDef.DWORD(0xffffff));
|
|
WinDef.RECT rect = new WinDef.RECT();
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = ret.getWidth();
|
|
rect.bottom = ret.getHeight();
|
|
User32.INSTANCE.FillRect(hdcMem, rect, hBrush);
|
|
Gdi32.INSTANCE.DeleteObject(hBrush);
|
|
|
|
boolean ok = User32.INSTANCE.DrawIconEx(hdcMem, 0, 0, hIcon, ret.getWidth(), ret.getHeight(), new WinDef.UINT(0), new WinDef.HBRUSH(Pointer.NULL), diFlags);
|
|
|
|
if (!ok) {
|
|
return false;
|
|
}
|
|
|
|
for (int x = 0; x < ret.getWidth(); x++) {
|
|
for (int y = 0; y < ret.getHeight(); y++) {
|
|
int rgb = Gdi32.INSTANCE.GetPixel(hdcMem, x, y).intValue();
|
|
int r = (rgb >> 16) & 0xff;
|
|
int g = (rgb >> 8) & 0xff;
|
|
int b = (rgb) & 0xff;
|
|
rgb = (b << 16) + (g << 8) + r;
|
|
ret.setRGB(x, y, rgb);
|
|
}
|
|
}
|
|
|
|
Gdi32.INSTANCE.SelectObject(hdcMem, hbmOld);
|
|
Gdi32.INSTANCE.DeleteObject(bitmap);
|
|
Gdi32.INSTANCE.DeleteDC(hdcMem);
|
|
User32.INSTANCE.ReleaseDC(null, hdcScreen);
|
|
return true;
|
|
}
|
|
|
|
private static void applyMask(BufferedImage image, BufferedImage mask) {
|
|
int width = image.getWidth();
|
|
int height = image.getHeight();
|
|
for (int x = 0; x < width; x++) {
|
|
for (int y = 0; y < height; y++) {
|
|
int masked = mask.getRGB(x, y);
|
|
int alpha = 255 - (masked & 0xff);
|
|
if (alpha != 0 && alpha != 255) {
|
|
System.out.println("a=" + alpha);
|
|
}
|
|
int rgb = image.getRGB(x, y);
|
|
int r = (rgb >> 16) & 0xff;
|
|
int g = (rgb >> 8) & 0xff;
|
|
int b = (rgb) & 0xff;
|
|
r = r * alpha / 255;
|
|
g = g * alpha / 255;
|
|
b = b * alpha / 255;
|
|
|
|
rgb = (r << 16) + (g << 8) + b;
|
|
|
|
rgb = (alpha << 24) | rgb;
|
|
image.setRGB(x, y, rgb);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static BufferedImage iconToImage(WinDef.HICON hIcon) {
|
|
ICONINFO info = new ICONINFO();
|
|
boolean ok = User32.INSTANCE.GetIconInfo(hIcon, info);
|
|
if (!ok) {
|
|
return null;
|
|
}
|
|
BufferedImage ret = null;
|
|
BITMAP bmp = new BITMAP();
|
|
if (info.hbmColor != null) {
|
|
int nWrittenBytes = Gdi32.INSTANCE.GetObject(info.hbmColor, bmp.size(), bmp);
|
|
if (nWrittenBytes > 0) {
|
|
ret = new BufferedImage(bmp.bmWidth.intValue(), bmp.bmHeight.intValue(), BufferedImage.TYPE_INT_ARGB);
|
|
}
|
|
} else if (info.hbmMask != null) {
|
|
int nWrittenBytes = Gdi32.INSTANCE.GetObject(info.hbmMask, bmp.size(), bmp);
|
|
if (nWrittenBytes > 0) {
|
|
ret = new BufferedImage(bmp.bmWidth.intValue(), bmp.bmHeight.intValue() / 2, BufferedImage.TYPE_INT_ARGB);
|
|
}
|
|
}
|
|
if (ret == null) {
|
|
return ret;
|
|
}
|
|
|
|
if (info.hbmColor != null) {
|
|
Gdi32.INSTANCE.DeleteObject(info.hbmColor);
|
|
}
|
|
if (info.hbmMask != null) {
|
|
Gdi32.INSTANCE.DeleteObject(info.hbmMask);
|
|
}
|
|
|
|
drawIcon(ret, hIcon, User32.DI_NORMAL);
|
|
BufferedImage mask = new BufferedImage(ret.getWidth(), ret.getHeight(), BufferedImage.TYPE_INT_RGB);
|
|
drawIcon(mask, hIcon, User32.DI_MASK);
|
|
applyMask(ret, mask);
|
|
|
|
return ret;
|
|
}
|
|
|
|
public static BufferedImage getShellIcon(String path) {
|
|
SHFILEINFO fi = new SHFILEINFO();
|
|
BaseTSD.DWORD_PTR r = Shell32.INSTANCE.SHGetFileInfo(path, 0, fi, fi.size(), Shell32.SHGFI_ICON | Shell32.SHGFI_SMALLICON);
|
|
if (r.intValue() == 0) {
|
|
return null;
|
|
}
|
|
return iconToImage(fi.hIcon);
|
|
}
|
|
|
|
public static BufferedImage extractExeIcon(String fullExeFile, int index, boolean large) {
|
|
PointerByReference iconsLargeRef = new PointerByReference();
|
|
PointerByReference iconsSmallRef = new PointerByReference();
|
|
int cnt = Shell32.INSTANCE.ExtractIconEx(fullExeFile, index, iconsLargeRef, iconsSmallRef, new WinDef.UINT(1)).intValue();
|
|
if (cnt == 0) {
|
|
return null;
|
|
}
|
|
Pointer iconsLarge = iconsLargeRef.getPointer();
|
|
Pointer iconsSmall = iconsSmallRef.getPointer();
|
|
|
|
WinDef.HICON icon;
|
|
if (large) {
|
|
icon = new WinDef.HICON(iconsLarge.getPointer(0));
|
|
} else {
|
|
icon = new WinDef.HICON(iconsSmall.getPointer(0));
|
|
}
|
|
|
|
BufferedImage ic = iconToImage(icon);
|
|
|
|
User32.INSTANCE.DestroyIcon(icon);
|
|
return ic;
|
|
}
|
|
|
|
public static List<com.jpexs.process.Process> listProcesses() {
|
|
if (!privAdjusted) {
|
|
adjustPrivileges();
|
|
}
|
|
List<com.jpexs.process.Process> ret = new ArrayList<>();
|
|
WinNT.HANDLE hSnapShot = Kernel32.INSTANCE.CreateToolhelp32Snapshot(new WinDef.DWORD(Kernel32.TH32CS_SNAPPROCESS), new WinDef.DWORD(0));
|
|
PROCESSENTRY32 pe = new PROCESSENTRY32();
|
|
if (Kernel32.INSTANCE.Process32First(hSnapShot, pe)) {
|
|
do {
|
|
int i;
|
|
i = 0;
|
|
for (; i < pe.szExeFile.length; i++) {
|
|
if (pe.szExeFile[i] == 0) {
|
|
break;
|
|
}
|
|
}
|
|
String exeFile = new String(pe.szExeFile, 0, i);
|
|
char[] outputnames = new char[1024];
|
|
WinNT.HANDLE tempProcess = Kernel32.INSTANCE.OpenProcess(Kernel32.PROCESS_QUERY_INFORMATION, false, pe.th32ProcessID);
|
|
if (tempProcess == null) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
int rn = Psapi.INSTANCE.GetProcessImageFileNameW(tempProcess, outputnames, 1024);
|
|
if (rn == 0) {
|
|
Logger.getLogger(Win32ProcessTools.class.getName()).log(Level.SEVERE, "Can't get EXE path");
|
|
}
|
|
} catch (Exception | UnsatisfiedLinkError e) {
|
|
//ignored
|
|
}
|
|
|
|
try {
|
|
int rn = Kernel32.INSTANCE.GetProcessImageFileNameW(tempProcess, outputnames, 1024);
|
|
if (rn == 0) {
|
|
Logger.getLogger(Win32ProcessTools.class.getName()).log(Level.SEVERE, "Can't get EXE path");
|
|
}
|
|
} catch (Exception | UnsatisfiedLinkError e) {
|
|
//ignored
|
|
}
|
|
i = 0;
|
|
for (; i < outputnames.length; i++) {
|
|
if (outputnames[i] == 0) {
|
|
break;
|
|
}
|
|
}
|
|
String fullExeFile = new String(outputnames, 0, i);
|
|
fullExeFile = ntPathToWin32(fullExeFile);
|
|
ret.add(new Win32Process(fullExeFile, exeFile, getShellIcon(fullExeFile), pe.th32ProcessID));
|
|
} while (Kernel32.INSTANCE.Process32Next(hSnapShot, pe));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
private static boolean pageReadable(MEMORY_BASIC_INFORMATION mbi) {
|
|
int iUnReadable = 0;
|
|
iUnReadable |= (mbi.state.intValue() == Kernel32.MEM_FREE) ? 1 : 0;
|
|
iUnReadable |= (mbi.state.intValue() == Kernel32.MEM_RESERVE) ? 1 : 0;
|
|
iUnReadable |= (mbi.protect.intValue() & WinNT.PAGE_WRITECOPY);
|
|
iUnReadable |= (mbi.protect.intValue() & WinNT.PAGE_EXECUTE);
|
|
iUnReadable |= (mbi.protect.intValue() & WinNT.PAGE_GUARD);
|
|
iUnReadable |= (mbi.protect.intValue() & WinNT.PAGE_NOACCESS);
|
|
return iUnReadable == 0;
|
|
}
|
|
|
|
public static Map<Long, InputStream> findBytesInProcessMemory(ProgressListener progListener, WinDef.DWORD dwProcessID, byte[][] findBytesAll) {
|
|
int maxFindLen = 0;
|
|
for (int i = 0; i < findBytesAll.length; i++) {
|
|
if (findBytesAll[i].length > maxFindLen) {
|
|
maxFindLen = findBytesAll[i].length;
|
|
}
|
|
}
|
|
Map<Long, InputStream> ret = new HashMap<>();
|
|
WinNT.HANDLE hOtherProcess = Kernel32.INSTANCE.OpenProcess(Kernel32.PROCESS_VM_READ | Kernel32.PROCESS_VM_WRITE | Kernel32.PROCESS_QUERY_INFORMATION | Kernel32.PROCESS_VM_OPERATION /*for VirtualProtectEx*/, false, dwProcessID);
|
|
List<MEMORY_BASIC_INFORMATION> pages = getPageRanges(hOtherProcess);
|
|
long totalMemLen = 0;
|
|
int progress = 0;
|
|
for (int pg = 0; pg < pages.size(); pg++) {
|
|
totalMemLen += pages.get(pg).regionSize.longValue();
|
|
}
|
|
|
|
long actualPos = 0;
|
|
List<Integer> guardedPages = new ArrayList<>();
|
|
for (int pg = 0; pg < pages.size(); pg++) {
|
|
MEMORY_BASIC_INFORMATION mbi = pages.get(pg);
|
|
if (pageReadable(mbi)) {
|
|
long addr = pointerToAddress(mbi.baseAddress);
|
|
int maxsize = mbi.regionSize.intValue();
|
|
long pos = 0;
|
|
long bufSize = 1024 * 512;
|
|
do {
|
|
NativeLongByReference bytesReadRef = new NativeLongByReference();
|
|
Memory buf = new Memory(bufSize);
|
|
boolean ok = Kernel32.INSTANCE.ReadProcessMemory(hOtherProcess, new Pointer(addr + pos), buf, new NativeLong(bufSize), bytesReadRef);
|
|
if (!ok) {
|
|
break;
|
|
}
|
|
if (bytesReadRef.getValue().longValue() == 0) {
|
|
break;
|
|
}
|
|
|
|
byte[] data = buf.getByteArray(0, bytesReadRef.getValue().intValue());
|
|
|
|
byte[] prevBytes = Arrays.copyOfRange(data, data.length - maxFindLen, data.length);
|
|
byte[] dataPlusPrev = mergeArrays(prevBytes, data);
|
|
loopi:
|
|
for (int i = 0; i < dataPlusPrev.length - maxFindLen; i++) {
|
|
loopk:
|
|
for (int k = 0; k < findBytesAll.length; k++) {
|
|
if (dataPlusPrev[i] == findBytesAll[k][0]) {
|
|
for (int p = 1; p < findBytesAll[k].length; p++) {
|
|
if (dataPlusPrev[i + p] != findBytesAll[k][p]) {
|
|
continue loopk;
|
|
}
|
|
}
|
|
long dataAddr = (long) (addr + pos - prevBytes.length + i);
|
|
ret.put(dataAddr, new ProcessMemoryInputStream(pages, hOtherProcess, pg, pos - prevBytes.length + i));
|
|
}
|
|
}
|
|
|
|
}
|
|
pos += bytesReadRef.getValue().longValue();
|
|
if (progListener != null) {
|
|
int newprogress = Math.round((actualPos + pos) * 100 / totalMemLen);
|
|
if (newprogress != progress) {
|
|
progress = newprogress;
|
|
progListener.progress(progress);
|
|
}
|
|
}
|
|
if (pos + bufSize >= maxsize) {
|
|
bufSize = maxsize - pos;
|
|
}
|
|
} while (bufSize > 0);
|
|
} else if (hasGuard(mbi)) {
|
|
if (unsetGuard(hOtherProcess, mbi)) {
|
|
guardedPages.add(pg);
|
|
pg--;
|
|
continue;
|
|
}
|
|
}
|
|
actualPos += mbi.regionSize.longValue();
|
|
int newprogress = Math.round(actualPos * 100 / totalMemLen);
|
|
if (newprogress != progress) {
|
|
progress = newprogress;
|
|
progListener.progress(progress);
|
|
}
|
|
}
|
|
|
|
//Set PAGE_GUARD back again
|
|
for (int pg : guardedPages) {
|
|
setGuard(hOtherProcess, pages.get(pg));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
private static boolean hasGuard(MEMORY_BASIC_INFORMATION mbi) {
|
|
return (mbi.protect.intValue() & WinNT.PAGE_GUARD) == WinNT.PAGE_GUARD;
|
|
}
|
|
|
|
private static boolean unsetGuard(HANDLE hOtherProcess, MEMORY_BASIC_INFORMATION mbi) {
|
|
if (!hasGuard(mbi)) {
|
|
return true;
|
|
}
|
|
int oldProt = mbi.protect.intValue();
|
|
int newProt = oldProt - WinNT.PAGE_GUARD;
|
|
IntByReference oldProtRef = new IntByReference();
|
|
boolean ok = Kernel32.INSTANCE.VirtualProtectEx(hOtherProcess, new WinDef.LPVOID(pointerToAddress(mbi.baseAddress)), mbi.regionSize, newProt, oldProtRef);
|
|
if (ok) {
|
|
mbi.protect = new NativeLong(newProt);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static boolean setGuard(HANDLE hOtherProcess, MEMORY_BASIC_INFORMATION mbi) {
|
|
if (hasGuard(mbi)) {
|
|
return true;
|
|
}
|
|
int oldProt = mbi.protect.intValue();
|
|
int newProt = oldProt | WinNT.PAGE_GUARD;
|
|
IntByReference oldProtRef = new IntByReference();
|
|
boolean ok = Kernel32.INSTANCE.VirtualProtectEx(hOtherProcess, new WinDef.LPVOID(pointerToAddress(mbi.baseAddress)), mbi.regionSize, newProt, oldProtRef);
|
|
if (ok) {
|
|
mbi.protect = new NativeLong(newProt);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static boolean privAdjusted = false;
|
|
|
|
public static boolean adjustPrivileges() {
|
|
|
|
WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1);
|
|
WinNT.TOKEN_PRIVILEGES oldtp = new WinNT.TOKEN_PRIVILEGES(1);
|
|
WinNT.LUID luid = new WinNT.LUID();
|
|
WinNT.HANDLEByReference hTokenRef = new WinNT.HANDLEByReference();
|
|
if (!Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(), WinNT.TOKEN_ADJUST_PRIVILEGES | WinNT.TOKEN_QUERY, hTokenRef)) {
|
|
return false;
|
|
}
|
|
WinNT.HANDLE hToken = hTokenRef.getValue();
|
|
if (!Advapi32.INSTANCE.LookupPrivilegeValue(null, WinNT.SE_DEBUG_NAME, luid)) {
|
|
Kernel32.INSTANCE.CloseHandle(hToken);
|
|
return false;
|
|
}
|
|
|
|
tp.PrivilegeCount = new WinDef.DWORD(1);
|
|
tp.Privileges = new WinNT.LUID_AND_ATTRIBUTES[1];
|
|
tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(luid, new WinDef.DWORD(WinNT.SE_PRIVILEGE_ENABLED));
|
|
|
|
IntByReference retSize = new IntByReference(0);
|
|
if (!Advapi32.INSTANCE.AdjustTokenPrivileges(hToken, false, tp, tp.size(), oldtp, retSize)) {
|
|
Kernel32.INSTANCE.CloseHandle(hToken);
|
|
return false;
|
|
}
|
|
Kernel32.INSTANCE.CloseHandle(hToken);
|
|
privAdjusted = true;
|
|
return true;
|
|
}
|
|
|
|
private static class ProcessMemoryInputStream extends InputStream {
|
|
|
|
private final List<MEMORY_BASIC_INFORMATION> pages;
|
|
|
|
private int currentPage = 0;
|
|
|
|
private long pagePos = 0;
|
|
|
|
private static final int BUFFER_SIZE = 1024 * 512;
|
|
|
|
private byte[] buf;
|
|
|
|
private int bufPos;
|
|
|
|
private final HANDLE hOtherProcess;
|
|
|
|
public ProcessMemoryInputStream(List<MEMORY_BASIC_INFORMATION> pages, HANDLE hOtherProcess, int currentPage, long pagePos) {
|
|
this.pages = pages;
|
|
this.hOtherProcess = hOtherProcess;
|
|
this.currentPage = currentPage;
|
|
this.pagePos = pagePos;
|
|
}
|
|
|
|
private boolean readNext() throws IOException {
|
|
MEMORY_BASIC_INFORMATION mbi = pages.get(currentPage);
|
|
if (!pageReadable(mbi)) {
|
|
if (hasGuard(mbi)) {
|
|
if (unsetGuard(hOtherProcess, mbi)) {
|
|
boolean ret = readNext();
|
|
setGuard(hOtherProcess, mbi);
|
|
return ret;
|
|
}
|
|
}
|
|
if (currentPage + 1 < pages.size()) {
|
|
pagePos = 0;
|
|
currentPage++;
|
|
return readNext();
|
|
}
|
|
return false;
|
|
}
|
|
long addr = pointerToAddress(mbi.baseAddress);
|
|
int maxsize = mbi.regionSize.intValue();
|
|
NativeLongByReference bytesReadRef = new NativeLongByReference();
|
|
Memory membuf = new Memory(BUFFER_SIZE);
|
|
NativeLong bufSize = new NativeLong(BUFFER_SIZE);
|
|
if (pagePos + bufSize.longValue() > maxsize) {
|
|
bufSize.setValue(maxsize - pagePos);
|
|
}
|
|
if (bufSize.longValue() == 0) {
|
|
if (currentPage + 1 < pages.size()) {
|
|
pagePos = 0;
|
|
currentPage++;
|
|
return readNext();
|
|
}
|
|
return false;
|
|
}
|
|
boolean ok = Kernel32.INSTANCE.ReadProcessMemory(hOtherProcess, new Pointer(addr + pagePos), membuf, bufSize, bytesReadRef);
|
|
if (!ok) {
|
|
throw new IOException("Cannot read memory");
|
|
}
|
|
if (bytesReadRef.getValue().longValue() == 0) {
|
|
return readNext();
|
|
}
|
|
pagePos += bytesReadRef.getValue().longValue();
|
|
|
|
buf = membuf.getByteArray(0, bytesReadRef.getValue().intValue());
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int read() throws IOException {
|
|
if ((buf == null) || (bufPos >= buf.length)) {
|
|
if (buf != null) {
|
|
bufPos = 0;
|
|
}
|
|
if (!readNext()) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return buf[bufPos++] & 0xff;
|
|
}
|
|
}
|
|
}
|