加壳的原理就是加密或者压缩程序中的已有资源,然后当程序执行后外壳将模拟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++ 对代码节的动态加解密的更多相关文章

  1. [改善Java代码]使用forName动态加载类文件

    动态加载(Dynamic Loading)是指在程序运行时加载需要的类库文件,对Java程序来说,一般情况下,一个类文件在启动时或首次初始化时会被加载到内存中,而反射则可以在运行时再决定是否需要加载一 ...

  2. AX 用代码创建FORM动态加控件,重载动态添加的控件的方法。

    eg. 范例:class\RFIDReadWriteForm/Build方法. formRun.controlMethodOverload(true); formRun.controlMethodOv ...

  3. Dex动态加载

    Dex动态加载是为了解决什么问题? 在Android系统中,一个App的所有代码都在一个Dex文件里面. Dex是一个类似Jar的存储了多个Java编译字节码的归档文件. 因为Android系统使用D ...

  4. Android应用安全之外部动态加载DEX文件风险

    1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...

  5. js动态加载的蒙板弹框

    我们访问一些网站时总会遇到这种点击后,背景像被打上一层模板一样,这个是怎么做到的呢? 它是将这个弹框div独立于页面容器wrap,设置position为absolute,将其水平垂直之后都居中,设置弹 ...

  6. goloader - golang动态加载的实现

    github地址:https://github.com/dearplain/goloader 这里有以前的一些思路:http://www.cnblogs.com/dearplain/p/8145985 ...

  7. android中使用jni对字符串加解密实现分析

    android中使用jni对字符串加解密实现分析 近期项目有个需求.就是要对用户的敏感信息进行加密处理,比方用户的账户password,手机号等私密信息.在java中,就对字符串的加解密我们能够使用A ...

  8. JavaScript与C#互通的DES加解密算法

    原文地址:传送门 本文提供了一个能使JavaScript与C#互通的DES加解密算法的实现,在前台页面中用JavaScript版本的DES算法将数据加密之后,传到服务器端,在服务器端可用C#版本的DE ...

  9. .NET Core加解密实战系列之——消息摘要与数字签名算法

    目录 简介 功能依赖 消息摘要算法 MD算法 家族发展史 应用场景 代码实现 MD5 示例代码 SHA算法 应用场景 代码实现 SHA1 SHA256 示例代码 MAC算法 HMAC算法的典型应用 H ...

随机推荐

  1. Spring Boot 老启动失败,这次再也不怕了!

    Spring Boot 项目是不是经常失败,显示一大堆的错误信息,如端口重复绑定时会打印以下异常: *************************** APPLICATION FAILED TO ...

  2. 基于4H-SIC的先进集成电路用n型LDMOS晶体管

    基于4H-SIC的先进集成电路用n型LDMOS晶体管 摘要: 通过对具有不同的设计方式的具有减小的表面电场的横向4H-SIC-N型-横向扩散金属氧化物半导体(LDMOS)晶体管进行测量和模拟,得到了得 ...

  3. [UWP] 模仿哔哩哔哩的一键三连

    1. 一键三连 什么是一键三连? 哔哩哔哩弹幕网中用户可以通过长按点赞键同时完成点赞.投币.收藏对UP主表示支持,后UP主多用"一键三连"向视频浏览者请求对其作品同时进行点赞.投币 ...

  4. C# 应用 - 使用 WepApp 接受 Http 请求

    库类: Owin.dll Owin.IAppBuilder Microsoft.Owin.dll Microsoft.Owin.OwinContext Microsoft.Owin.Hosting.d ...

  5. Go Module实战:基于私有化仓库的GO模块使用实践

    新年开工近一月,2021 年第一期 Open Talk 定档 3 月 18 日晚 8 点,本期我们邀请到了又拍云资深后端开发工程师刘云鹏和我们一起聊聊 Go 最新特性 Go Module 实战. 刘云 ...

  6. vue-cli脚手架安装及注意事项

    1.下载nodejs 链接:https://nodejs.org/en/直接下载电脑对应的版本即可. 13.5网上说不大稳定(一个表示①推荐用户版本,②最新版本) 2.安装nodejs 建议在D或者E ...

  7. frameset、frame和div 、iframe

    框架一般应用于首页的界面排版工作.把一个网页切割成多个页面管理.frame文件一般只包含框架的布局信息,不会包含其他内容,所有的页面效果都是在各个frameset页面内显示.他们都从属于frame文件 ...

  8. JMeter扩展Java请求实现WebRTC本地音视频推流压测脚本

    WebRTC是Web Real-Time Communication缩写,指网页即时通讯,是一个支持Web浏览器进行实时语音或视频对话的API,实现了基于网页的视频会议,比如声网的Agora Web ...

  9. ASP.NET Core 在 .NET 6 Preview 2 中的更新

    原文:<ASP.NET Core updates in .NET 6 Preview 2>,作者 Daniel Roth .NET 6 预览版 2 现已推出,其中包括许多对 ASP.NET ...

  10. Django之缓存、信号和图片验证码、ORM性能

    一. 缓存 1. 介绍 缓存通俗来说:就是把数据先保存在某个地方,下次再读取的时候不用再去原位置读取,让访问速度更快. 缓存机制图解 2.Django中提供了6种缓存方式 1. 开发调试 2. 内存 ...