有没有办法改变小提琴的工作目录?

如何解决有没有办法改变小提琴的工作目录?

我正在尝试使用 Fiddle 在 Ruby 中加载 C 共享库。

这是一个最小的例子:

require 'fiddle'
require 'fiddle/import'

module Era
  extend Fiddle::Importer

  dlload './ServerApi.so'

  extern 'int era_init_lib()'
  extern 'void era_deinit_lib()'
  extern 'int era_process_request(const char* request,char** response)'
  extern 'void era_free(char* response)'
end

Era.era_init_lib
begin
  # ...
ensure
  Era.era_deinit_lib
end

共享库加载没有问题。但是,当我调用 Era.era_init_lib 时,它会尝试加载其他库(Network.soProtobuf.so)。这些文件位于当前工作目录中(与 ServerApi.so 位于同一目录中)。

但是,当我尝试执行上面的代码时,我收到以下错误:

! Failed to load library: /home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so,error: /home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so: cannot open shared object file: No such file or directory

如果我将文件放在错误位置,说明一切正常。

我的猜测是fiddle的C工作目录与Ruby工作目录不同。我想将项目文件保留在项目中,而不是在Ruby安装目录中。

如何使用项目文件夹中的 Network.so

所有 *.so 文件均由第三方提供。我没有源代码,因此无法更改这些文件。函数签名由 documentation 提供。


Network.so 中搜索 strace 会得到以下结果:

readlink("/proc/self/exe","/home/username/.rvm/rubies/ruby-2."...,4096) = 44
openat(AT_FDCWD,"/home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so",O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
futex(0x7fcc16666d90,FUTEX_WAKE_PRIVATE,2147483647) = 0
futex(0x7fcc16b44520,2147483647) = 0
write(2,"! Failed to load library: ",26! Failed to load library: ) = 26
write(2,50/home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so) = 50
write(2,",error: ",9,error: )                = 9
write(2,109/home/username/.rvm/rubies/ruby-2.6.5/bin/Network.so: cannot open shared object file: No such file or directory) = 109
write(2,"\n",1)                       = 1

我还编写了一个 C 脚本,它执行相同的操作,当将文件放入同一目录时,该脚本运行良好。所以这可能是库的错误,我假设它检查了当前正在运行的程序的位置,然后尝试从该文件夹加载库。这可以解释作为 Ruby 脚本运行时的行为(因为它作为 Ruby 程序的一部分运行),而 C 二进制文件独立运行。


对于那些想要重新创建 (Linux) 问题的人。您可以从 here 下载必要的文件。这为您提供了 server-linux-x86_64.sh 文件。

支持的发行版有:Suse、Ubuntu、Debian、Red Hat 和 CentOS,但其他发行版也可能正常运行。

您可以运行安装程序,它会将文件放在 /opt/eset/RemoteAdministrator/Server 中。或者,假设大多数人不想安装完整的应用程序,您可以运行以下命令:

sed '1,/^# Start of TAR\.GZ file #$/d' server-linux-x86_64.sh | sed '1d' > server-linux-x86_64.tar.gz

从 .sh 文件中删除所有安装程序指令,只留下二进制 .tar.gz 数据,将其写入 server-linux-x86_64.tar.gz

将文件 ServerApi.soProtobuf.soNetwork.so 复制到您喜欢的目录中。在同一目录中创建一个 Ruby 脚本(带有问题代码)并运行该脚本。

解决方法

因为ServerApi.so会检查/proc/self/exe是否为后续所有要加载的文件的位置,而通过正常方式修改这个目标是非常困难的,所以只修改ServerApi.so本身更容易以便它使用除 proc 之外的其他东西作为源。

如果我们运行 strings ServerApi.so,我们可以验证要检查的位置是否存储在 ServerApi.so 中的字符串中:

strings ServerApi.so | grep 'proc/self/exe'
B/proc/self/exe

所以现在我们需要做的就是将此字符串修改为其他适合我们的内容。

修改字符串的最简单方法是将其替换为与原始长度完全相同的内容。这样我们就不必担心更改字符串末尾的零填充或意外更改 ServerApi.so 的总大小。

在这里我们可以看到一个合适的候选人可能是/tmp/scriptexe

/proc/self/exe
/tmp/scriptexe   <- same length

所以让我们这样做:

sed -e 's/proc\/self\/exe/tmp\/scriptexe/' ServerApi.so > ServerApi_Mod.so

现在我们可以验证更改:

strings ServerApi_Mod.so | grep scriptexe
B/tmp/scriptexe

接下来我们需要创建 /tmp/scriptexe 来实际指向我们的 Ruby 脚本:

ln -s /the/full/path/to/our/ruby/script.rb /tmp/scriptexe

然后我们修改我们的脚本:

dlload './ServerApi_Mod.so

现在我们可以正常运行了:

ruby script.rb

一切正常。

,

如果我们读取 strace 输出,我们会看到库从 /proc/self/exe 获取当前可执行位置,然后从那里搜索后续库。

/proc/self/exe 不容易修改,但通过使用指向当前目录中 Ruby 可执行文件的硬链接,我们可以诱使它指向一个新文件夹。

问题是制作硬链接需要 root。

无论如何,这里有一个独立的解决方案(请注意,它会在您第一次运行时要求输入 root 密码,以创建硬链接)。

将其放在脚本的顶部:

# Obtain path to current executable
exe = File.readlink("/proc/self/exe")

# Check if we are running the hard-liked version
if !exe.match /localruby/
  if !File.exist?('localruby')
    # Create a hard link to the current Ruby exe using sudo
    system("sudo ln #{exe} localruby")
  end

  puts "Restarting..."

  # In order to prevent infinite busy loop in case of some mishap
  sleep 1 

  # Rerun self using the hard-linked Ruby executable.
  # This will make /proc/self/exe point to the hard-link,which then
  # allows the ESET library to search for .so files in current folder.
  exec('./localruby',File.expand_path(__FILE__))
end

require 'fiddle'
require 'fiddle/import'

# ...rest of your script goes here...

无需任何额外 Ruby 代码的简单解决方案是手动创建硬链接,然后始终使用 ./localruby myscript.rb 运行脚本,而不是使用普通的 ruby myscript.rb

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-