吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2492|回复: 14
收起左侧

[KeyGenMe] 一个C#编写的神奇的KeyGenMe

[复制链接]
谁将平生葬倾城 发表于 2023-9-27 16:49
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

本帖最后由 谁将平生葬倾城 于 2023-9-27 21:41 编辑

一个C#编写的神奇的KeyGenMe

保护措施

无壳,有简单混淆。混淆强度不是太高。

题目要求

输入正确的序列号,提示 "注册成功!" 即可。

这是KeyGenMe,爆破和修改字符串提示信息不算。

回帖提供正确的序列号视为攻击成功!

成功截图:

附件:






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
无奈的地刺王 + 1 + 1 热心回复!
月之点点 + 1 + 1 我想知道这是啥混淆工具,居然可以防止反编译

查看全部评分

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

duwenjie15 发表于 2023-10-6 11:19
使用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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

免费评分

参与人数 2吾爱币 +3 热心值 +2 收起 理由
凉游浅笔深画眉 + 2 + 1 难点是反混淆,算法其实就是改了码表的base64,大佬牛逼
谁将平生葬倾城 + 1 + 1 牛逼牛逼,真大佬

查看全部评分

qq465881818 发表于 2023-9-28 13:26

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x
 楼主| 谁将平生葬倾城 发表于 2023-9-28 14:43
本帖最后由 谁将平生葬倾城 于 2023-9-28 17:41 编辑
qq465881818 发表于 2023-9-28 13:26

加油,离成功还有很远的距离。
头像被屏蔽
taotao1997 发表于 2023-9-30 21:48
提示: 该帖被管理员或版主屏蔽
罗萨 发表于 2023-10-4 17:21

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
谁将平生葬倾城 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

 楼主| 谁将平生葬倾城 发表于 2023-10-4 20:37
罗萨 发表于 2023-10-4 17:21
https://www.52pojie.cn/thread-1840543-1-1.html

什么玩意,帖子被删了?
 楼主| 谁将平生葬倾城 发表于 2023-10-5 09:47
罗萨 发表于 2023-10-4 17:21
https://www.52pojie.cn/thread-1840543-1-1.html

这是控制流混淆,直接特征码替换可能会导致代码执行流程错乱。
罗萨 发表于 2023-10-5 12:26
谁将平生葬倾城 发表于 2023-10-5 09:47
这是控制流混淆,直接特征码替换可能会导致代码执行流程错乱。

试一下就知道了 换完干净的很
头像被屏蔽
月之点点 发表于 2023-10-5 13:47
提示: 作者被禁止或删除 内容自动屏蔽
 楼主| 谁将平生葬倾城 发表于 2023-10-5 17:46
月之点点 发表于 2023-10-5 13:47
我现在很想知道。这是用什么工具混淆的。

github上随便搜的
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-23 15:30

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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