【问题标题】:How to transmit a function to anonymous pipe WinAPI?如何将函数传输到匿名管道 WinAPI?
【发布时间】:2012-12-14 11:51:21
【问题描述】:

我需要向匿名管道写入类似double (*fun)(double) 的内容,但以下WriteFile(pipe, fun, 4, written_bytes, 0)ReadFile(read_pipe, fun, 4, written_bytes, 0) 时导致管道接收器出错。有什么方法可以做到吗?

我有个主意。我可以创建一个具有相同类型字段的结构:

struct Foo
{
    double (*f)(double);
};

然后我写WriteFile(hWritePipe_StdIN, &to_process, sizeof(Foo), &bytes, 0); 但我有问题,管道接收器永远不会结束读取数据: ReadFile(hReadPipe, &to_process, sizeof(Foo), &bytes, 0);

【问题讨论】:

  • 只是为了确定。你想发送函数本身吗?还是要调用函数并传递结果?
  • @StackedCrooked 第一个版本。我想发送函数本身。

标签: c++ winapi pipe


【解决方案1】:

它有一些问题:

首先,您应该知道函数的大小。 如果有,你只需拨打WriteFile(pipe, funcPtr, funcSize, ...) 转移即可。

其次,该函数应该只包含position-independent code,并且不要寻址任何数据。 例如。这样的功能不起作用:

double fun(double x)
{
    int arr[10000]; // implicit function call (alloca or something like this)
    printf("some");
    static int some = 1;
    return globalVal + (++some);
}

因为函数printf将有不同的地址,并且在另一个进程中不会有静态变量和字符串。
(好吧,也许您也可以传输数据,但您无法生成 PI 代码。)

因此,有了所有这些限制,您可以发送一个函数:

__declspec(naked) double fun(double x) { __asm ret }

const auto funcSize = 1;
WriteFile(pipe, &fun, funcSize, ...);

【讨论】:

  • 收到后如何使用此功能?我需要像 fun = cos 这样的东西来工作。
【解决方案2】:

在本机代码中,您不能将函数(代码)本身发送到相同的进程或不同的进程。 (您可以尝试像@Abyx 建议的那样进行低级黑客攻击,但它严重限制了代码可以执行的功能,并且可能会让您不得不在汇编程序中手动编写所有代码。)

你也不能将函数的地址发送给另一个进程,因为每个进程都有自己独立的地址空间;在另一个进程中,该地址将包含不同的数据。

解决方案是创建一个共享库(最好是动态的),其中包含所有可能以这种方式发送的函数。为每个函数分配一些标签(例如编号或名称),让 DLL 维护标签和地址之间的映射。然后改为发送标签。

【讨论】:

  • +1 使用 DLL 并发送符号名称(Cave mangling!)是一个巧妙的想法。
【解决方案3】:

你在这里想要达到什么目的?您真的要自己编写 函数 吗?为什么?这不是您在 C++ 中可以轻松完成的事情,例如因为函数的大小没有明确定义。

您可能应该写 data,即 fun() 返回的数字:

const double value = fun(input);
DWORD numberOfBytesWritten;
WriteFile(pipe, &value, sizeof value, &numberOfBytesWritten, NULL);

您当然应该添加代码来检查输出。请注意,像这样编写二进制数据可能很脆弱。

【讨论】:

  • 我真的需要自己写函数,因为这个函数会用到fun(input)这样的子进程中。我在父进程中没有任何输入来写入数据。
【解决方案4】:

由于您使用的是 WinAPI,因此发送函数的本机方式是通过 COM。特别是,将函数公开为 COM 对象上的方法,获取 COM 名字对象,然后发送该名字对象。名字对象可以被序列化并通过管道发送。另一方可以反​​序列化名字对象并访问您的对象。

在水下,这是通过在 COM Running Object Table 中查找对象来实现的

【讨论】:

    【解决方案5】:

    看到这在 C++ 中过于复杂且容易出错(并且仅适用于非常有限的一组函数),我建议您为此使用脚本语言。除了已经提到的之外,指令缓存和 DEP 是您必须考虑的另外两件事。

    真的。将函数作为脚本传输,然后在另一端运行。让自己免于痛苦。

    Angelscript 的外观和感觉几乎像 C++,因此它可能是一个可能的候选者。

    现在,如果您因为需要脚本无法做到的事情而反对这一点,请知道:在这种情况下,C++ 也无法做到。

    除了上面提到的 PIC 代码问题 (@Abyx) 以及您无法安全或可移植地知道函数的大小这一事实之外,您可以想象通过管道发送并以有意义的方式执行的唯一 C++ 函数是严格的 const职能。在这里, const 的意思是例如GCC 的 __attribute__((const)),而不是 C++ 的 const 关键字。

    也就是说,任何这样的函数可能不会检查除其参数之外的任何值,并且除了返回值之外没有任何影响。原因很明显:不同的进程存在于不同的地址空间中,因此您引用的任何内容都毫无意义。你改变的任何东西都是没有意义的。
    现在,这正是脚本可以以安全、直接且可靠的方式执行的操作。考虑到您已经通过管道发送代码,开销可以忽略不计。

    【讨论】:

      猜你喜欢
      • 2019-08-09
      • 1970-01-01
      • 2014-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多