吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6457|回复: 22
收起左侧

[CTF] Gslab游戏安全竞赛社会组WP(第二轮第二题)

[复制链接]
loudy 发表于 2017-8-7 21:28
本帖最后由 loudy 于 2017-10-17 08:37 编辑

最近新开了一个微信公众号:风云处(fyc1687),欢迎大家多多交流。其中我会逐步把我学习逆向的经验、实例、技巧分享出来。
一、整体轮廓

      IDA载入,发现了TLSCreateThread反调试,直接nop掉即可。程序流程很清晰,但其中调用了mono生成的dll,且程序中自己实现了donet虚拟机(简单修改了msil指令集),导致dump出的encrypt.dll无法分析,也无法找出其中的函数。
0.png

二、encrypt.dll处理
  找到关键位置,发现明显的PE文件特征,dump大小为0x1200
1.png
  该dll文件进行了人为修改,导致PE编辑工具无法识别。结合PE格式手工识别,容易发现下图红线处应该为0 2.png
  修改后PE编辑工具可识别,但其中的donet元数据识别不准确,元数据信息也被修改。
3.png
  对照donet元数据格式,修改文件中下图标红出(自己生成一个donet的Dll文件,对照看更佳,本人就是用这种办法),第二条红线处改为‘s’,另外三条红线处清0(具体请参考doNet格式)。
4.png
  对照修改,直到能识别所有元数据,修改完成后如下图所示。
5.png
  此时可以用Reflector载入,但Refector只能识别类结构和函数名,却无法准确识别函数结构体,函数的实现看不到。实际上程序中用mono实现了一个本地.net运行时,经过分析发现,程序中实现的doNet虚拟机指令即在标准指令操作码的基础上加了0x0f,故只要找到函数体位置,手工或者自动实现将操作码数值减去0x0f0xD0以上操作码不变),而操作数不变,即可还原。此处可以用IDA识别MSIL,依次手动修改操作码。还原后,用Reflector载入,可以看到函数已经正确识别。
6.png 7.png
  本人是对照IDA手工修改的。
8.png
  可能是由于手工修改有差错,导致ConvertUIntToBytesEncryptDataFile两个函数没有反编译,但这两个函数比较简单,不影响分析。

二、主要算法
  (1ConvertBytesToUInt,将4字节转化为32位无符号整数。   
[C#] 纯文本查看 复制代码
private static uint ConvertBytesToUInt(byte[] input, int pos)
       {
            // This item is obfuscated and can not be translated.
            uint num = (uint)(input[pos]) + (uint)(input[pos + 1] << 0x8) + (uint)(input[pos + 2] << 0x10) + (uint)(input[pos + 3] << 0x18);
            return num;
}
   

  (2ConvertUIntToBytes,将32位无符号整数转化为4字节。      
[C#] 纯文本查看 复制代码
        private static byte[] ConvertUIntToBytes(uint x)
        {
            byte[] dst = new byte[4];
            for (int i = 0; i < 4; i++)
            {
                dst = (byte)(x & 0xff);
                x = x >> 8;
            }
            return dst;
        }

  (3CombineBytes,将byte[]连接起来。        
[C#] 纯文本查看 复制代码
        private static byte[] CombineBytes(byte[] bytes1, byte[] bytes2)
        {
            byte[] dst = new byte[bytes1.Length + bytes2.Length];
            Buffer.BlockCopy(bytes1, 0, dst, 0, bytes1.Length);
            Buffer.BlockCopy(bytes2, 0, dst, bytes1.Length, bytes2.Length);
            return dst;
        }

  (4Code,主要的编码函数,主要的逆向对象,对输入进行0x20轮的编码加密。        
[C#] 纯文本查看 复制代码
        private static uint[] Code(uint[] v, uint[] k) 
        {
            uint num = v[0];//0x54d6f3ea
            uint num2 = v[1];//0x1e865afc
            uint num3 = 0;
            uint num4 = Convert.ToUInt32(Math.Floor((double)((Math.Pow(5.0, 0.5) - 1.0) * Math.Pow(2.0, 31.0))));
            uint num5 = 0x20;
            while (num5-- > 0)
            {
                num += ((num2 << 4) ^ ((num2 >> 5) + num2)) ^ (num3 + k[(ushort)(num3 & 3)]);
                num3 += num4;
                num2 += ((num << 4) ^ ((num >> 5) + num)) ^ (num3 + k[(ushort)((num3 >> 11) & 3)]);
            }
            return new uint[] { num, num2 }; //0xbfd3b335  0xcc918c5e
        }

  (5Encrypt,对原数据加密,其中调用了上面这些函数。        
[C#] 纯文本查看 复制代码
        public static byte[] Encrypt(byte[] input)
        {
            uint[] k = new uint[] { 0x54d6f3ea, 0x15ac3f5d, 0x1e865afc, 0x6583a5b1 };
            byte[] buffer = new byte[0];
            int length = input.Length;
            byte[] buffer2 = new byte[8];
            int num2 = 7 - (length % 8);
            buffer2[0] = (byte)num2;
            for (int i = 0; i < num2; i++)
            {
                buffer2[i + 1] = (byte)((200 + num2) - i);
            }
            for (int j = 0; j < (7 - num2); j++)
            {
                buffer2[(j + num2) + 1] = input[j];
            }
            uint[] v = new uint[] { ConvertBytesToUInt(buffer2, 0), ConvertBytesToUInt(buffer2, 4) };
            v[0] ^= k[0];
            v[1] ^= k[2];
            v = Code(v, k);
            buffer = CombineBytes(CombineBytes(buffer, ConvertUIntToBytes(v[0])), ConvertUIntToBytes(v[1]));
            for (int m = 7 - num2; m < length; m += 8)
            {
                v[0] ^= ConvertBytesToUInt(input, m);
                v[1] ^= ConvertBytesToUInt(input, m + 4);
                v = Code(v, k);
                buffer = CombineBytes(CombineBytes(buffer, ConvertUIntToBytes(v[0])), ConvertUIntToBytes(v[1]));
            }
            return buffer;
        }

  (6EncryptDataFile,其主要逻辑即为读入文件(areyouok.png)内容,调用Encrypt对文件内容加密,将加密数据存入另一个文件(areyouok_encrypted

三、算法逆向
      Code函数中,num4虽然计算过程很复杂,但其实为固定值0x9e3779b9num3初值为0,最后一轮结束后num3 0xc6ef3720。根据该函数的对成性,可以写出Code函数的逆函数InvCode如下。        
[C#] 纯文本查看 复制代码
        private static uint[] InvCode(uint[] v, uint[] k)
        {
            uint num = v[0];
            uint num2 = v[1];
            uint num3 = 0xc6ef3720;
            uint num4 = Convert.ToUInt32(Math.Floor((double)((Math.Pow(5.0, 0.5) - 1.0) * Math.Pow(2.0, 31.0))));
            uint num5 = 0x20;
            while (num5-- > 0)
            {
                num2 -= ((num << 4) ^ ((num >> 5) + num)) ^ (num3 + k[(ushort)((num3 >> 11) & 3)]);
                num3 -= num4;
                num -= ((num2 << 4) ^ ((num2 >> 5) + num2)) ^ (num3 + k[(ushort)(num3 & 3)]);
            }
            return new uint[] { num, num2 };
        }

  因此对文件解密过程如下。      
[C#] 纯文本查看 复制代码
            int rNum = 0x1be8;
            byte[] rData = new byte[rNum];
            byte[] wData = new byte[0];
            FileStream rFile = new FileStream("data.encrypted", FileMode.Open);
            FileStream wFile = new FileStream("data.png",FileMode.Create);
 
            rFile.Read(rData, 0, rNum);
 
            uint x0 = 0, x1 = 0, x00 = 0, x11 = 0;
            uint[] k = new uint[] { 0x54d6f3ea, 0x15ac3f5d, 0x1e865afc, 0x6583a5b1 };
            for (int i = 0; i < rNum; i = i + 8)
            {
                uint[] v = new uint[] { ConvertBytesToUInt(rData, i), ConvertBytesToUInt(rData, i+4) };
                x00 = v[0];
                x11 = v[1];
                v = InvCode(v, k);
                if (i == 0)
                {
                    v[0] ^= k[0];
                    v[1] ^= k[2];
                }
                v[0] ^= x0;
                v[1] ^= x1;
                x0 = x00;
                x1 = x11;
                wData = CombineBytes(CombineBytes(wData, ConvertUIntToBytes(v[0])), ConvertUIntToBytes(v[1]));
            }
 
            for (int i = 0; i < rNum - 7; i++)
            {
                wData = wData[i + 7];
            }
 
            wFile.Write(wData, 0, rNum - 7);

  解密得到文件data.png,打开如下。

9.png
  通过以上代码对文件data.png加密,发现加密结果和题中给出结果(data.encrypted文件)一致,说明解密函数是正确的。winhex打开data.png文件,发现图中阴影部分(第二个“sRGBchunk)与png文件格式无关,且最后chunk最后的CRC32结果也不对,为无效chunk,猜测为嵌入的数据。
10.png
  将该chunk数据提取出,用winhex载入,发现下图红线处恰好为其后数据大小,这和bmp文件格式一致。
11.png
  将头两字节改为“BM”,然后另存为xy.bmp
12.png
  打开xy.bmp,得到最终结果。
13.png
  全文完。
12.png

Program.zip

1.5 KB, 下载次数: 6, 下载积分: 吾爱币 -1 CB

点评

图掉了,兄弟。  发表于 2017-8-7 22:12

免费评分

参与人数 11威望 +1 吾爱币 +18 热心值 +11 收起 理由
Three_fish + 1 + 1 谢谢@Thanks!
Rihanna + 2 + 1 热心回复!
WYWZ + 1 + 1 用心讨论,共获提升!
樱落丶未央 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
老虎爱吃素 + 1 + 1 热心回复!
Sound + 1 + 7 + 1 已经处理,感谢您对吾爱破解论坛的支持!
冰冰冰冰冰橙 + 1 + 1 用心讨论,共获提升!
无痕软件 + 1 + 1 用心讨论,共获提升!
a952779523 + 1 + 1 谢谢@Thanks!
55555555 + 1 + 1 我看不懂.所以我给分
守护神艾丽莎 + 1 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

KaQqi 发表于 2017-8-9 07:22
本帖最后由 cqr2287 于 2017-8-9 07:23 编辑
loudy 发表于 2017-8-8 19:28
这个不知道怎么弄,我粘贴时是好的

可以试试 插入-插入代码-c-输入内容-插入

编辑最右边一格有一个 <>符号的按钮,点它就行
 楼主| loudy 发表于 2017-8-10 22:47
cqr2287 发表于 2017-8-9 07:22
可以试试 插入-插入代码-c-输入内容-插入

编辑最右边一格有一个 符号的按钮,点它就行

改好了,新技能get

免费评分

参与人数 1热心值 +1 收起 理由
KaQqi + 1 热心回复!

查看全部评分

唯爱而生 发表于 2017-8-7 21:43
zbnysjwsnd8 发表于 2017-8-7 22:18
{:1_910:}图片GG

免费评分

参与人数 1热心值 +1 收起 理由
KaQqi + 1 我很赞同!

查看全部评分

 楼主| loudy 发表于 2017-8-7 22:22

现在呢,我这边一切正常,之前是外链图片,现在图片存本站

点评

可以了。。。  发表于 2017-8-7 22:23
trombe108 发表于 2017-8-7 22:30
什么东东啊
安之噗嗤 发表于 2017-8-8 00:00
膜拜
qiaoqiaota 发表于 2017-8-8 00:33
谢谢!正好需要,十分感激!
KaQqi 发表于 2017-8-8 07:18
后面的主要算法那粘贴的代码有点散架了.看不太习惯
a38695746 发表于 2017-8-8 07:40
好好谢谢楼住
无痕软件 发表于 2017-8-8 08:39
有启发!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 13:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表