一步一个脚印地耐心攀登,就是别去看顶峰,而要专注于在爬的路。

                                                                                        ——黑泽明

目录

1.查壳

2.IDA静态分析main函数

3.研究三重加密

第一重加密

第二重加密

第三重加密

4.解密


1.查壳

64bit  exe文件

2.IDA静态分析main函数

拖入IDA,找到main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{int v3; // eaxint v4; // eaxint v5; // eaxint result; // eaxchar Str; // [rsp+20h] [rbp-60h]char Str1; // [rsp+50h] [rbp-30h]char v9; // [rsp+90h] [rbp+10h]char v10; // [rsp+D0h] [rbp+50h]char Str2[8]; // [rsp+110h] [rbp+90h]int v12; // [rsp+14Ch] [rbp+CCh]_main();strcpy(Str2, "EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG");puts("Hello, please input your flag and I will tell you whether it is right or not.");scanf("%38s", &Str);if ( strlen(&Str) == 38&& (v3 = strlen(&Str), (unsigned int)encode_one(&Str, v3, &v10, &v12) == 0)&& (v4 = strlen(&v10), (unsigned int)encode_two(&v10, v4, &v9, &v12) == 0)&& (v5 = strlen(&v9), (unsigned int)encode_three(&v9, v5, &Str1, &v12) == 0)&& !strcmp(&Str1, Str2) ){puts("you are right!");result = 0;}else{printf("Something wrong. Keep going.");result = 0;}return result;
}

我们将flag输入到了str

if ( strlen(&Str) == 38
    && (v3 = strlen(&Str), (unsigned int)encode_one(&Str, v3, &v10, &v12) == 0)
    && (v4 = strlen(&v10), (unsigned int)encode_two(&v10, v4, &v9, &v12) == 0)
    && (v5 = strlen(&v9), (unsigned int)encode_three(&v9, v5, &Str1, &v12) == 0)
    && !strcmp(&Str1, Str2) )

可以看出正确的flag长度应该是38

根据函数名应该是有三次加密

看到第一次加密encode_one(&Str, v3, &v10, &v12) ,v10是引用的形式传参,v4 = strlen(&v10), (unsigned int)encode_two(&v10, v4, &v9, &v12) == 0,第二次在传str的地方传入了v10,第三次则是v9,可以猜测应该是对输入的str三重加密

最后对比str1,str2,相等,并且前面的条件都正确,就是正确的flag

str1,str2跟进

dup即英文duplicate的缩写,重复的意思,用来定义重复的字节、字、双字、结构等内存缓冲区。

?表示值是未定义的  汇编语言

说明str1,str2最初没有什么内容

emmm,不对

在主函数开始的时候,给Str2赋值了,

重点研究三重加密是什么

3.研究三重加密

第一重加密

__int64 __fastcall encode_one(const char *a1, int a2, char *a3, int *a4)
{int v5; // esiint v6; // esiint v7; // esiint v8; // [rsp+34h] [rbp-1Ch]int v9; // [rsp+38h] [rbp-18h]char *v10; // [rsp+40h] [rbp-10h]int v11; // [rsp+48h] [rbp-8h]int i; // [rsp+4Ch] [rbp-4h]unsigned __int8 *v13; // [rsp+70h] [rbp+20h]int v14; // [rsp+78h] [rbp+28h]int *v15; // [rsp+88h] [rbp+38h]v13 = (unsigned __int8 *)a1;v14 = a2;v15 = a4;if ( !a1 || !a2 )return 0xFFFFFFFFi64;v11 = 0;if ( a2 % 3 )v11 = 3 - a2 % 3;v9 = a2 + v11;v8 = 8 * (a2 + v11) / 6;v10 = a3;for ( i = 0; i < v9; i += 3 ){*v10 = alphabet[(char)*v13 >> 2];if ( v14 + v11 - 3 == i && v11 ){if ( v11 == 1 ){v5 = (char)cmove_bits(*v13, 6u, 2u);v10[1] = alphabet[v5 + (char)cmove_bits(v13[1], 0, 4u)];v10[2] = alphabet[(char)cmove_bits(v13[1], 4u, 2u)];v10[3] = 61;}else if ( v11 == 2 ){v10[1] = alphabet[(char)cmove_bits(*v13, 6u, 2u)];v10[2] = 61;v10[3] = 61;}}else{v6 = (char)cmove_bits(*v13, 6u, 2u);v10[1] = alphabet[v6 + (char)cmove_bits(v13[1], 0, 4u)];v7 = (char)cmove_bits(v13[1], 4u, 2u);v10[2] = alphabet[v7 + (char)cmove_bits(v13[2], 0, 6u)];v10[3] = alphabet[v13[2] & 0x3F];}v10 += 4;v13 += 3;}if ( v15 )*v15 = v8;return 0i64;
}

我们只需要看这个加密算法的核心部分,根据加密算法的特征,识别出什么加密算法

move_bit字面意思和使用这个函数的次数很像是base64,看一下加密算法中很显眼的这个alphabet数组

h是十六进制的意思,hex,按下快捷键a转换成字符看一下

发现确实应该是一个base64加密表

第二重加密

__int64 __fastcall encode_two(const char *a1, int a2, char *a3, int *a4)
{char *Source; // [rsp+40h] [rbp+10h]char *v6; // [rsp+50h] [rbp+20h]Source = (char *)a1;v6 = a3;if ( !a1 || !a2 )return 0xFFFFFFFFi64;strncpy(a3, a1 + 26, 0xDui64);strncpy(v6 + 13, Source, 0xDui64);strncpy(v6 + 26, Source + 39, 0xDui64);strncpy(v6 + 39, Source + 13, 0xDui64);return 0i64;
}

encode_two(&v10, v4, &v9, &v12) == 0

根据前面的推断,第三个参数应该是加密后的密文,用一个Source指针指向原来的明文,然后进行strncpy操作

strncpy(a3, a1 + 26, 0xDui64);
  strncpy(v6 + 13, Source, 0xDui64);
  strncpy(v6 + 26, Source + 39, 0xDui64);
  strncpy(v6 + 39, Source + 13, 0xDui64);

就是一个简单的替换加密

第三重加密

__int64 __fastcall encode_three(const char *a1, int a2, char *a3, int *a4)
{char v5; // [rsp+Fh] [rbp-11h]int i; // [rsp+14h] [rbp-Ch]char *v7; // [rsp+18h] [rbp-8h]const char *v8; // [rsp+30h] [rbp+10h]v8 = a1;if ( !a1 || !a2 )return 0xFFFFFFFFi64;v7 = a3;for ( i = 0; i < a2; ++i ){v5 = *v8;if ( *v8 <= 64 || v5 > 90 ){if ( v5 <= 96 || v5 > 122 ){if ( v5 <= 47 || v5 > 57 )*v7 = v5;else*v7 = (v5 - 48 + 3) % 10 + 48;}else{*v7 = (v5 - 97 + 3) % 26 + 97;}}else{*v7 = (v5 - 65 + 3) % 26 + 65;}++v7;++v8;}return 0i64;
}

第三重加密是凯撒加密

*v7 = (v5 - 48 + 3) % 10 + 48;这是典型的凯撒加密的特征

不了解凯撒加密阅读 凯撒加密

需要简单熟悉一下ASCLL码表,便于阅读

使用快捷键r改为字符,可以看出分别对于大小写字母和数字进行了移动三位的凯撒加密

分析完毕,开始爆破

4.解密

!strcmp(&Str1, Str2)

三重加密之后的字符串是Str1,Str2是一直的,当Str1等于Str2的时候会输出"you are right!"

我们就需要将Str2的值逆向三重解密,得到正确的flag

需要解密的密文EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG

第一重解密(凯撒加密的解密)

def decrypt_caesar(str, key=3):  # 解密函数text = ""for i in str:if ord(i) >= 65 and ord(i) <= 90:text += chr(65 + ((ord(i) - 65) - key) % 26)elif ord(i) >= 97 and ord(i) <= 122:text += chr(97 + ((ord(i) - 97) - key) % 26)elif ord(i) >= 48 and ord(i) <= 57:text += chr(48 + ((ord(i) - 48) - key) % 10)else:text+=ireturn textm1="EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG"
m2=decrypt_caesar(m1)
print(m2)

脚本运行结果

BjYjM2Mjk4NzMR1dIVHs2NzJjY0MTEzM2VhMn0=zQ3NzhhMzhlOD

第二重解密(替换加密)

就是一个四部分替换一下顺序,不写脚本了,简单手推

BjYjM2Mjk4NzM 3
R1dIVHs2NzJjY 1
0MTEzM2VhMn0= 4
zQ3NzhhMzhlOD 2
R1dIVHs2NzJjYzQ3NzhhMzhlODBjYjM2Mjk4NzM0MTEzM2VhMn0=

破解结果

R1dIVHs2NzJjYzQ3NzhhMzhlODBjYjM2Mjk4NzM0MTEzM2VhMn0=

第三重解密(base64解密)

import base64
a="R1dIVHs2NzJjYzQ3NzhhMzhlODBjYjM2Mjk4NzM0MTEzM2VhMn0="
b=base64.b64decode(a.encode());
print(b.decode())

也可以使用在线解密网站

GWHT{672cc4778a38e80cb362987341133ea2}

flag{672cc4778a38e80cb362987341133ea2}

边解题编写题解,别的buuctf逆向题解可以关注我的专栏reverse

[羊城杯 2020]easyre 1题解相关推荐

  1. [羊城杯 2020]easyre

    用PE查壳 用ida打开找到main函数 int __cdecl main(int argc, const char **argv, const char **envp) {int v3; // ea ...

  2. BUUCTF[羊城杯 2020]easyre

    64位无壳程序 IDA64打开 main函数: int __cdecl main(int argc, const char **argv, const char **envp) {int v3; // ...

  3. BUUCTF Reverse/[羊城杯 2020]easyre

    查看信息,无壳,64位程序 IDA打开分析代码,又是一个字符串比较的问题,输入flag,对flag加密三次,flag的长度为38 int __cdecl main(int argc, const ch ...

  4. [羊城杯 2020]GMC

    [羊城杯 2020]GMC 题目 from Crypto.Util.number import getPrime,bytes_to_long,getRandomNBitInteger from sec ...

  5. [羊城杯 2020]Power

    [羊城杯 2020]Power 题目 from Crypto.Util.number import * import gmpy2 from secret import flagp = getPrime ...

  6. [羊城杯 2020]RRRRRRRSA

    [羊城杯 2020]RRRRRRRSA 题目 import hashlib import sympy from Crypto.Util.number import *flag = 'GWHT{**** ...

  7. [羊城杯 2020]Bytecode [UTCTF2020]babymips

    文章目录 [羊城杯 2020]Bytecode 查看题目 python代码 注意点: BINARY_SUBTRACT 这个是减法 BINARY_SUBSCR 这个是索引 Z3约束脚本 注意点: 注意最 ...

  8. [羊城杯 2020]login [SUCTF2019]hardcpp

    文章目录 [羊城杯 2020]login 思路:一个py编译的exe,需要解包,然后反编译成py文件 1.解包:python pyinstxtractor.py login.exe 提示:pyinst ...

  9. [羊城杯 2020]逃离东南亚

    [羊城杯 2020]逃离东南亚 考点 复现过程 参考链接 考点 1.图片高度隐写 2.silenteye 3.空格与tab隐写 4.需要编程找到隐写内容并进行解码 复现过程 解压压缩包有三个压缩包文件 ...

最新文章

  1. IOS开发之----异常处理
  2. 验证网站地址是否有效
  3. php中$_get和$_post如何使用,怎么使用超级全局变量$_POST与$_GET
  4. day15 webUI自动化
  5. 处理Clob数据(转)关于oracle中大对象处理的一些方法和实例
  6. 树莓派进阶之路 (027) - 在Linux中增加swap空间
  7. Java学习(11-15天, 线性数据结构)
  8. android系统启动自动启动不了,怎么在android系统开机就运行某个应用
  9. 怎么样简单的进行dwg转pdf格式
  10. csrf 与 samesite
  11. Nahimic应用程序初始化失败
  12. 使用python替换word文档部分内容
  13. 蓝鸥iOS开发工程师职场提升路线图
  14. Requirement already satisfied的解决方案
  15. 神经网络的多任务学习概览
  16. 什么是自动气象站 校园气象站
  17. 路由器无线桥接的方法
  18. Dart- move html element
  19. 旅行家问题2(TSP,奇怪的转化模型)
  20. 小白,想入门程序员,应该从什么开始学,顺序是什么?

热门文章

  1. USB传输中出现的错误C0000030 endpoint halted
  2. 前端css基础知识点之sprite——雪碧(精灵)
  3. 淘宝上买了一件东西发生了什么
  4. Essay-时刻努力与坚持
  5. matlab里面q函数,标准正态分布的Q函数用 matlab 怎么写
  6. 使用 C# 开发智能手机软件:推箱子(十一)
  7. 2021-2022新版本IDEA创建项目没有JavaEE和Web选项?
  8. 计算机的优势和劣势_计算机二级证书的含金量不高?别小瞧,这4大优势用处不小...
  9. 多线程并发的一些解决思路
  10. kali-dmitry