VC实现SMC加密技术

来源:互联网 发布:tomcat 域名绑定 编辑:程序博客网 时间:2024/05/16 18:45

前言

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);

然后定位到节表。

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++;    }}

首先通过对PE结构的解析找到第一个节表所在的地方,然后用strcmp对Name字段进行比较,如果Name字段的值=.SMC 就说明是被加密的代码块,然后取出VirtualAddress和SizeOfRawData调用xorPlus对节表.SMC进行解密。

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编译
链接:http://pan.baidu.com/s/1kTvfWF1 密码:89wv
我的VS配色 O(∩_∩)O~
这里写图片描述

1 0
原创粉丝点击