无忧启动论坛

标题: 一个可以直接调用任意dll导出函数的微型js引擎 [打印本页]

作者: CodeHz    时间: 2020-11-1 15:41
标题: 一个可以直接调用任意dll导出函数的微型js引擎
总所周知,windows命令行工具有很多地方不够完善,而很多功能在dll中(win32 api)被实现,但是你没法轻易的在脚本/批处理中调用
最坑的是需要跨多个脚本,一会batch,一会vbs,过一会又要powershell(必须承认pwsh还是很强的,但是我相信大家不会为了一点小功能去开pwsh的)
当然有人可能会提rundll32,不过它只能适用于特定形式导出函数(极少数),仍然有相当数量的函数是没法这样调用的。。
当然我们可以专门整一个软件去实现这些缺失的功能,这对于正经的大项目,这个方法是合适的,但是对于短平快的脚本来说,这就有点大炮打蚊子的意思了(另一个原因是体积大了,不需要的功能太多了,而需要的可能也不一定覆盖完,毕竟每个人需求是不一样的)。


这就是我做这个工具的原因
简单来说就是整了一个c编译器到js解释器里去。
但是方便之处在于它不是只能编译到文件然后执行(但也可以生成exe dll),
而是允许直接在内存中运行,甚至可以在js中直接调用导出的函数(当然,对参数及返回类型有一定的限定,windows api要包装一层),
只要架构相同,就可以直接加载对应dll里的函数(c++的类除外,这个要折腾就复杂了)。

举个简单的栗子,这里用最基础的MessageBoxW举例(请不要使用A系列函数,有乱码的问题)
  1. // 先导入编译器类
  2. import { Compiler } from "builtin:c";
  3. // 然后初始化编译器类
  4. const compiler = new Compiler("memory");
  5. // 链接到user32以使用MessageBoxW函数
  6. compiler.link("user32");
  7. // 下面就插入一段c片段以包装这个函数(主要是调用约定的问题)
  8. // 一定要用String.raw``这样的形式包裹代码,不然里面的转义会破坏解析器
  9. compiler.compile(String.raw`
  10. // 记得启用 UNICODE 支持,由于技术限制,不支持 ANSI 文本字面量(特指中文),虽然这里没有用到
  11. #define UNICODE
  12. // 加上这个以加快编译
  13. #define WIN32_LEAN_AND_MEAN
  14. // 然后就要导入 windows.h 头文件,这个已经附带在包里了,不需要额外准备
  15. #include <windows.h>
  16. // 喜闻乐见的声明函数 PCWSTR 表示宽字符串
  17. void msgbox(PCWSTR text) {
  18.   // 然后调用 windows api
  19.   MessageBox(NULL, text, L"来自 js 的弹框", 0);
  20. }
  21. `);
  22. // 接着把里面的函数重定位出来
  23. const obj = compiler.relocate({
  24.   // 具体规则看 github 页面说明
  25.   msgbox: "w"
  26. });
  27. // import.meta.url 表示文件的url,
  28. // 另外有 import.meta.main 数组可以拿到调用参数(非入口文件是拿不到的,所以还能用来区分)
  29. obj.msgbox(`地址 ${import.meta.url}`);
复制代码
(js文件需要用utf-8编码保存,所以没法使用ANSI编码的文本字面量)
如果代码中存在错误,将会在运行时产生异常(然后会终止运行),通常不要捕获这个异常,直接让它退出是正确的。


下载地址在 https://github.com/codehz/tjs/releases (linux版本是实验性支持,问题很多,请不要用)
这里有更多代码示例 https://github.com/codehz/tjs-experiment 包括如何使用第三方dll和头文件,设定dll加载路径等,这里就不一一列出


作者: kkocdko    时间: 2020-11-1 16:35
我之前玩过node的原生绑定,现在有quickjs体积缩小不少,还是有点意思的。
作者: kkocdko    时间: 2020-11-1 16:37
诶,用zig写的?好新奇。
作者: CodeHz    时间: 2020-11-1 16:50
kkocdko 发表于 2020-11-1 16:35
我之前玩过node的原生绑定,现在有quickjs体积缩小不少,还是有点意思的。

但是node提供了很多基础功能((
不过还是有点和windows水土不服,以及作为一次性脚本的启动速度过慢问题
作者: wuyouaaa    时间: 2020-11-1 19:17
node.js 可以用 https://www.npmjs.com/package/ffi-napi
作者: Bluebells    时间: 2020-11-1 20:19
winapiexec
https://rammichael.com/winapiexec

calldll
http://www.ltr-data.se/opencode.html
http://www.ltr-data.se/files/calldll.zip
http://www.ltr-data.se/files/win64/calldll64.zip

RundllEx
忘记出处了, 直接提供: RundllEx.zip (72.47 KB, 下载次数: 10)
PS: 非原文件, 略微汉化了下

作者: CodeHz    时间: 2020-11-1 21:03
Bluebells 发表于 2020-11-1 20:19
winapiexec
https://rammichael.com/winapiexec

嗯,这些是很不错,能在不少场景解决问题,但是和我这个还是有点区别的,
考虑到有以下几个问题:
1. 部分api需要上下文,比如句柄,也就是说需要连续的一串调用才能实现功能,而显然句柄脱离的进程上下文是没有意义的(最简单的,列一个目录就需要一个FindFirstFileExW连续的FindNextFileExW配合最后FindClose完成)
2. 有些系统api需要使用复杂的结构体,比如NtQuerySystemInformation这类,显然也是很难在参数上编码结构体的。。
3. 回调函数,显然不可能把函数编码到参数里
作者: job111job    时间: 2020-11-6 16:27
支持原创




欢迎光临 无忧启动论坛 (http://bbs.wuyou.net/) Powered by Discuz! X3.3