函数/方法与Java的C / C ++暴露

问题描述 投票:0回答:1

Minecraft Modding的世界让我对Java和C / C ++库之间机制的差异感到好奇,以允许从外部调用库中的方法/函数。

我的理解是Minecraft Modding的出现是由于能够通过Java反编译/反射,以便对可以从库调用的类和方法进行反向工程。我相信Java类规范包含了很多关于类结构的元数据,允许代码以非预期的方式使用。

有一些混淆工具试图使反向工程Java变得更难,但总体来说似乎很难防止。

我不知道C / C ++的知识深度,知道在那里可以做到的程度。

对于C / C ++,代码是提前编译的。最终结果是特定于该平台的机器代码的汇编。 C / C ++具有外部化函数的概念,因此可以从库外部或可执行文件中公开它们。有些图书馆也有入口点。

通常,当连接到外部函数时,会有一个头文件列出可从库中编码的函数。

我假设需要一种机制将公开的函数映射到库/可执行机器代码程序集中的地址,以便函数调用在正确的位置进行。

通常,将函数调用与地址连接起来是链接器的工作。链接器仍然需要知道在哪里找到这些函数。

这让我想知道是否可以从根本上调用非导出函数。如果是这样,这需要能够找到他们的地址并理解他们的参数格式吗?

用C / C ++中的函数调用,据我所知,它通常是通过将参数分配给简单函数的寄存器或更复杂函数的参数数组来完成的。

我不知道在本机代码中调用非公共API的做法是否常见,或者这样做的固有困难是否使本机代码非常安全。

java c++ c reverse-engineering libraries
1个回答
1
投票

首先,有一些工具(具有不同的质量和功能)可以将编译后的机器代码反向工程回原始语言[或其他语言]。这样做的最大问题是诸如C和C ++之类的语言,结构中成员的名称没有名称,并且经常变得“平坦”,所以最初是这样的:

 struct user
 {
    std::string name;
    int age;
    int score;
 };

会变成:

 struct s0
 {
     char *f0;
     char *f1;
     int f2;
     int f3;
 };

[当然注意std::string可以用十几种不同的方式实现,而“两个指针”只是一个合理的变体]

当然,如果有一个描述库如何工作的头文件,您可以使用其中的数据结构来获得更好的类型信息。同样,如果文件中有调试信息,它可以用来以更好的方式形成数据结构和变量名。但是,想要将这些内容保密的人(通常)不会发送带有调试符号的代码,并且只发布调用公共功能的实际必要部分。

但是如果您了解这些是如何使用的[或者阅读一些例如显示“用户”的代码,您可以找出名称,年龄和分数是多少。

了解什么是数组以及什么是单独的字段也很困难。它是这样的:

 struct
 {
    int x, y, z;
 };

要么

 int arr[3];

几年前,我开始耐心纸牌游戏(类似于“纸牌”)。为此,我需要一种在屏幕上显示卡片的方法。所以我想“好吧,有一个用于Windows上现有的Solitaire,我打赌我可以弄清楚如何使用它”,事实上,我做到了。我可以按照自己的意愿画出俱乐部女王或两个黑桃。我从未完成过实际的游戏部分,但我确实设法从非公共共享库中加载了绘图功能。无论如何都不是火箭科学(有些人为具有数千个功能和非常复杂的数据结构的商业游戏做到这一点 - 这有两个或三个你需要调用的功能),但我没有花太多时间在它上面如果我没记错的话,几个小时,想出一个“有效”的想法。

但是对于问题的第二部分,插件接口(例如Photoshop的过滤器插件或视频编辑器中的过渡)通常被实现为“共享库”(又名“动态链接库”,DLL)。

操作系统中有一些功能可以将共享库加载到内存中,并按名称查询功能。这些函数的接口(通常)是预定义的,因此头文件中的函数指针原型可用于形成实际调用。

只要共享库的编译器和应用程序代码使用相同的ABI(应用程序二进制接口),当涉及到如何从调用者向函数传递参数时,所有这些都应该解决 - 它不像编译器那样随机使用它所喜欢的任何寄存器,参数以明确定义的顺序传递,以及哪个寄存器用于给定处理器体系结构的ABI规范定义的内容。 [如果你必须知道数据结构的内容会变得更加复杂,并且有不同版本的这种结构 - 例如某人有一个包含两个指针(开始和结束)的std::string,无论出于何种原因,设计被更改为一个指针和一个长度 - 应用程序代码和共享库都需要使用相同版本的std::string进行编译,否则会发生错误的事情!]

可以调用非公共API函数,但是通过调用查询按名称查找函数它们是不可发现的 - 你必须找出其他方法 - 例如通过知道“此函数是132字节的从函数XYZ“,当然,你也没有函数原型。

当然,Java Bytecode可以在许多不同的处理器体系结构中移植,增加了复杂性,机器代码仅适用于一组定义的处理器 - x86代码适用于Intel和AMD处理器(可能还有其他几种),ARM处理器代码使用ARM指令集开发的芯片工作,等等。您必须编译给定进程的C或C ++代码。

© www.soinside.com 2019 - 2024. All rights reserved.