解题过程中,虽然解出来了,但是磕磕绊绊犯了一些错误,记录一下


分析过程

PE查壳

有一个upx壳,最下面给了脱壳提示: upx.exe -d Replace.exe

脱壳结束,丢到IDA里,SHIF+F12,查看字符串,看到一个可疑的”Well Done!\n“,点进去看看,发现就是主函数,反汇编主函数

  • Buffer很明显是输入,且长度要<=37
  • 判断函数==1就成功,显然这就是关键

sub_401090函数(改了一点名称)

 1 // 最后要输出1
2 // a1是输入,a2是输入的长度且为35
3 int __fastcall sub_401090(int a1, int a2)
4 {
5 int v4; // edx
6 char char_v5; // al
7 int high4; // esi
8 int low4; // edi
9 char char_v8; // al
10 int v9; // eax
11 char char_v10; // cl
12 int v11; // eax
13 int v12; // ecx
14
15 if ( a2 != 35 )
16 return -1;
17 v4 = 0;
18 while ( 1 )
19 {
20 char_v5 = *(_BYTE *)(v4 + a1);
21 high4 = (char_v5 >> 4) % 16; // 先右移4位,相当于把原来8位的高4位数移动到低4位,新高4位全都置零——再%16,相当于取出变换后新8位的低4位——也就是取出原来数的高4位
22 low4 = ((16 * char_v5) >> 4) % 16; // 先*16,相当于左移4位,原来的低4位移动到高4位,新的低4位置零——再右移4位,相当于移回来了,不过高4位都是0——再%16,取出低4位——原就是取出原来数的低4位
23 char_v8 = byte_402150[2 * v4];
24 if ( char_v8 < 48 || char_v8 > 57 )
25 v9 = char_v8 - 87;
26 else
27 v9 = char_v8 - 48;
28 char_v10 = byte_402151[2 * v4];
29 v11 = 16 * v9; // v9*16,相当于左移4位————为后面组成新的8位做准备,作为新数的高4位
30 if ( char_v10 < 48 || char_v10 > 57 )
31 v12 = char_v10 - 87;
32 else
33 v12 = char_v10 - 48; // 作为新数的低4位
34 if ( (unsigned __int8)byte_4021A0[16 * high4 + low4] != ((v11 + v12) ^ 25) )// 16 * high4 + low4——操作的目的是组成新的8位数——其实就是原来输入的数
35 // ((v11 + v12) ^ 25)——将上面获得v11与v12组成新的数,与25异或
36 // 最后进行比较,相等才能return 1
37 break;
38 if ( ++v4 >= 35 )
39 return 1;
40 }
41 return -1;
42 }

总而言之,从byte_402150取一个元素作为char_v8,变换后获得组成高位的v11;从byte_402151取一个元素作为char_v10,变换后获得组成低位的v12,最后组成一个新的数去异或

【异或后得到的值】要与 【将输入作为下标,从byte_4021A0中取出的数】 相等

byte_402150与byte_402151

!!在这里我就犯了一个错误,我还以为是我IDA又出现问题了....byte_402150数组的32h后面没有 0 表示结束,所以要继续往下读取,一直到出现 0 ,即byte_402150是50+byte_402151

unsigned char ida_chars[] =
{
50,97, 52, 57, 102, 54, 57, 99, 51, 56, 51,
57, 53, 99, 100, 101, 57, 54, 100, 54, 100,
101, 57, 54, 100, 54, 102, 52, 101, 48, 50,
53, 52, 56, 52, 57, 53, 52, 100, 54, 49,
57, 53, 52, 52, 56, 100, 101, 102, 54, 101,
50, 100, 97, 100, 54, 55, 55, 56, 54, 101,
50, 49, 100, 53, 97, 100, 97, 101, 54, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0
};
unsigned char ida_chars[] =
{
97, 52, 57, 102, 54, 57, 99, 51, 56, 51,
57, 53, 99, 100, 101, 57, 54, 100, 54, 100,
101, 57, 54, 100, 54, 102, 52, 101, 48, 50,
53, 52, 56, 52, 57, 53, 52, 100, 54, 49,
57, 53, 52, 52, 56, 100, 101, 102, 54, 101,
50, 100, 97, 100, 54, 55, 55, 56, 54, 101,
50, 49, 100, 53, 97, 100, 97, 101, 54, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0
};

byte_4021A0

选中全部,SHIF+E-->选中‘C unsigned char array (decimal)’,得到数组的值(上面也是这么得到的)

unsigned char ida_chars[] =
{
99, 124, 119, 123, 242, 107, 111, 197, 48, 1,
103, 43, 254, 215, 171, 118, 202, 130, 201, 125,
250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
114, 192, 183, 253, 147, 38, 54, 63, 247, 204,
52, 165, 229, 241, 113, 216, 49, 21, 4, 199,
35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
235, 39, 178, 117, 9, 131, 44, 26, 27, 110,
90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
190, 57, 74, 76, 88, 207, 208, 239, 170, 251,
67, 77, 51, 133, 69, 249, 2, 127, 80, 60,
159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
188, 182, 218, 33, 16, 255, 243, 210, 205, 12,
19, 236, 95, 151, 68, 23, 196, 167, 126, 61,
100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
224, 50, 58, 10, 73, 6, 36, 92, 194, 211,
172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
141, 213, 78, 169, 108, 86, 244, 234, 101, 122,
174, 8, 186, 120, 37, 46, 28, 166, 180, 198,
232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
181, 102, 72, 3, 246, 14, 97, 53, 87, 185,
134, 193, 29, 158, 225, 248, 152, 17, 105, 217,
142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104, 65, 153,
45, 15, 176, 84, 187, 22
};

解题脚本(自己写的常规版本)

 1 key1=[
2 50,97, 52, 57, 102, 54, 57, 99, 51, 56, 51,
3 57, 53, 99, 100, 101, 57, 54, 100, 54, 100,
4 101, 57, 54, 100, 54, 102, 52, 101, 48, 50,
5 53, 52, 56, 52, 57, 53, 52, 100, 54, 49,
6 57, 53, 52, 52, 56, 100, 101, 102, 54, 101,
7 50, 100, 97, 100, 54, 55, 55, 56, 54, 101,
8 50, 49, 100, 53, 97, 100, 97, 101, 54
9 ]
10 key2=[
11 97, 52, 57, 102, 54, 57, 99, 51, 56, 51,
12 57, 53, 99, 100, 101, 57, 54, 100, 54, 100,
13 101, 57, 54, 100, 54, 102, 52, 101, 48, 50,
14 53, 52, 56, 52, 57, 53, 52, 100, 54, 49,
15 57, 53, 52, 52, 56, 100, 101, 102, 54, 101,
16 50, 100, 97, 100, 54, 55, 55, 56, 54, 101,
17 50, 49, 100, 53, 97, 100, 97, 101, 54
18 ]
19 str=[
20 99, 124, 119, 123, 242, 107, 111, 197, 48, 1,
21 103, 43, 254, 215, 171, 118, 202, 130, 201, 125,
22 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
23 114, 192, 183, 253, 147, 38, 54, 63, 247, 204,
24 52, 165, 229, 241, 113, 216, 49, 21, 4, 199,
25 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
26 235, 39, 178, 117, 9, 131, 44, 26, 27, 110,
27 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
28 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
29 190, 57, 74, 76, 88, 207, 208, 239, 170, 251,
30 67, 77, 51, 133, 69, 249, 2, 127, 80, 60,
31 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
32 188, 182, 218, 33, 16, 255, 243, 210, 205, 12,
33 19, 236, 95, 151, 68, 23, 196, 167, 126, 61,
34 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
35 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
36 224, 50, 58, 10, 73, 6, 36, 92, 194, 211,
37 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
38 141, 213, 78, 169, 108, 86, 244, 234, 101, 122,
39 174, 8, 186, 120, 37, 46, 28, 166, 180, 198,
40 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
41 181, 102, 72, 3, 246, 14, 97, 53, 87, 185,
42 134, 193, 29, 158, 225, 248, 152, 17, 105, 217,
43 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
44 140, 161, 137, 13, 191, 230, 66, 104, 65, 153,
45 45, 15, 176, 84, 187, 22
46 ]
47 flag = ""
48 for i in range(35):
49 v8 = key1[2*i]
50 if v8 < 48 or v8 > 57:
51 v11 = 16 * (v8 - 87)
52 else:
53 v11 = 16 * (v8 - 48)
54 v10 = key2[2 * i]
55 if v10 < 48 or v10 > 57:
56 v12 = v10 - 87
57 else:
58 v12 = v10 - 48
59 v4=((v11 + v12) ^ 25)
60 flag += chr(str.index(v4))
61
62 print(flag)

这里我犯了一个弱智错误

  • 最初写脚本的时候,想照着反汇编代码的思路去写,在后面写了一个 for j in range(len(str_data)): if str[i]==((v11 + v12) ^ 25):v4=((v11 + v12) ^ 25)
  • 结果导致运行没有报错,也没有结果
  • str[i]==((v11 + v12) ^ 25)这一行代码在每次循环中都会遍历str列表来查找是否存在相等的值,这会导致程序在执行时花费很长时间,因为它的时间复杂度是 O(n),其中 n 是str列表的长度。由于列表长度非常大,因此这种线性搜索的方法会非常慢,尤其是在内层循环中还嵌套了一个循环。这也解释了为什么代码没有输出也没有报错,因为它可能需要很长时间才能完成运行

解题脚本(枚举正向爆破)

这个版本是我参考别的大佬的wp时候学到的,记录一下

由于用了取余 % 运算,所以采用枚举正向爆破的方法,让flag中的每一个字符遍历常用的字符(ascii码表中32-126),带入加密算法,如果成功,就把这个flag存入

list1=[50, 97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54]
list2=[97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54]
list3=[99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
v4=0
flag=""
for i in range(35):
v8=list1[2*i]
if v8 < 48 or v8 > 57:
v9=v8 - 87
else:
v9=v8 - 48
v10=list2[2*i]
v11=16*v9
if v10 <48 or v10 > 57:
v12=v10-87
else:
v12=v10-48
v4=((v11+v12)^25)
for a in range(32,127):
v5=a
v6=(v5>>4)%16
v7=((16*v5)>>4)%16
if list3[16*v6+v7] == v4:
flag+=chr(a)
print(flag)

flag

flag{Th1s_1s_Simple_Rep1ac3_Enc0d3}

攻防世界 Replace Reverse二星题的更多相关文章

  1. 攻防世界 misc Exercise 刷题记录

    1.base64stego 1.zip伪加密 2. base64文件隐写,在网上找一个脚本

  2. 攻防世界pwn高手区——pwn1

    攻防世界 -- pwn1 攻防世界的一道pwn题,也有一段时间没有做pwn了,找了一道栈题热身,发现还是有些生疏了. 题目流程 拖入IDA中,题目流程如图所示,当v0为1时,存在栈溢出漏洞.在gdb中 ...

  3. 攻防世界 reverse 进阶 10 Reverse Box

    攻防世界中此题信息未给全,题目来源为[TWCTF-2016:Reverse] Reverse Box 网上有很多wp是使用gdb脚本,这里找到一个本地还原关键算法,然后再爆破的 https://www ...

  4. 攻防世界Web刷题记录(新手区)

    攻防世界Web刷题记录(新手区) 1.ViewSource 题如其名 Fn + F12 2.get post 3.robots robots.txt是搜索引擎中访问网站的时候要查看的第一个文件.当一个 ...

  5. CTF--web 攻防世界web题 robots backup

    攻防世界web题 robots https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=506 ...

  6. CTF--web 攻防世界web题 get_post

    攻防世界web题 get_post https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=5 ...

  7. 攻防世界web新手区做题记录

    学校信安协会第一次培训结束后的作业,要求把攻防世界的web新手区题目做一遍并写题解. 第一题 view_source 查看源代码右键不能用,但是F12能用,于是找到源代码 输入到flag框即可 后来在 ...

  8. 记录下做攻防世界的misc题

    0x00 记录一下,代表自己做过 0x01 flag_universe 看简介是来自2018年的百越杯. 将文件下载下来后,就一个flag_universe.pcapng文件,wireshark打开. ...

  9. 攻防世界 reverse evil

    这是2017 ddctf的一道逆向题, 挑战:<恶意软件分析> 赛题背景: 员工小A收到了一封邮件,带一个文档附件,小A随手打开了附件.随后IT部门发现小A的电脑发出了异常网络访问请求,进 ...

  10. 攻防世界 reverse tt3441810

    tt3441810 tinyctf-2014 附件给了一堆数据,将十六进制数据部分提取出来, flag应该隐藏在里面,(这算啥子re,) 保留可显示字符,然后去除填充字符(找规律 0.0) 处理脚本: ...

随机推荐

  1. 【华为机试ACM基础#01】字符串最后一个单词长度、计算某字符出现次数、提取不重复的整数(熟悉字符/字符串/整数的输入)

    字符串最后一个单词的长度 描述 计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000.(注:字符串末尾不以空格为结尾) 输入描述: 输入一行,代表要计算的字符串,非空,长度小于5000 ...

  2. Java链接Mysql数据库整理,尽管很简单,但还是分享出来,希望对那些初级朋友有所帮助!!!

    Java MySQL 连接 Java MySQL 连接 本章节我们为大家介绍 Java 如何使用 使用 JDBC 连接 MySQL 数据库. Java 连接 MySQL 需要驱动包,最新版下载地址为: ...

  3. 机器学习策略篇:详解满足和优化指标(Satisficing and optimizing metrics)

    满足和优化指标 要把顾及到的所有事情组合成单实数评估指标有时并不容易,在那些情况里,发现有时候设立满足和优化指标是很重要的,让我告诉是什么意思吧. 假设已经决定很看重猫分类器的分类准确度,这可以是\( ...

  4. webservice之jersey简单实用

    前言 项目中更需要使用到webservice,具体的是使用jersey.那么首先需要了解jersey和webservice的关系,捋顺webservice框架的各种实现,通过查阅相关博客,我个人总结w ...

  5. 使用 MyBatis 操作 Nebula Graph 的实践

    本文首发于 Nebula Graph Community 公众号 我最近注意到很多同学对于 ORM 框架的需求比较迫切,而且有热心的同学已经捐赠了自己开发的项目,Nebula 社区也在 working ...

  6. 三: MySQL的数据目录

    # MySQL的数据目录 1. MySQL8的主要目录结构 1.1 数据库文件的存放路径 MySQL数据库文件的存放路径:/var/lib/mysql/ MySQL服务器程序在启动时会到文件系统的某个 ...

  7. ASP.NET Core 移除已注册的过滤器

    背景 ABP vNext 默认对异常响应进行了处理,现在某个项目需要自定义异常响应结果. 问题 在 ABP vNext 的 MVC 模块当中,可以看到是通过 AddService(typeof(Abp ...

  8. MDC实现微服务链路追踪

    一.问题背景 在微服务架构中,我们没办法快速定位用户在一次请求中对应的所有日志,在排查生产问题的时候会非常困难,那是因为我们在输出的日志的时候没把请求的唯一标示输出到我们的日志中,导致我们没办法根据一 ...

  9. C++学习笔记之高级语法

    目录 高级语法 面向对象--类 对象的属性 运算符重载 拷贝构造函数 IO缓存 头文件的重复包含问题 深拷贝与浅拷贝 面向对象三大特性 高级语法 面向对象--类 C++使用struct.class来定 ...

  10. Web安全前端基础

    Web安全前端基础 1.Web前端介绍 2.前端代码语言简单学习 一.Web前端介绍 web前端就是前端网络编程,也被认为是用户端编程,是为了网页或者网页应用,而编写HTML,CSS以及JS代码,所以 ...