点击此处获得更好的阅读体验
WriteUp来源
题目描述
题目考点
- 内存取证
解题思路
首先分析Image类型
1 | c.\volatility_2.6_win64_standalone.exe -f image.vmem imageinfo |
然后查看一下运行中的进程:
1 | 0x85987160 vmtoolsd.exe 2408 2296 8 191 1 0 2021-01-17 15:03:40 UTC+0000 |
可以看到一个叫做EvilImage.exe
的进程,看上去明显不太对,于是首先将exe扣下来看看:
1 | .\volatility_2.6_win64_standalone.exe -f image.vmem --profile=Win7SP1x86_23418 procdump -p 1884 --dump-dir . |
之后检查代码逻辑:
1 | v3 = LoadLibraryW(L"Evil.dll"); |
发现是在读取同一目录下的一个叫做Evil.dll的dll,然后调用checkFlag
这个函数。那么我们可以尝试去查找这个dll。
1 | .\volatility_2.6_win64_standalone.exe -f image.vmem --profile=Win7SP1x86_23418 dlllist -p 2248 |
可以看到dll的路径,于是我们尝试把dll dump到文件中。
1 | .\volatility_2.6_win64_standalone.exe -f image.vmem --profile=Win7SP1x86_23418 filescan | findstr Evil.dll |
分析dll,首先找到我们需要分析的函数为checkFlag
1 | int checkFlag() |
之后直接分析sub_10001000
函数,根据关键字可知,使用了chacha20算法。于是这边直接照搬算法解密脚本,写一个解密函数
1 | int decrypt_fake() |
但是打印出来的flag却是错误的flag{This_flag___is__fake!_LoL}
,于是只能重新考虑这个问题。
如果直接选择dump内存中的dll,可能会避开这个坑
然而整个题目本身应该是有解的,于是重新考虑问题,进程中load的dll会不会并不是磁盘上的这个dll呢?
找到内存中的dll:
1 | .\volatility_2.6_win64_standalone.exe -f image.vmem --profile=Win7SP1x86_23418 dlldump --pid=1884 --dump-dir=1884 |
并且将其dump下来,重新用ida加载:
1 | int checkFlag() |
会发现逻辑和之前的完全不一样,于是这里猜测使用了一些奇怪的手段实现的文件换,观察内存中的字符串会发现,这个dll的名字应该也叫做Evil.dll
。之后的逻辑就是对这个函数进行逆向。可以看到,除应有的传入的flag之外,这里还会交互读入了一个变量,并且从后文的加密函数中使用这个变量,并且进行一个数学运算,揭开来之后作为后续的算法使用,不过总体来看,应该还是使用的chacha20。于是剩下的就是一些逆向工作(整体还是使用的chacha20)。
1 | struct chacha_ctx ctx; |
大佬WP by 魔法少女雪殇
常规取证
1 | volatility -f image.vmem --profile=Win7SP1x86 pslist |
找到可疑进程EvilImage,然后利用filescan|grep "Evil"寻找程序本体
发现EvilImage.exe与dll,然后filedump出来后,这些dll均为fake,只会解出fakeflag 正确操作:
1 | volatility -f image.vmem --profile=Win7SP1x86 dlllist -p 1884 |
利用dlldump导出正确的dll,导入ida进行逆向 逆向部分: 打开Evil.dll,找到checkFlag,使用反编译
1 | int __cdecl checkFlag(char *a1) |
这里是真正的dll,和fakedll的密钥扩展方式和加密方式相同,但是密钥和比对的文本不同,并且多了一步验证用户输入的操作。
其中sub_73441000
是密钥扩展函数,sub_73441140
是加密函数,sub_73441AB0
是scanf
在验证第二次输入的地方下断点,得到正确的影响key的输入 chunqiu!
查看加密函数,发现都是异或和移位操作,大概率再加密一次即可解出正确的明文,所以尝试再次加密密文。
在call sub_74331140的地方下断点,把用户输入(第一个参数)改为要比对的密文(byte_734430F8),将使用内存窗口观察第三个参数(v8)的变化,然后直接单步执行,发现v8已经变成了flag。
再次执行程序验证,确是flag。
Flag
1 | flag{R3im@aging_1ndir3ctly_LoL} |