——20230815——
[SWPUCTF 2021 新生赛]简简单单的解密
题目源码如下:
import base64,urllib.parse
key = "HereIsFlagggg"
flag = "xxxxxxxxxxxxxxxxxxx"
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]
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))
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
注释一波:
import base64,urllib.parse
key = "HereIsFlagggg"
flag = "xxxxxxxxxxxxxxxxxxx"
s_box = list(range(256)) # range()生成一系列连续的整数,list()生成列表,此处即生成一个0-255的数组
j = 0
for i in range(256):
a=len(key)
b=i%a # %——取模,返回除法的余数
c=key[b]
d=ord(c)
print('a=',a,'b=',b,'c=',c,'d=',d,'j=',j)
print('__i=',i,'__')
j = (j + s_box[i] + d) % 256
print('__j=',j,'__')
s_box[i], s_box[j] = s_box[j], s_box[i]
print('s_box[',i,']=',s_box[i],'s_box[',j,']=',s_box[j])
print('=====================================')
res = []
print('res=',res)
print('————————for loop 1————————')
i = j = 0 #i,j值归零
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]
print('new_for_i=',i,'new_for_j=',j,'s_box[i]=',s_box[i],'s_box[j]=',s_box[j],'t=',t,'k=s_box[t]=',k)
m=ord(s)
print('m=',m)
n=m^k
print('n=',n)
o=chr(n)
print('chr(n)=',o)
p=res.append(o) #append是属于python中的一个函数,它主要是用来在列表末尾添加新的对象。语法格式为list.append(obj)
print('res.append(chr(n)=',p)
print('————————for loop 2————————')
cipher = "".join(res)
# join(): 连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串
# 语法: 'sep'.join(seq),参数说明:sep:分隔符。可以为空,seq:要连接的元素序列、字符串、元组、字典
# 上面的语法即:以sep作为分隔符,将seq所有的元素合并成一个新的字符串
# 返回值:返回一个以分隔符sep连接各个元素后生成的字符串
# 以utf-8对cipher编码
# encode()用来给字符串使用指定的编码格式来编码字符串。与之对应的是解码decode()。
# 语法:str.encode(encoding='UTF-8',errors='strict')
# 参数说明:str:需要操作的字符串,也就是需要编码的字符串。
# encoding -- 需要使用的编码,如: UTF-8、GBK等。
# errors -- 设置不同错误的处理方案。默认为 'strict',意为编码错误引起一个UnicodeError。
# 其他可能得值有'backslashreplace', 'replace'、'ignore', 'xmlcharrefreplace', 以及通过 codecs.register_error() 注册的任何值。
crypt = (str
(base64.b64encode
(cipher.encode('utf-8'))
, 'utf-8')
) #将cipyer以utf-8编码后以base64加密,并转换成字符串类型
print('crypt=',crypt)
enc = str(base64.b64decode(crypt),'utf-8')#对上述结果进行base64解密
enc = urllib.parse.quote(enc)#把生成的cipher中的非ASCII字符转换成%**形式
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
然后……?(黑人问号脸),不得不说出题人是会玩的,差点以为搞了两次base64加密,原来是加密一次又解密,最后url转换一波。剩下的就跟上一题差不多了,生成key值的算法题目中已经给出,把给的enc转换回来, 逐个取值与key异或,将生成的ASCII值转换回来就完事了。
那么,走起来吧:
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"
crypt =urllib.parse.unquote(enc)
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]
a = []
i = j = 0
for s in crypt:
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]
a.append(chr(ord(s) ^ k))
flag = "".join(a)
print('flag=',flag)
最终flag get:
————20230818下午————
[SWPUCTF 2021 新生赛]re1
下载附件,是一个exe文件,先上die看下有没有壳:
看出来是没壳的,而且是个64位文件,那么ida64来一下:
按一下空格键,转换下显示模式,找到main函数后按F5转换成伪代码方便查看:
代码如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str2[1008]; // [rsp+20h] [rbp-60h] BYREF
char Str1[1000]; // [rsp+410h] [rbp+390h] BYREF
int i; // [rsp+7FCh] [rbp+77Ch]
_main();
strcpy(Str2, "{34sy_r3v3rs3}");
printf("please put your flag:");
scanf("%s", Str1);
for ( i = 0; i <= 665; ++i )
{
if ( Str1[i] == 101 )
Str1[i] = 51;
}
for ( i = 0; i <= 665; ++i )
{
if ( Str1[i] == 97 )
Str1[i] = 52;
}
if ( strcmp(Str1, Str2) )
printf("you are wrong,see again!");
else
printf("you are right!");
system("pause");
return 0;
}
这……有点太明显了啊,上面那个花括号里的……就是flag了,偷懒一把,手工把3换成e,4换成a,flag就出来了……
当然,按照正规程序,这样是不太行的,但我今天不想做了哈哈哈哈哈嗝……
————20230822————
[SWPUCTF 2021 新生赛]re2
下载附件,首先die
很好,无壳,64位,那么ida64走一波,找到main函数,伪代码看一眼,顺便注释一下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str2[64]; // [rsp+20h] [rbp-90h] BYREF #定义Str2字符串,长度64位
char Str[68]; // [rsp+60h] [rbp-50h] BYREF #定义Str字符串,长度68位
int v7; // [rsp+A8h] [rbp-8h] #定义变量v7为整数类型
int i; // [rsp+ACh] [rbp-4h] #定义变量i为整数类型
_main();
strcpy(Str2, "ylqq]aycqyp{"); // 对Str2赋值
printf(&Format);
gets(Str); //要求输入Str
v7 = strlen(Str); //令v7的值等于Str的长度值
for ( i = 0; i < v7; ++i ) //令i为0,若i的值小于v7,则i+1
{
if ( (Str[i] <= 96 || Str[i] > 98) && (Str[i] <= 64 || Str[i] > 66) ) //若当前Str字符的ASCII值小于等于96或大于98的同时小于等于64或大于66
Str[i] -= 2; //则当前Str字符ASCII值-2
else
Str[i] += 24; //否则+24
}
if ( strcmp(Str, Str2) ) //比较Str与Str2字符串
printf(&byte_404024);
else
printf(aBingo);
system("pause");
return 0;
}
看得出来,这里的Str经过for循环运算与Str2相等,则说明我们输入的就是flag了。本想用C语言写,然而……死去十几年的记忆终究是死去了,只好用python
flag=''
flag1=''
a=''
b=''
enco='ylqq]aycqyp{'
length=len(enco)
for i in range(length):
if (ord(enco[i]) <= 94 or ord(enco[i]) > 96 ) and (ord(enco[i]) <= 64 or ord(enco[i]) > 66):
a+=chr(ord(enco[i])+2)
else:
b+=chr(ord(enco[i])-24)
flag= "".join(a)
flag1= "".join(b)
print(flag)
print(flag1)
运行结果是
提交flag、结果错误,啊这……看了一眼像是caesar,于是厚着脸皮手动改成NSSCTF{nss
_caesar}提交,成功……
P.S 严重吐槽CSDN的编辑器,太特么垃圾了
————20230824凌晨————
[SWPUCTF 2021 新生赛]fakerandom
题目源码如下:
import random
flag = 'xxxxxxxxxxxxxxxxxxxx'
random.seed(1)
l = []
for i in range(4):
l.append(random.getrandbits(8))
result=[]
for i in range(len(l)):
random.seed(l[i])
for n in range(5):
result.append(ord(flag[i*5+n])^random.getrandbits(8))
print(result)
# result = [201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244]
这题目乍一看,不就是玩伪随机数嘛,一开始在分析的时候没有整明白random.seed()与random.getrandbits()函数的关系,以为直接从result中按顺序取值进行异或运算后解题
后面才发现random.seed()函数是用来改变随机数生成器的种子,没有参数时,每次生成的随机数是不一样的,而当seed()有参数时,每次生成的随机数是一样的。因此解题时同样需要通过random.seed()给定random.getrandbits()函数的种子
那么,本题源代码经注释如下:
import random
flag = 'xxxxxxxxxxxxxxxxxxxx' #定义flag字符串
random.seed(1) #设定以1为种子生成伪随机数,并将其作为getrandbits函数的种子
l = [] #定义空数组l
for i in range(4):
l.append(random.getrandbits(8)) # 本for循环在0~255之间随机取4个值,并赋值给l数组
result=[] #定义空数组result
for i in range(len(l)):
random.seed(l[i])
for n in range(5):
result.append(ord(flag[i*5+n])^random.getrandbits(8)) #参照上一for循环,本for循环中,分别以l数组各值作为本for循环中的getrandbits函数的种子,并将flag各位(即x)的ASCII值与生成的随机数进行异或运算后赋值给result数组
print(result)
# result = [201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244]
这样一看就明白多了,还是异或的老套路,只不过key由伪随机数构成,直接逆向就完事了
import random
flag = ''
random.seed(1)
l = []
result = [201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244]
for i in range(4):
l.append(random.getrandbits(8))
for i in range(len(l)):
random.seed(l[i])
for n in range(5):
flag+=chr(result[i*5+n]^random.getrandbits(8))
print(flag)
flag get
————20230825凌晨————
[SWPUCTF 2021 新生赛]非常简单的逻辑题
源码如下:
flag = 'xxxxxxxxxxxxxxxxxxxxx'
s = 'wesyvbniazxchjko1973652048@$+-&*<>'
result = ''
for i in range(len(flag)):
s1 = ord(flag[i])//17
s2 = ord(flag[i])%17
result += s[(s1+i)%34]+s[-(s2+i+1)%34]
print(result)
# result = 'v0b9n1nkajz@j0c4jjo3oi1h1i937b395i5y5e0e$i'
注释一波:
flag = 'xxxxxxxxxxxxxxxxxxxxx'
s = 'wesyvbniazxchjko1973652048@$+-&*<>'
result = ''
for i in range(len(flag)):
s1 = ord(flag[i])//17 #对x的ASCII值除以17后取整,定值为7
s2 = ord(flag[i])%17 #对x的ASCII值除以17后取余数,定值为1
print('ord(flag[i])=',ord(flag[i]),',i=',i,',s1=',s1,',s2=',s2)
a=s1+i
a1=a%34 # 取值范围为7~27
b=s2+i+1
b1=(-b)
b2=b1%34 #负数取余,计算方式为-(b1%34),例i=0时,b=2,b1=-2,b2=-(2%34)=-(0余2),故b2=-2
print('a=',a,',a1=',a1,',b=',b,',b1=',b1,',b2=',b2)
c=s[a1]
d=s[b1]
print('c=',c,'d=',d)
result += s[(s1+i)%34]+s[-(s2+i+1)%34] #令result值等于字符串s中第7~27位的值与第32~12位的值穿插叠加
print(result)
print('————————')
print(result)
# result = 'v0b9n1nkajz@j0c4jjo3oi1h1i937b395i5y5e0e$i'
然后愣是弄不懂要怎么解……先跳过
想了两个晚上也没想怎么把这题逆出来,看了其他师傅的也还是搞不明白,枯了……
只好换个思路,直接暴力破解……
flag=''
s = 'wesyvbniazxchjko1973652048@$+-&*<>'
result = 'v0b9n1nkajz@j0c4jjo3oi1h1i937b395i5y5e0e$i'
for i in range(len(result)//2):
for j in range(0,255):
s1=j//17
s2=j%17
tmp = s[(s1+i)%34]+s[-(s2+i+1)%34]
if (tmp == result[i*2:i*2+2]):
flag+=chr(j)
break
print(flag)
flag get……
有没有师傅行行好,教我一下怎么逆这个题啊,就是想不通T T
[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
好了不想做,先放着……
[SWPUCTF 2021 新生赛]easyapp
因为没有保存,所以这题的记录丢失……
过程就是先die一下看看有没有壳,发现是经过编译的,把扩展名改成zip
打开发现是个apk文件,用jdax破瓜后,在里面找到mainactivity和encoder
发现key是987654321,加密方式是异或
密文是一行unicode,转化后是一堆生僻字
解题代码如下:
result='棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌'
key=987654321
flag=''
for i in result:
a=ord(i)^key
print(a)
flag+= chr(a%128)
print(flag)
flag
[SWPUCTF 2021 新生赛]老鼠走迷宫
附件下载后又是没有扩展名,die后发现经过编译
于是把扩展名改成.exe,然后根据大佬的思路python逆向的常见思路_wiiish的博客-CSDN博客,用pyinstxtractor破瓜,接着在爆出来的文件里,找到struct.py,用文件头16位覆盖5.py的文件头。
接着反编译。
本想用pycdc的,结果翻了一堆文章就是整不明白怎么用cmake搞定它,无奈之下用了uncompyle6。
反编译后的代码如下:
# uncompyle6 version 3.9.0
# Python bytecode version base 3.7.0 (3394)
# Decompiled from: Python 2.7.18 (v2.7.18:8d21aa21f2, Apr 20 2020, 13:25:05) [MSC v.1500 64 bit (AMD64)]
# Embedded file name: 5.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 272 bytes
import random, msvcrt
row, col = (12, 12)
i, j = (0, 0)
maze = [
[
1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1],
[
1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 1],
[
1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
0, 0, 0, 1, 0, 1],
[
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1,
0, 1, 1, 1, 0, 1],
[
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
0, 1, 0, 0, 0, 1],
[
1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 1, 1, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0,
0, 0, 0, 1, 0, 1],
[
1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
1, 1, 0, 1, 0, 1],
[
1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
0, 1, 0, 0, 0, 1],
[
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
0, 1, 1, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 1],
[
1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1,
0, 1, 0, 1, 1, 1],
[
1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1,
0, 1, 0, 1, 0, 1],
[
1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
0, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1,
0, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1,
1, 1, 0, 1, 0, 1],
[
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 1],
[
1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
0, 1, 1, 1, 0, 1],
[
#### 总结
=============================================================
从转行到现在,差不多两年的时间,虽不能和大佬相比,但也是学了很多东西。我个人在学习的过程中,习惯简单做做笔记,方便自己复习的时候能够快速理解,现在将自己的笔记分享出来,和大家共同学习。
个人将这段时间所学的知识,分为三个阶段:
第一阶段:HTML&CSS&JavaScript基础
![](https://img-blog.csdnimg.cn/img_convert/3e0d5b0f6a97b823cc1ef22ff1a18191.png)
第二阶段:移动端开发技术
![](https://img-blog.csdnimg.cn/img_convert/fc21db0a800494796dc6408ce1486031.png)
第三阶段:前端常用框架
![](https://img-blog.csdnimg.cn/img_convert/644efd4ddd0f8d43535f1982ec0da6e4.png)
* 推荐学习方式:针对某个知识点,可以先简单过一下我的笔记,如果理解,那是最好,可以帮助快速解决问题;如果因为我的笔记太过简陋不理解,可以关注我以后我还会继续分享。
* 大厂的面试难在,针对一个基础知识点,比如JS的事件循环机制,不会上来就问概念,而是换个角度,从题目入手,看你是否真正掌握。所以对于概念的理解真的很重要。