[De1CTF2019]cplusplus
!(https://tianyu.xin/usr/uploads/2022/03/638757045.png)IDA打开main里面直接就能看到比较关键的字符串, 虽然题目叫cpp但是没看到明显的c++迹象, 整个逻辑不算长也不算短, 我们直接从判定逻辑往回看
!(https://tianyu.xin/usr/uploads/2022/03/1532598323.png)
这里可以看到一个变表, 确定Block的前五位
!(https://tianyu.xin/usr/uploads/2022/03/113363325.png)
如果前五位符合, v47符合条件高字mod低字为12, 高字除低字为3(a = b*3+12)二者之一即可(后面证明是要俩都满足, 这个条件写错了), 另外贯穿全文有一个关于时间的反调, 如果时间差太大就扬了.
emm, 看了一会没什么头绪, 把反调扬了来动调看看吧
!(https://tianyu.xin/usr/uploads/2022/03/2022107117.png)
把这几个exit都nop就好了
!(https://tianyu.xin/usr/uploads/2022/03/585213977.png)
我输入的是De1ta{1234567890}... 怎么就剩中间的了.., 不过第二次就正常了也没有深究
!(https://tianyu.xin/usr/uploads/2022/03/1200079630.png)
5910这个函数要返回false, 且这个checkvar必须是v5
checkvar和v5此时都是指向input的, 这是个恒真, 我们去看看5910
!(https://tianyu.xin/usr/uploads/2022/03/1744166863.png)
check1里出现了多次5A90这个函数, 都要返回1 这个函数里面有很多熟悉的48, 猜测跟字符转数字有关, 但是我总感觉这东西...传进去的是一样的.. 动调看看好了, 这里的第一个参数是头指针, 第二个参数是尾指针. 这要是不动调光靠肉眼看, 看一年也未必看得出来.., i不能大于0x1999,
!(https://tianyu.xin/usr/uploads/2022/03/1347079806.png)
如果是数字0,会返回一, 不然不接受一位数字, 不是数字也不接受.
!(https://tianyu.xin/usr/uploads/2022/03/1313990389.png)
本来画了一堆箭头是想解释了, 感觉整体难度不大, 就是字符转数字嘛.. 唯一要求是不能大于0x1999 = 6553, 最后结果放在第三个参数的第一个位置.
动调试一下猜得对不对, 输了个6123, 出来个13EB, 没问题
回到check1里面把这个数还给第一个参数, 然后准备进入下一个5A90(起名叫atoi了)
!(https://tianyu.xin/usr/uploads/2022/03/1088903551.png)
这个v11是一个'@', v12是数字之后的下一个字符, 可以判断这里应该是四位数接#接4位数这样. 第一次动调的时候这里\0直接. 输入的是1234@5678!
!(https://tianyu.xin/usr/uploads/2022/03/3706913540.png)
动调到第二个分隔符是#, 改成1234@5678#4321
这三个数字分别是4d2,162e,10e1, 后面可能会用得到, 分别存在了arg1的+1, +5, +9处
29B0这个函数传进来的是4d2, 这个函数里面有两个大表达式需要满足, 看看表达式变量怎么来的, 前面有几个函数实在是太复杂了, 一看就不想让我分析, 这个exit0一定不能碰, 所以如果爆破不是多值的话就没什么问题
!(https://tianyu.xin/usr/uploads/2022/03/3160871837.png)
断在这里之后发现v8直接就是4D2, 那我们爆破之即可.
```cpp
if( ((((((((v8 >> 11) ^ v8) & 0xFF3A58AD) << 7) ^ (v8 >> 11) ^ v8) & 0xFFFFDF8C) << 15) ^ ((((v8 >> 11) ^ v8) & 0xFF3A58AD) << 7) ^ (v8 >> 11) ^ v8 ^ (((((((((v8 >> 11) ^ v8) & 0xFF3A58AD) << 7) ^ (v8 >> 11) ^ v8) & 0xFFFFDF8C) << 15) ^ ((((v8 >> 11) ^ v8) & 0xFF3A58AD) << 7) ^ (v8 >> 11) ^ v8) >> 18)) != 0xD4CBCF03 )
```
真长啊... 直观点看大概就是这么个玩意
!(https://tianyu.xin/usr/uploads/2022/03/3627646631.png)
第一次在0到111没爆出来... 突然意识到我的4D2不在111范围内根本就到不了这儿, 需要在111的范围内爆破, 现在我得想个办法怎么才能把这个东西单独拿出来爆破呢...
```python
a = "eQDtW91a0qwryuLZvbXCEK8VghjklzxIOPASBNM2RsdfF56TYU34p7ioGHJcnm"
b = "De1ta"
for i in b:
print(a.index(i), end="")
#20637
```
先把第二段的弄出来了, 第三段的值和第一段有关, 暂时没法看,但是能过第一段的话, 第三段也能直接拿到, 应该比较简单吧.
我实在是没想到这东西能怎么patch或者拿出来.4400这个函数里面有一些magicnumber, 我先尝试搜了0x989680, 没有什么结果, 还有一个0x9908B0DF
!(https://tianyu.xin/usr/uploads/2022/03/3154950948.png)
这里说明了这是个梅森缠绕器算法随机数生成器
但是..我还是没能成功分析好, 最后无奈看了题解, 这里就引用一下吧, 网上大部分题解都一笔带过了, 引一个官方的算法流程
>
```
void boostFunc(unsigned short& num) {
//随机数check
//预期的num是78
if (num > 111) {
_exit(0);
}
boost::mt19937 rng(num);
rng.discard(num % 12);
//拷贝构造,保留了所有状态
boost::mt19937 rng_(rng);
rng_.discard(num / 12);
//这里相当于丢弃了num个随机结果
if (rng_() != 3570126595) {
_exit(0);
}
num -= (rng_() % 45); // 45
}
```
一个`unsigned short`传入,小于等于111,把它作为随机引擎的种子,丢弃掉`num % 12`个随机数,然后用一次随机引擎的拷贝构造
> 注意,这里拷贝构造会完全保留随机引擎的状态,而不是回归初始状态
>
> 在IDA中就表现为直接一个memcpy
接着再丢弃掉`num/12`个随机数
然后输出一个随机数要求等于`3570126595`,最后由于是引用,传入的数值被改变
---
在IDA里很难看出这么多东西, 我觉得, Chamd5说patch之后让它自己跑循环了, 我也不是很清楚怎么做到的, 这种调试方法还需学习, 如果是dll之类的能直接ctype调用就好了(
第三段低位是0x22,高位是输入, 这小学数学算一下就是114了..
所以flag是78@20637#114
晕, 这个第一段和后两段的难度完全不一样嘛, 这怎么分析..而且这代码多重指针, 真的是很难看.
吐槽完毕, 还是我太菜了. 这里还要补一句, 一开始以为是返回值不能大于0x1999, 后来发现只要最后进循环的时候不大于1999就行了, 也就是最后可能会再乘10的 Y1rannn 发表于 2022-3-25 01:50
这里还要补一句, 一开始以为是返回值不能大于0x1999, 后来发现只要最后进循环的时候不大于1999就行了, 也就 ...
我天 我看你博客我以为我怎么看东西这么模糊了啊 原来是主题特效... 技术贴一定要顶 Y1rannn 发表于 2022-3-25 01:50
这里还要补一句, 一开始以为是返回值不能大于0x1999, 后来发现只要最后进循环的时候不大于1999就行了, 也就 ...
确实,程序都是一遍遍跑,一遍遍完善的, ConMiko 发表于 2022-3-25 08:34
我天 我看你博客我以为我怎么看东西这么模糊了啊 原来是主题特效...
有hover效果, 鼠标放上透明度就变了 题主前面的图看不了了,我看不明白了55555,就是mage-20220325004403468.png开始
页:
[1]