Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >EmmyLua Attach Debugger浅析

EmmyLua Attach Debugger浅析

作者头像
fangfang
发布于 2021-10-29 07:00:01
发布于 2021-10-29 07:00:01
3.2K0
举报
文章被收录于专栏:方方的杂货铺方方的杂货铺

导语

最近一段时间做的工作主要是为引擎提供Lua的IDE,包括编辑智能提示和调试部分。

 一开始想的方案是用类似BabeLua的方式, 基于VSSDK去构建IDE。

这么选择的原因主要是基于两个:

1. 业余自己尝试基于Scintilla.Net, 和CodeProject上开源的一个C# 版的LuaInterpreter搭建过一个简单的LuaIDE, 花的时间很长, 效果么...问题比较多就是了, 图找不到了,黑历史之一...翻到一张存货, 贴一下

2. 我们目前的编辑器部分主要是用C#搭建, 选基于C#的BabeLua不会引入新的语言。

3. BabeLua本身是基于VS的, 很多体验可以跟原来的VS C++编码调试保持一致。

提到了BabeLua, 就顺带简单介绍一下BabeLua的构成了:

BabeLua本身使用Irony作为LUA->AST的生成工具, Irony本身是一个泛用途的语法分析工具, 所以其实原来BabeLua提取的Lua信息并不多, 针对编辑来说, 能够提供的辅助信息和检查相对来说也就会比较弱了。 我们最初的想法是先用MoonSharp替换掉Irony, 提供更好的AST生成, 有更多的信息, 这样就可以做更复杂的Checker和相关的操作了。

这部分是组里孙总做的,孙总的动作还是相当快的(^_^), 大概花了一天时间就做完了,其实也能说明, VS + VSSDK, 确实是一种不错的选择, IDE整体成型还是很快的。 实际尝试结果晒图一张:

当然,因为通过并不复杂的尝试,EmmyLua挂我们自己引擎的脚本比预想中简单, 在修了一轮Bug之后, 就可以有模有样的跑起来了, 加上EmmyLua本身功能完备非常多, 这条VSSDK的线就这样暂停了。。。

所以其实入坑EmmyLua, 纯属偶然, 也能说明几个Lua IDE对比, EmmyLua的开发完成度应该是最高的, 代码组织也比较良好, 上手也很快。 下文回归正题介绍EmmyLua Attach Debugger的实现。

EmmyLua Attach Debugger概述

EmmyLua的Attach Debugger部分脱胎于Decoda, 不过作者阿唐本身也对原来的代码做了大量的调整, 比如原来的Decoda其实是只支持32bit程序的, 也只兼容当时的lua和luajit. EmmyLua整合了libpe, 可以很好的提取32位和64位应用程序下需要hook 的lua api的地址. 针对Lua5.2和5.3也做了很多改动(存在一些小问题, 处理起来并不麻烦, 后文会作简单介绍的).

EmmyLua的Attach Debugger由两部分组成, 一部分是JavaKotlin代码, 另外一部分是C++代码.

AttachDebugger Java和Kotlin代码

代码结构如下图所示:

value文件夹: 是用来描述Hook的App中发送过来的各种Lua数据类型信息的.

vfs:是Attach模式额外多出来的功能, hook后可以监控到不在Source文件夹中的脚本(比如直接用loadstring方式加载的脚本等), 所以会存在一个vfs用来表达仅在内存中的那部分脚本. 其他像LuaAttachDebugProcess: 是用来实现IDEA的Lua调试功能的, 与Debug Session交互相关的逻辑入口基本都在此处.

其他: 本文重点讲述C++部分, 所以此处不详细展开了, 有兴趣的可以自行翻阅EmmyLua的源码.

AttachDebugger C++部分代码

C++部分代码的工程位于: IntelliJ-EmmyLua\debugger\attach\windows\attach.sln.

工程结构如下图所示:

先分别简单介绍一下各工程的作用:

1. EasyHookDll.dll: 用于对Windows应用程序进行Hook的库.

2. emmy.arch.exe: 主要是两个功能, 进程architecture检测和系统进程列表获取.

3. emmy.backend.dll: Attach Debugger的主体部分, 真正加载到调试的目标程序进程空间进行调试交互的Dll.

4. emmy.tool.exe: 这个EXE主要的作用是拿到进程ID后, 根据进程的architecture对要调试的目标应用注入对应32bit/64bit的emmy.backend.dll.

5. Lua.exe: 这个应该是个废弃掉的lua.exe, 目前EmmyLua插件侧有比较完备的工作于JVM上的Lua VM, 很多功能直接在JVM上那个Lua虚拟机上实现即可, 不需要再绕到C++这边跑一遍再传回结果.

6. Shared.lib: 一些工具类的封装, 比如封装系统临界区的CriticalSection类, 封装命名管道的Channel类, 以及真正用来获取Windows系统中进程的 GetProcesses()函数等.

以上就是Attach Debugger的C++组成部分概述. (EmmyLua 目前的Remote Debugger使用的是MobDebug, 被调试的程序运行MobDebug, 然后将结果序列化为可执行的Lua字符串, 再回到EmmyLua本身的虚拟机上执行提取结果, 所以完全不依赖C++这部分的所有代码).

感觉EasyHookDll.dll, Shared.lib, Lua.exe, emmy.arch.exe功能相对单一, 结构也比较简单, 就不详细展开了, 重点聊一下emmy.backend.dll, emmy.tool.exe这两个, 对于一个典型的Attach Debugger的实现, 具备一定的参考性.

大致的工作流程

7. IDEA Plugin创建 emmy.tool.exe的进程, 并以命令行的方式传入目标调试程序的进程ID等必要信息

8. 在emmy.tool.exe执行过程中尝试根据传入的进程ID打开对应目标调试进程.

9. 尝试为目标调试进程加载emmy.backend.dll

10. 尝试在目标调试进程中开启一个独立的线程执行Backend的初始化

11. 在Backend初始化线程中尝试根据进程信息查找所有需要的Lua Api函数

12. 查找Lua Api函数成功后尝试Hook需要的Lua Api(像lua_load()等函数都需要hook)

13. 通知emmy.tool.exe Backend初始化成功

14. 通知EmmyLua Plugin调试环境初始化成功

15. 向目标调试进程发送调试命令

16. Backend处理调试命令后返回执行结果到EmmyLua Plugin

还有一种直接启动EXE附加调试的方式, 流程基本一致, 除了最开始的地方是直接发送目标EXE路径, 工作目录, 命令行参数到emmy.tool.exe, emmy.tool.exe创建目标进程后直接执行后续的从3开始的步骤, 以及当EmmyLua的DebugSession结束时, 会一起结束目标进程外(此时的emmy.tool.exe不会在附加成功后退出, 而是会执行一个loop, 等待EmmyLua的退出通知, 收到退出通知后会直接结束创建的目标进程并结束自己)

Backend代码浅析

具体的代码我就不展开了, 重点通过自己挂接我们自己的客户端程序和编辑器的过程碰到的问题以及解决问题的方法简单说一下Backend的实现.

刚开始的时候我看了一下官方Git仓库上的Issues, 阿唐有说Attach Debugger这部分是从Decoda迭代过来的, 存在一些问题, 已经是打算重构的状态了.

翻开源码工程看了一下, 代码结构还挺清晰的, 当时同事正在尝试替换BabeLua的AST生成模块, 反正调试这块不管用什么方式, 总是有需要的. 所以就开始尝试用EmmyLua去挂接我们自己的客户端了. 然后发现能改得动, 就一直尝试往下推进了. 中间EmmyLua的作者阿唐也提供了很多信息, 有效的加速了我挂接我们自己的EXE正常调试Lua的过程.

问题1: 尝试用EmmyLua直接启动客户端, 然后就没有然后了(没有收到检测Lua Api成功的消息)

通过跟踪定位, 发现LuaDll.cpp中的 LoadSymbolsRecursively()没有正常的工作, 一开始我以为我们引擎的lua api没有正确导出, 后面通过检测引擎本身的代码, 以及使用dependency.exe进行查看, 确认我们的Core.dll中有导出所有的lua5.3的api符号. 最后通过跟踪调试, 大概定位到了是libpe这一块工作异常, 具体原因不明, 只知道并没有能正确搜索到Core.dll中导出的lua api接口. 先列出大概的坐标代码:

进而发现libpe也是一个Git上开源的库, 就直接到对应的Git仓库拉取了它的最新代码, 通过BeyondCompare对比, 发现EmmyLua中用的libpe只是简单处理了64位兼容, 并没有作出其他修改. 这部分因为基本能定位是libpe没有正确解析出对应的导出函数, 所以就转而直接拿libpe源码直接去分析我们的Core.dll了, 然后发现libpe的示例也不能正确输出Core.dll的函数,

定位后发现, 是peParseExportTable()的时候, 指定的maximum 过小导致的, 直接改成如下图所示:

所有函数都正常输出到命令行了, 总共有5000多个导出函数, lua api位于尾部, 重新Check EmmyLua的代码, 发现在EmmyLua的LoadSymbolsRecursively()函数中, peParseExportTable()指定的最大导出符号数过小(1000), 所以肯定是没有办法检查到Core.dll中位于5000多序号的Lua Api的:

修改上图中的导出符号个数到0xff, 重新挂接客户端, 发现已经能正确检测到Lua并输出了相应的日志, 但是, 程序马上就崩溃了(黑人问号脸)...

简单调试后发现依然是崩在前一个Bug出现的地方, 然后导致崩溃的dll是 avcodec-57.dll(ffmpeg的dll), 直接用libpe的preview.exe运行avcodec-57.dll, 分析了老半天后, 发现问题是出在libpe.cpp中, peParseExportTable()的时候, 实际上应用程序输出的是导出函数的个数, 但连带着导出的字符串一起并入了最大导出个数中, 导致一些dll会直接发生崩溃(实际处理的函数个数超出EXE包含的):

作如下修改后, 代码合并到emmy.backend.dll, 挂调试启动EXE, 经过漫长的loading, 断点成功了!

问题2: 挂断点进入调试状态后, 监控栈上的变量, 弹出如下对话框, 程序又崩了...

定位后发现是emmylua中对5.2+的Lua版本, 依然在使用lua_upvalueindex(4)的方式在尝试获取global表的索引, 这种方式lua5.2+已经不在支持, 所以会出现push到栈顶进行操作的global表为nil, 后续stack的操作不是正常进行的, 外层的stack top 验证失败, 直接贴出修改的部分如下:

问题3: 直接调试启动客户端是能够正常挂上去的, 然后改成启动客户端后再Attach, 各种报错或者直接崩溃

其中有个错误刚好群友贴了, 借图用一下, 报错如下图所示:

这个问题查的时间相对久, 有点莫名奇妙, 最后还是从直接调试启动和附加启动的差异找到了一点线索: 直接调试启动, 速度比较慢, 客户端加载资源的时候其实Lua虚拟机基本是不工作的, 而Attach的情况, 客户端已经进到Login界面, Lua虚拟机是一直在持续工作的. 对照代码仔细分析了一下, 发现EmmyLua的Lua Api查找, Hook Lua Api的时候, 并没有提供任何保护, 也就是Hook注册之后, 如果目标应用程序的Lua虚拟机正在工作, 那么马上就会触发emmylua本身注册过去的lua hook, 但问题是这个时候下框所示的那部分状态重置的代码可能还没有被执行, 那么Hook那边执行的时候所有状态都还是没有初始化的, 也就导致了各种奇怪的崩溃, 先放图:

标1的地方是后面添加的保护, 与下图所示Hook处的保护是对应的, 防止Hook过程正在进行的时候(Decoda原来的设计应该是允许单一App同时存在多个版本的Lua的, 所以扫描到一种Lua Api之后并不会马上停止整个扫描过程, 而是继续扫描剩余的Dll和EXE中是否存在其他版本的Lua):

至此客户端部分的Lua 直接启动或者Attach调试均能正常工作, Detach后再重新附加目标进程, 也可以正确的触发调试.

问题4: 编辑器的Lua 调试支持

原本以为编辑器应该是顺理成章的支持了, 结果内网试了一下, 挂上去就崩溃, 最后发现是基于.net framework的EXE按照目前emmylua提供的机制, 不能正确的检测应用程序的architecture, 比如我们的情况是64位的应用, 检测出来却是32位的, 所以尝试给64位的应用附加了32位的emmy.backend.dll, 这肯定是会导致报错退出的. 用了一个相对临时的方案Fix了. 这里不再细说了.

问题5: 如果当前EmmyLua的IDE是自动断点到运行报错的脚本处, Detach目标程序, 会导致目标程序崩溃

这个问题是因为EmmyLua调试退出的时候破坏了Lua Stack上的内容, Hook的错误处理函数退出后, 调用原来的Lua错误处理函数, 一般会将栈顶(-1位置)的变量当成字符串来处理, 因为栈顶并不是字符串, 会直接触发崩溃, 简单把报错的message push回栈顶, 程序即可正常工作了.

总结

这篇文章是在尝试完EmmyLua的RemoteDebug后写的, 由于各方面的原因, 最后选择了用C++重新实现MobDebug的App端, 这部分内容会在下一篇<<EmmyLua Mobdebug浅析>>中再去展开, 实现RemoteDebug的C++版加深了我对Attach版细节的理解, 这两个调试器EmmyLua的作者阿唐应该已经打算重构了, 对于我而言, 在处理问题的过程中熟悉了一个Lua Attach调试器以及Remote调试器工作的方方面面, 还是有所收获的, 一个好的Attach调试器对于客户端工作的开展还进比较有助益的, 也希望EmmyLua的调试可以越做越好, 抛出整个处理过程, 就当是抛砖引玉了.

PS: 以上修改源码已经PR到EmmyLua官方Git上, 参考链接:

https://github.com/EmmyLua/IntelliJ-EmmyLua/pull/243

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C#脚本实践(五): 调试器
以前用过lua, 调试时很痛苦. 当然现在已经有比较成熟的调试器了, 比如decoda 在没有调试器之前都是怎么调试的呢? printf打印到控制台之类的输出窗口. 如果做了热更新的话可以边改边看 输
逍遥剑客
2018/05/23
9980
.NET/C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
一般来说,大家在需要监听全局消息的时候会考虑 SetWindowsHookEx 这个 API。或者需要处理一些非自己编写的窗口的消息循环的时候,也会考虑使用它。
walterlv
2023/10/22
1.6K0
.NET/C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
钩子原理及实例:实现键盘钩子截获密码
钩子能截获系统并得理发送给其它应用程序的消息,能完成一般程序无法完成的功能。Windows系统是建立在事件驱动的机制上的,也就是整个系统都是通过消息的传递来实现的。而钩子是Windows系统中非常重要的系统接口,用它可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。钩子的种类很多,每种钩子可以截获并处理相应的消息,如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。
全栈程序员站长
2022/06/27
2.1K0
钩子原理及实例:实现键盘钩子截获密码
利用DLL Proxying技术隐匿执行恶意代码
我们通过DLL 侧载可以实现隐匿执行恶意代码,但存在一个问题,那就是需要去找到被劫持的DLL文件的导出函数以及确定哪个导出函数在DLL 被加载时会被执行。这个问题可以通过 DLLProxying技术去解决,该技术在保证自己想要执行的代码被执行的情况下简化这一查找的步骤又能保持原有二进制文件正常的调用被劫持 DLL 文件里的导出函数,进一步实现隐匿化。
Ms08067安全实验室
2025/03/03
990
利用DLL Proxying技术隐匿执行恶意代码
白加黑保姆教程通杀主流杀软
简单来说就是通过白名单的exe运行来去加载恶意的dll达到shellcode加载的目的,那么就需要对exe加载的dll进行了解。
亿人安全
2024/05/22
7360
白加黑保姆教程通杀主流杀软
在射击游戏中防止玩家作弊
本篇继续阅读学习《有趣的二进制:软件安全与逆向分析》,本章是在射击游戏中防止玩家作弊,学习内存转储和如何保护软件不被破解
红客突击队
2022/09/29
7730
在射击游戏中防止玩家作弊
DLL劫持详解
DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件。
红队蓝军
2022/05/17
2.1K0
DLL劫持详解
EmmyLua MobDebug浅析
EmmyLua的remote debug是通过 mobdebug来实现的, 本文先对Mobdebug本身的实现做一下介绍, 再展开后续的部分.
fangfang
2021/10/29
1.4K0
EmmyLua MobDebug浅析
白加黑免杀制作(详细)
最近被微步的一篇文章吸引了,里面讲到银狐通过自解压白 exe + 黑 dll 执行截取主线程添加自启动,发现 dll 与普通的免杀有很大的不同,决定自己尝试一下,虽然我之前没有做过白加黑免杀,感觉应该不会太难,但是当我真正尝试的时候才发现很多问题,如:
Creaper
2023/11/20
8.1K2
白加黑免杀制作(详细)
VS2015 远程调试:Remote Debugger
  使用VS远程调试器Remote Debugger,我们可以调试部署在不同机器上的应用程序,如桌面应用程序和Asp.Net应用程序。
战神伽罗
2019/07/24
2.8K0
VS2015 远程调试:Remote Debugger
总结到目前为止发现的所有EDR绕过方法
所有关注攻击性安全社区的人都会在过去两年中一次又一次地遇到Userland hooking, Syscalls, P/Invoke/D-Invoke等术语。我自己也遇到了一些我不完全理解的博客文章和工具。我有时觉得我需要从头开始积累知识。由于我在很多情况下不需要这些“新”技术,我把这些课题的研究推迟了几个月。
黑伞安全
2021/02/26
9.5K0
总结到目前为止发现的所有EDR绕过方法
vulntarget-g
这里就按拓朴图中的来修改VMnet的配置,并恢复快照至初始状态,若还有问题可以跟着搭建文档来一遍
MssnHarvey
2023/02/06
7760
C/C++ 远程线程DLL注入
64位进程,就得用64位的EXE来CreateRemoteThread, 另外DLL也应该是64位
王瑞MVP
2022/12/28
6140
让你 nodejs 水平暴增的 debugger 技巧
我觉得学习 nodejs 除了要掌握基础的 api、常用的一些包外,最重要的能力是学会使用 debugger。因为当流程复杂的时候,断点调试能够帮你更好的理清逻辑,有 bug 的时候也能更快的定位问题。
刘小夕
2021/07/19
1.1K0
让你 nodejs 水平暴增的 debugger 技巧
JDK自带工具之概览
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/toc.html
IT小马哥
2020/03/18
6660
服务器开发语言比较
以下比较的基础都是基于一种编程语言+一定的第三方或者自己编写的网络库和底层进行的,Skynet稍微特殊,但总体比较合适放到比较中来 C# 开发效率:Windows下可以通过VisualStudio进行开发,其他平台可以使用MonoDevelop,非常方便 运行效率:JIT的性能优化比较到位,能适应90%性能环境 部署便捷性:可以通过交叉编译生成其他平台的可执行文件,通过mono运行可执行文件 调试便捷性:VisualStudio和MonoDevelop调试均很方便, 还可远程调试 上手度:对C系语言熟悉的几
李海彬
2018/03/21
1.9K0
服务器开发语言比较
通过挂钩 LSASS 中的函数来提取本地哈希
这是我前段时间在 Gitbook 上发布的分析的转贴。MsvpPasswordValidate基本上,当您在 Windows 上以任何本地用户身份进行身份验证时,LSASS 通过NtlmShared.dll 导出的函数检查该用户的 NT 哈希与提供的密码的 NT 哈希。如果你钩住MsvpPasswordValidate你可以在不接触 SAM 的情况下提取这个散列。当然,要在 LSASS 中挂钩此功能,您需要管理员权限。从技术上讲,它也适用于至少登录过一次机器的域用户,但生成的哈希不是 NT 哈希,而是 MSCACHEv2 哈希。
Khan安全团队
2022/03/28
1.3K0
内网渗透-导出HASH的多种方式
在内网渗透中当我们得到一台高权限用户的身份时,就可以抓取到当前机器上的各类密码。虽然任务要求是导出域hash的方式,但在内网渗透中,获取当前机器的hash也有可能获取到域用户的hash,因此这里也分析一下如何获取当前机器的明文密码。
亿人安全
2024/08/13
5380
内网渗透-导出HASH的多种方式
ring3层恶意代码实例汇总
之前一期我们学习了 IAT 的基本结构,相信大家对 C++ 有了一个基本的认识,这一期放点干货,我把 ring3 层恶意代码常用的编程技术给大家整理了一下,所有代码都经过我亲手调试并打上了非常详细的注释供大家学习,如下图:
信安之路
2018/08/08
9420
ring3层恶意代码实例汇总
实战 | DLL劫持思路和研究
DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件。
HACK学习
2021/11/02
2.4K0
相关推荐
C#脚本实践(五): 调试器
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档