使用de4dot反混淆失败,使用ilspy查看失败,使用dnspy关键函数无法打开反编译查看,楼主反反编译器太厉害了。
所以这里使用的是自己写的IL查看工具
可以看到Rgdhkl4pre0继承来自Form是该程序的主窗体,其中ObSFH4就是刚才在dnspy中无法查看反编译的类型,推测验证代码就藏在其中。
从Metadata信息来看这个方法没有异常处理程序,没有swich分支混淆,不过体积达到了惊人的280K,77039条指令。
其中在GyTJb9nLa中的DjAzNWBx应该是Program的Main入口函数
看到其中拦截了异常
[C#] 纯文本查看 复制代码 AppDomain.CurrentDomain.UnhandledException += GyTJb9nLa.u8klHZPY;
这里应该就是验证失败的分支,作者降低了难度让所有的失败都以throw的形式抛出异常,使得验证逻辑简化了不少。
回到ObSFH4方法中,把方法跟踪一下,其7万余条指令最终产生了高达1112514002次指令执行,最高一条指令执行了35366次。
观察其大部分指令为ldc.i4 ceq brfalse这类型的分支指令,我们忽略执行次数过高的指令关注执行次数为1的指令,很快发现了
这里开始应该就是访问txtbox控件获取字符串的地方,但是指令还是太多了,我们需要对指令流反混淆。
这里反混淆包括去除Nop,将SizeOf转为立即数,利用虚拟机合并可计算指令
这里包括但操作数指令
[IL] 纯文本查看 复制代码 //neg 0x65
//not 0x66
//conv.i1 0x67
//conv.i2 0x68
//conv.i4 0x69
//conv.i8 0x6A
//conv.r4 0x6B
//conv.r8 0x6C
//conv.u4 0x6D
//conv.u8 0x6E
双操作数指令
[IL] 纯文本查看 复制代码 //add 0x58
//sub 0x59
//mul 0x5A
//div 0x5B
//div.un 0x5C x
//rem 0x5D
//rem.un 0x5E x
//and 0x5F
//or 0x60
//xor 0x61
//shl 0x62
//shr 0x63
//shr.un 0x64 x
//add.ovf 0xD6
//add.ovf.un 0xD7 x
//mul.ovf 0xD8
//mul.ovf.un 0xD9 x
//sub.ovf 0xDA
//sub.ovf.un 0xDB x
//ceq 0xFE01
//cgt 0xFE02
//cgt.un 0xFE03
//clt 0xFE04
//clt.un 0xFE05
移除无用分支指令
[IL] 纯文本查看 复制代码 brfalse.s
brtrue.s
beq.s
bge.s
bgt.s
ble.s
blt.s
bne.un.s
bge.un.s
bgt.un.s
ble.un.s
blt.un.s
brfalse
brtrue
beq
bge
bgt
ble
blt
bne.un
bge.un
bgt.un
ble.un
blt.un
switch
模拟合并System.Math,System.Convert等数学运算,
最后我们得到了一个较为清洁的代码
将反混淆后的代码写入并重新跟踪,并对关键clt、Ldsfld、Stsfld、Stelem_I1指令和String.get_Length()、Object.ToString()、Encoding.GetString()、StringBuilder.GetLength()、StringBuilder.Chars[Index]、Striing.IndexOff方法下断,我们得以分析到其关键指令流程
这里获取输入并转为byte[]数组
将输入转为字符串
然后使用StringBuilder.Append组装了一个日语字典,并使用ToString()取出
这里开始组装最终密钥
我们跳到源码看一下组装流程
[IL] 纯文本查看 复制代码 [76131] 0 callvirt System.Char System.Text.StringBuilder.get_Chars(Int32 index)
[76132] 0 callvirt System.Int32 System.String.IndexOf(Char value)
[76133] 0 add
[76134] 0 stsfld System.Int32 <Module>.FixedUpdate
[76135] 0 ldsfld System.Byte[] <Module>.GetTypes
[76136] 0 ldsfld System.Int32 <Module>.get_Syntax
[76137] 0 dup
[76141] 0 ldc.i4 1
[76174] 0 add
[76175] 0 stsfld System.Int32 <Module>.get_Syntax
[76176] 0 ldsfld System.Int32 <Module>.FixedUpdate
[76185] 0 ldc.i4 16
[76218] 0 shr
[76227] 0 ldc.i4 255
[76260] 0 and
[76261] 0 conv.u1
[76262] 0 stelem.i1
虽然我们发现了
[IL] 纯文本查看 复制代码 [76625] 0 ldsfld System.Byte[] <Module>.GetTypes
[76626] 0 ldlen
[76627] 0 conv.i4
[76635] 0 ldc.i4 9
[76668] 0 ceq
[76672] 0 ldc.i4 0
[76703] 0 ceq
[76704] 0 stsfld System.Boolean <Module>.LogWarning
[76705] 0 ldsfld System.Boolean <Module>.LogWarning
[76706] 0 brfalse 76710
[76708] 0 newobj System.Exception..ctor()
[76709] 0 throw
[76710] 0 ldsfld System.Byte[] <Module>.GetTypes
[76714] 0 ldc.i4 0
[76747] 0 ldelem.u1
[76756] 0 ldc.i4 215
[76790] 0 bne.un 76914
[76791] 0 ldsfld System.Byte[] <Module>.GetTypes
[76799] 0 ldc.i4 8
[76833] 0 ldelem.u1
[76842] 0 ldc.i4 33
[76875] 0 ceq
结合上下逻辑我们得到其Key验证代码为
[C#] 纯文本查看 复制代码 public static bool Key(string hex)
{
List<byte> temp = new List<byte>();
for (int i = 0; i < (hex.Length / 2); i++)
{
byte m = Convert.ToByte(hex.Substring(i * 2, 2), 16);
temp.Add(m);
}
string key = Encoding.Default.GetString(temp.ToArray());
string dic = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやよらりるれろわをぐげござじずぞだぢづでばびぶべぱぴぷぺぽ";
int round = key.Length / 4;
byte[] temp2 = new byte[round * 3];
for (int i = 0; i < round; i ++)
{
int start = i * 4;
int m1 = dic.IndexOf(key[start]);
int m2 = dic.IndexOf(key[start + 1]);
int m3 = dic.IndexOf(key[start + 2]);
int m4 = dic.IndexOf(key[start + 3]);
int m5 = ((m1 << 18) + (m2 << 12) + (m3 << 6) + m4);
start = i * 3;
temp2[start] = (byte)(m5 >> 16);
temp2[start + 1] = (byte)(m5 >> 8);
temp2[start + 2] = (byte)(m5);
}
if (temp2.Length != 9)
return false;
return temp2[0] == 215 && temp2[8] == 33;
}
所以其KeyGen代码应为
[C#] 纯文本查看 复制代码 public static string KeyGen()
{
byte[] m = Encoding.Default.GetBytes("成功");
string dic = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやよらりるれろわをぐげござじずぞだぢづでばびぶべぱぴぷぺぽ";
int[] indexs = new int[12];
Random random = new Random();
indexs[0] = 0x35;
indexs[1] = 0x30;
indexs[10] = 0x00;
indexs[11] = 0x21;
for (int i = 2; i < indexs.Length - 2; i++)
indexs[i] = random.Next(dic.Length);
StringBuilder b2 = new StringBuilder();
foreach (int index in indexs)
b2.Append(dic[index]);
byte[] data = Encoding.Default.GetBytes(b2.ToString());
b2.Clear();
foreach (byte b in data)
b2.Append(b.ToString("X2"));
return b2.ToString();
}
生成一个实验一下A4C5A4B8A4D5A4DDA4C0A4D9A4D4A4B1A4BAA4BFA4A2A4E1
|