首页
社区
课程
招聘
[旧帖] [原创]坛中一个C#.net Plese Find Password 的全面分析 0.00雪花
发表于: 2010-7-11 00:06 3486

[旧帖] [原创]坛中一个C#.net Plese Find Password 的全面分析 0.00雪花

2010-7-11 00:06
3486

针对文:http://bbs.pediy.com/showthread.php?t=110507

见到该帖后受不得诱惑,从仅有的28kx币中拿出2kx下载学习,的确很有意思,但也存在疑问,在此一并提出.

该帖中提及的代码叫Crack Me Hamishebahar,从GOOGLE中搜索应该来自伊朗的一个黑客和破解论坛,该作者已经给出了PASSWORD,但寻求求解它的方法.

下面我们对代码进行分析:

1)首先我们看到的程序是个loader,它要求您输入一个可多行的password,不如说是一个解码KEY,然后通过这个KEY解码程序目录下的一个加密DLL,并通过Assembly.Load()加载后执行.正确加载执行后会弹出一个伊朗文的提示框,否则英文提示PASSWORD错误.

2)下面我们看它的关键:如何验证KEY和解码加DLL:

/// <summary>
        /// 这可是关键!
        /// 1)先取头五个字节来验证 password(其实也就是解码KEY)
        /// 2)文件最后五字节放着,正式文件开始五字节的解码结果,用来验证解码是否正确,不正确就不白费功夫了.
        /// 3)接下来按照解码KEY长度,一段段取来解码并显示进度,最后把剩下部分解码但去掉最后的八个字节,(三个一字节计算因子,一个五字节验证用值)
        /// 4)结果是个DLL,把它返回
        /// </summary>
       /// <param name="LoadFile"></param>
       /// <param name="Password"></param>
       /// <returns></returns>
        public byte[] GetPasswordByte(string LoadFile, string Password)
        {
            List<byte> list = new List<byte>();
            if (File.Exists(LoadFile))
            {
                byte[] buffer = new byte[Password.Length];
                using (FileStream stream = new FileStream(LoadFile, FileMode.OpenOrCreate))
                {
                    if (this.MainPrg != null)
                    {
                        this.MainPrg.Maximum = Convert.ToInt32(stream.Length);
                        this.MainPrg.Value = 0;
                    }
                    stream.Seek(stream.Length - 8L, SeekOrigin.Begin);
                    this.Rnd1 = Convert.ToByte(stream.ReadByte());  //保存那个DLL尾-8处的一个字节
                    stream.Seek(stream.Length - 7L, SeekOrigin.Begin);
                    this.Rnd2 = Convert.ToByte(stream.ReadByte());  //保存那个DLL尾-7处的一个字节
                    stream.Seek(stream.Length - 6L, SeekOrigin.Begin);
                    this.Rnd3 = Convert.ToByte(stream.ReadByte());  //保存那个DLL尾-6处的一个字节


                    byte[] buffer2 = new byte[5];
                    byte[] password = new byte[5];
                    stream.Seek(stream.Length - 5L, SeekOrigin.Begin);
                    stream.Read(buffer2, 0, 5);                     //取那个DLL尾-5处的五个字节

                    stream.Seek(0L, SeekOrigin.Begin);
                    stream.Read(password, 0, 5);                    //取DLL开头的五个字节
                      
                    password = this.GetPassword(password.ToList<byte>(), Password); //取文件开头五字节解码


                    if (!this.Check(buffer2, password)) //和验证值比较看是否解码正确,以证明Password是对的
                    {
                        return null;
                    }

                    //下面开始真正的解码工作
                    stream.Seek(0L, SeekOrigin.Begin);
                    for (int i = 0; i < stream.Length; i++)
                    {
                        if ((i + Password.Length) >= (stream.Length - 8L))
                        {
                            int count = Convert.ToInt32(stream.Length) - i;
                            buffer = new byte[count];
                            stream.Seek((long) i, SeekOrigin.Begin);
                            stream.Read(buffer, 0, count);
                            buffer = this.GetPassword(buffer.ToList<byte>(), Password);
                            list.AddRange(this.SelectList(buffer.ToList<byte>(), 0, count - 8));
                            if (this.MainPrg != null)
                            {
                                this.MainPrg.Value = this.MainPrg.Maximum;
                                Application.DoEvents();
                            }
                            goto Label_024C;
                        }
                        stream.Seek((long) i, SeekOrigin.Begin);
                        stream.Read(buffer, 0, Password.Length);
                        buffer = this.GetPassword(buffer.ToList<byte>(), Password);
                        list.AddRange(this.SelectList(buffer.ToList<byte>(), 0, Password.Length));
                        if (this.MainPrg != null)
                        {
                            this.MainPrg.Value += Password.Length;
                            Application.DoEvents();
                        }
                        i += Password.Length - 1;
                    }
                }
            }
        Label_024C:
            return list.ToArray();
        }
/// <summary>
        /// 看看它在做什么?按Password的长度逐段调用解码方法解码,开始或最后不够Password的长度时按实际长度解码
        /// </summary>
        /// <param name="RET"></param>
        /// <param name="Password"></param>
        /// <returns></returns>
        public byte[] GetPassword(List<byte> RET, string Password)
        {
            List<byte> list = new List<byte>();
            for (int i = 0; i < RET.Count; i += Password.Length)//步长为password文本的长度,第一次时RET.Count为五,其后则取Password.Length为RET.Count,最后取文件剩下的长度
            {
                if ((i + Password.Length) > RET.Count)//如果当前完成位置再按步长增加超出要解码的字节数组长时
                {
                    list.AddRange(this.GetPasswordByte(this.SelectList(RET, i, RET.Count - i), Password));//取剩下的部分解码
                    break;
                }
                list.AddRange(this.GetPasswordByte(this.SelectList(RET, i, Password.Length), Password).ToList<byte>());//按password文本的长度,一段段解码
            }
            return list.ToArray();
        }
/// <summary>
        /// 解码方法:
        /// 
        /// 对每个字节在0x00~0xff范围内进行轮式加减操作,如下:
        /// (0~255轮操作)加214
        /// (0~255轮操作)减199
        /// 加第二个参数对应字节 (0~255轮操作)
        /// 减第二人参数的长度 (0~255轮操作)
        /// 加3   (0~255轮操作)
        /// 
        /// 其实是种按字节解码的方法,传入字节的多少没什么关系,只要字节数不大于Password长度,分多段解后合起来和一次解都一样
        /// </summary>
        /// <param name="MyByte"></param>
        /// <param name="Password"></param>
        /// <returns></returns>
        private byte[] GetPasswordByte(List<byte> MyByte, string Password)
        {
            List<byte> list = MyByte;
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = this.GoPByte(this.Rnd3, list[i], true);
                list[i] = this.GoPByte(this.Rnd2, list[i], false);
                list[i] = this.GoPByte(Convert.ToByte(Password[i]), list[i], true);
                list[i] = this.GoPByte(Password.Length, list[i], false);
                list[i] = this.GoPByte(this.Rnd1, list[i], true);
               
            }
            return list.ToArray();
        }

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 30
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习了。看来楼主很有见地
2010-7-11 00:24
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这个crack me确实很难搞定。好长时间都搞不懂
2010-7-11 00:42
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
4
有点久了, 大致上只记得当时我是放弃DOS头猜法, 就如你讲的复杂又真搞得出来吗?
而且网上并无这CM的资讯所以无法得知者是否变太.

我用的方法:  一般dll文件后面皆是 00
  1. 找出 Block 长度, 否则免谈.
     .dll(最后8byte不看) 最后是 1A F8 F1 06, 往前找同其值,
     找到后位置相减即为 Block Len.  (1BFC-1B82=7A)
  2. 有了长度就可算出 Block 起点
      看一下起点是落在 1B82 ~ 1BFC 的何处
     ((1B82 div 7A) + 1)*7A = 1BA4
     所以一个完整的被编码Block位置在 1BA4 ~ 最后 因byte不够, 可参看上一个 Block 即知
     假设解密后为 00 00 00 00 00 ...............

如此破之
2010-7-11 01:31
0
雪    币: 8
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
太好了 大牛
2010-7-11 03:10
0
雪    币: 160
活跃值: (29)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
果然精妙,眼前一下又是一片天空,太好了,谢谢!
2010-7-11 08:51
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
7
邀请码大约是10天一次发放
你没问题的
2010-7-11 11:26
0
雪    币: 160
活跃值: (29)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
先谢谢你的鼓励!
2010-7-11 22:26
0
雪    币: 160
活跃值: (29)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
安心学知识吧!
2010-7-16 17:56
0
雪    币: 3
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
LZ用什么反编译的呢,用REFLECT看有点奇怪
2010-7-16 23:18
0
雪    币: 160
活跃值: (29)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
有什么奇怪的呢?你是说那个dll吗?它是动态载入的,而且是被加密了不能用的,只有你的password对了,解密出来才是一个真正的pe格式文件.

从C++通常的习惯来看,类似于这样:

一个主程序,调用了一个dll,功能写在这个dll中.但这个dll被以逐位的方式进行了加密,不再是一个pe文件了.主程序要用户输入一个口令(一个解密key),然后它用这个key解密这个不成样子的dll,接下来才用LoadLibary载入并执行这个dll,key不对拦载错误告诉你:错了!,解对了,当然执行的也就很顺畅,dll内的内容就表现出来了.

所以解密前,那个dll就是一堆乱码.而主程序只是个加载和解码辅助程序.不知道我是不是猜对了您的发问本意,多交流,共同进步!
2010-7-16 23:42
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
膜拜下,仔细看看过程
2010-7-17 00:16
0
雪    币: 2477
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
膜拜下,仔细看看过程
2010-7-23 14:25
0
游客
登录 | 注册 方可回帖
返回
//