C#逆向接触的不多 一些C#的用法也不熟悉 正好跟着ZM师傅的WP复现一遍学一学
题目附件+最终工程 : https://wwk.lanzouj.com/iMUBa1rp2icb
因为这题我们要自己编写加载 所以最好把C#提取出来 用ILSPY把核心模块re1提取出来 vs2022打开
这样就很方便 也能很容易查看交叉引用
输入fakeflag后得到这种输出
本来是一个while true 但是会因为随机到除数为零而导致异常
只是这里的异常没有处理?
而Flaghelper那儿有AppDomain.CurrentDomain.UnhandledException += delegate
搜了搜发现C#的委托可以用来实现事件和回调方法
注意到这里:
就是在遍历右边列出的一大堆 FlagMachine_xxxx
而chosen刚好取出的也是4位
下面的SetFlag
Vmeflag
然后这个setflag是套着的 一个套一个 还会输出BrainPower
…
发现其共有接口是 IFlagMachine
但是每个实现都对flag异或了不同的值
最终在 FakeFlagMachine
的Vmeflag
进行最后的校验
看 IsRealFlag
一个大check 但是这些都是写好了的 我们只需要关注参数怎么来的
关键点就是parameter 追溯到前面的ResetState
发现是8byte
往前跟踪一下看看这个参数怎么传进来的
如果能动调就很显然 但是前面有一大段函数进行了反调试check 只能静态分析
不难猜到其实Meow~!?!
那四个8byte的字符串就是传进来的parameter
分析一下现在得到的信息:
输入一个长度为72的flag
取四个字符串中的一个作为parameter
在一大堆FlagMachine_xxxx
中找到与flag前4个字符匹配的进行调用 每个函数xor的值不一样
最后进入IsRealFlag
check
那么就爆破可能情况吧 : parameters+FlagMachine_xxxx
用python提取出函数名的xxxx 修改C#进行爆破
提取文件名:
import os
filepath = r"D:\浏览器下载\moectf2023天网\re1\KoitoCoco.MoeCtf"
namelist = os.listdir(filepath)
names = []
for c in namelist:
try:
if(c[-8]=='_'):
names.append(c[-7:-3])
except:
pass
with open(r"D:\浏览器下载\moectf2023天网\re1\dic.txt","r+") as f:
for name in names:
f.write(name)
f.write('\n')
print("[+] Done!")
由于我们是ILSPY反编译 不可能完全还原 如果调用全部的话肯定编译错误
所以我们只在几个关键.cs修改 不必加载整个程序 利用 C#顶级语句
可以不用是用Main
修改Program.cs
using System;
using System.IO;
using System.Linq;
using System.text;
using KoitoCoco.MoeCtf;
string[] s = File.ReadAllLines("./dic.txt");
string[] paras = { "Meow~!?!", "meoW?!~~", "me0w~?!!", "mEow????" };
foreach (var para in paras)
{
Console.Write(para + ": ");
foreach(var ss in s)
{
string text = "moectf" + ss;
string chosen = text.Substring(7, 4);
// 下面这段照抄原程序遍历的代码
if (Activator.CreateInstance((from item in AppDomain.CurrentDomain.GetAssemblies()
from type in item.GetTypes()
where type.Name.EndsWith(chosen)
select type).FirstOrDefault((Type i) => i.Name.Contains("FlagMachine"), typeof(FlagMachine))) is IFlagMachine flagMachine)
{
flagMachine.SetFlag(Encoding.UTF8.GetBytes(s4));
flagMachine.VmeFlag(text);
}
}
Console.Write(para + " Finished!\n");
}
然后修改IsRealFlag 只check前11位 然后满足条件就输出parameters和11位的flag
public static bool IsRealFlag(byte[] flag, byte[] paramaters)
{
ResetState(paramaters);
int[] array = new int[72]
{
143, 75, 130, 35, 251, 51, 51, 49, 92, 145,
151, 13, 30, 200, 47, 14, 231, 100, 49, 169,
56, 25, 94, 176, 116, 11, 128, 10, 186, 63,
185, 45, 216, 55, 190, 72, 130, 200, 139, 252,
58, 250, 37, 151, 179, 220, 200, 35, 111, 41,
100, 87, 203, 54, 7, 81, 59, 153, 165, 71,
255, 195, 220, 144, 112, 243, 227, 251, 228, 232,
246, 251
};
int[] array2 = new int[11]; // 我们现在爆破check前11位 moectf{xxxx
for (int k = 0; k < 11; k++)
{
array2[k] ^= GetNextSpellcard();
}
for (int l = 0; l < 11; l++)
{
array[l] ^= flag[l] ^ array2[l];
}
bool ok = true;
for(int i = 0; i < 11; i++)
{
if (array[i]!=0)
ok = false;
}
if (ok == true)
{
Console.Write("Find!\n");
Console.WriteLine(Encoding.UTF8.GetBytes(flag));
foreach(var par in paramaters)
{
Console.Write(par);
Console.Write(", ");
}
Console.WriteLine();
}
}
写好直接是跑不起来一点…
捣鼓半天终于跑起来了 几个点注意:
- 【.Net Core】编译.net core时报错“找不到资产文件“project.assets.json”
- 把isrealflag那个cs前面也要加上 using System;…
然后删掉那些没啥用的b/c/i/j .cs 然后根据报错慢慢调整 就能make来跑起来了
啊哈哈哈…
Let the bass kick Ooooooo…
那就把唱BrainPower
的删掉吧…
把ButAnother
和YetAnother
两个函数里的Jooo…删掉
然后就开始爆破~
慢慢等 毕竟要跑 4x9906
由于是复现 我直接把para顺序调一调
!!!
得到了parameters 那么直接再次修改Program.cs调用输出即可
我们直接在KoitoMagicalShop.cs
加一个函数 直接xor输出
KoitoMagicalShop.Get_Ans:
public static bool Get_Ans(byte[] paramaters)
{
ResetState(paramaters);
int[] array = new int[72]{
143, 75, 130, 35, 251, 51, 51, 49, 92, 145,
151, 13, 30, 200, 47, 14, 231, 100, 49, 169,
56, 25, 94, 176, 116, 11, 128, 10, 186, 63,
185, 45, 216, 55, 190, 72, 130, 200, 139, 252,
58, 250, 37, 151, 179, 220, 200, 35, 111, 41,
100, 87, 203, 54, 7, 81, 59, 153, 165, 71,
255, 195, 220, 144, 112, 243, 227, 251, 228, 232,
246, 251
};
int[] array2 = new int[72];
for (int k = 0; k < 72; k++)
{
array2[k] ^= GetNextSpellcard();
}
for (int l = 0; l < 72; l++)
{
Console.Write((array[l] ^ array2[l]));
Console.Write(' ');
}
var b = true;
return b;
}
Program.sc
byte[] paras = { 231, 239, 247, 240, 136, 161, 120, 14 };
KoitoMagicalShop.Get_Ans(paras);
转成chr
moectf{nUynafeaaz_gOoD_jo6!_you_have_fed_The_CaT_in_The_neT!_xSMrlYDuuM}
总结: 很好的题 加深了一点对C#的理解 也学会了如何用ILSPY+VS来修改&重编译C#工程