首页
社区
课程
招聘
[原创]KCTF2025 day9 wp
发表于: 2025-9-2 10:10 2779

[原创]KCTF2025 day9 wp

2025-9-2 10:10
2779

DIE查出来一个Enigma Virtual Box壳, 直接放弃静态分析, 通过附加调试的方式进行动态分析

输入SN前在IDA挂起线程, 然后输入后步出到用户领空为止:

QQ_1756776323922

查看RAX可以看到刚刚输入的SN字符串, 同时可以观察出程序使用的库底层储存字符串的逻辑:

QQ_1756776499071

程序先对Name进行了简单的hash, 最终结果存放在v8:

QQ_1756776603933

当输入的是公开序列号对应的Name时v8为55, 输入KCTF时v8为27

第一次用到SN在main+12B, 观察处理完的结果, 看到了大量重复的9, 结合序列号的格式, 大概率是{digit}{count}l的格式, 只是最后的l被省略, 而这里处理完的字符串因为太长是用类似链表的方式储存的, 偏移8, 10h, 18h的成员分别代表当前段, 上一段, 当前段的长度:

QQ_1756777070979

下一次对SN的处理在main+276, 同时还用到了上面Name的hash, 它被以十进制字符串的形式储存起来了:

QQ_1756777504285

通过硬件断点跟踪数据流发现它和SN用空格拼接起来了:

QQ_1756777620479

步出至用户领空, 发现这个拼接的字符串上面还有一个路径字符串:

QQ_1756777745414

QQ_1756777886003

结合上面用空格拼接的字符串, 很有可能是当作命令行参数传给了这个释放出来的PE

找到这个PE, 发现是一个python打包程序, 解包反编译后得到以下py代码:

和上面的想法差不多, 通过命令行参数进行了一个除法, 得到的是十进制字符串, 但是有3个命令行参数, 找到最后拼接的作为精度的参数:

QQ_1756778121548

实际上到这一步就不用分析下面的程序的, 因为程序给出了能通过校验的55 / N1的N1, 对应到KCTF的27, 只需要算出27 / N2 = 27 / (N1 * 27 / 55) = 55 / N1的N2即为正确答案:

struct str
{
  void *nop;
  _DWORD len;
  _WORD s[];
};
struct str
{
  void *nop;
  _DWORD len;
  _WORD s[];
};
from decimal import Decimal, getcontext
import os
import sys
 
def reciprocal(m, n, prec):
    getcontext().prec = int(prec)
    result = Decimal(m) / Decimal(n)
    return result
 
def main(arg1, arg2, arg3):
    sys.set_int_max_str_digits(int(arg3))
    reciprocal_value = reciprocal(arg1, arg2, arg3)
    print(reciprocal_value)
if __name__ == '__main__':
    arg1 = sys.argv[1]
    arg2 = sys.argv[2]
    arg3 = sys.argv[3]
    main(arg1, arg2, arg3)
from decimal import Decimal, getcontext
import os
import sys
 
def reciprocal(m, n, prec):
    getcontext().prec = int(prec)
    result = Decimal(m) / Decimal(n)
    return result
 
def main(arg1, arg2, arg3):

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回