1

我正在使用 JNA 调用 user32.dll 和 kernel32.dll 的方法。到目前为止,它工作正常。我遇到了一些问题,我知道我必须调用这个方法。

void SendCommandToConsole( char* Cmd )
{
    DWORD dwCall = 0x004C1030;
    __asm
    {
        push Cmd;
        push 0;
        call dwCall;
    }
}

SendCommandToConsole ( "rp 2000" );

但我什至不明白它是什么?这个 __asm 在做什么?

如果我使用的标签不正确,请添加适当的标签。:)

编辑 按照建议添加了 .Net 和 C# 标签。上面的代码是 C# 或 .NET,可能有这种语言知识的人可以告诉我们它实际上是什么,以及我们如何在 java 中做到这一点。

4

6 回答 6

5

只是为了展示幕后发生的事情:

你的来电:

SendCommandToConsole(“rp 2000”);

正在使用 (char* Cmd) 类型的参数调用函数 (SendCommandToConsole)。

在上述情况下,(char* Cmd) 等同于“rp 2000”的字符串 (sic)。

现在幕后发生的事情是高级语言(在您的示例中为 Java)需要告诉低级语言如何用他们理解的语言解释它们的指令。

所以拿上面的例子(“我想调用函数“SendCommandToConsole”,字符串参数为“rp 2000”),意味着我们需要与低级语言进行通信:

  • “uppity-ups 希望我们运行命令”。“哦,对了,哪一个?”
  • “他们告诉我‘SendCommandToConsole’”
  • “哦,那个家伙?他住在下面的地址‘0x004C1030’。”
  • “哦,你知道那哥们的地址吗?你能把这个自大要送的包裹送到吗?”
  • “当然可以,但他只接受特定顺序的包裹,而且只接收特定类型的包裹。”
  • “没问题,我这里有他们的清单……让我们看看它是否符合这家伙的要求。”

“首先,那个地址的家伙只想知道两件事,他们必须有条不紊:

  • 你要我做什么,
  • 我应该向谁报告结果?”

“好吧,这很容易”

我会断言我想让他做什么:

  • “命令”
  • 现在我将断言我希望他向谁报告结果:“没有人 (0)”

好吧,我给他打电话……你可以继续你的一天了。

(因为是“无效”的回报,也就是说你不关心交易的结果)

于 2012-04-26T07:20:40.803 回答
2

这意味着后面有一个汇编代码块。

dwCall 是指向带有一个参数的汇编过程的指针 -> 指向堆栈上以零结尾的字节数组的指针。为了正确调用它,您必须将指针压入堆栈,您只能通过汇编程序来执行此操作。

于 2012-04-10T04:35:25.090 回答
2

在 JNA 中,您可以使用Function.getFunction(Pointer)来获取可用于控制对特定地址的调用的对象。

Function dwCall = Function.getFunction(new Pointer(0x12345678));
String CMD = "SomeCommand";
Integer ARG = new Integer(0);
dwCall.invoke(void.class, new Object[CMD, ARG]);

假设函数使用 C 调用约定,上面的代码可以工作。最终,您可能希望动态查找函数地址而不是对其进行硬编码,并且您可能希望使用 JNA 回调而不是直接调用 Function 对象,但上面的代码提供了您所要求的基本功能for(你应该改写你原来的问题;你不想执行汇编代码,你想在给定的地址调用一个函数)。

使用 JNA 回调映射将允许您更自然地调用函数。

// Use StdCallCallback if the function called uses stdcall rather than cdecl
public class MyCallback extends Callback {
    void invoke(String cmd, int arg);
}

Pointer addr = new Pointer(0x1235678);
MyCallback cb = (MyCallback)CallbackReference.getCallback(MyCallback.class, addr);
cb.invoke("SomeCommand", 0);

请注意,这两个示例都假定您已经使用 JNA 加载了相关的 DLL,通常是通过Native.loadLibrary().

另请注意,签名实际上可能是void dwCall(int arg, String cmd); cdecl 和 stdcall 约定从右到左将参数推送到堆栈上,目前我的想法还不够清晰,无法正确映射...

于 2012-04-30T15:42:20.003 回答
1

没有 Java 等价物,Java 不允许这种低级控制。您需要将 C 代码编译为 DLL 并使用 JNA/JNI 调用它。

编辑1:以上仅适用于一般的汇编代码。有关使用 JNA 在地址处调用 stdcall 或 cdecl 函数的信息,请参阅 techmage 的回复。

__asm 块允许您在 C 源文件中使用汇编。汇编代码调用地址为 0x004C1030 的函数(可能是任何函数),通过指针和零作为参数传递字符串。

直接调用地址是个坏主意。除非您非常了解程序和操作系统的底层内部结构,否则您可能不会得到您期望的结果。调用它很可能会使您的程序崩溃。

于 2012-04-30T15:11:49.733 回答
0

你为什么不只是调用SendCommandToConsole()函数?该函数所做的是进行 Windows 系统调用,您不应该编写执行此操作的函数,您应该调用执行此操作的函数。

于 2012-04-25T23:24:19.633 回答
0

我想真正的问题是“rp 2000”是做什么的?如果它使用参数 2000 运行 rp.exe,那么您可以使用 java.lang.Runtime 来做同样的事情。如果我们知道它做了什么,那么在 java 中可能会有一些东西可以做到这一点。

于 2012-04-28T20:30:46.160 回答