首页
社区
课程
招聘
[转帖]titan - VMProtect devirtualizer by archercreat
发表于: 2023-11-7 07:49 4309

[转帖]titan - VMProtect devirtualizer by archercreat

2023-11-7 07:49
4309

titan - VMProtect devirtualizer

I'm releasing my VMProtect devirtualizer for others to research, learn, and improve. This project started in 2018 as a hobby project and was rewritten at least 4 times. During my research, I've met with awesome people, made friends, and learned a lot. The tool is for educational purposes only, it works for vmprotect < 3.8 but produces less than ideal output.


https://github.com/archercreat/titan


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2023-11-7 07:52 被linhanshi编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (5)
雪    币: 3070
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark
2023-11-7 17:38
1
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3

titan - VMProtect devirtualizer


I'm releasing my VMProtect devirtualizer for others to research, learn, and improve. This project started in 2018 as a hobby project and was rewritten at least 4 times. During my research, I've met with awesome
people, made friends, and learned a lot.

How does it work?


The tool uses Triton for emulation, symbolic execution, and lifting. The easiest way to match VM handlers is to match them on the Triton AST level. The tool symbolizes vip and vsp registers and propagates memory loads and stores. Almost every handler ends with the store (to the stack, vm register or memory). We take Triton AST of the value that is being stored and match against known patterns:

1
2
3
4
5
6
7
8
9
10
11
// Match [vsp] + [vsp].
//
static bool match_add(const triton::ast::SharedAbstractNode& ast)
{
    if (ast->getType() == triton::ast::EXTRACT_NODE)
    {
        return match_add(ast->getChildren()[2]->getChildren()[1]);
    }
    return ast->getType() == triton::ast::BVADD_NODE
        && is_variable(ast->getChildren()[1], variable::vsp_fetch);
}

No matter how obfuscated handlers are, it is possible to match them with a single x86 instruction! Once the handler is identified, it is lifted into a basic block. Once the basic block is terminated, the partial control-flow graph is computed and the RIP register is sliced, giving the address of the next basic block. The process repeats until no new basic blocks are found.
Every basic block is lifted into separate LLVM function. The process of building control-flow graph comes down chaining calls to basic block functions in the right order.
The tool has few custom LLVM passes like no-alias and memory coalescing passes. The only pass that is left to implement is flag synthesis pass which will give the cleanest LLVM bitcode.

Usage

The tool requires 3 arguments:

  • Path to vmprotect intrinsics file
  • Path to virtualized binary
  • Virtual address of vm entry point
1
2
3
4
5
./build/titan
titan: for the -i option: must be specified at least once!
titan: for the -b option: must be specified at least once!
titan: for the -e option: must be specified at least once!
./build/titan -i intrinsics/vmprotect64.ll -b samples/loop_hash.0x140103FF4.exe -e 0x140103FF4

Acknowledgements

Matteo Favaro and Vlad Malagar for answering my sometimes dumb questions, helping to find bugs in llvm bitcode, giving motivation and new ideas.

翻譯

titan - VMProtect devirtualizer


 我将我的 VMP 反虚拟化工具公开,供其他人学习、研究、改进。(作者已经删库)这个项目始于 2018 年,这是我的一个业余爱好项目,其中至少经历了 4 次重写。在研究 vmp 的过程当中,我遇到了贵人,结交了朋友,学到了很多。(哈,看样子技术不是人生的全部。不过,技术是结交朋友的桥梁)

工作原理


 该工具使用 Triton 进行仿真、符号执行和将基本的汇编代码提升至 AST 形式。匹配 VM_HANDLE 的方式是通过在 Triton AST 层进行匹配。该工具将 VIP 和 VSP 等虚拟机寄存器符号化,并传播内存加载和存储。几乎每个 VM_HANDLE 都以存储的方式结束。(将 VM_HANDLE 的执行结果保存到Stack、VREG、Memory)。

 我们通过 Triton AST 对当前正在存储的值进行处理,并通过特定的模式进行匹配。

1
2
3
4
5
6
7
8
9
10
11
// Match [vsp] + [vsp].
//
static bool match_add(const triton::ast::SharedAbstractNode& ast)
{
    if (ast->getType() == triton::ast::EXTRACT_NODE)
    {
        return match_add(ast->getChildren()[2]->getChildren()[1]);
    }
    return ast->getType() == triton::ast::BVADD_NODE
        && is_variable(ast->getChildren()[1], variable::vsp_fetch);
}

 无论程序如何混淆 VM_HANDLE,都会有一条 X86 指令与之匹配!(这意味着即使源程序是 64 位平台的,还原后的结果也是 x86 平台下的指令)一旦识别出 VM_HANDLE,就将它移入基本块当中。一旦基本块结束,就会计算部分的控制流并切分 RIP 寄存器,给出下一个基本块的地址。这一过程会不断重复,直到找不到新的基本块为止。(哈,看样子它并不是图灵完全的)
 每个基本块都将被提升为独立的 LLVM function。构建控制流图的过程,就是按正确顺序链式调用基本模块函数的过程。
 这个工具有一些自定义的 LLVM Pass,例如 no-aliasmemory coalescing 俩个 pass,唯一要做的工作就是将代码转换为 pass,它将提供最简洁的 LLVM bitcode

使用教程

 这个工具需要提供三个参数:

  • VMProtect 内联文件(看了下项目文件,编译 intrinsics 文件夹中的项目即可)
  • 虚拟化后的 PE 文件
  • 虚拟机入口地址
1
2
3
4
5
./build/titan
titan: for the -i option: must be specified at least once!
titan: for the -b option: must be specified at least once!
titan: for the -e option: must be specified at least once!
./build/titan -i intrinsics/vmprotect64.ll -b samples/loop_hash.0x140103FF4.exe -e 0x140103FF4

致谢

感谢 Matteo Favaro 与 Vlad Malagar 俩位师傅回答我那有时很蠢的问题, 帮我找到了 LLVM bitcode 的 BUG,给予了我新的动力和想法。

最后于 2024-8-30 03:10 被zZhouQing编辑 ,原因:
上传的附件:
2024-8-30 03:02
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4

作者删库了,来补个档。
论坛的 MarkDown 编辑内容一长,会出现卡顿。如果需要翻译文献,最好使用特定的工具编写文档。(如:VsCode、Typeora、Word等)编写好后,将内容复制过来发布。(被卡傻眼了,这么点内容,竟然会花半小时时间)

最后于 2024-8-30 03:13 被zZhouQing编辑 ,原因:
2024-8-30 03:04
0
雪    币: 596
活跃值: (958)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
有编译好的嘛?大佬
2024-8-30 08:31
0
雪    币: 8764
活跃值: (5240)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
Mark
2024-8-30 09:07
0
游客
登录 | 注册 方可回帖
返回
//