首页
论坛
课程
招聘
雪    币: 214
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝

[调试逆向] [原创]影子系统激活算法初步

2009-2-10 18:25 7284

[调试逆向] [原创]影子系统激活算法初步

2009-2-10 18:25
7284
影子系统2008激活码算法探讨初步
By 小飞 lankerr
废话少说,直入主题。
        主程序将输入的激活码发送到驱动中验证,强行修改返回值是不起作用的。
用OD载入PowerMaster.exe,程序用了三种花指令来隐藏对DeviceIoControl调用,其间还有四次异常处理,两次为单步来反调试器,只要去下个StrongOD.dll,即OD的插件就可以躲过检查。外壳程序调用DeviceIoControl时,ControlCode为7C320,InBuff中为输入的注册码,长度为0x1E即30个字符(必须是大写),不过我们在输入的是如:123456789F-123456789L-123456789Y程序会将中间的’-‘号删除,然后到驱动SnpShot.sys中验证。OD是不能跟踪到系统内核的,要用SoftIce(开始我走了弯路,我用Wdasm来反汇编SnpShot.sys找不到IRP分派,用SoftIce跟踪DeviceIoControl的调用才到SnpShot.sys中,后来学用IDA时,反汇编才看到了IRP分派情况)。
真正进入主题,驱动中怎么验证计算激活码?
分两步
一、        将激活码用‘查表法’求模得到一个串。
二、        将上面的串用一加密算法得出一加密串,然后与一长为0x10的串比较,相等则激活成功。
那么我们先说怎样用‘查表法’得出这个串。
a:如下图,我们输入下图这个串“123456789F123456789L123456789Y”

b:用到的表为
CString                GhostKey="D54X379EPJWCYKN1TUFH82VABLSM6QGR";        //查表用到的表,共32个字符
方式为依为返回激活码每个字符在上表中的序数,如1的序数为15,F的序数为21。
C代码:
//=========================================
//
//                查表法返回相应字符的序号
//
//=========================================
int CMy2008Dlg::ScanKeyTable(char T)
{
        int                i=0;

        for(i=0;i<32;i++)
        {
                if(T == GhostKey.GetAt(i))
                        return i;
        }
        return 0;
}
c:将上面返回的值,进行5次循环,求余数,返回‘0’或‘1’,作为下一函数的参数。在这我没用C代码,因为IDIV指令好像没有用C来表示的,还有位移指如rol等也不能C来表示….,函数名之所以叫BB0Mod,是因为在驱动中这个Function地址后三位是BB0
int CMy2008Dlg::BB0Mod(int iii, int sn)
{
        __asm
        {
                cdq
                mov  eax,iii
                mov  ecx,8
                idiv ecx
                mov  ecx,edx
                mov  dl,1
                shl  dl,cl
                mov  eax,sn
                and  dl,al
                neg  dl
                sbb  edx,edx
                neg  edx
                mov  iii,edx
        }
        return iii;
}
d:将循环次数对8求余,根据上面的返回值‘1’或‘0’决定是‘与’或是‘或’操作。这里要用到一新字串:
unsigned        char        XorKey[56]="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
                                        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";长度不需要这么长的,我测试用多写了。
void CMy2008Dlg::DDEMod(int KeySnMod, int kkk)
{
        __asm
        {
                mov        eax,kkk
                cdq
                push 8
                pop         ecx
                idiv ecx
                mov  ebx,1
                mov  ecx,edx
                shl  bl,cl
                lea  ecx,XorKey
                add  eax,ecx
                cmp  KeySnMod,0
                jz         AndByte
                or   [eax],bl
                jmp  DDEmodReturn
AndByte:
                not  bl
                and  [eax],bl
DDEmodReturn:
        }
        return;
}
查表和以及上面两个函数调用情况如下:
For(int j=0;j<30;j++)
{       
        :ScanKeyTable(char T);
                For(int i=0;i<5;i++)
                {
                        BB0Mod(int iii, int sn);
                        DDEMod(int KeySnMod, int kkk);
                }
}
e:上面执行结束后,情况如下图
}

激活码”123456789F123456789L123456789Y”生成”AF 12 11 78 A1 46 BE 4A E0 85 9A FC 11 81”,这所以后面的计算,是因为下面的操作会将81后面的字符填为0,可能是不纳入计算(事实上好像是只计算0x10长度大小)。速个调用如下:
void CMy2008Dlg::OnCalc()
{
        UpdateData(TRUE);
        CString showMsg;
        CString ActiveKey;

        ActiveKey=m_Key1+m_Key2+m_Key3;
        int                KeySn=0;
        int                KeySnMod=0;
        int                kkk=0;
        CString temp;
        for(int j=0;j<30;j++)
        {
                KeySn = ScanKeyTable(ActiveKey.GetAt(j));
                temp.Format("%02d   ",KeySn);
                showMsg+=temp;
                for(int j=0;j<5;j++)
                {
//                        __asm int 3
                        KeySnMod = BB0Mod(j,KeySn);
                        DDEMod(KeySnMod,kkk);
                        kkk++;
                        temp.Format("%d ",KeySnMod);
                        showMsg+=temp;
                }
                temp.Format("\r\n",KeySn,KeySnMod);
                showMsg+=temp;
        }
//        showMsg.Format("%s,字串长:%d",ActiveKey,GhostKey.GetLength());
        ::MessageBox(NULL,showMsg,"显示字符",0x1040);
        char        showBuff[512];
        ::wsprintf(showBuff,"%02X %02X %02X %02X %02X %02X %02X %02X-%02X %02X %02X %02X %02X %02X %02X %02X\r\n\
                %02X %02X %02X %02X %02X %02X %02X %02X",
                XorKey[0],XorKey[1],
                XorKey[2],XorKey[3],
                XorKey[4],XorKey[5],
                XorKey[6],XorKey[7],
                XorKey[8],XorKey[9],
                XorKey[10],XorKey[11],
                XorKey[12],XorKey[13],
                XorKey[14],XorKey[15],
                XorKey[16],XorKey[17],
                XorKey[18],XorKey[19],
                XorKey[20],XorKey[21],
                XorKey[22],XorKey[23]);
        ::MessageBox(NULL,showBuff,"显示Xor字符",0x1040);
}

以上完了成第一步了。到这有一些想法:
一、        影子系统2008在互联网上至今没注册机,全是修改SYS驱动文件达到激活目的,可能是不能做出注册机,或是通用性差。
二、        激活码经过一系列变化,再和指写的内容比较,如不想修改SYS文件,好像只能穷举。用密码工具扫描这个SYS文件时,提示是MD5,经以分析加密函数,发现只是大量的进位乘计算,将结果用于新的计算,进行32循环,看样不是MD5。除非知道用于比较的内存串计算方法,否则还是只能穷举。
三、        ……很多

HWS计划·2020安全精英夏令营来了!我们在华为松山湖欧洲小镇等你

最新回复 (14)
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2009-2-10 18:30
2
0
哈哈,沙发,慢慢看看
雪    币: 215
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
skyege 活跃值 2 2009-2-10 19:15
3
0
分析很透彻,支持……
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
冰山客 活跃值 2009-2-10 20:52
4
0
比较精辟的文章
雪    币: 306
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhupf 活跃值 2009-2-10 23:45
5
0
我也支持一下.
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
likemasm 活跃值 2009-2-11 07:55
6
0
拜读一下,积累中,这种保护与解密的斗争像战斗片,有看头!顶一下。
雪    币: 214
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
lankerr 活跃值 2009-2-11 23:02
7
0
DWORD                *KeyA=NULL;
DWORD                *KeyB=NULL;
unsigned long TempA=0;
unsigned long MulA=0;
unsigned long MulB=0;
unsigned long MulC=0;
unsigned long MulD=0;
unsigned long TempKeyA=0;
unsigned long TempKeyB=0;
void CMy2008Dlg::OnCalc()
{              ....
        KeyA=(unsigned long *)XorKey;
        KeyB=(unsigned long *)(XorKey+4);
        MUL802(*KeyA,*KeyB);
}
long CMy2008Dlg::MUL802(unsigned long a, unsigned long b)
{       
        TempA = a;
        //a:参数1的高位×参数2的低位
        a = a >>16;
        MulA = a * (b & 0xffff);
        //b:参数1的低位×参数2的低位
        MulB = (TempA & 0xffff) * (b & 0xffff);
        //c:参数1的低位×参数2的高位
        MulC = (TempA & 0xffff) * (b >>16);
        MulD = MulA + MulC;

        TempKeyA = MulB + (MulD << 16);
        TempKeyB = 0 + (MulD >> 16);
        if(TempKeyA >=(MulD << 16))
        {
                //d:参数1的高位×参数2的高位
                TempKeyB = a * (b >> 16) + TempKeyB;
        }
//TempKeyA、TempKeyB就是结果
        return 0;
}

在这儿有点问题,参数b是参a的一个Copy,值是一样的?(之所以打?号是只经过了第一执行,还没测试后面的循环)
雪    币: 326
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
快雪时晴 活跃值 4 2009-2-11 23:21
8
0
驱动全部用IDA分析的?
雪    币: 214
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
lankerr 活跃值 2009-2-12 00:41
9
0
IDA看流程,用SoftIce分析的
雪    币: 209
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
turkeypj 活跃值 2009-2-12 09:39
10
0
这个帖子有点意思
雪    币: 181
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wxq 活跃值 2009-2-13 13:04
11
0
强,学习了,支持一下。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hudia 活跃值 2009-2-13 22:09
12
0
不懂。。。。。。
雪    币: 265
活跃值: 活跃值 (28)
能力值: ( LV13,RANK:350 )
在线值:
发帖
回帖
粉丝
moonife 活跃值 8 2009-2-24 19:02
15
0
我下的软件好像已经破解好了的,我也下个注册的实战一下
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
txia 活跃值 2009-2-25 19:06
16
0
支持楼主呀,分析得不错
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
ziyihou 活跃值 1 2009-2-25 19:41
17
0
强贴,学习一下,慢慢看
游客
登录 | 注册 方可回帖
返回