首页
论坛
课程
招聘
[原创]VC实现SMC加密技术
2015-6-20 22:42 15775

[原创]VC实现SMC加密技术

2015-6-20 22:42
15775
先祝各位看官端午节快乐吧~
前言
SMC是一种局部代码加密技术,通过对一段代码进行加密来达到增加逆向工程难度或者免杀的目的。
编写SMC代码不是汇编语言的专利。——《加密与解密 第三版》

是的,SMC不仅能使用汇编上实现,还能很容易的使用VC实现,但是有一个比较致命缺陷:要精准的定位某个函数非常麻烦,所以我们就要以区块为加密的基础单位。
预备知识
需要一点点的PE结构基础就ok啦。
加密算法
既然是加密,就必然需要加密算法。Internet上有许多优秀的开源加密算法,在这篇文章中我将使用自己编写的加密算法。
加密原理简单,是大家耳熟能详的异或加密。
异或的运算方法是一个二进制运算:
1^1=0
0^0=0
1^0=1
0^1=1
两者相等为0,不等为1.
对于一个字符来说,都可以用二进制码来表示.如A:01000001
字符的异或就是对每一位进行二进制运算.
用于加密算法时,假设你要加密的内容为A,密钥为B,则可以用异或加密:
C=A^B
在数据中保存C就行了.
用的时候:
A=B^C
即可取得原加密的内容,所以只要知道密钥,就可以完成加密和解密.

根据原理可以推导出,加密函数也自带解密功能。
void xorPlus(char *soure,int dLen,char *Key,int Klen)
{
    for (int i=0;i<dLen;)
    {
        for (int j=0;(j<Klen) && (i<dLen);j++,i++)
        {
            soure[i]=soure[i] ^ Key[j];
            soure[i]=~soure[i];
        }
    }
}

参数说明
1. soure 被加数据的指针
2. dLen 被加密数据的长度
3. key 密匙数据的指针
4. key 的长度
NOTE:这个函数即时加密函数也是解密函数。

保护敏感代码
这里的敏感代码指的是Cracker和杀毒软件感兴趣的代码,也许你并不想让它们轻松地得到想要的结果。
因为定位一个具体的函数很繁琐,所以我们选择直接定位一个节表。把敏感的代码放入一个新的节表中,然后在需要的时候进行解密,这就是SMC动态加密技术的精髓。
如何把敏感代码放入一个新的节表中?
#pragma code_seg(".SMC")
void Fun1()
{
    MessageBoxA(NULL,"正在执行被加密算法。",NULL,MB_OK);
}
#pragma code_seg()
#pragma comment(linker, "/SECTION:.SMC,ERW")

#pragma code_seg(“.SMC”) 是一条预编译指令,作用是告诉链接器下面的代码放入 .SMC 代码段中。参数是代码段节表名,学过PE结构的人都知道,节表名<=8 个字符
#pragma code_seg() 是指示链接器,下面的代码放在原来的代码段中。
因为我们是加密敏感代码,而不是主程序代码,所以必须把它切换回去,要不然加密的时候主程序也被一起加密了,就没有负责解密的代码了。
#pragma comment(linker, “/SECTION:.SMC,ERW”) 是设置节表的属性。因为这个节表的数据是要被解密的,所以它必须具有可读写的属性;因为解密后这个节表中有代码,所以它必须具有可执行的属性。当然,这一步不是必须的,也可以在解密前调用VirtualProtect函数来修改内存属性。
一般写法:
#pragma code_seg(".SMC")
#include "关键的源代码.h"
#pragma code_seg()
#pragma comment(linker, "/SECTION:.SMC,ERW")

现在,你可以尝试调用Fun1() ,它是能准确无误的执行的。
解密我们的代码

现在来说说如何解密。
要解密我们首先要定位到镜像文件的载入基址。
这还不简单?GetModuleHandle(0);
解密程序首先通过对PE结构的解析找到第一个节表所在的地方,然后对Name字段进行比较,如果Name字段的值=.SMC 就说明是被加密的代码块,然后取出VirtualAddress和SizeOfRawData调用xorPlus对节表.SMC进行解密。
void SMC(char *pBuf,char *key)
{
    // SMC 加密XX区段
    const char *szSecName = ".SMC";
    short nSec;
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS pNtHeader;
    PIMAGE_SECTION_HEADER pSec;
    pDosHeader=(PIMAGE_DOS_HEADER)pBuf;
    pNtHeader=(PIMAGE_NT_HEADERS)&pBuf[pDosHeader->e_lfanew];
    nSec=pNtHeader->FileHeader.NumberOfSections;
    pSec=(PIMAGE_SECTION_HEADER)&pBuf[ sizeof(IMAGE_NT_HEADERS)+pDosHeader->e_lfanew];
    for (int i=0;i<nSec;i++)
    {
        if (strcmp((char *)&pSec->Name,szSecName)==0)
        {
            int pack_size;
            char *packStart; 
            pack_size=pSec->SizeOfRawData;
            packStart = &pBuf[pSec->VirtualAddress];
            //VirtualProtect(packStart,pack_size,PAGE_EXECUTE_READWRITE,&old);
            xorPlus(packStart,pack_size,key,strlen(key));
            //AfxMessageBox(_T("SMC解密成功。"));
            return;
        }
        pSec++;
    }
}


调用被加密的函数:
void CTestDlg::OnBnClickedButton2()
{
    __try
    {
        Fun1();
    }
    __except(1)
    {
        UnPack(KeyBuffer); //修正数据
        AfxMessageBox(_T("Key不正确,请重新输入。"));
    }
}

如果解密失败,Fun1() 一定会发生异常,主程序捕获这个异常并提示用户,就可以达到注册码检查的目的。。。

加密我们的敏感代码
读者可能已经注意到了,编译器肯定是没有加密功能的,所以只有我们自己写程序来加密。

原理:
打开PE文件->定位到节表->查找 .SMC 节表->加密.SMC节表
void SMC(HANDLE hFile,char *key)
{
    // SMC 加密XX区段
    HANDLE hMap;
    const char *szSecName = ".SMC";
    char *pBuf;
    int size;
    short nSec;
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS pNtHeader;
    PIMAGE_SECTION_HEADER pSec;

    size = GetFileSize(hFile,0);
    hMap=CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,size,NULL);
    if (hMap==INVALID_HANDLE_VALUE)
    {
_viewf:
        AfxMessageBox(_T("映射失败"));
        return ;
    }
    pBuf=(char *)MapViewOfFile(hMap,FILE_MAP_WRITE|FILE_MAP_READ,0,0,size);
    if(!pBuf) goto _viewf;
    pDosHeader=(PIMAGE_DOS_HEADER)pBuf;
    pNtHeader=(PIMAGE_NT_HEADERS)&pBuf[pDosHeader->e_lfanew];
    if (pNtHeader->Signature!=IMAGE_NT_SIGNATURE)
    {
        AfxMessageBox(_T("不是有效的win32 可执行文件"));
        goto _clean;
    }
    nSec=pNtHeader->FileHeader.NumberOfSections;
    pSec=(PIMAGE_SECTION_HEADER)&pBuf[ sizeof(IMAGE_NT_HEADERS)+pDosHeader->e_lfanew];
    for (int i=0;i<nSec;i++)
    {
        if (strcmp((char *)&pSec->Name,szSecName)==0)
        {
            int pack_size;
            char *packStart; 
            pack_size=pSec->SizeOfRawData;
            packStart = &pBuf[pSec->PointerToRawData];
            xorPlus(packStart,pack_size,key,strlen(key));
            AfxMessageBox(_T("SMC加密成功。"));
            goto _clean;
        }
        pSec++;
    }
    AfxMessageBox(_T("未找到 .SMC 段"));
_clean:
    UnmapViewOfFile(pBuf);
    CloseHandle(hMap);
    return ;
}


写在最后
vs2012编译的MFC工程的基址是变动,如果基址是变动的,程序每次在载入后都会进行重定位,敏感代码中的绝对地址就会被改变,因为改写的时候在解密代码之前。所以当解密后将会得到错误的结果。所以,这个技术不适用与基址会变得DLL中。
你需要这样配置:

源代码:
一个工程,两个项目,分别是:
SMC Pack SMC加密程序
Test 被加密的程序
使用VS2012编译
SMC pack.zip
如果觉得看雪的排版不好,可以转到csdn博客去阅读http://blog.csdn.net/pandaos/article/details/46575441

第五届安全开发者峰会(SDC 2021)议题征集正式开启!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (26)
雪    币: 1398
活跃值: 活跃值 (119)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ggggg 活跃值 2015-6-21 01:48
2
0
实用时可以把这个异或加密换成别的算法~~
雪    币: 1818
活跃值: 活跃值 (5178)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2015-6-21 08:33
3
0
当年写的类似思路的一个CrackMe
http://past.pediy.com/showthread.php?t=8211
雪    币: 7503
活跃值: 活跃值 (160)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
achillis 活跃值 15 2015-6-21 11:39
4
0
楼主写得不错,很清晰
雪    币: 1992
活跃值: 活跃值 (235)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
CRoot 活跃值 2015-6-21 12:26
5
0
学习了 。。
雪    币: 4550
活跃值: 活跃值 (442)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
friendanx 活跃值 2015-6-21 12:49
6
0
简单清晰明了,学习了
雪    币: 1015
活跃值: 活跃值 (260)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Rookietp 活跃值 2015-6-21 17:58
7
0
解密后dump
雪    币: 1453
活跃值: 活跃值 (1592)
能力值: ( LV15,RANK:645 )
在线值:
发帖
回帖
粉丝
无名侠 活跃值 10 2015-6-21 18:49
8
0
可以把密匙作为注册码,让用户输入。
雪    币: 31
活跃值: 活跃值 (228)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
靴子 活跃值 2015-6-21 19:40
9
0
MARK!
雪    币: 1166
活跃值: 活跃值 (80)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
Ericky 活跃值 6 2015-6-21 23:37
10
0
mark  学习了
雪    币: 1015
活跃值: 活跃值 (260)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Rookietp 活跃值 2015-6-22 01:47
11
0
学习了,蛮喜欢看楼主的帖子,思路清晰~
雪    币: 69
活跃值: 活跃值 (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
hulucc 活跃值 2015-6-22 09:10
12
0
注册码泄露了怎么办
雪    币: 71
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mumaren 活跃值 2015-6-22 13:37
13
0
先mark
放假再look
雪    币: 1081
活跃值: 活跃值 (302)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
欣喜 活跃值 2015-6-22 22:34
14
0
硬盘序列号等+注册码
注册码泄漏了也没关系。
雪    币: 137
活跃值: 活跃值 (362)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
niuzuoquan 活跃值 2015-6-23 07:54
15
0
mark
雪    币: 57
活跃值: 活跃值 (42)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
LOVEZ 活跃值 2015-6-23 10:35
16
0
感谢分享
雪    币: 69
活跃值: 活跃值 (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
hulucc 活跃值 2015-6-23 15:19
17
0
SMC怎么和硬盘序列号结合呢
雪    币: 113
活跃值: 活跃值 (85)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Fido 活跃值 2015-6-23 17:47
18
0
学习了...............
雪    币: 58
活跃值: 活跃值 (12)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
sunnysab 活跃值 2015-6-24 13:30
19
0
写的挺好,学习,表示为数不多的看得懂的文章之一哈
顺便浏览下博客
雪    币: 122
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
张振江 活跃值 2015-6-24 19:42
20
0
mark,感谢LZ
雪    币: 85
活跃值: 活跃值 (64)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wodexinren 活跃值 2015-6-25 14:55
21
0
学习一下,感谢分享
雪    币: 4482
活跃值: 活跃值 (261)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
menglv 活跃值 2015-6-27 12:55
22
0
学习一下,留个脚印。
雪    币: 23
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dppdpp 活跃值 2015-6-28 00:13
23
0
这东西整明白了,vmp就好搞了。
雪    币: 69
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
StartAoA 活跃值 2015-7-1 09:23
24
0
思路不错~~
雪    币: 144
活跃值: 活跃值 (27)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
透明色 活跃值 2 2015-7-1 21:02
25
0
值钱的代码 都放在dll 里了 ,  这个用不上
游客
登录 | 注册 方可回帖
返回