little fish (re)
链接:https://pan.baidu.com/s/1Wpl5KjFQf33hgQpE29YuKQ
提取码:slh8
复制这段内容后打开百度网盘手机App,操作更方便哦
程序打不开,提示缺少libstdc++-6.dll,做完google半天找这个库下载,但都是32位的。。想验证flag都不行。。
ida中main函数伪代码,很简单:
加密函数整体:里面还涉及2个表,且加密有点绕。感觉是什么加密。。但不清楚。。
之后从百度了其中的一个表中部分数据,从一篇文章中找到加密算法:
其实题目文件有提示,但对于不知道这个加密算法来说就是没有提示。。。
然后找blowfish加密算法文章学习。讲的好清楚
再次回到ida中看题目中的加密算法,对比下,这次当然是清楚好多,也确定了就是正常的blowfish加密。
先是写找到网上的blowfish加密算法,使用C语言写来模拟了下,然后解密:
1 |
|
python的话,找到了可以使用Crypto模块。
goole和百度下用法:得到和C语言中一样的结果:
最后,本题关键就是算法的学习。
magic_number (pwn)
第一次遇到,利用vsyscall中的ret指令充当滑梯,直到可以通过覆盖低字节处得到我们指定函数的地址。
查保护:关键就是程序开启了PIE。
PIE全称是position-independent executable,中文解释为地址无关可执行文件,该技术是一个针对代码段(.text)、数据段(.data)、未初始化全局变量段(.bss)等固定地址的一个防护技术,如果程序开启了PIE保护的话,在每次加载程序时都变换加载地址。
本题,栈溢出,控制程序走向即可。但难的就是有PIE使程序每次加载的地址不一样。
利用vsyscall绕过PIE。可以利用的地址是0xffffffffff600000、0xffffffffff600400、 0xffffffffff600800,因为他们是不变的。
首先查看利用proc文件查看程序加载的基地址:
更改ida载入的基地址使其与之对应。找到要下断的地址。
gdb下断调试,通过查看栈确定需要使用vsyscall的个数。可以看到使用4个即可。
找到需要控制程序走向的目的地址。(即system(‘bin/sh’);)
所以最后只需将最低字节的80覆盖为A8即可。
exp:
1 | from pwn import * |
VM_WORLD(re)
链接:https://pan.baidu.com/s/1BYmMrqGaiKT6W_HVd9eoPA
提取码:5b5o
复制这段内容后打开百度网盘手机App,操作更方便哦
一个简单的虚拟机题目,从学校师傅哪里学会了修复ida无法F5switch语句的方法。
首先简单看一下:
所以进入OD动态到关键函数,并dump出,载入ida:可以看到是不能F5的。
但看了一下这个函数的代码也不是很长,直接读汇编将其写成了C语言代码:一个简单的虚拟机。
1 |
|
其实就只有异或和加减操作,简答逆一下即可:
1 |
|
后面问了出题师傅,才知道那个是可以修复一下的。其实就是switch语句的每个跳转用了一张表来存储,但由于基地址等对不上,导致分析出错。
所以首先修改与表对应的基地址,然后恢复储存跳转的表。
最后手动修改swicth的声明:
olfo(2020.10.17 n1ctf)
首先打开ida看不到发现没有找到main函数,这是加了花指令,ida找不到。。从start可以看到。
花指令很少(2种)也很简单,手动去除都可。。
jmp
call
然后就是用fork()函数创建一个子进程,返回2次,当是父进程时返回一个大于0的数,且在父进程使用ptrace函数获得一些后面异或需要的数据。
对于我,关键就是fork()多进程的调试,这里ida我动调一直在wait状态。。
然后找到gdb多进程调试。使用set follow-fork-mode [parent|child]指定调试的进程,用show follow-fork-mode查看被调试的进程。fork 多进程调试
其它的就不说了,最后直接idapython得到flag。
还有就是一篇关于ptrace理解的文章(很详细):ptrace
ctfshow_大牛杯(2021/5/4)
easy
一个base移位的操作,然后考了一个逻辑表达式化简,记录一下。
首先看到移位:
每5个变4个,实质就是把5*8 = 40位,分成了40/10 = 4,1个字节存放不下,所以结果使用dword型数据存放的。这和那些base64,base32都是一个道理,就看怎么分配那些位。base64:除以6;base32:除以5;其它都是依次类推。
然后逻辑表达式运算:4一个都是一样的计算,每次处理4个字节,一共16个字节。把这个运算写出来:(a^b)&(~(a&b)) = a^b;
显然,上面的&运算是不可逆的,数字电路学过这种化简的,对上面可进行如下的化简:最后就是一个异或。
最后开始用C语言写了一个常规的移位还原:
1 |
|
其实这种用python处理起来是十分方便的,也通用。首先提取出所有的二进制位,然后根据分配原则,还原就好了。
1 | enc = [0x000001A9, 0x00000233, 0x00000179, 0x0000017F, 0x000001A5, 0x000002C6, 0x00000137, 0x00000358, 0x000000E1, 0x00000305, 0x000003EC, 0x00000153, 0x0000015D, 0x00000247, 0x0000017B, 0x00000201] |
GKCTF(2021.6)
KillerAid
一个C#逆向,C#层是第一层加密,关键加密在dll中。
使用dnspy看到c#层:涉及输入id和code的简单异或加密。
可以看到最后调用了CheckCode函数,这是一个从载入的dll中导出的函数。
到ida中调试该dll,直接闪退,那一般就是有反调试了,
直接找了找IsDebuggerPresent相关的函数,确实有但下断后调试根本没有断下来。
然后猜测是动态获取相关api来调用的方式,像一些恶意文件的做法,也果然在字符串中找了IsDebuggerPresent相关反调试相关的字符串,从字符串定位到:
接着继续向上找相关函数调用,来到的反调试函数,这里面的反调试还不少,多种多样:
继续向上回溯,可以发现是创建一个线程来调用这个这个反调试的函数,那直接将这个创建线程的函数patch掉就能调试了。
以上也是本题相对于比较隐藏的一个点,利用动态获取所有要使用的api的方式隐藏反调试的代码。
后面就很常规了。
看到从这个dll导出的CheckCode函数,一个标准的aes加密,只是加密了32轮,然后每轮的key和iv不一样,分析时做了一定的注释:
1 | __int64 __fastcall CheckCode(__int64 input_code) |
解密脚本:
1 | from Crypto.Cipher import AES |
验证: