加壳的原理就是加密或者压缩程序中的已有资源,然后当程序执行后外壳将模拟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. CentOS安装libxml2报undefined reference to `gzopen64'

    主要是记录一下安装时候踩的坑 CentOS在make libxml2的时候,会报这个错误 ./.libs/libxml2.so: undefined reference to `gzopen64' c ...

  2. iot漏洞入门

    路由器漏洞入门 下载项目https://github.com/praetorian-inc/DVRF 安装quem sudo apt install qemu-user-static 安装gdb-mu ...

  3. 浅析MyBatis(一):由一个快速案例剖析MyBatis的整体架构与运行流程

    MyBatis 是轻量级的 Java 持久层中间件,完全基于 JDBC 实现持久化的数据访问,支持以 xml 和注解的形式进行配置,能灵活.简单地进行 SQL 映射,也提供了比 JDBC 更丰富的结果 ...

  4. 小技巧!CSS 整块文本溢出省略特性探究

    今天的文章很有意思,讲一讲整块文本溢出省略打点的一些有意思的细节. 文本超长打点 我们都知道,到今天(2020/03/06),CSS 提供了两种方式便于我们进行文本超长的打点省略. 对于单行文本,使用 ...

  5. vue+lib-flexible实现大小屏幕,超大屏幕的适配展示。

    p.p1 { margin: 0; font: 12px "PingFang SC" } span.s1 { font: 12px "Helvetica Neue&quo ...

  6. for-in 语句

    for-in 语句循环专门用于遍历范围,列表,元素和字典等可迭代对象. 循环中的变量的值受for-in循环控制,该变量将会在每次循环开始时自动被赋值,因此程序不应该在循环中对该变量进行赋值 for-i ...

  7. python-3-2

    一 切片 1.切片是list取值的一种方式 列子: nums = ['a','b','c','d','e','f','h','g','k','l','kk','nn','ee'] 取b和c元素出来 p ...

  8. 攻防世界 reverser secret-galaxy-300

    secret-galaxy-300 school-ctf-winter-2015 运行程序 完全没有flag的身影呀 ida查看字符串 也没有相关信息 动态调试,看运行后内存信息 发现了一串字符 al ...

  9. SpringBoot-08 SpringSecurity

    SpringBoot-08 SpringSecurity 创建了一个新项目,创建时选择导入starter-web 1.环境搭建 1.1 导入thymeleaf <dependency> & ...

  10. Python面向对象练习题

    1.模拟栈操作原理 先进后出 ​1.初始化(创建一个存储数据的列表) 2.进栈使用列表保存数据 ​ 3.出栈 使用列表删除数据 ​ 4.查看栈顶元素 切片获取列表最后一位数据 ​5.判断是否为空栈 6 ...