首页
社区
课程
招聘
[原创]SMC与算法结合的快速运用 VC++ (含DEMO和工具源代码)
发表于: 2009-7-31 01:54 12214

[原创]SMC与算法结合的快速运用 VC++ (含DEMO和工具源代码)

2009-7-31 01:54
12214

今天看到《加密与解密 第三版》中关于SMC(Self_Modifying Code)技术实现一章,有自己的一点想法,有可能是前辈早已走过的路,如果内容有重复冲突的话,敬请原谅!
PS:我是菜鸟,高手请直接跳过 :)

SMC技术的原理我这里就不罗嗦了,加密与解密中说得很清楚。
DEMO程序以SMC用于序列号校验为例,加密工具则是实现对DEMO程序中SMC代码的快速加密!

个人觉得要实现SMC主要是解决以下问题:
1,程序本身需解密代码的定位(即需解密代码的起始地址和结束地址)。
2,加密工具对程序需加密部分代码的定位。
3,解密算法是SMC程序强度的关键。这个算法对代码来说是可逆,但对CRACKER来说,却是不可逆的。

我们来一一实现上面3个问题:
1,在程序中定位需加密的起始和结束地址。
    _asm mov address1,offset begindecrypt   // 取待加密代码首地址  关键!
    _asm mov address2,offset enddecrypt     // 取待加密代码末地址  关键!

      begindecrypt  
       {

        需被加密和解密的代码
      }
     enddecrypt     

     以上代码即可实现begindecrypt  为的地址为address1,enddecrypt 地址为address2。

2,定义加密工具所用的标签。这些机器码和字符将在PE文件中体现,并对程序无影响。且插入的字符可被用于加密工具定位。

#define SMCEncryptBegin \
                __asm _emit 0xEB \      机器码EB是JMP的意思,
                __asm _emit 0x10 \      表示要跳到0X10 字节后的地址,后面的SMCENCRYPTBEGIN正好是0x10个,因此对程序无影响。
                __asm _emit 'S' \
                __asm _emit 'M' \
                __asm _emit 'C' \
                __asm _emit 'E' \
                __asm _emit 'N' \
                __asm _emit 'C' \
                __asm _emit 'R' \
                __asm _emit 'Y' \
                __asm _emit 'P' \
                __asm _emit 'T' \
                __asm _emit 'B' \
                __asm _emit 'E' \
                __asm _emit 'G' \
                __asm _emit 'I' \
                __asm _emit 'N' \
                __asm _emit 0x00 \

#define SMCEncryptEnd \
                __asm _emit 0xEB \
                __asm _emit 0x0E \
                __asm _emit 'S' \
                __asm _emit 'M' \
                __asm _emit 'C' \
                __asm _emit 'E' \
                __asm _emit 'N' \
                __asm _emit 'C' \
                __asm _emit 'R' \
                __asm _emit 'Y' \
                __asm _emit 'P' \
                __asm _emit 'T' \
                __asm _emit 'E' \
                __asm _emit 'N' \
                __asm _emit 'D' \
                __asm _emit 0x00 \

以上的emit 为在编译的时侯,将机器语言指令直接嵌入目标码中,不必借助于汇编语言和汇编编译程式。这样在生产的PE文件(即生成的EXE文件)就有了SMCENCRYPTBEGIN,SMCENCRYPTEND字样。

由以上两点,可以写出对函数内任意代码段的加解密,程序如下:
#if _ENABLE_SMCENCRYPT_
    DWORD address1,address2,encryCodeSize;
      _asm mov address1,offset begindecrypt   // 取待加密代码首地址  关键!
    _asm mov address2,offset enddecrypt     // 取待加密代码末地址  关键!
    encryCodeSize=address2-address1;  //得到待加密代码的大小
    //首先解密代码段,因为程序生成后已被加密工具加密。
    DecryptBlock((DWORD *)address1,encryCodeSize,Name);
      SMCEncryptBegin  //给加密工具定位的加密开始地址标签
    begindecrypt:    //给程序自己定位的解密开始地址标签
#endif

{
        需被加密的代码段

}

#if _ENABLE_SMCENCRYPT_
     enddecrypt: //给程序自己定位的解密结束标签
   SMCEncryptEnd//给加密工具定位的加密结束标签
   //加密还原回去,否则第二次解密就错了
   EncryptBlock((DWORD *)address1,encryCodeSize,Name);//调用后加密代码段
#endif

3,算法的选用,我这里选用了RC4,主要是因为a,RC4是成熟算法,强度大;b,RC4的密钥应用完即可丢弃,在程序中不需体现。c,RC4可以生成明文和密文的位数一致的序列,方便加解密时对SIZE的运算。程序主要代码如下:
bool RC4EncryptBlock(void *pStartAddr, int nLength,  LPTSTR strKey)
{
        unsigned char rc4_key[128]={0};
        int key_length = 0;

    key_length = strlen(strKey);
        if(!key_length)//如果长度为0
                return false;

        strcpy((char   *)rc4_key,(LPSTR)(LPCTSTR)strKey);

        struct rc4_state rc4_Encry;

        if(!pStartAddr || nLength <= 0)
                return false;

        unsigned char *pEncry = (unsigned char *)pStartAddr;

        memset(&rc4_Encry,0,sizeof(rc4_Encry));
        rc4_setup(&rc4_Encry,rc4_key,key_length);//得到一个数组
        rc4_crypt(&rc4_Encry,pEncry,nLength);
               
        return true;
}

strKey为RC4的输入密钥,这里可以为F(用户名,序列号)以实现多组用户名和序列号的搭配,我DEMO中为了简便,直接以用户名为KEY。 address1即加密起始地址,它是一个指针,运行完RC4EncryptBlock函数后,指针对应的内容即变换为加密后的内容,解密函数和加密函数同,都为XOR指令。如果密钥(即用户名)不正确的话则解出来的代码即为乱码,运行时即会出现异常错误,可以用CATCH捕获处理。DEMO程序中代码示例如下:
try
{
#if _ENABLE_SMCENCRYPT_
     _asm mov address1,offset begindecrypt   // 取待加密代码首地址
    _asm mov address2,offset enddecrypt     // 取待加密代码末地址
    encryCodeSize=address2-address1;  //得到待加密代码的大小
   //首先解密代码段
   RC4EncryptBlock((DWORD *)address1,encryCodeSize,Name);
    SMCEncryptBegin  //给加密工具定位的标签
   begindecrypt:    //给程序自己定位的标签
#endif

     if(CalcRegCode(Name,SN,szBuff,128))//调用注册码计算函数,
        OnOK();

#if _ENABLE_SMCENCRYPT_
      enddecrypt:
      SMCEncryptEnd
       //加密还原回去,否则第二次解密就错了
    RC4EncryptBlock((DWORD *)address1,encryCodeSize,Name);
#endif

}

catch(...)
{
    ::MessageBox(NULL,_T("!!Unknown exception,Wrong Code or Crecked!"),_T("Error"),MB_OK);
//记得恢复加密代码段
#if _ENABLE_SMCENCRYPT_
      RC4EncryptBlock((DWORD *)address1,encryCodeSize,Name);//调用后加密代码段
#endif       
}

如此,DEMO程序的注意点已全部解决,我们再来分析SMC加密的实现原理:
1,读取PE文件(即程序生成的EXE文件),读取程序写入的标签,这里SMCENCRYPTBEGIN,SMCENCRYPTEND.得到其开始、结束地址,就可知道需要加密的位置和SIZE了。
2,与程序对应的加密方法加密,同样选择RC4。用户自己选择RC4 KEY,这里的KEY将成为DEMO程序中用户输入的正确用户名。
3,加密后写入PE文件即可。

加密工具界面如图:



可实现程序中多处SMC + RC4的快速加密,当然了,也可以扩展为多处不同算法加密,这个自己发挥吧。


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

上传的附件:
收藏
免费 7
支持
分享
最新回复 (10)
雪    币: 15
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
Thanks zenghw For Very Nice Source
2009-7-31 05:49
0
雪    币: 364
活跃值: (1736)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
好的,学习一下
2009-7-31 09:32
0
雪    币: 388
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
学习 时间 实践
2009-7-31 10:08
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
5
应用很方便的,大家可以试试看。
码了很多字,很想知道有没有价值 :)
2009-7-31 11:13
0
雪    币: 264
活跃值: (11)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
6
SDK 非常好的资料..
2009-8-2 11:31
0
雪    币: 418
活跃值: (63)
能力值: ( LV12,RANK:260 )
在线值:
发帖
回帖
粉丝
7
遇到识货的了,
我也觉得SMC加算法用得好的话很强大。
2009-8-4 17:05
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
8
2009-07-31,的贴子,,偶今天才来膜拜
2009-9-7 18:40
0
雪    币: 215
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
这么好的帖子,感谢
2009-9-11 17:02
0
雪    币: 351
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
b不错哦。学习。。
2009-9-13 05:39
0
雪    币: 144
活跃值: (36)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
用在dll中有问题,解密后的代码写回去总是有一个字节改不回来,是Copy-On-Write导致的??不懂,请高手解答。
2009-9-13 20:39
0
游客
登录 | 注册 方可回帖
返回
//