学习目的:
- 虽然.net程序老了,但偶尔会有阴间比赛会有,所以熟悉一下其中一个重要工具。
- 重新复习一下dump 修改操作 和动调的具体应用。
- 要仔细看懂没学过的函数或方法的具体作用,不然会一开始就走岔路。
.net程序
用dnSpy打开调试程序。
起初是这部分内容。刚看时查GetMethod没看仔细,以为是调用该函数。但实际上,是获取该函数的地址的byte并保存为一个数组。
之后作解密操作。即通过下边的计算,将其改为可以操作的程序,且不是保存在MetMett这个函数。而是在另一个函数MetM。
可以看到有Froml.bb 和 array 几个数组
解题思路
打开程序后开始寻找关键函数,发现MetMett函数没有被反编译,起初以为是有什么混淆
说明一下几个关键的函数
MetMetMet
获取输入,转base64,之后调用函数MetM,这个函数是通过上边提到的MetMett变化而来
之后进行对比,判断对错
因此程序执行流程为:
- 通过对MetMett函数的机器码进行解密操作,生成一个函数MetM,这个函数是解密后的MetMett
- 输入经过base64变换后与MetM函数比较。
这里采用动态调试的解题办法
在 Form1()下断,启动。
打开调试->窗口->监视。输入bb。这样我们就可以获取bb的值了。
我们需要先确认函数MetMett的地址
打开后即函数的地址,可以看到是没解密前的机器码,我们就可以确定了地址
在 红框处下断
之后看bb的值,已经发生改变
用十六进制编辑器 winhex等工具 用此时的bb的值替换掉地址处的值,这样便成功还原了关键函数 MetMett
重新打开文件,效果如下:
private static void MetMett(byte[] chk, byte[] bt)
{
if (bt.Length == 12)
{
chk[0] = 2;
if ((bt[0] ^ 16) != 74)
{
chk[0] = 1;
}
if ((bt[3] ^ 51) != 70)
{
chk[0] = 1;
}
if ((bt[1] ^ 17) != 87)
{
chk[0] = 1;
}
if ((bt[2] ^ 33) != 77)
{
chk[0] = 1;
}
if ((bt[11] ^ 17) != 44)
{
chk[0] = 1;
}
if ((bt[8] ^ 144) != 241)
{
chk[0] = 1;
}
if ((bt[4] ^ 68) != 29)
{
chk[0] = 1;
}
if ((bt[5] ^ 102) != 49)
{
chk[0] = 1;
}
if ((bt[9] ^ 181) != 226)
{
chk[0] = 1;
}
if ((bt[7] ^ 160) != 238)
{
chk[0] = 1;
}
if ((bt[10] ^ 238) != 163)
{
chk[0] = 1;
}
if ((bt[6] ^ 51) != 117)
{
chk[0] = 1;
}
}
}
因此,易得脚本
import base64
bt = [0 for i in range(12)]
print(bt)
bt[0] = chr(74 ^ 16)
bt[3] = chr(70 ^ 51)
bt[1] = chr(87 ^ 17)
bt[2] = chr(33 ^ 77)
bt[11] = chr(17 ^ 44)
bt[8] = chr(144 ^ 241)
bt[4] = chr(68 ^ 29)
bt[5] = chr(102 ^ 49)
bt[9] = chr(181 ^ 226)
bt[7] = chr(160 ^ 238)
bt[10] = chr(238 ^ 163)
bt[6] = chr(51 ^ 117)
print(base64.b64decode("".join(bt)))
# dYnaaMic