【问题标题】:Why does Kernel32 OpenProcess function return null?为什么 Kernel32 OpenProcess 函数返回 null?
【发布时间】:2020-10-04 14:01:18
【问题描述】:

我正在尝试制作一个使用 JNA 读取另一个(非 Java 和 32 位)应用程序内存的应用程序。到目前为止,我知道如何找到模块的 process IDbase address。在读取内存之前,我需要打开进程,OpenProcess 函数只返回 null。另外,我使用的是 Windows 10。

    // process id (pid) is known

    final int PROCESS_VM_READ=0x0010;
    final int PROCESS_QUERY_INFORMATION=0x0400;
      
    WinNT.HANDLE processHandle = Kernel32.INSTANCE.OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, true, pid);

如何获取进程句柄?

【问题讨论】:

  • Kernel32.GetLastError() 或更好的ntdll.RtlGetLastNtStatus() 告诉你原因。最常见的原因 - 访问被拒绝和无效的进程 ID
  • 好的,我检查了这个,但访问被拒绝。那我如何获得此访问权限?
  • 如果您有调试权限 - 启用它。这对你的情况一定有帮助

标签: java winapi jna handle


【解决方案1】:

您需要为当前进程启用debug privilege,以便查询当前用户以外的任何人拥有的进程的信息。该链接显示了 C 中的代码,但您可以将该代码移植到 JNA。

这是程序启动时的一次性方法调用。

我是这样做的(向@RbMm 表示改进):

/**
 * Enables debug privileges for this process, required for OpenProcess() to get
 * processes other than the current user
 *
 * @return {@code true} if debug privileges were successfully enabled.
 */
private static boolean enableDebugPrivilege() {
    HANDLEByReference hToken = new HANDLEByReference();
    boolean success = Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(),
            WinNT.TOKEN_QUERY | WinNT.TOKEN_ADJUST_PRIVILEGES, hToken);
    if (!success) {
        LOG.error("OpenProcessToken failed. Error: {}", Native.getLastError());
        return false;
    }
    try {
        WinNT.LUID luid = new WinNT.LUID();
        success = Advapi32.INSTANCE.LookupPrivilegeValue(null, WinNT.SE_DEBUG_NAME, luid);
        if (!success) {
            LOG.error("LookupPrivilegeValue failed. Error: {}", Native.getLastError());
            return false;
        }
        WinNT.TOKEN_PRIVILEGES tkp = new WinNT.TOKEN_PRIVILEGES(1);
        tkp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(luid, new DWORD(WinNT.SE_PRIVILEGE_ENABLED));
        success = Advapi32.INSTANCE.AdjustTokenPrivileges(hToken.getValue(), false, tkp, 0, null, null);
        int err = Native.getLastError();
        if (!success) {
            LOG.error("AdjustTokenPrivileges failed. Error: {}", err);
            return false;
        } else if (err == WinError.ERROR_NOT_ALL_ASSIGNED) {
            LOG.debug("Debug privileges not enabled.");
            return false;
        }
    } finally {
        Kernel32.INSTANCE.CloseHandle(hToken.getValue());
    }
    return true;
}

【讨论】:

  • 代码结尾错误。 AdjustTokenPrivileges 即使失败也返回 true。糟糕的设计API。需要随时致电GetLastError() 以获取检查结果。但是更简单的是通过一次调用BOOLEAN b; RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);
  • @RbMm 感谢您的指点。我会调整的。但是,关于“AdjustTokenPrivileges 即使失败也返回 true”,这仅在部分成功的情况下才成立。但是,当设置单个特权时,这是一个不可能的结果,因此它要么完全成功,要么完全失败。我没有看到 Windows API 中记录的RtlAdjustPrivilege()。使用未记录的函数是一种糟糕的做法。
  • 但是,当设置一个单一的权限时,这是一个不可能的结果,所以它要么完全成功,要么完全失败。 - 你错了。即使您尝试设置令牌中不存在的单一特权 - 即使在这种情况下,返回码也将是 STATUS_NOT_ALL_ASSIGNED (0x106) 和 AdjustTokenPrivileges 返回 true。只有GetLastError()给你最终答复
  • 真的if (Native.getLastError() == 0)可以进行条件检查。 AdjustTokenPrivileges 的返回值可以完全忽略。总是需要致电Native.getLastError() 并检查结果。您也可以使用字符串SE_DEBUG_NAME 并将其转换为LUID (SE_DEBUG_PRIVILEGE)。尽管这个值是众所周知的并且记录在 wdm.h 中。您的代码通常可以且标准。我只是记下检查正常/失败。 RtlAdjustPrivelege 让我们通过单个 api 调用来完成这一切,但正式它没有记录
猜你喜欢
  • 2016-07-25
  • 1970-01-01
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多