buu re wp
buuoj re wp
CrackRTF
- ida定位main函数F5
|
|
-
题目需要输入两次密码,分别经加密函数后与已知字符串比较
-
第一次加密
-
加密前
atoi
函数作用是把string形式的数字转化为int类型的数字,提示前6位密码为6位数字 -
sub_40100A
是第一个加密函数,内部调用了windows库的加密函数,可以通过查看windows官方文档辨别参数得知为sha1加密,我这里是用动调对比在线加密网站加密结果确定加密算法为sha1
-
|
|
- sha1是单向散列函数,没法逆,幸好是6位数字,直接爆破拿到密码
123321
|
|
-
同理第二个加密算法可知为md5,但没有限定为数字,试了试6位数字爆破没有结果,6位全字符爆破不现实
-
继续往下看
sub_40100F
传参调用了输入的str
|
|
- sub_401005函数内部进行逐位异或
|
|
-
_8数组初值为资源AAA中的值,可用ResourceHacker查看资源得到
-
lpString的值可由RTF文件头得到
7B 5C 72 74 66
,但这只有5位,翻看大佬wp好像第6位默认是0x31?但这一点翻了会google未找到依据 -
我这里是先用异或解出前5位,然后结合md5爆破出最后一位,虽然麻烦,但确保正确
|
|
运行程序输入两次密码,会生成dbapp.rtf
文件,打开即可看到flagFlag{N0_M0re_Free_Bugs}
[2019红帽杯]easyRE
-
参考官方wp,这真是道眼力题。。
-
进ida,首先看到start函数,啥也不是,翻string窗口,很显眼的
You found me
,跟进去
|
|
-
两次输入,两次加密比较,都很常规
-
第一个异或解密
|
|
-
第二个可以看出来是base64加密了10遍,解密得到
https://bbs.pediy.com/thread-254172.htm
,然后寄! -
翻各种奇奇怪怪的系统函数实现,也没看出来个所以然,看了看wp,其实上面文章中也有提示,但我也没认真看((
-
在第二次加密后比较的字符串位置后面,还存着一个
规律的字符串
- 查交叉引用定位函数
sub_400D35
|
|
- 第一次异或得到前四位为
flag
,第二次异或输出flag
|
|
[FlareOn4]login
- 解压压缩包得到一个html文件,源码如下
|
|
- 计算
rotFlag
属于是极致的压行了,为的就是让人迷糊看不懂,翻译成py大概长这样
|
|
-
flag所有位会先加上13,然后如果符合if条件会再减26
-
要想完全理清楚一位一位逆回去很麻烦,但总的来说逆回去要么加13要么减13
-
盲猜flag是有意义的字符串,所以我把可能的情况全列出来(一位两种可能),人工挑选正确答案
|
|
- 程序输出
|
|
-
其中如果某一行既有字母又有非字母,可以直接舍弃非字母,因为非字母开始就不会被替换
-
仔细看一会,得到
flag{[email protected]}
[GUET-CTF2019]re
-
拖入ida发现函数很少,感觉有壳,果然是upx,先脱壳然后再进ida
-
主要函数
|
|
- 主要加密在sub_4009AE
|
|
- 上z3搞它
|
|
- 打印flag
|
|
-
这里有两个小问题
-
伪代码中16、17两位顺序反了,但因为z3搞的时候是顺着命名未知数的,所以反上加反等于顺序正确,不用修改
-
另一点就是第6位缺失,并未进行判断,实测无论第6位是什么,源程序都会输出
Correct!
,应该是多解,但无奈buu平台上只认第6位为1
-
-
故
flag{e165421110ba03099a1c039337}
[SUCTF2019]SignIn
- 进ida看到main函数
|
|
-
标准的用gmp库实现的RSA算法
-
利用gmpy2库解出flag
|
|
[WUSTCTF2020]level1
- main函数
|
|
- 有强转直接逆不太保险,正着直接爆出来
|
|
-
(这两天题咋越做越简单了,,
[MRCTF2020]Transform
-
进ida就能看到main函数,简单改一下变量名
|
|
- 直接逆拿flag
|
|
[ACTF新生赛2020]usualCrypt
- 进ida看main函数
|
|
- encrypt函数
|
|
-
出题人在寒顺的开头和结尾耍了一点小心思
-
上面先简单的换了个base64的表,下面把base64编码后的字符串中的字母进行大小写转换
-
最终得到的字符串与已知字符串比较
-
写脚本拿flag
|
|
Youngter-drive
-
参考g0ul4sh的wp,大佬写得很详细,学到很多
-
总的来说,这是一道很有意思的题
-
先要脱upx壳,然后拖进ida,main函数
|
|
CreateThread
API 会创建新线程,这道题涉及到多线程。CreateMutex
创建一个互斥体,用于防止多线程中出现资源争用,即多个线程同时读写同一个资源的情况,所创建的互斥体的句柄会存到全局变量hObject
中(注意前面的两个冒号表示是全局变量,而不是这个函数里同名的局部变量)。这里创建了两个线程,入口点分别位于函数StartAddress
和sub_41119F
StartAddress
线程内部函数
|
|
|
|
-
这里发现个小问题,通过函数实现判断sub__41112C函数和内部sub_411940函数参数顺序颠倒,猜测是stdcall和cdecl传参顺序不同引起的,但ida识别错误
-
sub_41119F
线程内部函数
|
|
- 自己做的时候不懂多线程,以为这个函数没啥用,导致卡死
查 MSDN 知,可以用
WaitForSingleObject
等待互斥体的使用权(ownership)空闲出来,并获取使用权,然后再访问和其他线程共享的资源,访问完后,用ReleaseMutex
释放使用权,给其他线程使用的机会4。通过比较两线程的函数,很容易知道所共享的资源就是全局变量dword_418008
,它的初值是 29。而这两个线程一前一后创建,理论上是StartAddress
先获得使用权,后来的sub_41119F
进入等待状态,前者执行一次循环后释放使用权,与此同时后者等待结束、获得使用权,进入循环,循环完后释放使用权,前者又获得使用权,如此循环往复。也就是说,两个线程的操作是交替进行的。
-
故实现的功能是奇数位加密,偶数位不变
-
还是喜欢直接爆
|
|
-
爆破中间又发现了个算法的小问题,按这样加密table中的第一位永远也用不到,且必须最后加个\0才能防止数组下标越界,可能是出题人的疏忽,还是故意?
-
最后还有个小坑,输入应该为30位,但程序验证的即我们所能解出的只有29位,应为多解,但出题人以及buu平台上默认最后一位是E才能correct
-
总结一下,这道题集合了upx脱壳,反调试(但可以像我一样只静态分析),多线程这么多知识点,可以说十分优秀了,也让我学到了很多
[WUSTCTF2020]level2
-
没啥说的,纯新手题,upx脱个壳,ida打开汇编main函数就能看到flag{Just_upx_-d}
相册
-
安卓逆向,就对着jeb使劲翻吧
-
有一个C2类比较有用
|
|
-
可以看到像
MAILUSER``MAILPASS
这样的变量很像是我们所要的邮箱 -
但还是对java/jeb不熟悉,单知道JNI却不知道NativeMethod,还以为是什么内置函数,找半天也找不到,后面查到有关java中的native才懂原来和JNI基本是一个东西
-
于是解压apk,在lib文件夹中找到so文件,拖进ida,找export,看到了
Java_com_net_cn_NativeMethod_m
,跟进去就能看到base64编码的字符串MTgyMTg0NjUxMjVAMTYzLmNvbQ==
-
base64decode得邮箱
[email protected]
[MRCTF2020]Xor
-
异或拿flag
[HDCTF2019]Maze
-
upx脱壳,进ida
-
有个花指令,稍微修一下,就能F5了,main函数
|
|
- string窗口翻翻就能找到地图,总共70个字符,试了试应该是10*7
|
|
-
手动走一下ssaaasaassdddw,即flag{ssaaasaassdddw}
[GWCTF 2019]xxor
-
main函数
|
|
- 输入六串数字,先进行tea加密,然后进sub_400770要解一个小方程组
|
|
|
|
- 逆过来先z3解方程
|
|
- 然后tea解密
|
|
-
long_to_bytes一下拿flag{re_is_great!}
[MRCTF2020]hello_world_go
-
main函数
|
|
-
翻aFlagHelloWorld就能看到flag{hello_world_gogogo}
-
这道题最有用的是让我装了idaGolangHelper
[WUSTCTF2020]level3
-
main函数
|
|
-
可以看出最终flag是这段字符串
d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD==
base64解密得到的 -
但标准base64解密出来是乱码,说明对base64做了手脚、
-
其实是在start函数中藏了一个换表的操作
|
|
-
可以计算拿到新表,但更好的方法是直接动调就能拿到新表
-
写脚本拿flag
|
|
[FlareOn4]IgniteMe
- main函数
|
|
- 主要内容在check函数
|
|
- 异或拿flag
|
|
[FlareOn6]Overlong
-
由题目结合数组猜测数据没有打印完全
-
把代码dump下来,循环次数加大,运行即可拿flag
|
|
[FlareOn3]Challenge1
- main函数
|
|
- sub_401260函数
|
|
-
看到下面的
aZyxabcdefghijk
就感觉有点base64换表那味,试了一下,还真是 -
脚本
|
|
[ACTF新生赛2020]Oruga
-
新颖的迷宫题
-
逻辑函数
|
|
-
只要当前字符为0,就朝一个方向一直走下去,越界就寄了
-
手动走一下
-
flag:actf{MEWEMEWJMEWJM}
[Zer0pts2020]easy strcmp
-
出题人在main函数之前修改了strcmp函数
-
动调找到修改后的代码
|
|
-
其实是把input减去qword_559B07401060与
zer0pts{********CENSORED********}
比较 -
刚开始想逐位解密,但发现中间8位有问题,应该是有进位的原因
-
还是得强转成qword运算,但实测这么算出来最后会多一位
*
,删掉即可
|
|
-
flag{l3ts_m4k3_4_DETOUR_t0d4y}
[ACTF新生赛2020]Universe_final_answer
-
main函数
|
|
- 验证函数
|
|
- 直接上z3
|
|
- ida里的数据顺序很乱,手动调整一下
|
|
-
拿到key,运行程序输入key拿到flag
Crack me
-
集合了各种反调试的一道题
-
main函数
|
|
-
先后输入用户名(welcomebeijing)和密码,每次输入过后有一个
sub_CD24BE
函数,动调发现对user和passwd都没影响,跳过即可 -
主要加密/判断在
sub_CD1830
函数
|
|
-
从上到下总共三次反调试操作,上面已经是patch过的版本(对应汇编jz与jnz互改)
-
上面一个while循环实现了从字符串数据中获得原本字符值,具体可动调试试
-
下面加密部分大致可分为3块,下面倒着分析
-
第一块
-
整个函数最后返回验证的是
check
值,而check值应由sub_CD1470
获得 -
sub_CD1470
函数
|
|
-
可见有意义字符串
dbappsec
,把check异或上相应的值正好是验证所需的0xab94,由此可得到v17的值 -
第二块
-
倒退上去是
sub_CD1710
函数
|
|
-
首先下面第二个if else中的else一定不会被执行,因为a3不可能大于v3,具体依赖参数分析
-
第一个if内的条件又是个反调((
-
1 2 3 4 5 6 7 8 9 10
BOOL CheckDebug() { STARTUPINFO si; GetStartupInfo(&si); if (si.dwFlags!=1 || si.dwX!=0 || si.dwY!=0 || si.dwXSize!=0 || si.dwYSize!=0 || si.dwXCountChars!=0 || si.dwYCountChars!=0 || si.dwFillAttribute!=0) { return TRUE; } else { return FALSE; } }
-
按说题目给的if判断应该是正常情况下(不在调试)满足if条件,进行异或
-
但这却是问题所在,要得到buu平台上的flag不能进这个异或,是buu出了问题?还是有什么更大的坑?暂时不得而知
-
第三块
|
|
-
由以上两步拿到了v17的值,这一步是要得到v15的值
-
如何得到
byte_CE6050[(unsigned __int8)(v8 + v13)]
的值是关键 -
unsigned __int8
的强制类型转换确保数组下标在0-255(8位) -
可行的方案理论上有两种
-
动调到循环开始dump下来byte_CE6050的值,然后把整个代码dump下来跑一遍,但由于担心在我没注意的地方byte_CE6050被修改,我选择了第二种方法
-
纯动调取值,这里遇到的麻烦是ida里调试的时候无法直接查看表达式的值,需要自己去找比较麻烦,但能确保数据正确
-
-
最后得到的8个值
key = [0x2a,0xd7,0x92,0xe9,0x53,0xe2,0xc4,0xcd]
-
脚本
|
|
-
不加第二步时输出buu平台可过的
flag{d2be2981b84f2a905669995873d6a36c}
特殊的base64
-
main函数
|
|
- 还是base64换表,直接上脚本吧
|
|
-
b’flag{Special_Base64_By_Lich}'
[WUSTCTF2020]level4
-
这道题是个体力活
-
main函数
|
|
- 已知二叉树的中序遍历和后序遍历(运行即可得到),求先序遍历
|
|
- 但由于中间有重复字符,搞了一会没搞出来,转而去看init函数,即二叉树的构建过程,这里需要手动修一下结构体,最终效果
|
|
- 结构体如下,val的大小可以观察一下汇编中的数据得到
|
|
-
根据只有左右节点,没有父节点的特点可以确定23号为root
-
然后建立整棵树
|
|
-
先序遍历走一下拿到flag
wctf2020{This_IS_A_7reE}
[网鼎杯 2020 青龙组]singal
-
主要函数如下
|
|
-
a1是前面初始化时生成的一个表,可以看出全程不会改变
-
变量值都是已知的,求flag
-
目的简单明确,把它逆了,但有很多细节问题
-
-
a1里存的并非全是操作数,有些是需要参与运算的值,上一步的操作决定步长(即下一步的操作),逆过来的时候无法判断步长(即a1_cnt是减1还是减2)
-
v3,v4,v5,v6的结束值即逆写的初值需要确定
-
default里goto label_2需要明白其实没啥用
-
-
针对以上解决方案(可能不是最优
-
-
所有操作后步长(a1_cnt)均设置成最小步长-1,然后加一个判断,是否是真正的操作数,不是的话再a1_cnt-1
-
v3分析一下会发现运行时会先被赋值后进行运算,所以无需初值。至于v4,v5,v6,这几个得自己数一遍,如果只是遍历一遍看进哪个case可能会把非操作数算上,还好数量不太大,最后数出来三个数都是15
-
至于default正常运行是不会进去的,忽略即可
-
-
最后贴出脚本,调试了好久才出,写得有点繁琐但不想改了((
|
|
-
flag{757515121f3d478}
[GUET-CTF2019]number_game
-
第二次做这题了,发现了种非预期解(
-
main函数
|
|
- sub_400758
|
|
- sub_400807
|
|
- copy
|
|
- sub_400917
|
|
- 从后往前看,
sub_400917
函数结合byte_601060
发现是个5*5的数独,手动填一下
|
|
-
得到了主函数中的
a1a
0421421430
-
上面两个函数,将input逐层建了一个二叉树,然后再中序遍历赋值给
ala
-
正常做法是根据得到的
ala
即中序遍历建树,由于树从左到右生长,确保了答案的唯一性,这是我第一次做的时候的做法,如图
|
|
- 这次做突然有个大胆的想法,算法只是改变了数字的顺序,那么可不可能会在几次改变顺序后循环呢?于是有了以下尝试,每次将上一次动调得到的改变后的数组当作下一次的输入,幸运的是,第6次过后我就获得了成功,数据如下
|
|
-
没有严谨的证明,但这确实不失为一种很高效的非预期解
-
flag{1134240024}