首页 > 代码库 > [逆向][Writeup]EIS2016 chkflag - .NET程序逆向

[逆向][Writeup]EIS2016 chkflag - .NET程序逆向

这是一道比较简单的逆向题,难点之处在于chkflag.exe是.NET编译生成的,如果用IDA进行逆向难度很大,因此本题主要考察.NET逆向工具的使用。题目中使用的二进制文件可以从我的github上下载:https://github.com/gsharpsh00ter/reverse

0x01 工具准备

在对.NET程序进行反编译时,常用的一个工具为.NET Reflector,但是目前该工具是收费的。本例中我们使用另一款开源的.NET反编译工具dnSpy。dnSpy是一款开源的基于ILSpy发展而来的.NET程序的编辑、反编译和调试神器,可对.NET程序进行反编译和动态调试,界面友好,功能强大。

dnSpy下载地址:

https://github.com/0xd4d/dnSpy/releases

下载后解压直接运行即可,但是需要先安装.NET框架。安装后进行逆向分析和调试的界面如下:

技术分享

0x02 逆向

将chkflag.exe拖入dnspy,查看入口函数,如下:

 1 // chkflag.Module1
 2 // Token: 0x06000001 RID: 1 RVA: 0x00002048 File Offset: 0x00000248
 3 [STAThread]
 4 public static void Main()
 5 {
 6     ReadOnlyCollection<string> commandLineArgs = MyProject.Application.CommandLineArgs;
 7     ulong num = 91713730301111000uL;
 8     string @string = Resources.ResourceManager.GetString("f");
 9     string string2 = Resources.ResourceManager.GetString("i");
10     string description = MyProject.Application.Info.Description;
11     //命令行必需有8个参数
12     if (commandLineArgs.Count != 8)
13     {
14         Console.WriteLine(string2);
15         return;
16     }
17     string[] array = Resources.ResourceManager.GetString("p").Split(new char[]
18     {
19          
20     });
21     checked
22     {
23         int num2 = commandLineArgs.Count - 1;
24         //命令行的每一个参数需要符合array中规定的格式
25         for (int i = 0; i <= num2; i++)
26         {
27             if (!LikeOperator.LikeString(commandLineArgs[i], array[i], CompareMethod.Binary))
28             {
29                 Console.WriteLine(@string);
30                 return;
31             }
32         }
33         //将所有的命令行参数拼接成一个字符串
34         string text = string.Join("", commandLineArgs);
35         string text2 = "";
36         string text3 = "";
37         int num3 = text.Length - 1;
38         //对拼接的字符串进行处理,如果某字符为数字,则拼接到text3,反之拼接到text2
39         for (int j = 0; j <= num3; j++)
40         {
41             char c = text[j];
42             if (char.IsDigit(c))
43             {
44                 text3 += Conversions.ToString(c);
45             }
46             else
47             {
48                 text2 += Conversions.ToString(c);
49             }
50         }
51         //如果拼接后的text3逆序之后转化为整数为num(91713730301111000uL),并且text2逆序之后为description,则将在命令行打印flag
52         if (ulong.Parse(Strings.StrReverse(text3)) == num && Strings.StrReverse(text2).Equals(description))
53         {
54             Console.WriteLine("EIS{" + string.Join("_", commandLineArgs) + "}");
55             return;
56         }
57         Console.WriteLine(@string);
58     }
59 }

0x03 分析

处理逻辑比较简单。首先,程序会检查命令行参数的个数,参数必须有8个,否则会打印“参数错误”而退出。

 技术分享

然后,程序会检查每一个参数是否符合指定的格式,参数格式在array中指定,通过动态调试,可以得到array的内容如下:

 技术分享

即:["?#?","?##","?#??#?##?","?#","?#?#?#?","#?#","?#??#","?#?#"],其中’?’表示字母,’#’表示数字,比如”?#?”表示第一个参数应该是“字母+数字+字母”的形式。

之后程序将命令行所有的参数进行拼接,成为一个字符串。

拼接完命令行参数后,会继续对拼接的字符串进行处理,如果某字符为数字,则拼接到text3,反之拼接到text2

最后,对text2和text3进行判断。如果text3逆序之后转化为整数为num,并且text2逆序之后为description,则将在命令行打印flag。

Num的值在反编译得到的代码中可以看到,为91713730301111000UL。

Description可以通过动态调试得到,为“aFhgRhrVcRttcffDTTn”

 技术分享

通过上述逻辑,用如下python代码进行逆向计算,即可得到我们向chkflag传递的命令行参数:

 1 #!/usr/bin/python2
 2 
 3 patterns     = ["?#?","?##","?#??#?##?","?#","?#?#?#?","#?#","?#??#","?#?#"]
 4 num            = "91713730301111000"
 5 desc        = "aFhgRhrVcRttcffDTTn"
 6 args        = []
 7 numidx         = 0
 8 descidx     = 0
 9 for pattern in patterns:
10     arg = ""
11     for k in xrange(0, len(pattern)):
12         if pattern[k] == ?:
13             arg += desc[::-1][descidx]
14             descidx += 1
15         else:
16             arg += num[::-1][numidx]
17             numidx += 1
18     args.append(arg)
19 print args

打印出的命令行参数为:

[‘n0T‘, ‘T00‘, ‘D1ff1c11t‘, ‘t0‘, ‘R3c0V3r‘, ‘7h3‘, ‘R1gh7‘, ‘F1a9‘]

在命令行运行chkflag,并传递上述参数,可得flag:

技术分享

最终flag为:

EIS{n0T_T00_D1ff1c11t_t0_R3c0V3r_7h3_R1gh7_F1a9}

[逆向][Writeup]EIS2016 chkflag - .NET程序逆向