题目:


IDA反编译

主函数

 1 int __cdecl main(int argc, const char **argv, const char **envp)
2 {
3 char s2[144]; // [rsp+0h] [rbp-1A0h] BYREF
4 char s1[128]; // [rsp+90h] [rbp-110h] BYREF
5 char input[136]; // [rsp+110h] [rbp-90h] BYREF
6 int key; // [rsp+198h] [rbp-8h]
7 int input_len; // [rsp+19Ch] [rbp-4h]
8
9 memset(input, 0, 0x80uLL);
10 memset(s1, 0, sizeof(s1));
11 memset(s2, 0, sizeof(s2));
12 s2[0] = 0x9C;
13 s2[1] = 0xCC;
14 s2[2] = 0x88;
15 s2[3] = 0x76;
16 s2[4] = 0xD7;
17 s2[5] = 0x89;
18 s2[6] = 0x78;
19 s2[7] = 0xEC;
20 s2[8] = 0x7C;
21 s2[9] = 0xD7;
22 s2[10] = 0x89;
23 s2[11] = 0x71;
24 s2[12] = 0xE3;
25 s2[13] = 0x6D;
26 s2[14] = 0x98;
27 s2[15] = 0x17;
28 s2[16] = 0x94;
29 s2[17] = 0xF;
30 s2[18] = 0xCA;
31 s2[19] = 0x9F;
32 s2[20] = 0x7E;
33 s2[21] = 0xD9;
34 s2[22] = 0xA0;
35 s2[23] = 0x8A;
36 s2[24] = 0x79;
37 s2[25] = 0xD1;
38 s2[26] = 0x80;
39 s2[27] = 0x77;
40 printf(&byte_400A66, s2, 18LL);
41 fgets(input, 128, stdin);
42 input_len = strlen(input);
43 if ( input[input_len - 1] == 10 )
44 input[input_len - 1] = 0;
45 key = generate_key(877);
46 encrypt((__int64)input, (__int64)s1, 2024, key);
47 if ( !memcmp(s1, s2, 128uLL) )
48 puts("success");
49 else
50 puts("fail");
51 return 0;
52 }

加密函数

 1 __int64 __fastcall encrypt(__int64 input, __int64 s1, int num2024, int key)
2 {
3 __int64 result; // rax
4 int i; // [rsp+20h] [rbp-8h]
5 int v6; // [rsp+24h] [rbp-4h]
6 unsigned int v7; // [rsp+24h] [rbp-4h]
7
8 v6 = 0;
9 for ( i = 0; i <= 127; ++i )
10 {
11 result = *(unsigned __int8 *)(i + input); // input[i]=result
12 if ( (_BYTE)result )
13 {
14 v7 = key + num2024 + v6;
15 *(_BYTE *)(i + s1) = *(_BYTE *)(i + input) + v7;// s1[i]=input[i]+v7
16 // v7是偏移量
17 result = (v7 >> 4) ^ *(unsigned __int8 *)(i + s1);// 等于没有
18 v6 = (v7 >> 4) ^ *(unsigned __int8 *)(i + s1);// v6储存的是上一个result的值
19 }
20 }
21 return result;
22 }

KEY

1 __int64 __fastcall generate_key(int a1)
2 {
3 return (unsigned int)(1540483477 * a1 + 305419896) >> 16;
4 }

输入值

s2 = [
0x9C, 0xCC, 0x88, 0x76, 0xD7, 0x89, 0x78, 0xEC,
0x7C, 0xD7, 0x89, 0x71, 0xE3, 0x6D, 0x98, 0x17,
0x94, 0x0F, 0xCA, 0x9F, 0x7E, 0xD9, 0xA0, 0x8A,
0x79, 0xD1, 0x80, 0x77
]

个人记录

获得key值——C代码

参考大佬的部分wp:2024ctfshow元旦水友赛 RE re_signin-CSDN博客

 1 #include<stdio.h>
2
3 unsigned int ge(unsigned int s) {
4 s = 1540483477 * s + 305419896;
5 return (s >> 16);
6 }
7
8 int main() {
9 unsigned int k = 877; // 为变量 k 赋一个初始值
10 unsigned int key = ge(k); // 调用 ge 函数来计算密钥 key
11 printf("%x", key); // 使用 %x 格式化字符串打印无符号整数值(十六进制)
12 return 0;
13 }

最初的代码11行用的是"%u"——打印出来的是十进制数:41041

但是参考了大佬的py代码:ctfshow 元旦水友赛部分wp | M4sh1r0の万事屋 (m4shir0.com)

大佬用的是十六进制,写解题脚本的时候也是多用0xA051这种十六进制数,就改成"%x"

关于大佬解题wp的疑惑

大佬代码

 1 key = 0xA051
2 num = 2024
3 table = []
4 cmp = [0x9C, 0xCC, 0x88, 0x76, 0xD7, 0x89, 0x78, 0xEC, 0x7C, 0xD7, 0x89, 0x71, 0xE3, 0x6D, 0x98, 0x17, 0x94, 0x0F, 0xCA, 0x9F, 0x7E, 0xD9, 0xA0, 0x8A, 0x79, 0xD1, 0x80, 0x77]
5
6 tb = 0
7 flag = []
8 for i in range(28):
9 ta = key + num + tb
10 flag.append((cmp[i] - (ta&0xff)) & 0xff)
11 tb = (ta >> 4) ^ cmp[i]
12 print(''.join(chr(i) for i in flag))

flag.append((cmp[i] - (ta&0xff)) & 0xff)——这一部分的我没看懂

ta是偏移量,加密代码里是与偏移量相加,解题脚本里面就相减,这我能理解

(ta&0xff)) & 0xff——这个我就不太理解为什么这样写

以下是关于疑问的解答(参考:C语言的整数溢出机制 - 知乎 (zhihu.com)

ta&0xff——提取了ta中的最低8位,为了获取一个有效字节值(8位)

为什么是8位?

首先这是一个无符号位char类型数对于signed char,正整数最大值为127,负整数最小值为128。unsigned char所能表示的最大值为255。

有符号整型溢出又可分为向上溢出和向下溢出。假设用k个字节表示一个整型变量, 那么这个变量可以表示的有符号整数的范围是-2^(8k-1) ~ 2^(8k-1) – 1

那么两个正整数或者两个负整数相加就有可能超过这个整型变量所能表示的范围

向上超出>2^(8k-1) – 1我们称之为向上溢出

向下超出<-2^(8k-1), 我们称之为向下溢出

无论是向上溢出还是向下溢出,绝对值都在相对于无符号整型能表示的范围内————对于signed char,如果结果为400,超出了位数表示范围,取结果的低八位

& 0xff——这个操作是为了确保结果在一个字节范围内(0到255),因为解密的结果应该是一个字节

那可以去掉吗?

GPT回答:

在这种情况下,去掉 `(ta&0xff)` 后的 `& 0xff` 是可能的,但是需要对解密结果的范围进行一些考虑。

`(ta&0xff)` 的目的是确保偏移量 `ta` 的范围在0到255之间,因为偏移量是一个字节(8位)的值。在实际应用中,这个操作可以确保解密结果在0到255之间,即一个字节的范围内。

如果你确定在加密过程中偏移量的计算不会导致超出一个字节的范围(例如,`key`、`num` 和 `tb` 的取值都在合适的范围内),那么去掉 `(ta&0xff)` 后的 `& 0xff` 是可以的。

但是,如果你不确定加密过程中的偏移量是否会超出一个字节的范围,保留 `& 0xff` 可以确保解密结果始终在合适的范围内,这样更加安全可靠。


flag

ctfshow{happy_2024_jiayou_a}

re_signin 【ctfshow_元旦水友赛】Reserve的更多相关文章

  1. 第一次线上OJ水友赛

    偶然的机会遇到了这个神奇的网站http://www.luogu.org/   巧遇今天又有小比赛果断去试试,为我的蓝桥北京之旅练练手. 苦苦的在机房刷了一下午,大概做到了6点半. 最激动的是等成绩了, ...

  2. 【题解】LFYZNoip前水题赛 T6

    垃圾出题人们在30分钟内完成了讨论,出题,命题,造数据,跑std的所有环节 luv的化学竞赛题 题目背景 luv_letters 在肝化学竞赛题,他的梦想是混个省一,但是遗憾的是他今年的省二莫名消失了 ...

  3. 0RAYS元旦招新赛

    一共有4道pwn题,题目不算难,但是挺考验调试能力的. pie 一个main函数就四次溢出... 第一次leak canary,第二次leak libc,第三次直接覆盖返回地址为one_gadgets ...

  4. 【Cocos2d-x游戏引擎开发笔记(25)】XML解析

    原创文章,转载请注明出处:http://blog.csdn.net/zhy_cheng/article/details/9128819 XML是一种非常重要的文件格式,由于C++对XML的支持非常完善 ...

  5. CQOI2019(十二省联考)游记

    CQOI2019(十二省联考)游记 Day -? 自从联赛爆炸,\(THUWC\)爆炸,\(WC\)爆炸(就没有不爆炸的)之后我已经无所畏惧... 听说是考\(4.5 h\)吗? Day -1 \(Z ...

  6. 魔兽争霸RPG游戏-军团战争-游戏经验总结

    终于要写这篇了,上一篇是个意外. 2015年关注,一代鬼王Xun和GGL比赛.晚上11点之后,经常有水友赛.主播xun,会带着一帮小弟,玩一些游戏.比如魔兽争霸6v6,2v2,RPG游戏-军团战争,疯 ...

  7. 【集训第二天·翻水的老师】--ac自动机+splay树

    今天是第二天集训.(其实已经是第三天了,只是昨天并没有机会来写总结,现在补上) 上午大家心情都很愉快,因为老师讲了splay树和ac自动机. 但到了下午,我们的教练竟然跑出去耍了(excuse me? ...

  8. dota有哪些经典的典故或笑话?

    ----------------------------------------------------dota有哪些经典的典故或笑话?虽然现在玩游戏也没什么热情了, 但是看到这些还是笑尿,笑点低 = ...

  9. 聚光灯下的熊猫TV技术架构演进

    2015年开始的百播大战,熊猫TV是其中比较特别的一员. 说熊猫TV是含着金钥匙出生的公子哥不为过.还未上线,就频频曝光,科技号,微博稿,站上风口浪尖.内测期间更是有不少淘宝店高价倒卖邀请码,光内测时 ...

  10. 【网络可靠版】Extjs4 Treegrid 使用实例

    最近调试EXTJS 4的treegrid实例,看了很多水友的文章,以及官方的demo, 没一个可靠的,全都无法显示出来.像对于我们习惯用C++的coder来说,EXTJS简直就是一群无政府土匪来维护的 ...

随机推荐

  1. 2023年多校联训NOIP层测试7+【LGR-149-Div.3】洛谷基础赛 #2 & qw Round -1

    普及模拟3 \(T1\) 最大生成树 \(100pts\) 简化题意:给定一个 \(n(1 \le n \le 1 \times 10^5)\) 个点的完全图,给定各点的点权 \(a_i(1 \le ...

  2. JS Leetcode 852. 山脉数组的峰顶索引图解分析,高高的山峰一起吹山风吧。

    壹 ❀ 引 本题来自LeetCode 852. 山脉数组的峰顶索引,难度依旧是简单,也是一道考二分法的题目,题目描述如下: 符合下列属性的数组 arr 称为 山脉数组 : arr.length > ...

  3. ghost方式批量安装win7

    1.   需求介绍: 最近工作中需要给几百台PC安装win7操作系统,同时需要安装系统驱动和一些办公软件.刚开始是使用U盘制作的win7启动盘安装,发现效率太低,因为中间需要人监控安装进度以待安装好系 ...

  4. Go语言并发编程(4):sync包介绍和使用(下)-Once,Pool,Cond

    sync包下:Once,Pool,Cond 一.sync.Once 执行一次 Once 简介 sync.Once 是 Go 提供的让函数只执行一次的一种实现. 如果 once.Do(f) 被调用多次, ...

  5. OFDM系统各种调制阶数的QAM误码率(Symbol Error Rate)与 误比特率(Bit Error Rate)仿真结果

    本文是OFDM系统的不同QAM调制阶数的误码率与误比特率仿真,仅考虑在高斯白噪声信道下的情景,着重分析不同信噪比下的误码(符号)率性能曲线,不关心具体的调制与解调方案,仿真结果与理论的误码率曲线进行了 ...

  6. Centos8上安装python3.X

    一.更新yum源 命令:yum update 二.更新依赖环境 命令:yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sq ...

  7. 【Azure Batch】在中国区批处理服务(Mooncake Batch Account)上实验自动池(Auto Pool)的创建/删除

    问题描述 在Azure Batch的介绍文档中,提出了自动池的概念, 它可以在任务完成后,自动删除Pool资源,详细介绍:https://docs.azure.cn/zh-cn/batch/nodes ...

  8. 【Azure Redis 缓存 Azure Cache For Redis】Redis支持的版本及不同版本迁移风险

    问题描述 1. Azure Redis缓存支持的版本包括4.0以及6.0(预览) 这种情形下,可以使用PaaS服务提供的 Azure Redis 缓存(4.0版本).Azure Redis对6.0的支 ...

  9. 【Azure API 管理】APIM添加Log-to-eventhub的策略后,一些相关APIM与Event Hub的问题

    问题描述 1)    APIM 到Event Hub 写入日志是否有数量限制,比如每秒最大写入数量: 2)    是否可以在同一个APIM配置多个Event Hub,如果可以该APIM写入日志的峰值是 ...

  10. For 循环跟yield区别?

    for循环遍历一个万亿级别的长列表,会将这个列表的全部数据载入到内存中去,如果你的内存很小就会溢出,即使是内存很大,这个操作也是十分占用资源的. 而使用生成器,则会将数据的状态(例如:遍历到列表的哪个 ...