64位PE壳编写指南

文章目录

    • 前记
    • x64壳
    • 后记
    • reference

文章首发于微信公众号《渗透测试安全攻防》

前记

  • 开源的关于PE压缩和加密壳几乎都是32位,于是学习写一个64位的壳供参考,其原理差别不大
  • 学写PE壳是熟悉PE结构很好的方式
  • 项目已开源,求个stars嘻嘻嘻
https://github.com/coleak2021/PE64shell

x64壳

代码分布:

stub:外壳,负责解密.text,修复解析IAT,跳转到原来的OEP

PE64shell:将stub的.text节和导入表打包尾加到待加壳的PE并修改一系列文件头信息

效果展示:

在这里插入图片描述

后记

变量存储

#include<string>
#include<iostream>
using namespace std;
static int C = 6;//.data节
int c=5;//.data节
int main() {
	int a = 10;//ebp-8
	int n = ++a;//ebp-c
	c = n;
	cout << n<<endl<< c << endl;
	cout << &n << endl <<&a<< endl<<&c<< endl;
	cout << C << endl << &C;
}

11
11
000000A4DBF7FBB0
000000A4DBF7FBB4
00007FF7064FBC80
6
00007FF7064FBC84

rdata、idata、data

权限:

  • .rdata:只读,不可修改。
  • .idata:通常为读
  • .data:读写,允许修改全局和静态变量。

存储内容:

  • .rdata:存储const修饰的变量
  • .idata:导入函数的代码段,存放外部函数地址
  • .data:存储可变的全局和static变量
//把数据段融入代码段
#pragma comment(linker,"/merge:.data=.text")
//把只读数据段融入代码段
#pragma comment(linker,"/merge:.rdata=.text")
//设置代码段为可读可写可执行
#pragma comment(linker,"/section:.text,RWE")

windbg

0:005> dt _PEB
ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 BitField         : UChar
   +0x003 ImageUsesLargePages : Pos 0, 1 Bit
   +0x003 IsProtectedProcess : Pos 1, 1 Bit
   +0x003 IsImageDynamicallyRelocated : Pos 2, 1 Bit
   +0x003 SkipPatchingUser32Forwarders : Pos 3, 1 Bit
   +0x003 IsPackagedProcess : Pos 4, 1 Bit
   +0x003 IsAppContainer   : Pos 5, 1 Bit
   +0x003 IsProtectedProcessLight : Pos 6, 1 Bit
   +0x003 IsLongPathAwareProcess : Pos 7, 1 Bit
   +0x004 Padding0         : [4] UChar
   +0x008 Mutant           : Ptr64 Void
   +0x010 ImageBaseAddress : Ptr64 Void
   +0x018 Ldr              : Ptr64 _PEB_LDR_DATA

0:005> !peb
PEB at 00000046b97eb000

0:005> dt _PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
   +0x000 Length           : Uint4B
   +0x004 Initialized      : UChar
   +0x008 SsHandle         : Ptr64 Void
   +0x010 InLoadOrderModuleList : _LIST_ENTRY
   +0x020 InMemoryOrderModuleList : _LIST_ENTRY
   +0x030 InInitializationOrderModuleList : _LIST_ENTRY
   +0x040 EntryInProgress  : Ptr64 Void
   +0x048 ShutdownInProgress : UChar
   +0x050 ShutdownThreadId : Ptr64 Void

0:005> dt nt!_PEB Ldr Ldr. 00000046b97eb018
ntdll!_PEB
   +0x018 Ldr  : 0x00000224`f6bb0000 _PEB_LDR_DATA
      +0x000 Length : 0
      +0x004 Initialized : 0 ''
      +0x008 SsHandle : 0x010040fd`e9f11c7d Void
      +0x010 InLoadOrderModuleList : _LIST_ENTRY [ 0x00000002`ffeeffee - 0x00000224`f6bb0120 ]
      +0x020 InMemoryOrderModuleList : _LIST_ENTRY [ 0x00000224`f6bb0120 - 0x00000224`f6bb0000 ]
      +0x030 InInitializationOrderModuleList : _LIST_ENTRY [ 0x00000224`f6bb0000 - 0x00000000`000000ff ]
      +0x040 EntryInProgress : 0x00000224`f6bb0740 Void
      +0x048 ShutdownInProgress : 0 ''
      +0x050 ShutdownThreadId : 0x00000001`000000a5 Void
      
0:005> dt _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY
   +0x010 InMemoryOrderLinks : _LIST_ENTRY
   +0x020 InInitializationOrderLinks : _LIST_ENTRY
   +0x030 DllBase          : Ptr64 Void
   +0x038 EntryPoint       : Ptr64 Void
   +0x040 SizeOfImage      : Uint4B
   +0x048 FullDllName      : _UNICODE_STRING
   +0x058 BaseDllName      : _UNICODE_STRING

getKernel32Addr

#include<windows.h>
#include<iostream>

ULONGLONG GetKernel32Addr()
{
	ULONGLONG dwKernel32Addr = 0;
	// 获取PEB的地址
	_TEB* pPeb =(_TEB*) __readgsqword(0x60);
	// 获取PEB_LDR_DATA结构的地址
	PULONGLONG pLdr = (PULONGLONG) * (PULONGLONG)((ULONGLONG)pPeb + 0x18);
	//模块初始化链表的头指针InInitializationOrderModuleList
	PULONGLONG pInLoadOrderModuleList = (PULONGLONG)((ULONGLONG)pLdr + 0x10);
	// 获取链表中第一个模块信息,exe模块
	PULONGLONG pModuleExe = (PULONGLONG)*pInLoadOrderModuleList;
	// 获取链表中第二个模块信息,ntdll模块
	PULONGLONG pModuleNtdll = (PULONGLONG)*pModuleExe;
	// 获取链表中第三个模块信息,Kernel32模块
	PULONGLONG pModuleKernel32 = (PULONGLONG)*pModuleNtdll;
	// 获取kernel32基址
	dwKernel32Addr = pModuleKernel32[6];
	return dwKernel32Addr;
}

ULONGLONG MyGetProcAddress()
{
	ULONGLONG dwBase = GetKernel32Addr();
	// 1. 获取DOS头
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)dwBase;
	// 2. 获取NT头
	PIMAGE_NT_HEADERS64  pNt = (PIMAGE_NT_HEADERS64)(dwBase + pDos->e_lfanew);
	// 3. 获取数据目录表
	PIMAGE_DATA_DIRECTORY pExportDir = pNt->OptionalHeader.DataDirectory;
	pExportDir = &(pExportDir[IMAGE_DIRECTORY_ENTRY_EXPORT]);
	DWORD dwOffset = pExportDir->VirtualAddress;
	// 4. 获取导出表信息结构
	PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(dwBase + dwOffset);
	DWORD dwFunCount = pExport->NumberOfFunctions;
	DWORD dwFunNameCount = pExport->NumberOfNames;
	// Get Export Address Table
	PDWORD pEAT = (PDWORD)(dwBase + pExport->AddressOfFunctions);
	// Get Export Name Table
	PDWORD pENT = (PDWORD)(dwBase + pExport->AddressOfNames);
	// Get Export Index Table
	PWORD  pEIT = (PWORD)(dwBase + pExport->AddressOfNameOrdinals);

	for (int i = 0; i < dwFunNameCount; i++) {
		if (!strcmp((char*)pENT[i]+ dwBase, "GetProcAddress"))
			return dwBase + pEAT[pEIT[i]];
	}
	return 0;
}
int main()
{
	std::cout << GetProcAddress(GetModuleHandleA("Kernel32"), "GetProcAddress") << std::endl;
	std::cout <<std::hex<< MyGetProcAddress()<<std::endl;
	system("pause");
	return 0;
}

0x30 / sizeof(ULONGLONG) 的计算是为了将字节偏移量转换为元素偏移量

0x30 是一个以字节为单位的偏移量,表示我们希望跳过的内存区域的大小(在这个例子中是 48 字节)

sizeof(ULONGLONG)ULONGLONG 类型的大小(在大多数系统上是 8 字节)

0x30 / sizeof(ULONGLONG) 就是 48 / 8 = 6

#include “lib.h”+#pragma comment(lib,“lib.lib”)/loadlibrarya+getproaddress

  • #pragma comment(lib, “lib.lib”)

编译器在链接阶段将 lib.lib 添加到项目中。它是在编译时静态确定的。可以直接调用库中的函数,而不需要在运行时手动加载库。仅链接而不使用的时候不会触发dllmain,使用时会先触发dllmain

  • loadlibrarya

程序运行时动态加载 DLL并触发dllmain

zstd压缩

#include <windows.h>
#include<iostream>
#include "zstd.h"

#pragma comment(lib,"D:\\c_project\\libzstd_static.lib")

int compre(PVOID input, int dwFileSize, PVOID output);
int decompre(PVOID input, int dwFileSize, PVOID output);
#include "zstd.h"

void mymemcpy_s(char* cc1, int s1, char* cc2)
{
    for (int i = 0; i < s1; i++)
         *cc1++= *cc2++;

}
int compre(PVOID input, int dwFileSize, PVOID output) {
    // 计算压缩后的最大缓冲区大小
    size_t compressed_size_bound = ZSTD_compressBound(dwFileSize);
    char* compressed_data = new char[compressed_size_bound];

    // 压缩数据
    size_t compressed_size = ZSTD_compress(compressed_data, compressed_size_bound, input, dwFileSize, 1);
    mymemcpy_s((char*)output, compressed_size, compressed_data);
    delete[] compressed_data;
    return compressed_size;
}

int decompre(PVOID input, int dwFileSize, PVOID output) {
    // 先计算解压后所需的最大缓冲区大小
    unsigned long long decompressed_size = ZSTD_getFrameContentSize(input, dwFileSize);

    // 分配解压后的数据缓冲区
    char* decompressed_data = new char[decompressed_size];

    // 解压数据
    size_t result = ZSTD_decompress(decompressed_data, decompressed_size, input, dwFileSize);
    if (ZSTD_isError(result)) {
        delete[] decompressed_data;
        return 1;
    }
    mymemcpy_s((char*)output, decompressed_size, decompressed_data);
    delete[] decompressed_data;
    return 0;
}

DllCharacteristics

IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE (0x0040)
DLL 支持重定位,可以加载到随机基址。影响 PE 文件随机基址。

IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY (0x0080)
强制进行代码完整性检查,确保 DLL 的完整性和安全性。

IMAGE_DLLCHARACTERISTICS_NX_COMPAT (0x0100)
与 NX (No-Execute) 兼容,防止在代码段之外的内存区域执行代码,提高安全性。

IMAGE_DLLCHARACTERISTICS_NO_ISOLATION (0x0200)
支持隔离,但此映像不需要隔离环境的保护。

IMAGE_DLLCHARACTERISTICS_NO_SEH (0x0400)
禁用结构化异常处理 (SEH),该映像中不能包含任何 SEH 处理程序。

IMAGE_DLLCHARACTERISTICS_NO_BIND (0x0800)
指示不绑定此映像到特定 DLL 地址,使其加载更灵活。

0x1000 (Reserved)
保留项。

IMAGE_DLLCHARACTERISTICS_WDM_DRIVER (0x2000)
指示映像是一个使用 Windows 驱动程序模型 (WDM) 的驱动程序。

0x4000 (Reserved)
保留项。

IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
映像支持终端服务器环境,具有终端服务器感知。

x64/x86

pe64也就ImageBaseVAIATOFT等、堆栈大小等是ULONGLONG,其他和pe32基本保持一致

reference

https://blog.schnee.moe/posts/SimpleDpack/
https://www.cnblogs.com/z5onk0/p/17287215.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/915465.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3D意识(3D Awareness)浅析

一、简介 3D意识&#xff08;3D Awareness&#xff09;主要是指视觉基础模型&#xff08;visual foundation models&#xff09;对于3D结构的意识或感知能力&#xff0c;即这些模型在处理2D图像时是否能够理解和表示出图像中物体或场景的3D结构&#xff0c;其具体体现在编码场景…

Web安全之SQL注入---基础

文章目录 SQL注入简介SQL注入基础SQL注入分类SQL注入流程 SQL注入简介 什么是SQL注入&#xff1f; SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严&#xff0c;攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句&#xff0c;在管理…

黄仁勋对话孙正义:日本的AI新饼、Arm的AI野心与英伟达的东亚新机会

2020 年的软银世界大会上&#xff0c;孙正义与黄仁勋围绕「What’s Next for AI」展开了一次围炉对谈。黄仁勋穿着标志性的皮夹克坐在火堆旁&#xff0c;畅谈了将 Arm 纳入麾下的重要价值&#xff0c;孙正义也毫不吝啬赞美之词&#xff0c;称老黄在未来 10 年会达到史蒂夫 乔布…

【案例】Excel使用宏来批量插入图片

一、场景介绍 我有一个excel文件&#xff0c;需要通过一列的文件名称&#xff0c;按照规则给批量上传图片附件。 原始文件&#xff1a; 成功后文件&#xff1a; 二、实现方法 1. 使用【wps】工具打开Excel文件&#xff0c;将其保存为启用宏的文件。 2.找到编辑宏的【VB编辑器…

Kubernetes-ArgoCD篇-01-简介

1、什么是Argo CD Argo CD 是针对 Kubernetes 的声明式 GitOps 持续交付工具。 Argo CD官方文档地址&#xff1a;https://argo-cd.readthedocs.io Argo CD源码地址&#xff1a;https://github.com/argoproj/argo-cd 1.1 关于Argo Argo是一个开源的项目&#xff0c;主要是扩…

odoo17 前端 在头像下拉 dropdown 自定义菜单

odoo17 前端 在头像下拉 dropdown 自定义菜单 其实很简单, 我们先找到原来已经创建好的, 找到代码位置 使用 我的资料 为例 odoo-17.0\addons\hr\static\src\user_menu\my_profile.js /** odoo-module **/import { _t } from "web/core/l10n/translation"; import …

时序预测 | Python基于CNN-transformer时间序列预测

时序预测 | Python基于CNN-transformer时间序列预测 目录 时序预测 | Python基于CNN-transformer时间序列预测预测效果基本介绍参考资料 预测效果 基本介绍 时序预测 | Python基于CNN-transformer时间序列预测 Cnn-transformer-自适应稀疏自注意力ASSA-对比归一化contranorm预…

(干货)Jenkins使用kubernetes插件连接k8s的认证方式

#Kubernetes插件简介 Kubernetes 插件的目的是能够使用 Kubernetes 配合&#xff0c;实现动态配置 Jenkins 代理&#xff08;使用 Kubernetes 调度机制来优化负载&#xff09;&#xff0c;在执行 Jenkins Job 构建时&#xff0c;Jenkins Master 会在 kubernetes 中创建一个 Sla…

Python学习25天

# 切片语法&#xff1a;序列[起始索引:结束索引:步长]&#xff0c;起始不写默认为0&#xff0c;结束不写默认取到结尾&#xff0c;步长不写默认为1(步长为-反向截取&#xff0c;最后一位起始序列为-1),左闭右开&#xff0c;切片后原序列不变 str "lx,hahaha,呵呵" s…

API接口精准获取商品详情信息案例

在当今数字化时代&#xff0c;电子商务平台的蓬勃发展&#xff0c;使得商品信息的获取变得尤为重要。API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;作为连接前端用户界面与后端服务的桥梁&#xff0c;扮演着至关重要的角色。本文…

MySQL算数运算符基础:详解与入门

目录 背景&#xff1a; 过程&#xff1a; 1.加法与减法运算符 1.2扩展&#xff1a; 1.3运算结果得出结论 &#xff1a; 2.乘法和除法运算 ​2.1练习&#xff1a; 2.2运算结果得出结论 &#xff1a; 3.求模取余运算符 3.1练习&#xff1a; 总结&#xff1a; 背景&a…

【vue2.0入门】vue基本语法

目录 引言一、页面动态插值1. 一般用法 二、计算属性computed三、动态class、style绑定四、条件渲染与列表渲染五、事件处理六、表单输入绑定七、总结 引言 本系列教程旨在帮助一些零基础的玩家快速上手前端开发。基于我自学的经验会删减部分使用频率不高的内容&#xff0c;并不…

丹摩征文活动 | 丹摩智算平台:服务器虚拟化的璀璨明珠与实战秘籍

丹摩DAMODEL&#xff5c;让AI开发更简单&#xff01;算力租赁上丹摩&#xff01; 目录 一、引言 二、丹摩智算平台概述 &#xff08;一&#xff09;平台架构 &#xff08;二&#xff09;平台特点 三、服务器虚拟化基础 &#xff08;一&#xff09;虚拟化的概念 &#xf…

蓝牙5.0模块助力闹钟升级,开启智能生活第一步

随着智能家居产业的快速发展&#xff0c;智能闹钟作为其中一个重要的品类&#xff0c;逐渐从单一的时间提醒功能演变为集音频播放、语音交互、智能控制等多种功能于一体的智能设备。而在这些功能的实现中&#xff0c;蓝牙音频模组扮演着核心角色。 1、蓝牙音频模组的功能概述 …

POI word转pdf乱码问题处理

1.使用poi 转换word文档成pdf 导入依赖 <dependency><groupId>com.aspose</groupId><artifactId>words</artifactId><version>16.8.0</version></dependency>2.代码实现: SneakyThrowspublic void wordToPdf(String docPath,…

有趣的Midjourney作品赏析(附提示词)

中文提示词&#xff1a;国风少年 C4D软件,高分辨率,超细节,超现实主义, 英文提示词&#xff1a;National Style Youth Cinema4D,high resolution,hyper detailed,surrealism, --niji 6 --ar 1:1 中文提示词&#xff1a;粘土模型&#xff0c;男性穿着中世纪欧洲蓝色盔甲&#x…

猫头虎分享: 小米大模型升级第二代MiLM2:从一代到二代,能力飞跃提升

小米大模型升级第二代MiLM2&#xff1a;从一代到二代&#xff0c;能力飞跃提升 大家好&#xff0c;我是猫头虎&#xff0c;今天给大家带来一篇关于小米大模型MiLM2的深度解读。作为技术圈的重磅消息&#xff0c;小米的第二代大模型&#xff08;MiLM2&#xff09;在多项领域实现…

解决Anaconda出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url

解决Anaconda出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url 第一类情况 在anaconda创建新环境时&#xff0c;使用如下代码 conda create -n charts python3.7 错误原因&#xff1a; 默认镜像源访问速度过慢&#xff0c;会导致超时从而导致更新和下载失败。 解决方…

【机器学习】机器学习中用到的高等数学知识-2.概率论与统计 (Probability and Statistics)

概率分布&#xff1a;理解数据的分布特征&#xff08;如正态分布、伯努利分布、均匀分布等&#xff09;。期望和方差&#xff1a;描述随机变量的中心位置和离散程度。贝叶斯定理&#xff1a;用于推断和分类中的后验概率计算。假设检验&#xff1a;评估模型的性能和数据显著性。…