buureservewp(2)
[GUET-CTF2019]re
这道题挺简单的
查壳,upx,然后脱壳,用shift+f12找字符串,找到主函数
发现correct的条件与sub_4009ae函数有关,点进去
1 | { |
发现这么多数字都是v4数组里面的,不过关键少了个a1[6],然后a1[17]跟a1[16]位置反了,写个脚本吧:
1 |
|
然后最终的flag,少了第六位的值,那就一个数字一个字母的试呗,最终得到flag
e跟6之间加一个1就对了
[WUSTCTF2020]level1
这一题也挺简单的
ida里面,shift + f12查看字符串,找到flag,进入函数
可以看到是有20次循环,然后打开给出的txt文本,发现只有19个数字,那么第一位给0
0,198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000
然后看着伪代码,写成c语言的形式:
1 |
|
[SUCTF2019]SignIn
进入ida找到main函数
__gmpz_init_set_str 函数:
*int mpz_init_set_str (mpz_t rop, const char str, int base) [Function]
作用就是将 str 字符数组以 base 指定的进制解读成数值并写入 rop 所指向的内存。该程序通过调用这个函数来实现数据的初始化赋值。
__gmpz_powm 函数:
void mpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const mpz_t mod) [Function]
计算 base 的 exp 次方,并对 mod 取模,最后将结果写入 rop 中
这种计算跟rsa一样
我们需要理解一下rsa的加密解密过程
图中的E是公钥(E和 φ(N)互为质数),N是公共模数(质数 P 、Q相乘得到N),MOD就是模运算
图中的D是私钥(私钥由这个公式计算得出E * D % φ(N) = 1),N是公共模数(质数 P
、Q相乘得到N),MOD就是模运算,φ(N)是欧拉函数(由这个公式计算得出φ(N) = (P-1)(Q-1))。
所以:
密文:ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
N:103461035900816914121390101299049044413950405173712170434161686539878160984549
e:65537
然后根据N求出q和p
再用工具求出d
然后写python代码:
1 | # 无注释 |
也可以先把m的值转为十六进制,再把十六进制转为字符串
m=185534734614696481020381637136165435809958101675798337848243069
十六进制:73756374667b50776e5f405f68756e647265645f79656172737d
字符串:suctf{Pwn_@_hundred_years}
因为函数一开始就是把输入的字符串转为十六进制的,然后算出来的又是十进制,所以就逆回去
libnum库:
数字型(不论是十六进制还是十进制)与字符串之间的转换:
1 | > import libnum |
1 | import libnum |
还有二进制与字符串的转换:
1 | import libnum |
1 | import libnum |
[MRCTF2020]Transform
这题也挺简单的
看主函数:
首先flag长度为33.
byte_414040数组的值已经知道了,然后跟dword_40F040数组进行异或。
然后以dword_40F040数组为flag数组的下标等于byte_414040数组,就能解出来了
脚本:
1 |
|
[WUSTCTF2020]level2
这道题。。。。。。怎么说呢。。。。。
脱完壳,看ida,我以为是个陷阱,没想到就直接是个flag
好吧,没想到,反正主函数我也没找到。。。。。。。
[ACTF新生赛2020]usualCrypt
看主函数
byte_40E0E4:输入的字符串经过加密后进行比较,是则对
进入加密函数,发现是base64加密,再看看密码表
加密的开始,有个关于密码表的函数,看一下
首先两个数组,看后俩位,简单记作【AA,A0】
v1 = aa的第六位
aa第六位=a0第六位
a0第六位=v1
=================
v1 = aa的第七位
aa第七位=a0第七位
a0第七位=v1
最后那个while语句控制循环次数,交换到第14位停止
然后看两个密码表:
a0:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
aa:LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
如果a0不接着aa的话,那么位数不足
那么两个交换的也就是:GHIJKLMNO跟QRSTUVWXY换
最后的密码表:
ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/
变化的密码表知道了,然后解密之后的字符串还会经历一个函数:大小写转换函数:
sub_401030
大小写转换的伪代码,分析:
在区间(97,122)小写字母会-32,变成大写
在区间(65,90)大写字母会+32,变成小写
我觉得第二个if语句少了个else,不然我就能理解的更快了。。。。(LOBYTE前边)加个else
然后跟一个数组进行一对一比较,而那个数组也给了
那么思路来了:
①先大小写转换
②再解密
脚本①:
1 |
|
脚本②:最后用了别人的base64,换了个表,懒得自己弄了。。。。。
至于最后为什么解密字符串第一个多了一个Z:
原理跟上面那个AA和A0数组的情况一样,7A的文本是:z
上下两个数组连起来的,所以多了一个z,也就是Z。。。。。。。
Youngter-drive
脱壳,打开ida查看main函数
这是一个多线程,首先有两个线程:hObject和v2
先进入hObject:
一个函数和一个减减
先看函数:
首先排除不是26个字母的范围了
再看减减:
1D是29,我猜flag长度30
再进入第二个线程:
只有一个减减
继续往下看,还有一个sub_411190函数:
估计就是经过加密后的函数跟off_418004数组进行对比,相同则输出,且是30的长度,那就确定了,falg长度是30,但上面那个是29,感觉。。。。。。不妙
目前出现过两个数组:off_418000和off_418004,找出来:
所以,总结一下:
两个线程,一个加密然后减减,一个只减减,而减的数字是29
说明只有奇数进行加密,偶数不变
加密函数:
先判断输入的值是否是大小写
判断之后,匹配两个数组的值是否一样,如果004数组的值跟000数组的值一样,找000数组那个值的下标
如果是大写:下标+96,小写:下标+38
为什么在脚本里是大写+96,而伪代码里面是大写+38,那是因为,脚本里面判断大小写的是a数组(加密过后的),伪代码里面是flag,还没有加密过,所以反了
脚本(因为没有除26个字母之外的字符,所以就简化了):
1 |
|
最后给了一个长度位29的flag,少了一位,猜出来是E
中间有个堆栈不平衡的知识点:
F5 sub_411940函数失败
我们点击菜单栏>>Options>>General>>勾选Stack points
发现飘红的上方的sp值都是负的,我们用Alt+K改为正的值或者改为0x00
就能查看伪代码了
之后关于加密函数我又分析了一波,不想让自己半知半解
a = b[flag[1]-38]
逆向求flag:
先求出来 b = a Ascii值的那一位,然后位数+38
自己太菜了,这么简单的逻辑还有想半天哎~😓