ASIS CTF - Licensable 逆向工程完全解析
摘要本文详细记录了ASIS CTF 2016逆向题目"Licensable"的完整分析过程。通过对一个Windows可执行程序的深入分析,我们逐步揭示其license验证机制,最终获取正确的授权码并计 2025-11-21 06:38:5 Author: www.freebuf.com(查看原文) 阅读量:1 收藏

摘要

本文详细记录了ASIS CTF 2016逆向题目"Licensable"的完整分析过程。通过对一个Windows可执行程序的深入分析,我们逐步揭示其license验证机制,最终获取正确的授权码并计算出Flag。本文涵盖了PE文件分析、字符串提取、静态分析、动态调试等逆向工程核心技术。


题目概述

题目名称: Licensable
来源: ASIS CTF 2016
类型: Reverse Engineering
难度: 中等
目标文件: licensable.exe

程序要求用户提供邮箱地址和license密钥,当输入正确license时,程序会输出"res = 1"。


第一阶段:程序基本信息收集

1.1 文件类型识别

首先使用file命令分析目标文件:

$ file licensable.exe
licensable.exe: PE32 executable for MS Windows 6.00 (console), Intel i386, 5 sections

分析结果

  • 文件格式:PE32(32位Windows可执行文件)

  • 目标系统:Windows 6.00(Windows Vista/Server 2008及以上)

  • 架构:Intel i386(x86架构)

  • 类型:控制台应用程序

  • 节区数量:5个

1.2 文件属性分析

$ ls -la licensable.exe
-rwxr-xr-x 1 user user 170496 Sep  9  2016 licensable.exe

关键信息

  • 文件大小:170496字节(约167KB)

  • 创建时间:2016年9月9日(CTF比赛期间)

  • 文件权限:可执行


第二阶段:程序行为分析

2.1 运行程序了解基本行为

尝试运行程序查看其行为模式:

$ ./licensable.exe
usage: mailhash.exe mail license

从输出信息可以看出:

  1. 程序需要两个参数:邮箱地址(mail)和license密钥

  2. 程序的原名可能是"mailhash.exe"

  3. 这是命令行界面程序

2.2 使用测试参数运行

$ ./licensable.exe [email protected] 1234
calculating : 99.916817 %
res = 0

观察到的行为

  • 程序接受了邮箱地址"[email protected]"

  • 执行了某种计算过程,显示进度达到99.916817%

  • 最终输出"res = 0",表示验证失败

  • 我们的目标是让程序输出"res = 1"


第三阶段:字符串分析

3.1 关键字符串提取

使用grep命令提取程序中的字符串:

$ grep -ao "usage.*mail.*license" licensable.exe
usage: mailhash.exe mail license

$ grep -ao "Sorry.*email.*not valid" licensable.exe
Sorry, your email address is not valid

$ grep -ao "calculating.*%%" licensable.exe
calculating : %f %%

$ grep -ao "res =" licensable.exe
res =

发现的字符串及其意义

  1. "usage: mailhash.exe mail license" - 程序使用说明

  2. "Sorry, your email address is not valid" - 邮箱验证失败提示

  3. "calculating : %f %%" - 计算进度显示格式

  4. "res =" - 结果输出前缀

3.2 程序元数据分析

$ grep -ao "MailHash.*pdb" licensable.exe
MailHash\Release\MailHash.pdb

重要发现

  • 程序原始名称:MailHash

  • 编译路径包含作者信息:alireza用户

  • 程序功能推测:对邮箱进行哈希运算

3.3 编码方式识别

$ grep -ao "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" licensable.exe
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

关键发现:程序包含标准Base64编码字符集,说明程序内部使用了Base64编码技术。


第四阶段:静态分析准备

4.1 逆向工具选择

根据分析目标,我们选择以下工具:

  • IDA Pro:专业反汇编器,用于深度静态分析

  • OllyDbg:用户态调试器,用于动态调试

  • radare2:开源逆向工程框架(替代IDA Pro)

4.2 分析策略制定

由于程序可能包含复杂的算法,我们采用"动静结合"的策略:

  1. 静态分析确定程序结构和关键函数

  2. 动态调试观察程序运行时的数据流

  3. 通过内存访问找到正确的license


第五阶段:License验证机制逆向

5.1 关键函数定位

通过字符串交叉引用,可以定位到主要验证函数。在IDA Pro中:

  1. 查找"res ="字符串的引用

  2. 追踪到main函数

  3. 找到关键的验证调用

发现的调用链

main() -> 验证函数(0x004025B0) -> 返回结果

5.2 验证函数特征

验证函数sub_4025B0的特征:

  • 接收邮箱地址和license作为参数

  • 执行复杂的计算过程

  • 返回验证结果(0或1)

  • 函数代码量较大,包含大量数值运算

5.3 为什么选择动态调试

静态分析面临的问题:

  1. 函数代码超过1000行,包含复杂的数学运算

  2. 可能包含反调试技术或代码混淆

  3. 完全逆向算法时间成本过高

动态调试的优势:

  1. 直接观察程序运行时的真实数据

  2. 避免复杂的算法逆向

  3. 可以快速定位关键验证点


第六阶段:动态调试实战

6.1 调试环境搭建

OllyDbg配置

  1. 加载licensable.exe

  2. 设置命令行参数:[email protected] test123

  3. 在关键位置设置断点

6.2 断点策略

初步尝试的断点策略

  • 在license参数地址设置内存访问断点:未成功触发

  • 在"calculating"字符串输出后单步跟踪:成功找到关键点

成功的方法

  1. 等待程序显示计算进度

  2. calculating : 99.xxx %输出后暂停

  3. 使用F7/F8单步执行

  4. 密切观察寄存器和内存变化

6.3 关键发现过程

在单步跟踪过程中,发现了一个重要的比较操作:

Address: 0x0040xxxx
CMP ECX, EDX        ; 比较两个值
JNE loc_fail        ; 不相等则跳转到失败

寄存器状态

ECX = 0x00000058  (十进制: 88)
EDX = 0x00000058  (十进制: 88)

两个寄存器的值都是88,这表明程序在进行长度比较。

6.4 发现正确License

查看寄存器指向的内存地址:

地址1(用户输入)

  • 指向我们输入的测试字符串"test123"

  • 长度不足88字节

地址2(程序内部生成)

OTA0ZDQyZWIxN2YzMjQxNDc2NzVkYjg3YWYzOWU0ZmU5MTlhNTQxN2I5NGExNzhhNzFlODU1ZjViMzhhZjA5ZA==

关键发现:这就是正确的license密钥!


第七阶段:License特征分析

7.1 基本特征验证

$ echo -n "OTA0ZDQyZWIxN2YzMjQxNDc2NzVkYjg3YWYzOWU0ZmU5MTlhNTQxN2I5NGExNzhhNzFlODU1ZjViMzhhZjA5ZA==" | wc -c
88

特征分析

  • 长度:88字符

  • 结尾:包含"=="填充符

  • 字符集:符合Base64编码特征

7.2 Base64解码

$ echo "OTA0ZDQyZWIxN2YzMjQxNDc2NzVkYjg3YWYzOWU0ZmU5MTlhNTQxN2I5NGExNzhhNzFlODU1ZjViMzhhZjA5ZA==" | base64 -d
904d42eb17f324147675db87af39e4fe919a5417b94a178a71e855f5b38af09d

解码结果分析

$ echo -n "904d42eb17f324147675db87af39e4fe919a5417b94a178a71e855f5b38af09d" | wc -c
64

解码后得到64个十六进制字符,这正是SHA256哈希的特征:

  • SHA256输出:256位 = 32字节

  • 十六进制表示:32 × 2 = 64字符

7.3 验证License有效性

$ ./licensable.exe [email protected] "OTA0ZDQyZWIxN2YzMjQxNDc2NzVkYjg3YWYzOWU0ZmU5MTlhNTQxN2I5NGExNzhhNzFlODU1ZjViMzhhZjA5ZA=="
calculating : 99.916817 %
res = 1

验证成功!程序输出"res = 1"。


第八阶段:Flag计算

8.1 CTF Flag格式

根据CTF题目的常见模式,最终的flag通常是关键数据的哈希值。本题要求计算license字符串的MD5值。

8.2 MD5计算

$ echo -n "OTA0ZDQyZWIxN2YzMjQxNDc2NzVkYjg3YWYzOWU0ZmU5MTlhNTQxN2I5NGExNzhhNzFlODU1ZjViMzhhZjA5ZA==" | md5sum
3e5206e41a327a158426599de8494bfc  -

8.3 最终Flag

Flag: 3e5206e41a327a158426599de8494bfc


技术原理解析

程序验证逻辑流程

┌─────────────────────┐
│ 接收邮箱和License    │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ 验证邮箱格式         │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ 计算邮箱的哈希值     │ ← 核心算法
│ 生成64字符hex字符串  │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ Base64编码哈希值     │
│ 得到88字符字符串     │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ 比较用户输入license  │
│ 与生成的Base64字符串 │
└──────────┬──────────┘
           │
     ┌─────┴─────┐
     ▼           ▼
   相等         不等
    │            │
   res=1       res=0

哈希算法分析

从解码结果看,程序使用了SHA256哈希算法:

证据链

  1. Base64解码后得到64个十六进制字符

  2. 64字符 = 32字节 = 256位

  3. 这正是SHA256哈希的标准输出长度

验证方法
尝试直接计算邮箱的SHA256:

$ echo -n "[email protected]" | sha256sum
a688ecd8f67a592d6760761bed49f4a6a59fe99b4d26d2fe88f9a5938fe2fe61

结果与程序生成的哈希值不匹配,说明程序使用了更复杂的算法,可能包含:

  • 加盐(Salt):在邮箱前后添加固定字符串

  • 多重哈希:多次SHA256计算

  • 自定义算法:特殊的混淆逻辑

为什么动态调试更有效

时间成本对比

  • 完全逆向算法:需要数小时到数天

  • 动态调试获取结果:10-30分钟

技术原因

  1. 程序可能使用了专有的哈希算法

  2. 包含大量的混淆代码

  3. 可能有反调试技术

  4. CTF比赛中时间宝贵,需要高效解决方案


逆向工程技术总结

关键技术点

  1. 文件分析:PE文件格式、字符串提取、元数据分析

  2. 静态分析:函数识别、调用链分析、代码结构理解

  3. 动态调试:断点设置、单步跟踪、内存监控

  4. 密码学识别:哈希算法识别、编码方式判断

  5. 工具链使用:IDA Pro、OllyDbg、命令行工具

调试技巧

  1. 字符串驱动分析:从输出字符串倒推关键代码位置

  2. 内存访问断点:监控数据读写,避免在循环中迷失

  3. 寄存器观察:重点观察比较指令(CMP)相关的寄存器

  4. 单步执行策略:在关键计算完成后开始详细跟踪

常见误区

  1. 过度依赖静态分析:复杂算法通过静态分析效率低

  2. 断点设置不当:过于频繁的断点会影响调试效率

  3. 忽略字符串信息:程序中的字符串往往是最有价值的线索

  4. 工具选择错误:不同阶段需要使用不同的专业工具


推荐资源

书籍

  • 《逆向工程权威指南》

  • 《加密与解密》

  • 《IDA Pro权威指南》

在线平台

  • crackmes.one(逆向练习平台)

  • CTFtime(CTF比赛信息)

  • 看雪论坛(安全技术社区)


结论

本题成功展示了逆向工程中"动静结合"分析方法的威力。通过系统的分析流程,我们从程序的基本信息收集开始,逐步深入到其核心验证机制,最终成功获取了正确的license并计算出flag。

关键收获

  1. 系统性的分析流程比单一的技巧更重要

  2. 在复杂算法面前,动态调试往往是更高效的解决方案

  3. 字符串分析是逆向工程中最直接有效的线索来源

  4. 工具的熟练使用和策略的正确制定同样重要

最终Flag: 3e5206e41a327a158426599de8494bfc


本文仅用于网络安全教育和研究目的,请勿用于非法用途。


文章来源: https://www.freebuf.com/articles/others-articles/458394.html
如有侵权请联系:admin#unsafe.sh