Project1

标题: 抽象语法树提取/加载 [打印本页]

作者: SixRC    时间: 2021-1-9 01:30
标题: 抽象语法树提取/加载
本帖最后由 SixRC 于 2021-1-9 03:53 编辑

虽然本来确实不想写了
但还是来了

简介:
   ruby1.8执行代码的方式是分析代码->生成语法树->执行语法树 (1.9之后也会构建语法树 但是在执行前会生成字节码 目测这样)
这个脚本可以预先提取语法树 然后加载执行 即省去了代码处理的过程  即消去了明文代码
   代码依旧可以通过语法树进行还原 只要有耐心
当然 加上混淆会更好 不过暂时不想写了 手动混淆吧

正文:

仅适用于RGSS103J
ast.zip (254.2 KB, 下载次数: 13, 售价: 1 星屑)
解压到游戏目录
提取:
RUBY 代码复制
  1. dump_filename = "scripts.ast"
  2. inf = ""
  3. c = 0
  4. for i in $RGSS_SCRIPTS
  5.   c += 1
  6.   next if c == 1
  7.   df = i[2]
  8.   inf += Zlib::Inflate.inflate(df)
  9. end
  10. dll = Win32API.new("kernel32","LoadLibraryA","p","l").call("RGSS103J")
  11. dump = Win32API.new("dump","dump","lp","v")
  12. Win32API.new("dump","init","l","v").call(dll)
  13. dump.call(inf.__id__*2, dump_filename)
  14. exit

插到所有脚本最上面
然后运行游戏就会在目录下生成提取好的语法树
这里 init 用于初始化ruby内部函数信息
dump形式为 void dump(int str, char* fn)
str是要提取的代码 fn保存文件名 可以自己根据需要改

加载与运行:
RUBY 代码复制
  1. dump_filename = "scripts.ast"
  2. dll = Win32API.new("kernel32","LoadLibraryA","p","l").call("RGSS103J")
  3. load = Win32API.new("load","eval","pl","v")
  4. Win32API.new("load","init","l","v").call(dll)
  5. raw = open(dump_filename,"rb"){|i|i.sysread(File.size(dump_filename))}
  6. load.call(raw, raw.size)

这里 eval形式为 void eval(char* raw, unsigned len) 效果是构建并运行
raw为提取的二进制流 len为其长度
可以自己根据需要改
(比方marshal dump二进制流塞到data/然后默认加密打包)

发布时可以删掉 dump.dll 和所有其余代码了  不要忘记备份代码

假如提取或构建时出现错误 请提供尽可能短的可复现代码以及出错信息 便于查错
但不保证修复

   通过提取语法树 消去原代码 在一定程度上可以认为ruby代码是安全的
基于此 在代码里进行各种检测游戏/加密资源的过程也可以认为是安全的
这是写这个脚本的本意
作者: lisliz    时间: 2021-1-9 10:26
本帖最后由 lisliz 于 2021-1-9 10:38 编辑

js里也有类似的技术,V8的snapshot。

看来像js和ruby的常规模式都是这样【分析代码->生成语法树->字节码->执行】

但js的V8引擎还会在运行时尝试把热点代码编译成【特定于CPU架构的本地代码(机器码)】,让代码跑得更快。
此外js里还有还有AOT模式,就是代码一加载就预先编译成特定于CPU架构的本地代码(机器码)的模式。

即为【分析代码->机器码->执行】,因为V8引擎有这种强大的特点,我个人倒是觉得js的运行效率比ruby更快。


例如下面一段代码在js里就是AOT模式。

JAVASCRIPT 代码复制
  1. function PhysicsASM(stdlib, foreign, heap) {
  2.         "use asm";
  3.         var HEAP = new stdlib.Float64Array(heap);
  4.         function vectorProduct(x1, y1, x2, y2) {
  5.                 x1 = +x1; y1 = +y1; x2 = +x2; y2 = +y2;
  6.                 return +(+(x1 * y2) - +(x2 * y1));
  7.         }
  8.         return {
  9.                 vectorProduct:vectorProduct
  10.         }
  11. }


运行游戏,打印这个函数,你会发现函数体已经变成了[ native code ],已经被AOT模式编译成机器码。





欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1