C/C++ 对代码节的动态加解密
加壳的原理就是加密或者压缩程序中的已有资源,然后当程序执行后外壳将模拟PE加载器对EXE中的区块进行动态装入,下面我们来自己实现一个简单的区块加解密程序,来让大家学习了解一下壳的基本运作原理。
本次使用的工具,依旧是上次编写的PETools: https://www.cnblogs.com/LyShark/p/12960816.html
加密第一个节表:
#include <stdio.h>
#include <Windows.h>
#include <ImageHlp.h>
#pragma comment(lib,"Imagehlp.lib")
void EncrySection(LPSTR szFileName)
{
HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
printf("节表数量: %d \n", FileHdr->NumberOfSections);
printf("节虚拟地址: %x \n", pSection->Misc.VirtualSize);
printf("读入FOA基地址: %x \n", pSection->PointerToRawData);
printf("读入节表长度: %x \n", pSection->SizeOfRawData);
DWORD dwRead = 0;
PBYTE pByte = (PBYTE)malloc(pSection->SizeOfRawData);
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
memset(pByte, 0, pSection->SizeOfRawData);
ReadFile(hFile, pByte, pSection->SizeOfRawData, &dwRead, NULL);
for (int x = 0; x < pSection->SizeOfRawData; x++)
pByte[x] ^= 0x10;
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
WriteFile(hFile, pByte, pSection->SizeOfRawData, 0, FILE_BEGIN);
UnmapViewOfFile(lpBase);
}
int main(int argc, char * argv[])
{
EncrySection("c://win32.exe");
system("pause");
return 0;
}
当需要打印第二个节只需要递增指针.
void EncrySection(LPSTR szFileName)
{
HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
printf("节表数量: %d \n", FileHdr->NumberOfSections);
printf("节虚拟地址: %x \n", pSection->Misc.VirtualSize);
printf("读入FOA基地址: %x \n", pSection->PointerToRawData);
printf("读入节表长度: %x \n", pSection->SizeOfRawData);
DWORD dwRead = 0;
PBYTE pByte = (PBYTE)malloc(pSection->SizeOfRawData);
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
memset(pByte, 0, pSection->SizeOfRawData);
// 逐字节读入
for (int x = 0; x < pSection->PointerToRawData; x++)
{
ReadFile(hFile, &pByte[x], 1, &dwRead, NULL);
}
for (int x = 0; x < pSection->SizeOfRawData; x++)
pByte[x] ^= 0x10;
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
WriteFile(hFile, pByte, pSection->SizeOfRawData, 0, FILE_BEGIN);
pSection++;
printf("节虚拟地址: %x \n", pSection->Misc.VirtualSize);
printf("读入FOA基地址: %x \n", pSection->PointerToRawData);
printf("读入节表长度: %x \n", pSection->SizeOfRawData);
UnmapViewOfFile(lpBase);
}
循环加密所有的节,可能会出现问题
#include <stdio.h>
#include <Windows.h>
#include <ImageHlp.h>
#pragma comment(lib,"Imagehlp.lib")
void EncrySection(LPSTR szFileName,DWORD Key)
{
HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
printf("[-] 加密节表数量: %d \n", FileHdr->NumberOfSections);
for (int x = 0; x < FileHdr->NumberOfSections; x++)
{
printf("[-] 节虚拟地址: 0x%08X 虚拟大小: 0x%08X\n", pSection->VirtualAddress,pSection->Misc.VirtualSize);
printf("[-] 读入FOA基地址: 0x%08X 节表长度: 0x%08X \n\n", pSection->PointerToRawData,pSection->SizeOfRawData);
DWORD dwRead = 0;
PBYTE pByte = (PBYTE)malloc(pSection->SizeOfRawData);
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
memset(pByte, 0, pSection->SizeOfRawData);
ReadFile(hFile, pByte, pSection->SizeOfRawData, &dwRead, NULL);
for (int x = 0; x < pSection->SizeOfRawData; x++)
{
pByte[x] ^= Key;
}
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
WriteFile(hFile, pByte, pSection->SizeOfRawData, 0, FILE_BEGIN);
free(pByte);
pSection = pSection + 1;
}
UnmapViewOfFile(lpBase);
}
int main(int argc, char * argv[])
{
EncrySection("c://win32.exe",0x10);
system("pause");
return 0;
}
添加壳代码
#include <stdio.h>
#include <Windows.h>
#include <ImageHlp.h>
#pragma comment(lib,"Imagehlp.lib")
void EncrySection(LPSTR szFileName, DWORD Key)
{
HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
printf("[-] 节虚拟地址: 0x%08X 虚拟大小: 0x%08X\n", pSection->VirtualAddress, pSection->Misc.VirtualSize);
printf("[-] 读入FOA基地址: 0x%08X 节表长度: 0x%08X \n", pSection->PointerToRawData, pSection->SizeOfRawData);
printf("[*] 已对 %s 节 --> XOR加密/解密 --> XOR密钥: %d \n\n", pSection->Name, Key);
DWORD dwRead = 0;
PBYTE pByte = (PBYTE)malloc(pSection->SizeOfRawData);
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
memset(pByte, 0, pSection->SizeOfRawData);
ReadFile(hFile, pByte, pSection->SizeOfRawData, &dwRead, NULL);
for (int x = 0; x < pSection->SizeOfRawData; x++)
{
pByte[x] ^= Key;
}
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
WriteFile(hFile, pByte, pSection->SizeOfRawData, 0, FILE_BEGIN);
pSection->Characteristics = 0xE0000020;
free(pByte);
FlushViewOfFile(lpBase, 0);
UnmapViewOfFile(lpBase);
}
void DecodeCode(LPSTR szFileName)
{
// 第一步修正程序OEP位置,修正为最后一个节的地址
HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
DWORD ImageBase = NtHdr->OptionalHeader.ImageBase;
DWORD BaseRVA = NtHdr->OptionalHeader.AddressOfEntryPoint;
printf("Base RVA %x \n", BaseRVA);
PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
// 首先得到最后一个节的指针,然后找到里面的虚拟偏移值,填入到程序OEP位置即可。
DWORD SectionNum = FileHdr->NumberOfSections;
char Code[] =
{
"\x60"
"\xb8\x00\x00\x00\x00"
"\x80\x30\x88"
"\x40"
"\x3d\xff\x4f\x40\x00"
"\x75\xf5"
"\x61"
"\xb8\x00\x00\x00\x00"
"\xff\xe0"
};
DWORD dwWrite = 0;
printf("%x \n", ImageBase + pSection->VirtualAddress);
*(DWORD *)&Code[2] = ImageBase + pSection->VirtualAddress;
*(DWORD *)&Code[11] = ImageBase + pSection->VirtualAddress + pSection->Misc.VirtualSize;
*(DWORD *)&Code[19] = ImageBase + BaseRVA;
pSection = pSection + (SectionNum - 1);
printf("得到最后一个节的实际地址: %x \n", pSection->PointerToRawData);
SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
WriteFile(hFile, (LPVOID)Code, sizeof(Code), &dwWrite, NULL);
FlushViewOfFile(lpBase, 0);
UnmapViewOfFile(lpBase);
}
加壳的首要目标是要创建一个具有可写属性的新节

我们使用PESection对win32.exe加一个.hack节,然后大小为2048

加入后再次使用PETools工具检查,发现已经添加成功了。

下一步就是将.text节进行加密了,这里为了简单我使用的是异或加密,如下是加密前的机器码。

使用我们编写的工具进行加密,传入两个参数,一个是文件,一个则是加密密钥

加密有区段会变成如下样子。

接着使用 addpack 传入一个参数,写入解密代码。

电脑管家可能会拦截,请将其取出来。

我们X64dbg载入看看,程序默认停在了,我们的壳的位置,。

运行后对.text节进行动态解密,然后一个jmp跳转到程序的OEP位置即可,这也就是壳的基本原理。

C/C++ 对代码节的动态加解密的更多相关文章
- [改善Java代码]使用forName动态加载类文件
动态加载(Dynamic Loading)是指在程序运行时加载需要的类库文件,对Java程序来说,一般情况下,一个类文件在启动时或首次初始化时会被加载到内存中,而反射则可以在运行时再决定是否需要加载一 ...
- AX 用代码创建FORM动态加控件,重载动态添加的控件的方法。
eg. 范例:class\RFIDReadWriteForm/Build方法. formRun.controlMethodOverload(true); formRun.controlMethodOv ...
- Dex动态加载
Dex动态加载是为了解决什么问题? 在Android系统中,一个App的所有代码都在一个Dex文件里面. Dex是一个类似Jar的存储了多个Java编译字节码的归档文件. 因为Android系统使用D ...
- Android应用安全之外部动态加载DEX文件风险
1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...
- js动态加载的蒙板弹框
我们访问一些网站时总会遇到这种点击后,背景像被打上一层模板一样,这个是怎么做到的呢? 它是将这个弹框div独立于页面容器wrap,设置position为absolute,将其水平垂直之后都居中,设置弹 ...
- goloader - golang动态加载的实现
github地址:https://github.com/dearplain/goloader 这里有以前的一些思路:http://www.cnblogs.com/dearplain/p/8145985 ...
- android中使用jni对字符串加解密实现分析
android中使用jni对字符串加解密实现分析 近期项目有个需求.就是要对用户的敏感信息进行加密处理,比方用户的账户password,手机号等私密信息.在java中,就对字符串的加解密我们能够使用A ...
- JavaScript与C#互通的DES加解密算法
原文地址:传送门 本文提供了一个能使JavaScript与C#互通的DES加解密算法的实现,在前台页面中用JavaScript版本的DES算法将数据加密之后,传到服务器端,在服务器端可用C#版本的DE ...
- .NET Core加解密实战系列之——消息摘要与数字签名算法
目录 简介 功能依赖 消息摘要算法 MD算法 家族发展史 应用场景 代码实现 MD5 示例代码 SHA算法 应用场景 代码实现 SHA1 SHA256 示例代码 MAC算法 HMAC算法的典型应用 H ...
随机推荐
- C# webapi跨域
C# webapi跨域 第一种在Web.config中<system.webServer>节点中配置(不支持多个域名跨域) 1 <httpProtocol> 2 <c ...
- windows10 缺失 msvcp140.dll 解决办法
1.问题描述 我更新完windows10 驱动后,出现计算机缺失msvcp140.dll文件,虚机和QQ都无法启动 2.解决办法 查找大量文章,最终发现通过重新安装 Visual Studio 201 ...
- FreeBSD 中文TTY控制台
freebsd新型终端VT,支持cjk,所以丢个字体进去,就能显示中文了1,首先你没有改过控制台程序,使用的是默认的,,2,最新版本,本说明是以freebsd12.1release字体格式为.fnt命 ...
- CF533F Encoding 题解
题目链接CF533F Encoding 提示1: \(\mathcal O(26^2*n)\) 的算法可通过.常用的几种字符串匹配算法kmp,AC自动机,哈希都可以解决该问题 (后两者可以优化到 ...
- 数据搬运组件:基于Sqoop管理数据导入和导出
本文源码:GitHub || GitEE 一.Sqoop概述 Sqoop是一款开源的大数据组件,主要用来在Hadoop(Hive.HBase等)与传统的数据库(mysql.postgresql.ora ...
- 聊一聊桥接(JSBridge)的原理
一.前言 如今的互联网时代也称移动互联网时代,基本上每个人每天都会花费大量时间在移动设备上,早期的移动端应用大都使用原生开发(android,ios),而现在的移动开发技术选型上基本都是混合开发(Hy ...
- JSP配置虚拟路径及虚拟主机
1.tomact解压后目录 bin:可执行文件(startup.bat shutdown.bat) conf:配置文件(server.xml) lib:tomcat以来的jar文件 log:日志文 ...
- 浅析MyBatis(四):全自动写代码的MyBatis逆向工程
在前面几篇文章中,笔者介绍了 MyBatis 的运行流程,在此基础上简单介绍了手写 MyBatis 简易框架与自定义 MyBatis 插件的步骤,相信大家对于 MyBatis 框架的使用流程已经游刃有 ...
- Java例题_27 100以内的素数
1 /*27 [程序 27 求素数] 2 题目:求 100 之内的素数 3 */ 4 5 /*分析 6 * 素数:是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数. 7 * 同第二题: ...
- 极速精简 Go 版 Logstash
前言 今天来介绍 go-zero 生态的另一个组件 go-stash.这是一个 logstash 的 Go 语言替代版,我们用 go-stash 相比原先的 logstash 节省了2/3的服务器资源 ...