NSSCTF reverse题目解析(详细版)持续更新

目录

[SWPUCTF 2021 新生赛]简简单单的逻辑

[SWPUCTF 2021 新生赛]re1

[NSSCTF 2022 Spring Recruit]easy C

 [SWPUCTF 2021 新生赛]简简单单的解密

 [SWPUCTF 2021 新生赛]re2

[LitCTF 2023]世界上最棒的程序员

[WUSTCTF 2020]level2

[SWPUCTF 2021 新生赛]非常简单的逻辑题​编辑

[GFCTF 2021]wordy(花指令)

[HUBUCTF 2022 新生赛]simple_RE

[SWPUCTF 2021 新生赛]fakerandom

 [SWPUCTF 2022 新生赛]base64

 [NISACTF 2022]string

 [NSSRound#3 Team]jump_by_jump(花指令)

 [NISACTF 2022]sign-ezc++(命名空间)

[HNCTF 2022 Week1]超级签到

[MoeCTF 2022]Reverse入门指北

 [SWPUCTF 2022 新生赛]babyre

 [SWPUCTF 2022 新生赛]easyre

[UTCTF 2020]Basics(RE)

[HNCTF 2022 WEEK2]e@sy_flower

[LitCTF 2023]ez_XOR

[SWPUCTF 2021 新生赛]fakebase(模逆向爆破)

 [BJDCTF 2020]JustRE

[NISACTF 2022]ezpython(python反编译)

 [LitCTF 2023]enbase64(循环变表)

 [SWPUCTF 2021 新生赛]easyapp(安卓apk逆向)

 [NSSCTF 2022 Spring Recruit]easy Python

 [HUBUCTF 2022 新生赛]ezPython(pyc文件的处理)

[GDOUCTF 2023]Check_Your_Luck(Z3库求解)

 [HNCTF 2022 Week1]贝斯是什么乐器啊?

 [SWPUCTF 2022 新生赛]base64-2

 [HNCTF 2022 Week1]X0r

[BJDCTF 2020]Easy(动态调试)

[HUBUCTF 2022 新生赛]help(动态调试,迷宫)

 [SWPUCTF 2022 新生赛]upx

[SWPUCTF 2021 新生赛]老鼠走迷宫(python反编译+迷宫)

[羊城杯 2020]easyre


var code = "efa10eef-31c3-4615-b73c-931dd7951c22"

[SWPUCTF 2021 新生赛]简简单单的逻辑

附件是一个.py文件

原代码的含义是

将list[]数组进行操作得到一个key

利用key和flag进行异或操作,得到16进制的result

 所以可以得到大致的逆向代码框架

result='bcfba4d0038d48bd4b00f82796d393dfec' list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25] flag = '' for i in range(len(list)): key = (list[i]>>4)+((list[i] & 0xf)<<4) ...... print(flag)

 重点就是对以下语句进行逆向

result += str(hex(ord(flag[i])^key))[2:].zfill(2)

 该语句的含义是

  1. 使用异或运算符^对字符的ASCII码和密钥key进行异或操作,得到一个新的整数值。
  2. 使用内置函数hex()将该整数值转换为十六进制字符串。
  3. 使用字符串的切片操作[2:]去掉十六进制字符串的前缀部分(0x)。
  4. 使用字符串的填充操作zfill(2)在字符串的左侧填充0,使其达到2位长度

 因此的到逆向语句

flag += chr(int(result[i*2:i*2+2],16)^key)

 这里要注意的就是16进制和字符间的转换

int(string,16)的功能就是将16进制转为10进制

因此得到完整的脚本

result='bcfba4d0038d48bd4b00f82796d393dfec' list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25] flag = '' for i in range(len(list)): key = (list[i]>>4)+((list[i] & 0xf)<<4) flag += chr(int(result[i*2:i*2+2],16)^key) print(flag)

 

[SWPUCTF 2021 新生赛]re1

查壳

用ida打开,shift+F12

F5查看伪代码

相当简单,意思就是将输入的flag中的e转为3,将a转为4后,如果与{34sy_r3v3rs3}相同,则正确

flag

{easy_reverse}

[NSSCTF 2022 Spring Recruit]easy C

 查看源码

#include <stdio.h> #include <string.h> int main(){ char a[]="wwwwwww"; char b[]="d`vxbQd"; //try to find out the flag printf("please input flag:"); scanf(" %s",&a); if(strlen(a)!=7){ printf("NoNoNo\n"); system("pause"); return 0; } for(int i=0;i<7;i++){ a[i]++; a[i]=a[i]^2; } if(!strcmp(a,b)){ printf("good!\n"); system("pause"); return 0; } printf("NoNoNo\n"); system("pause"); return 0; //flag 记得包上 NSSCTF{} 再提交!!! }

 是C语言,意思是

输入flag为a[],按位加一后与2亦或,得到b[]

因此逆向思路:

将b[]按位与2亦或,再减一,得到的就是flag

payload

#include <stdio.h> int main() { char a[] = "d`vxbQd"; for (int i = 0; i < 7; i++) { a[i] = a[i] ^ 2; a[i]--; printf("%c", a[i]); } return 0; }

 flag

easy_Re

 [SWPUCTF 2021 新生赛]简简单单的解密

 查看源码

import base64,urllib.parse key = "HereIsFlagggg" flag = "xxxxxxxxxxxxxxxxxxx" s_box = list(range(256))#洗牌算法得到S盒,用于后续的RC4加密 j = 0 for i in range(256): j = (j + s_box[i] + ord(key[i % len(key)])) % 256 s_box[i], s_box[j] = s_box[j], s_box[i] #进行RC4加密 #从字符串 flag 中逐个取出字符,并根据洗牌算法生成一个密钥字符。将字符与密钥字符进行异或运算,得到加密后的字符,并将其添加到 res 列表中 res = [] i = j = 0 for s in flag: i = (i + 1) % 256 j = (j + s_box[i]) % 256 s_box[i], s_box[j] = s_box[j], s_box[i] t = (s_box[i] + s_box[j]) % 256 k = s_box[t] res.append(chr(ord(s) ^ k)) #使用 Base64 编码将 cipher 转换为字节字符串 crypt。 #将 crypt 进行 URL 编码,得到最终的结果 enc cipher = "".join(res) crypt = (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8')) enc = str(base64.b64decode(crypt),'utf-8') enc = urllib.parse.quote(enc) print(enc) # enc = %C2%A6n%C2%87Y%1Ag%3F%C2%A01.%C2%9C%C3%B7%C3%8A%02%C3%80%C2%92W%C3%8C%C3%BA

 RC4加密:

用从1~256个字节的可变长度密钥初始化一个256字节的状态矢量S,S的元素记为S[0],s[1],…,S[255],从始至终置换后的S包含从0~255的所有8比特数。对于加密和解密中应用的密钥流的产生,密钥流中的每个密钥k是由S中255 个元素按一定的方式选出一个元素而生成 每生成一个密钥k,S中的元素就被重新置换一次。

虽然每一次的s盒都不一样,但是rc4为对称加密,加解密过程可逆,因此解密直接按原程序跑就可以(因为由流程可以看出只有最后一步异或操作是对字符串的加密,前面的操作均为对s盒的更改运算,而且最后一步异或也可逆)

 因此得到payload

import base64 import urllib.parse key = "HereIsFlagggg" enc = '%C2%A6n%C2%87Y%1Ag%3F%C2%A01.%C2%9C%C3%B7%C3%8A%02%C3%80%C2%92W%C3%8C%C3%BA' #解码URL字符串 flag = urllib.parse.unquote(enc) #生成RC4加密的盒子 s_box = list(range(256)) j = 0 for i in range(256): j = (j + s_box[i] + ord(key[i % len(key)])) % 256 s_box[i], s_box[j] = s_box[j], s_box[i] #解密flag res = [] i = j = 0 for s in flag: i = (i + 1) % 256 j = (j + s_box[i]) % 256 s_box[i], s_box[j] = s_box[j], s_box[i] t = (s_box[i] + s_box[j]) % 256 k = s_box[t] res.append(chr(ord(s) ^ k)) flag = ''.join(res) print(flag)

flag

NSSCTF{REAL_EZ_RC4}

 [SWPUCTF 2021 新生赛]re2

先查壳

使用ida打开,shift+F12查看字符串

 ctrl+x跳转

 F5查看伪代码

大小写的ab都向后24位,其他的都向前2位

所以最终字符串里有大小写的y,z都要分类讨论一下到底是减二得到的还是加24得到的。

int __cdecl main(int argc, const char **argv, const char **envp) { char Str2[64]; // [rsp+20h] [rbp-90h] BYREF char Str[68]; // [rsp+60h] [rbp-50h] BYREF int v7; // [rsp+A8h] [rbp-8h] int i; // [rsp+ACh] [rbp-4h] _main(); strcpy(Str2, "ylqq]aycqyp{"); printf(&Format); gets(Str); v7 = strlen(Str); for ( i = 0; i < v7; ++i ) { if ( (Str[i] <= 96 || Str[i] > 98) && (Str[i] <= 64 || Str[i] > 66) ) Str[i] -= 2; else Str[i] += 24; } if ( strcmp(Str, Str2) ) printf(&byte_404024); else printf(aBingo); system("pause"); return 0; }

对照以下ASCll码表,加上一点猜测可以得到‘

flag{nss_caesar}

[LitCTF 2023]世界上最棒的程序员

使用查壳工具进行查看详细信息

可知是32位未加壳程序,使用IDA 32 查看

导入后如图,按shift+f12查看字符串

答案显然

[WUSTCTF 2020]level2

很简单的一个题,其实就是考了upx脱壳。

下完查壳发现有upx,使用脱壳工具

已经没壳了,使用ida打开,答案显然

[SWPUCTF 2021 新生赛]非常简单的逻辑题

下载后就是一个py文件,明显就是一个存粹的逻辑题

利用flag得到一个下标,奇数偶数位分别正序和倒序从s数组里取字符得到result

下标的计算方法就是flag中对应字符的ASCLL码值整除+取余之和再+i(奇数+1+i再倒序)

由此得到逆向的脚本思路

 由此得到最终脚本

[GFCTF 2021]wordy(花指令)

查壳之后显示没壳,64位,因此使用ida打开

打开后发现是花指令

花指令实质就是一串垃圾指令,它与程序本身的功能无关,并不影响程序本身的逻辑。在软件保护中,花指令被作为一种手段来增加静态分析的难度,花指令也可以被用在病毒或木马上,通过加入花指令改变程序的特征码,躲避杀软的扫描,从而达到免杀的目的,本文将介绍一些常见的花指令的形式,花指令一般被分为两类,被执行的和不会被执行的。

 查看内存信息时找到了红色的位置,是花指令的头,往后翻到了结尾

需要将这些乱码中EBFF全部nop为90才能正常显示,这里需要使用idapython这一ida自带的工具

文件--脚本命令(shift+F2)

输入nop脚本

start=0x1135 end=0x3100 for i in range(start,end): if get_wide_byte(i)==0xEB: if get_wide_byte(i+1)==0xFF: patch_byte(i,0x90)

 

转换完后发现原本的乱码全都转成了正确的字符,合理推测flag就藏在这一大堆字符中,因此还要写一个脚本将所有的字符完整输出,从而方便查看flag(脚本自行理解或借助chatgpt)

start=0x1135 end=0x3100 for i in range(start,end): if get_wide_byte(i)==0xC0: print(chr(idaapi.get_byte(i+2)),end='')

话说回来,其实这道题很奇怪,直接查看16位数据就可以找到flag了,但是比较考验运气

[HUBUCTF 2022 新生赛]simple_RE

查看后无壳,放入ida反编译

可以看到加密过程就是对已知的字符和对应的加密表对应,结构和base64一样,v6即为输入的flag,通过sub_401570()函数加密,最后与 a5mc58bphliax7j 比较,但实质上base64的表已经被替换为

qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD

输入的密文为

5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8==

其实直接shift+F12就可以看到

可见这其实就是一个base64变表加密有两种方法可以破解

一是在线解密网站CyberChef(自行摸索)

二是脚本

import base64 yuanma = '5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8==' xinbiao = 'qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD' jiubiao = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' print(base64.b64decode(yuanma.translate(str.maketrans(xinbiao,jiubiao))))

这里用到了maketrans模块,其本身作用是进行映射,在这里的作用就是实现变表,从而利用新的表进行base64.b64decode解密

[SWPUCTF 2021 新生赛]fakerandom

下载完也是一个简单的xor亦或程序,只需要将xor步骤重复一次即可,唯一的难点是原函数flag为字符串而得到的result为数组,主要是亦或前将字符转为了数字,因此需要让result再次亦或然后转为字符输出

本题难度不大,就当练练python吧(这里详细写一下)

 这题看似给了一个随机数来和flag的每一位亦或,实则因为种子seed的存在,所谓的随机数是“固定的”。因此直接写出核心程序

要注意的就是字符和数字的转换,要将chr去除

for i in range(len(l)): random.seed(l[i]) for n in range(5): flag.append(result[i*5+n]^random.getrandbits(8))

前面的也就可以顺利的补齐

import random result = [201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244] random.seed(1) l = [] for i in range(4): l.append(random.getrandbits(8)) flag=[] for i in range(len(l)): random.seed(l[i]) for n in range(5): flag.append(result[i*5+n]^random.getrandbits(8))

最后只需再将结果转换为字符输出即可

import random result = [201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244] random.seed(1) l = [] for i in range(4): l.append(random.getrandbits(8)) flag=[] for i in range(len(l)): random.seed(l[i]) for n in range(5): flag.append(result[i*5+n]^random.getrandbits(8)) for num in flag: char = chr(num) print(char, end='')

 [SWPUCTF 2022 新生赛]base64

 下载的文件没有后缀名,直接查壳

 用IDA64打开,查看字符串后锁定

 F5查看伪代码

 strcmp就是比较函数,比较V3和S2是否相同,直接点S2查看就行了

 显然是BASE64加密,自由选择工具解密即可

 [NISACTF 2022]string

查壳,注意这里的linux,后面要用到

IDA打开,查看伪代码,显然这段是生成flag的

 代码其实很简单,稍微解释一下

利用种子seed,使每次生成的随机数v4是一样的,再将其进行固定的算法得到13位答案

要注意的是,Windows下和Linux下的随机数种子表是不一样的,因此代码中要写入

srand(0x2766)

 由此得到exp

#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { srand(0x2766); printf("NSSCTF{"); for(int m = 0; m < 13; ++m) { int v4 = rand(); printf("%d",(unsigned int)(v4 % 8 + 1)); } printf("}\n"); return 0; }

 注意,这里讲一下linux中如何运行c脚本

将文件在win系统下编写完,重命名为1.c

gcc 1.c -o 1.out

运行后会生成一个1.out文件

./1.out

生成结果

 如图

 

 [NSSRound#3 Team]jump_by_jump(花指令)

 一道简单的花指令题目。

 花指令就是一个指令 后面的机器码就是指令的内容 当把内容改掉 反汇编就会错误 导致后面都出错 从而阻止反编译,因此我们要使其正常就需要把错的花指令patch掉就行

 

前面的jz和jnz是0继续和非0继续,也就是必须运行call指令,很明显的一个花指令的示意

 call为花指令,后面的机械码是不完整的,反汇编在此开始出错,因此直接将call使用patch功能改为nop

 也可以按D查看data,可以看到中间那一行OE8h是没用的

 选中call

 现在就可以正常反编译了

 找到flag

注:其实我没这样操作之前就能看到flag了。。。感觉是题目没出好,花指令没起作用

 [NISACTF 2022]sign-ezc++(命名空间)

 常规操作,查壳分析

 查看伪代码后发现存在一个命名空间human,回到内存搜索文本human

 

 exp

result = [0x44, 0x59, 0x59,0x49, 0x5E, 0x4C, 0x71, 0x7E, 0x62, 0x63, 0x79, 0x55, 0x63, 0x79, 0x55, 0x44, 0x43, 0x59, 0x4B, 0x55, 0x78, 0x6F, 0x55, 0x79, 0x63, 0x6D, 0x64, 0x77, 0x14] flag = [] # 存储加密后的结果 for i in range(len(result)): flag.append(chr(result[i] ^ 0xA)) # 加密操作,并将结果转换为字符 print(''.join(flag)) # 将列表中的字符连接起来并输出

 

[HNCTF 2022 Week1]超级签到

 

 

将o换成0就行了

[MoeCTF 2022]Reverse入门指北

 [SWPUCTF 2022 新生赛]babyre

 

 [SWPUCTF 2022 新生赛]easyre

[UTCTF 2020]Basics(RE)

[HNCTF 2022 WEEK2]e@sy_flower

 ida分析出来是错的 点一下红色的位置,使用patch将开头换为90即nop

这样就可以了,将光标移到,,main函数的位置,按P,反编译成功

F5查看伪代码,实现反编译

显然做了两个操作

1.将Arg奇偶位互换

2.按位与0x30进行异或操作

exp

Arglist = 'c~scvdzKCEoDEZ[^roDICUMC' Arglist = ''.join(chr(ord(c) ^ 0x30) for c in Arglist) v3 = len(Arglist) for i in range(v3 // 2): Arglist = Arglist[:2*i] + Arglist[2*i+1] + Arglist[2*i] + Arglist[2*i+2:] print(Arglist)

[LitCTF 2023]ez_XOR

 先查壳,为32位程序

可以看出自定义了一个xor函数,对v8的内容进行了操作。

注意这个v8[13]=0是没用的,因为字符串无法改为整数型

 

 这里可以看出是每一位与3*a2进行异或,而a2对应的即xor(str1,3)中的3

 exp

v8 = "E`}J]OrQF[V8zV:hzpV}fVF[t" flag = "" for char in v8: # 将字符的ASCII值与密钥9进行异或操作 decrypted_char = chr(ord(char) ^ 9) flag += decrypted_char print(flag)

 

[SWPUCTF 2021 新生赛]fakebase(模逆向爆破)

flag = 'xxxxxxxxxxxxxxxxxxx' s_box = 'qwertyuiopasdfghjkzxcvb123456#$' tmp = '' for i in flag: tmp += str(bin(ord(i)))[2:].zfill(8) b1 = int(tmp,2) s = '' while b1//31 != 0: s += s_box[b1%31] b1 = b1//31 print(s) # s = u#k4ggia61egegzjuqz12jhfspfkay

题目考察的是模运算的逆向

总体思路就是:

将flag的每一位都转换成八位二进制数,然后凭借成一个很长的二进制数b1,因此b1自然也很大。然后b1每次对31取余,余数对应s在s_box中的下标

 难点:

b1每次都会整除31,假设b1为100101000101001100011000101010101001100101010100011...............00101010101110

在逆向时,要从s的最后一位,从小到大去逆向得到b1的值.

比如最后一位y,说明余数是6,则对应最后一轮的b1范围是(31*0+6)~(31*30+6)

 因此逆向的第一步是反过来得到b1的值,这里需要爆破来确定最后一次的b1大小,这会影响整个的大小。

s_box = 'qwertyuiopasdfghjkzxcvb123456#$' s = 'u#k4ggia61egegzjuqz12jhfspfkay' for i in s[::-1]: b1 = b1*31 +s_box.index(i)

利用libnum库的n2s函数直接得到b1最终所对应的字符串内容

import libnum s_box = 'qwertyuiopasdfghjkzxcvb123456#$' s = 'u#k4ggia61egegzjuqz12jhfspfkay' for k in range(30): b1 = k for i in s[::-1]: b1 = b1*31 +s_box.index(i) print(libnum.n2s(int(b1)))

最终flag

NSSCTF{WHAt_BASe31}

 [BJDCTF 2020]JustRE

 查看字符串的时候发现一个很像flag的东西,查看一下伪代码

 

 输出的是1999902069a45792d233ac

 

 试了一下发现flag就是NSSCTF{1999902069a45792d233ac}

这题没啥特别的思路 也可没看出什么考点 应该就是这样做的

[NISACTF 2022]ezpython(python反编译)

查看信息,发现是python编写的,因此需使用pyinstxtractor.py工具

下载地址:PyInstaller Extractor download | SourceForge.net

反编译方法

1.将下载的.EXE文件和pyinstxtractor.py放在同一目录下

打开终端

python pyinstxtractor.py ez_python.exe

 会生成一个文件夹

 打开后看到src和struct文件,这是反编译的中的重点

 为src文件添加.pyc后缀,并使用winhex打开

 

 src的文件头应该和struct的开头一样,由此可见src文件丢失了Magic Number

复制前11位到src文件中,使其变成正确的形式

打开该位置下的终端

下载 uncompyle6模块

pip install  uncompyle6

进行反编译

uncompyle6 src.pyc > src.py

 生成反编译后的.py文件

值得一提的是,在运行该指令时,win11系统下的python3.1版本会报错,这是一个非常棘手的问题,在这里提供完美的解决方法

报错情况如下:

运行后会报错并显示

 意思是该文件的第187行存在问题,打开该文件查看

 全文搜索变量 canonic_python_version

 可以看到这个模块是从magics文件引入的,所以要到magics文件中去修改参数

 打开magics.py 找到限制版本的那一行 大概在445行附近

先查看自己的python版本

 保存后就能正常实现反编译了

 打开后代码如下,显然当result为decrypt2('AAAAAAAAAAAfFwwRSAIWWQ==',key)时可以输出正确的flag

flag = 'IAMrG1EOPkM5NRI1cChQDxEcGDZMURptPzgHJHUiN0ASDgUYUB4LGQMUGAtLCQcJJywcFmddNno/PBtQbiMWNxsGLiFuLwpiFlkyP084Ng0lKj8GUBMXcwEXPTJrRDMdNwMiHVkCBFklHgIAWQwgCz8YQhp6E1xUHgUELxMtSh0xXzxBEisbUyYGOx1DBBZWPg1CXFkvJEcxO0ADeBwzChIOQkdwXQRpQCJHCQsaFE4CIjMDcwswTBw4BS9mLVMLLDs8HVgeQkscGBEBFSpQFQQgPTVRAUpvHyAiV1oPE0kyADpDbF8AbyErBjNkPh9PHiY7O1ZaGBADMB0PEVwdCxI+MCcXARZiPhwfH1IfKitGOF42FV8FTxwqPzBPAVUUOAEKAHEEP2QZGjQVV1oIS0QBJgBDLx1jEAsWKGk5Nw03MVgmWSE4Qy5LEghoHDY+OQ9dXE44Th0=' key = 'this is key' try: result = input('please input key: ') if result == decrypt2('AAAAAAAAAAAfFwwRSAIWWQ==', key): print(decrypt1(base64.b64decode(decrypt2(flag, result)))) else: if result == key: print('flag{0e26d898-b454-43de-9c87-eb3d122186bc}') else: print('key is error.') except Exception as e: pass

 如果直接用this is key 就会得到这种情况

 可以先得出经过处理后的key

print(decrypt2('AAAAAAAAAAAfFwwRSAIWWQ==', key))

 flag:NSSCTF{5236cb7d-f4a7-4080-9bde-8b9e061609ad}

 [LitCTF 2023]enbase64(循环变表)

 查壳

 打开以后是base64操作,点开base64函数发现里面别有洞天

 点击basechange

 

 就是一个通过v3不断调整表内各个字符位置的变换,进行了48轮

写脚本得到变表后的新表

v3 = [16, 34, 56, 7, 46, 2, 10, 44, 20, 41, 59, 31, 51, 60, 61, 26, 5, 40, 21, 38, 4, 54, 52, 47, 3, 11, 58, 48, 32, 15, 49, 14, 37,0, 55, 53, 24, 35, 18, 25, 33, 43, 50, 39, 12, 19, 13, 42, 9, 17, 28, 30, 23, 36, 1, 22, 57, 63, 8, 27, 6, 62, 45, 29] ntable = [] otable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" for i in range(48): ntable=[] for j in range(64): ntable.append(otable[v3[j]]) otable = "".join(ntable) print("".join(ntable),end="\n")

 得到新表

gJ1BRjQie/FIWhEslq7GxbnL26M4+HXUtcpmVTKaydOP38of5v90ZSwrkYzCAuND

 接下来就可以进行解密了,编写变表解密脚本

ntable = 'gJ1BRjQie/FIWhEslq7GxbnL26M4+HXUtcpmVTKaydOP38of5v90ZSwrkYzCAuND'#新表 flag_1 = "GQTZlSqQXZ/ghxxwhju3hbuZ4wufWjujWrhYe7Rce7ju"#密文 import base64 otable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"#旧表 flag = base64.b64decode(flag_1.translate(str.maketrans(ntable, otable))) print(flag)

或者直接利用在线工具

 [SWPUCTF 2021 新生赛]easyapp(安卓apk逆向)

 下载的附件是zip文件首先要解压缩

 发现是apk,使用jadx进行反编译

找到main函数,发现在后面有一个添加一段奇怪的汉字字符串的过程

 看到前面有个encoder的加密函数,点进去看看,发现就是个异或的函数,前面那段汉字就是这里的c,按位与key进行异或操作

 据此编写脚本,但发现不对,发现后面main函数中对key有赋值,前面的12345678只是初始值

 由此得到脚本

s = "棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌" key = 987654321 for i in s: flag += chr(ord(i)^key%128) print(flag)

值得一提的是,汉字是可以ord转为Ascll码的,一个汉字两个字节,具体参考这位师傅的博客

ord()和chr()对中文字符的应用_chr() 汉字表示范围-CSDN博客

 [NSSCTF 2022 Spring Recruit]easy Python

 下载的代码如下

import string def encode(string,string2): tmp_str = str() ret = str() bit_string_str = string.encode() remain = len( string ) % 3 remain_str = str() for char in bit_string_str: b_char = (bin(char)[2:]) b_char = '0'*(8-len(b_char)) + b_char tmp_str += b_char for i in range(len(tmp_str)//6): temp_nub = int(tmp_str[i*6:6*(i+1)],2) ret += string2[temp_nub] if remain==2: remain_str = tmp_str[-4:] + '0'*2 temp_nub = int(remain_str,2) ret += string2[temp_nub] + "=" elif remain==1: remain_str = tmp_str[-2:] + '0'*4 temp_nub = int(remain_str,2) ret += string2[temp_nub] + "="*2 return ret.replace("=","") res = encode(input(),string.ascii_uppercase+string.ascii_lowercase+string.digits+'+/') if res == "TlNTQ1RGe2Jhc2U2NCEhfQ": print("good!") else: print("bad!")

 其实就是一个很标准的base64的加密过程,后面判断如果过输入"TlNTQ1RGe2Jhc2U2NCEhfQ"则返回good,说明密文即"TlNTQ1RGe2Jhc2U2NCEhfQ",可是base64的密文字符数是6的倍数,因此需要在后面补上两个==(具体base64加密原理请参考其他师傅的博客base64加密原理详解_64base加密-CSDN博客

TlNTQ1RGe2Jhc2U2NCEhfQ==

 题目不难,但有点为了出题而出题的意思

 [HUBUCTF 2022 新生赛]ezPython(pyc文件的处理)

 使用uncomple6进行反编译

 uncompyle6 ezPython.pyc > ez.py

 打开后查看代码,就是先将字符转为整数型再base58再base64,只需要反过来base64解密+base58解密+整数转字符即可

这里整数转字符需要用到libnum函数

# uncompyle6 version 3.9.0 # Python bytecode version base 3.7.0 (3394) # Decompiled from: Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr 5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] # Embedded file name: .\ezPython.py # Compiled at: 2022-09-03 23:53:44 # Size of source mod 2**32: 444 bytes from Crypto.Util.number import * import base64, base58 password = open('password.txt', 'r').read() tmp = bytes_to_long(password.encode('utf-8')) ans = base64.b64encode(base58.b58encode(str(tmp))).decode() print("I've forgot my password,could you please help me find the password?") if ans == 'M0hBajFITHVLcWV6R1BOcEM5MTR0R0J3eGZVODV6MTJjZUhGZFNHQw==': print('You get the password!') else: print('Wrong! try again') # okay decompiling ezPython.pyc

import libnum

flag = 22385992650816784030032474165

print(libnum.n2s(flag))

 HUBUCTF@1405

[GDOUCTF 2023]Check_Your_Luck(Z3库求解)

 题目就是给出了一个很复杂的方程

#include <iostream> using namespace std; void flag_checker(int v, int w,int x,int y,int z); int main(){ int v,w,x,y,z; cout << "Input 5 random number and check your luck ;)" << endl; cout << "Num1: "; cin >> v; cout << "Num2: "; cin >> w; cout << "Num3: "; cin >> x; cout << "Num4: "; cin >> y; cout << "Num5: "; cin >> z; cout << endl; flag_checker(v,w,x,y,z); } void flag_checker(int v,int w, int x, int y, int z){ if ((v * 23 + w * -32 + x * 98 + y * 55 + z * 90 == 333322) && (v * 123 + w * -322 + x * 68 + y * 67 + z * 32 == 707724) && (v * 266 + w * -34 + x * 43 + y * 8 + z * 32 == 1272529) && (v * 343 + w * -352 + x * 58 + y * 65 + z * 5 == 1672457) && (v * 231 + w * -321 + x * 938 + y * 555 + z * 970 == 3372367)){ cout << "Congratulations, Here is your flag:\n"; cout << "flag{" << v << "_" << w << "_" << x << "_" << y << "_" << z << "}" << endl; } else{ cout << "\nSeems your luck is not in favor right now!\nBetter luck next time!" << endl; } }

先下载模块(别下成Z3了,那是另一个东西)

pip install z3_solver

编写脚本模板

from z3 import *

a, s, d = Ints('a s d')
x = Solver()
x.add(a-d == 18)
x.add(a+s == 12)
x.add(s-d == 20)
check = x.check()
print(check)
model = x.model()
print(model)
# sat
# [a = 5, d = -13, s = 7]

编写脚本

from z3 import * v,w,x,y,z = ints('v w x y z') result = solver() result.add(v * 23 + w * -32 + x * 98 + y * 55 + z * 90 == 333322) result.add(v * 123 + w * -322 + x * 68 + y * 67 + z * 32 == 707724) result.add(v * 266 + w * -34 + x * 43 + y * 8 + z * 32 == 1272529) result.add(v * 343 + w * -352 + x * 58 + y * 65 + z * 5 == 1672457) result.add(v * 231 + w * -321 + x * 938 + y * 555 + z * 970 == 3372367) check = result.check() print(check) model = result.model() print(model)

NSSCTF{4544_123_677_1754_777}

 [HNCTF 2022 Week1]贝斯是什么乐器啊?

 查壳,看信息

 对应表和密文

 就是简单地将每一位减去i,再进行base64加密

 点进自定义的base_encode函数 看一下是不是常规的加密 发现没问题

 

 那就直接写脚本就行了

a = 'NRQ@PAu;8j[+(R:2806.i' result = "" for i in range(len(a)): result += chr(i + ord(a[i])) print(result)

NSSCTF{B@se64_HAHAHA}

 [SWPUCTF 2022 新生赛]base64-2

 查壳,看信息

 用ida打开,查看伪代码,就是一个简单的变表加密

 直接使用网站就能解出,用脚本也行

 [HNCTF 2022 Week1]X0r

 查壳

ida反编译然后查看伪代码就是将输入的东西进行一个简单的异或然后加900的操作

点进arr查看要比较的对象的内容

由此编写脚本

flag = '' f2 = [0x3FE, 0x3EB, 0x3EB,0x3FB, 0x3E4, 0x3F6, 0x3D3, 0x3D0, 0x388, 0x3CA, 0x3EF, 0x389, 0x3CB, 0x3EF, 0x3CB, 0x388, 0x3EF, 0x3D5, 0x3D9, 0x3CB, 0x3D1, 0x3CD] for i in range(0,22): flag+=chr((f2[i]-900)^0x34) print(flag)

NSSCTF{x0r_1s_s0_easy}

[BJDCTF 2020]Easy(动态调试)

查看信息

使用IDA打开,查看字符串,但是转到内存里面反复查看都一无所获

 他的意思是让我自己找,那首先查看_main函数,再看看前面的_ques函数

 这段就是在打印*具体按照程序的设定来执行

 找到函数对应的内存的位置00401520

为了动态调试该函数,在main处下断点,然后点击调试

 修改EIP指向ques函数对应的内存地址

 点击F9运行,得到flag

 这题的考点就是他动态调试的时候会跳过ques函数,所以利用main函数作为跳板,实现动态调试指定函数的操作

[HUBUCTF 2022 新生赛]help(动态调试,迷宫)

 查看伪代码,创建了一个迷宫函数,答案是md5加密的

查看迷宫函数内部,就是打印一个16x16的迷宫,因此只需要在动态调试的时候选择F8单步步过(不进入函数内部),然后点进函数查看迷宫内容就可以得到解

下断点

随便输入

F5

按F8单步步过,然后点到map查看你内容

手搓成16x16就行了

wwdddwwwaaawwwwwwwwwddddssssdddssdsssssssdddwwwwddsssd

 [SWPUCTF 2022 新生赛]upx

 先进行UPX脱壳(查壳忘记截图了)

使用IDA打开

 写一个简单的异或脚本

a = 'LQQAVDyWRZ]3q]zmpf]uc{]vm]glap{rv]dnce' flag = '' for i in range(0,len(a)): flag += chr(ord(a[i]) ^ 2) print(flag)

[SWPUCTF 2021 新生赛]老鼠走迷宫(python反编译+迷宫)

查壳发现是pylnstaller打包的,先对其进行解包(自行添加后缀.exe)

python pyinstxtractor.py 1.exe

打开生成的文件夹,找到.exe.manifest和对应的无后缀的们见,为其添加后缀.pyc

并使用winhex打开,将其文件开头改成和struct改成一样

 打开该目录下的终端

uncompyle6 5.pyc>src.py

 成功完成反编译,生成.py文件

打开后就是一个简单的迷宫代码

手搓就行了(真讨厌做迷宫,这题又臭又长,搓死我了)

得到路径

sssssddssddssaaaassssddwwddddssssssaawwaassssddssaassddddwwddssddwwwwwwwwaawwddwwwwaaaawwddwwwwddssssddwwwwddddwwddddssaassaassddddssddssaassssssddsssssss

进行md5加密,结果就是flag

[羊城杯 2020]easyre(base+凯撒)

 查壳

要求输入一个Str,长度是38,后面的操作就是进行了三次加密,encode_one,encode_two,encode_three,点进去依次查看

点进encode_one查看

很像是base64加密,点进alphabet查看

按a转换为字符

就是base表,所以可以确定是base64

接下来查看encode_two,显然就是一个字符串的重新排列

 最后看encode_three是一段位移,其实就是凯撒

因此逐个进行解密

先将凯撒解密,这里用脚本也行,用工具也可以

得到

BjYjM2Mjk4NzMR1dIVHs2NzJjY0MTEzM2VhMn0=zQ3NzhhMzhlOD

 直接手动换回去就行了

最后进行base64解密,得到flag

[SWPUCTF 2022 新生赛]xor

查壳

打开就是一个很简单的异或运算

[NSSRound#3 Team]jump_by_jump_revenge(花指令+模逆向)

查壳

查不出什么东西,打开也没法反编译,再根据他的标题,显然是一个花指令的题,那么第一步就是去花。找到内存里加花指令的地方

选中红色区域,patch

将开头改成90

改完如下

然后选中函数开头,按p重新编译

成功得到伪代码

可以看到题目对明文进行了一个两次取余的加密操作

可以简化为

v0=(Str1[i] + Str1[k]) % 96 + 32

 k其实就是一个常数

k = (i * i + 123) % 21

 因此在写逆向脚本时,我们先跳过32这个东西,直接说96的相关操作,前面两次从明文中取到的数字加起来一定不超过128+128<96*3,所以逆向时不需要96次,只需要3次

for j in range(3):
        x = (ord(a[i]) - 32 + j * 96 - ord(a[k]))

但是要将爆破结果中不符合范围的数字筛选掉

if x>=33 and x<=126:
        #print(chr(x))
            a[i]=chr(x)
            break

由此得到完整的代码

a = ['~','4','G','~','M',':','=','W','V','7','i','X',',','z','l','V','i','G','m','u','4','?','h','J','0','H','-','Q','*'] for i in range(28, -1, -1): k = (i * i + 123) % 21 for j in range(3): x = (ord(a[i]) - 32 + j * 96 - ord(a[k])) if x>=33 and x<=126: #print(chr(x)) a[i]=chr(x) break flag = '' for i in a: flag += i print(flag)

[SWPUCTF 2022 新生赛]py2

就是一个常规的python反编译,具体可以参考前面的几个题目,写的很详细了,这里就不详细写了

放在同一目录下执行

找到pyc文件,添加后缀并且修改文件头

执行uncompyle6

得到py文件查看即可

很明显的base64加密


__EOF__

本文作者XFocus
本文链接https://www.cnblogs.com/XFocus/p/18543177.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   XFocus666  阅读(252)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示