『杂项』SMC 加密技术

admin 2023年3月7日08:28:04评论19 views字数 4099阅读13分39秒阅读模式
『杂项』SMC 加密技术

点击蓝字,关注我们

『杂项』SMC 加密技术



日期: 2022-08-22

作者: Mr-hello

介绍: SMC是一种动态代码自解密技术。


0x00 前言

这篇文章起因是因为某一年的省赛初赛出题时,我用到了这个知识点,但是当时设计出的没有实现其动态执行,只是将函数前 122 位进行了一次异或加密,然后手工放在了程序里面,并没有实现其动态解密并执行。

0x01 言归正传

我找到了几篇相关文章,才明白 SMC 加密技术具体应该如何使用。使用伪代码进行解释该技术的话,如下:

proc main:............IF .运行条件满足  CALL DecryptProc (Address of MyProc)//对某个函数代码解密  ........  CALL MyProc                           //调用这个函数  ........  CALL EncryptProc (Address of MyProc)//再对代码进行加密,防止程序被Dump
......end main

通过伪代码来看,好像实现起来很简单,于是我先写了一个 Demo,这里采用了添加代码段节区的方式实现该技术。

#include<Windows.h>#include<string>#include<string.h>using namespace std;   #include <iostream>
#pragma code_seg(".hello")
void Fun1(){ int a = 1; int b = 3; cout << a + b << endl;}#pragma code_seg()#pragma comment(linker, "/SECTION:.hello,ERW")
void Fun1end(){
}
void xor(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]; } }}void SMC(char* pBuf, char* key) //SMC解密/加密函数{ const char* szSecName = ".hello"; 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]; xor(packStart, pack_size, key, strlen(key)); return; } pSec++; }}
void UnPack(char* Key) //解密/加密函数{ char* hMod; hMod = (char*)GetModuleHandle(0); //获得当前的exe模块地址 SMC(hMod, Key);}

解释一下以上代码,首先 SMC 技术实现基本思路应该是:

  • 有两个函数,一个函数加密,一个函数解密,两者对应。

  • 找到要进行SMC的代码地址,在程序开始的地方设置对该地址数据的解密函数。

  • 取出要进行SMC的代码的字节码,对其进行加密操作得到一串加密数据。

  • 用这串加密数据替换原代码的字节码。

这里为了方便,我只采用了异或进行加密,所以解密函数和加密函数是同一个。上述代码中的 UnPack 函数以及 SMC 函数就是解密的关键,其中复杂的是 SMC 函数,最前面的变量定义和赋值作用是为了得到整个程序的区段信息,其中 pSec 中存储区段信息, nSec 中存储区段数量,所以后面 for 循环是为了找到自己想要加密/解密的区段的起始地址以及区段大小。然后进入 xor 函数进行加密/解密操作。

这里使用 SMC 技术的时候,我选择使用建立自定义的字段方式进行实现,然后对该字段的内容进行保护。就像代码里的 Fun1 函数,就放在了自定义的 .hello 区段里面,为什么要放在自定义区段?当然是为了方便设置区段的读写权限,pragma comment(linker, "/SECTION:.hello,ERW") 这个就是设置 .hello 区段可读可写可执行。

Demo 的调用代码就很简单了:

c ¨K6K ¨K7K int main() { char key[7] = {"123123"}; UnPack(key); //解密 Fun1(); UnPack(key); //复原 return 0; }

然后还要设置一个为该 Demo 进行加密的程序,因为 SMC 技术第一步是解密操作,那么当然首先要对其进行加密才能起到隐藏关键代码的效果。加密程序的设计和 Demo 的样式基本相同,写了一个 MFC 进行选择文件加密。

c #include<Windows.h> ¨K8K ¨K9K using namespace std; void xor(char* soure, int dLen, char* Key, int Klen) { ¨K12K } void SMC(HANDLE hFile, char* key) { // SMC 加密XX区段 HANDLE hMap; const char* szSecName = ".hello"; char* pBuf; int size; short nSec; PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeader; PIMAGE_SECTION_HEADER pSec; ¨K13K _clean: UnmapViewOfFile(pBuf); CloseHandle(hMap); return; } void main() { //取得文件路径部分 TCHAR szFilePath[MAX_PATH]; OPENFILENAME ofn = { 0 }; memset(szFilePath, 0, MAX_PATH); memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.hInstance = GetModuleHandle(NULL); ofn.nMaxFile = MAX_PATH; ofn.lpstrInitialDir = "."; ofn.lpstrFile = szFilePath; ofn.lpstrTitle = "选择PE文件"; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrFilter = "(*.*)*.exe;*.dll"; GetOpenFileName(&ofn); ¨K14K }

可以看到加密思路依然是遍历打开文件的所有区段信息,找到对应区段的代码进行异或加密。

加密前和加密后的静态反编译对比。

『杂项』SMC 加密技术

『杂项』SMC 加密技术

源程序在未加密之前,设定的执行顺序中需要先对 .hello 区段进行解密操作,但是由于本身还未加密,所以源程序是无法运行的,但是执行加密之后再运行是可以正常输出的。

『杂项』SMC 加密技术

当然在设计这个程序的时候,踩了一个坑点,就是 ASLR 地址空间布局随机化,什么意思呢,简单理解就是静态分析时看到的函数地址,在其动态的时候会改变为随机的某个地址。但是为什么这个机制会影响设计的 Demo 呢,首先我们来看一下设计的 Demo 程序在开启 ASLR 机制编译,静态分析的情况。

『杂项』SMC 加密技术

『杂项』SMC 加密技术

接下来看一下动态分析的情况。

『杂项』SMC 加密技术

『杂项』SMC 加密技术

在开启 ASLR 机制的时候,程序加载时会先去更改程序中的字节码,如果 SMC 技术在程序加载过程中就把字节码给更改了之后,可能导致解密失败。所以这个问题致使我在测试过程中发现将程序加密之后竟然无法跑起来,直到后来我才意识到这个问题,因为在程序未加密时,该地址上的字节码指向某个函数的地址,所以程序在每次加载时都会去更改该地址上的数据,来实现重定向,但是一旦改了数据,我就无法通过解密函数,得到正确的字节码,导致程序崩溃。

后面我把基址随机选项关闭之后,问题得到解决。

0x02 一些思考

网上关于该技术的文章有很多,并且都明确表示可以对抗静态分析,但是不适用动态分析,因为 SMC 技术,在运行过程中会有自解密的过程,一旦动态运行到解密结束再去分析,就可以还原出代码逻辑,进行分析即可。

这种技术手段,虽然不能有效的对抗动态分析,但是仍被大量运用,最常见的是木马病毒文件,可以使用该种技术很好的对抗杀毒软件的静态查杀,攻击者可以使用该种技术将危险函数代码字段进行加密,以达到消除特征码,特征函数的效果。

前文提到 SMC 代码加密技术,有很多种实现方式,其中我用的这种是较为简单的实现方式,而且这种方式创建了一个特殊的区段,有点此地无银的意思,其他的几种方式可以更具迷惑性,这个作者后面会再研究一下,希望会有该系列的第二篇文章。

免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。

『杂项』SMC 加密技术

宸极实验室

宸极实验室隶属山东九州信泰信息科技股份有限公司,致力于网络安全对抗技术研究,是山东省发改委认定的“网络安全对抗关键技术山东省工程实验室”。团队成员专注于 Web 安全、移动安全、红蓝对抗等领域,善于利用黑客视角发现和解决网络安全问题。

团队自成立以来,圆满完成了多次国家级、省部级重要网络安全保障和攻防演习活动,并积极参加各类网络安全竞赛,屡获殊荣。

对信息安全感兴趣的小伙伴欢迎加入宸极实验室,关注公众号,回复『招聘』,获取联系方式。




原文始发于微信公众号(宸极实验室):『杂项』SMC 加密技术

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年3月7日08:28:04
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   『杂项』SMC 加密技术https://cn-sec.com/archives/1248529.html

发表评论

匿名网友 填写信息