cgctf RE HomuraVM

本文深入探讨了HomuraVM的逆向解析过程,通过分析其复杂指令集和反调试机制,逐步揭示了其内部工作原理。从初步的IDA导入到最终的逻辑解析,文章详细记录了每一步的挑战与解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

咕王也不知道今天能不能做出来,从分值上来看,这个是第二男的题目呢

ELF,拖进IDA

我听见雨滴落在青青草地,这一堆指令是还没解析过么,还是什么的,比前两个VM难多了

最终的判断模块

还算OK,起始的v43和最终的v6开始的字符串我们可以知道

函数存在两个比较可疑的,8DC和8AA,8DC中还潜套了另外的8AA

8AA里就是一大堆getpid

8DC最后有个JUMPOUT,跳转的地方是解释语句

逻辑还OK,先把索引v1找出来,然后基地址是1048,找出对应语句

这个语句吓到我了,萌新表示没见过这样的

然后参考了一个大佬的做法,豁然开朗:https://sh1rker.github.io/2018/09/29/cgctf-homuraVM/

我先输了一些字符然后gdb看一下流程,但是可能是因为反调试的原因,我调试到一半会炸掉

唉,不能偷懒猜猜猜了,只能直接看汇编了,之前那些并行的白框框没个看一下

随便分析各大概

可以看见一个好消息,[]对应构成一个循环,{}对应构成一个循环,每个字符代表一个指令,而不是不同组合的,那就不计较清楚了,具体分析出来的指令,链接里有

我个人觉得最好的方法还是把反调试patch掉,然后动态猜猜猜

processing……

 

### 逆向工程(RE)题目的设计方法与技巧 在 CTF(Capture The Flag)竞赛中,逆向工程(Reverse Engineering, RE)类题目是极具挑战性和趣味性的部分。这类题目要求参赛者分析给定的二进制文件或程序,理解其内部逻辑,并从中提取隐藏的 Flag。为了设计出高质量且有趣的逆向工程题目,可以从以下几个方面入手。 #### 1. **选择合适的编程语言和平台** 逆向工程题目的设计首先需要考虑目标受众的技术水平以及比赛的整体难度分布。常见的逆向题目可以基于不同的编程语言和平台,例如: - **C/C++:** 使用标准的编译器生成 ELF 或 PE 文件,适合考察选手对汇编语言、函数调用约定的理解。 - **Python:** 通过打包工具(如 PyInstaller)将脚本转换为可执行文件,增加逆向难度。 - **Java/.NET:** 这些语言的字节码相对容易反编译,但可以通过混淆工具(如 ProGuard、Obfuscator)提高分析难度。 - **VB6/C#:** 对于初学者来说,这些语言的 GUI 程序可以提供直观的交互界面,同时也可以嵌入复杂的逻辑判断。 #### 2. **引入多层保护机制** 为了增加解题难度,可以在程序中加入多种保护机制,迫使选手深入分析代码结构。例如: - **加壳(Packing):** 使用 UPX、VMProtect 等工具对可执行文件进行压缩或虚拟化,使反汇编结果难以直接阅读。 - **混淆控制流:** 插入虚假的跳转指令或冗余的条件判断,干扰静态分析工具的流程图生成。 - **自修改代码:** 在运行时动态修改自身代码段,使得调试器无法准确还原原始逻辑。 - **时间检测与反调试:** 添加检查调试器存在的代码片段,或者限制程序在特定时间内完成计算,否则触发错误分支 [^4]。 #### 3. **构建复杂的数据处理逻辑** Flag 的生成或验证过程通常涉及一些算法逻辑,可以通过以下方式提升题目深度: - **加密算法实现:** 将 Flag 明文通过简单的加密算法(如 XOR、RC4、Base64 编码)进行变换后存储在内存中。 - **数学运算与约束求解:** 设计一个依赖用户输入并通过一系列数学运算生成 Flag 的程序,例如线性方程组、模幂运算等。 - **状态机与状态转移:** 构建有限状态机模型,要求选手理解状态转移规则并找到正确的输入路径才能到达输出 Flag 的状态节点。 #### 4. **利用图形界面与资源嵌入** 对于初学者友好型的题目,可以使用图形界面来引导选手逐步探索程序行为。例如: - **GUI 输入验证:** 设计一个带按钮和文本框的窗口应用程序,当用户输入特定字符串时显示 Flag。 - **资源文件嵌入:** 将 Flag 或关键数据以图片、音频等形式嵌入到程序资源中,要求选手从资源表中提取信息。 - **网络通信模拟:** 模拟服务器端与客户端之间的简单协议交互,在本地伪造响应内容以绕过远程验证逻辑。 #### 5. **结合动态链接库(DLL/so)与插件架构** 为了进一步提升题目复杂度,可以将核心逻辑拆分到多个模块中,形成模块化结构: - **DLL 加载与导出函数调用:** 主程序仅负责加载外部 DLL 并调用其中的函数,而真正关键的逻辑存在于 DLL 内部。 - **插件式架构:** 使用插件系统(如 COM 组件、ELF 动态符号绑定),让程序在运行时根据环境配置加载不同功能模块。 #### 6. **设计多层次提示与线索** 优秀的逆向题目不仅考验技术能力,还应具备良好的用户体验。因此,可以设置如下机制帮助选手逐步接近答案: - **错误提示与日志输出:** 当用户尝试非法输入时,程序可以输出带有误导性质的日志信息,引导其思考正确方向。 - **调试信息保留:** 在 Release 版本中保留少量调试符号(如函数名、变量名),有助于降低入门门槛。 - **隐藏彩蛋与 Easter Egg:** 在程序中埋藏非必要的趣味性内容,鼓励选手深入挖掘细节。 --- ### 示例代码:简单 XOR 加密 Flag 验证程序(C++) ```cpp #include <iostream> #include <string> // Encrypted flag: "CTF{Rev3rsing_1s_fun}" unsigned char encrypted_flag[] = { 0x18, 0x07, 0x1B, 0x1A, 0x0E, 0x15, 0x0D, 0x19, 0x14, 0x03, 0x11, 0x0E, 0x1C, 0x02, 0x10, 0x19, 0x12, 0x07, 0x0A, 0x18, 0x05, 0x1E, 0x13, 0x0F, 0x19, 0x1A, 0x0B, 0x1D, 0x0E, 0x15, 0x0D, 0x00 }; std::string xor_decrypt(unsigned char* data, int len) { std::string result; char key = 'K'; // Simple XOR key for (int i = 0; i < len; ++i) { result += data[i] ^ key; } return result; } int main() { std::string decrypted = xor_decrypt(encrypted_flag, sizeof(encrypted_flag)); std::cout << "Enter password: "; std::string input; std::cin >> input; if (input == "secret") { std::cout << "Flag: " << decrypted << std::endl; } else { std::cout << "Access denied." << std::endl; } return 0; } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值