攻防世界 Replace Reverse二星题
解题过程中,虽然解出来了,但是磕磕绊绊犯了一些错误,记录一下
分析过程
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二星题的更多相关文章
- 攻防世界 misc Exercise 刷题记录
1.base64stego 1.zip伪加密 2. base64文件隐写,在网上找一个脚本
- 攻防世界pwn高手区——pwn1
攻防世界 -- pwn1 攻防世界的一道pwn题,也有一段时间没有做pwn了,找了一道栈题热身,发现还是有些生疏了. 题目流程 拖入IDA中,题目流程如图所示,当v0为1时,存在栈溢出漏洞.在gdb中 ...
- 攻防世界 reverse 进阶 10 Reverse Box
攻防世界中此题信息未给全,题目来源为[TWCTF-2016:Reverse] Reverse Box 网上有很多wp是使用gdb脚本,这里找到一个本地还原关键算法,然后再爆破的 https://www ...
- 攻防世界Web刷题记录(新手区)
攻防世界Web刷题记录(新手区) 1.ViewSource 题如其名 Fn + F12 2.get post 3.robots robots.txt是搜索引擎中访问网站的时候要查看的第一个文件.当一个 ...
- CTF--web 攻防世界web题 robots backup
攻防世界web题 robots https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=506 ...
- CTF--web 攻防世界web题 get_post
攻防世界web题 get_post https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=5 ...
- 攻防世界web新手区做题记录
学校信安协会第一次培训结束后的作业,要求把攻防世界的web新手区题目做一遍并写题解. 第一题 view_source 查看源代码右键不能用,但是F12能用,于是找到源代码 输入到flag框即可 后来在 ...
- 记录下做攻防世界的misc题
0x00 记录一下,代表自己做过 0x01 flag_universe 看简介是来自2018年的百越杯. 将文件下载下来后,就一个flag_universe.pcapng文件,wireshark打开. ...
- 攻防世界 reverse evil
这是2017 ddctf的一道逆向题, 挑战:<恶意软件分析> 赛题背景: 员工小A收到了一封邮件,带一个文档附件,小A随手打开了附件.随后IT部门发现小A的电脑发出了异常网络访问请求,进 ...
- 攻防世界 reverse tt3441810
tt3441810 tinyctf-2014 附件给了一堆数据,将十六进制数据部分提取出来, flag应该隐藏在里面,(这算啥子re,) 保留可显示字符,然后去除填充字符(找规律 0.0) 处理脚本: ...
随机推荐
- Lucene介绍与使用
Lucene介绍与使用 原文链接:https://blog.csdn.net/weixin_42633131/article/details/82873731 不选择使用Lucene的6大原因? 原文 ...
- go-ini解析ini文件
文档 https://github.com/go-ini/ini https://ini.unknwon.io/docs/intro/getting_started go get -u gopkg.i ...
- 【C# .Net】继承重写父类方法,C# 与 JAVA的不同之处
一直都没仔细研究c#重写,new关键字的作用,最近在回头看书,复习C#基础的时候才发现了 C# 重写和 JAVA大不一样的地方. C# 提供特定实现的子类可以重写(override)标识为 virtu ...
- nftables语法及例子
先上我自己实际测试通过的例子,用例子便于在实践中学习: # 0 --- 说明 ---下面例子中的单引号目的是为了避免nftable参数中的星号.花括号.分号等符号被shell展开解释掉了,导致nft命 ...
- 用Pandoc生成TXT格式的目录
我一直使用Markdown格式写作,使用Pandoc生成PDF和Word格式的文档.Pandoc能生成很好的章节和目录,但有时候,也需要生成TXT格式的目录,今天就尝试了一下. 由于我写的内容章节比较 ...
- Linux操作系统加固建议
1.1.1 口令锁定策略 1.执行备份 (1).redhat执行备份: #cp -p /etc/pam.d/system-auth /etc/pam.d/system-auth_bak (2).SUS ...
- liunx 安装 python 虚拟环境, 各种方法,
liunx 安装 python 虚拟环境,主要是要解决工作中需要用到python3.6,但是系统的2.7又不能动,安装系统组件时避免造成冲突.低版本的python安装django uwsgi 等都用 ...
- stm32 boot0硬件接法导致的概率性启动失败问题总结和反思
概要 问题概要,板子在稳压电源上工作很好,可一旦接了电池,stm32就会出现概率性的无法启动.加上项目比较急,这个问题阻塞一直无法量产.真是非常的要命啊. 思路分析 既然是不同的电源会导致这个问题 ...
- 解决jenkins Git Publisher自动打tag的问题
简单配置一下 然后开始构建,然后报错如下 The recommended git tool is: NONE using credential 647ee613-5032-4894-aaeb-fe07 ...
- Google Chart API学习(二)
书接上回: combo-charts: <html> <head> <script type="text/javascript" src=" ...