TLS隐藏的入口点

简介:
TLS简介
1. 什么是TLS?
 
TLS是Thread Local Storage(线程局部存储)的简称,是一项解决多线程内部变量使用问题的技术。用于将某些数据和一特定线程关联起来,即,这些数据为关联线程所独有(私有)。在多线程编程中, 同一个变量, 如果要让多个线程共享访问, 那么这个变量可以使用关键字volatile进行声明; 而如果一个变量不想被多个线程共享访问, 那么就应该使用TLS。
 
2. 如何使用TLS编程?

TLS使用非常简单, 只要对变量声明时使用__declspec(thread)修饰就可以了。例如:
_declspec(thread)  int g_nData = 0;

3. 一个使用TLS的例子
// --------------------------------------------------------------------------------------------------------
#include <windows.h> 
#include <stdio.h> 
 
#define THREADCOUNT 4 
DWORD dwTlsIndex; 
 
int iNUM_OF_CALL_COMMON=0;
int iNUM_OF_CALL_THREAD=0;
 
VOID ErrorExit(LPSTR); 
 
VOID CommonFunc(VOID) 

   LPVOID lpvData; 
 // Retrieve a data pointer for the current thread. 
 iNUM_OF_CALL_COMMON++;
 
   lpvData = TlsGetValue(dwTlsIndex); 
   if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS)) 
      ErrorExit("TlsGetValue error"); 
 
// Use the data stored for the current thread. 
    printf("common: thread %d: lpvData=%lx\n", 
      GetCurrentThreadId(), lpvData); 
 
   Sleep(5000); 
}
 
 
DWORD WINAPI ThreadFunc(VOID) 

   LPVOID lpvData; 
 
// Initialize the TLS index for this thread. 
 iNUM_OF_CALL_THREAD++;
 
   lpvData = (LPVOID) LocalAlloc(LPTR, 256); 
   if (! TlsSetValue(dwTlsIndex, lpvData)) 
      ErrorExit("TlsSetValue error"); 
 
   printf("thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData); 
 
   CommonFunc(); 
 
// Release the dynamic memory before the thread returns. 
    lpvData = TlsGetValue(dwTlsIndex); 
   if (lpvData != 0) 
      LocalFree((HLOCAL) lpvData); 
 
   return 0; 
}
 
 
int main(VOID) 

   DWORD IDThread; 
   HANDLE hThread[THREADCOUNT]; 
   int i; 
 
// Allocate a TLS index. 
    if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) 
      ErrorExit("TlsAlloc failed"); 
 
// Create multiple threads. 
    for (i = 0; i < THREADCOUNT; i++) 
   
      hThread[i] = CreateThread(NULL, // default security attributes 
         0,                           // use default stack size 
         (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function 
         NULL,                    // no thread function argument 
         0,                       // use default creation flags 
         &IDThread);              // returns thread identifier 
 
   
// Check the return value for success. 
      if (hThread[i] == NULL) 
         ErrorExit("CreateThread error\n"); 
   }
 
 
  // printf("All threads were created.\n");
   for (i = 0; i < THREADCOUNT; i++) 
      WaitForSingleObject(hThread[i], INFINITE); 
 
   TlsFree(dwTlsIndex);
 
   printf("The nums of thread is: %d\n",iNUM_OF_CALL_THREAD);
   printf("The nums of call is: %d\n",iNUM_OF_CALL_COMMON);
 
   return 0; 
}
 
 
VOID ErrorExit (LPSTR lpszMessage) 
{  
   fprintf(stderr, "%s\n", lpszMessage); 
   ExitProcess(0); 
}
  
// --------------------------------------------------------------------------------------------------------

4. T L S的内部数据结构
 
1.jpg
图1 用于管理T L S的内部数据结构
 
 
每个标志均可设置为FREE或者INUSE,表示TLS槽( s l o t )是否正在使用。Microsoft保证至少TLS_MINIMUM_AVAILABLE位标志是可供使用的。
 
5. 相关API
 
Windows TLS的API: TlsAlloc, TlsFree, TlsSetValue, TlsGetValue。
 
● DWORD TlsAlloc(); //(若要使用动态T L S,首先必须调用TlsAlloc函数)
 
这个函数命令系统对进程中的位标志进行扫描,并找出一个FREE标志。然后系统将该标志从FREE改为INUSE,并且TlsAlloc返回位数组中的标志的索引。DLL(或APP)通常将该索引保存在一个全局变量中,因为它的值是每个进程而不是每个线程使用的值。
 
● BOOL TlsSetValue( //将一个值放入线程的数组中
 
DWORD dwTlsIndex,
 
PVOID pvTlsValue);
 
● PVOID TlsGetValue(DWORD dwTlsIndex); //要从线程的数组中检索一个值
 
● BOOL TlsFree(DWORD dwTlsIndex); //当在所有线程中不再需要保留TLS槽时
 
 
 
参考资料:Jeffrey Richter《《Programming Applications for Microsoft Windows (4th Ed.)》》Chapter 21
 
6. TLS目录
 
7.JPG
TLS Callback Functions
这是线程建立和退出时的回调函数, 包括主线程和其他线程.AddressOfCallBacks 是指向函数指针数组的指针, 以 0 结束.
typedef  struct _TEB  {
NT_TIB Tib;
PVOID EnvironmentPointer;
CLIENT_ID Cid;
PVOID ActiveRpcInfo;
PVOID ThreadLocalStoragePointer; ; 2ch
PPEB Peb; ; 30h
ULONG LastErrorValue; ; 34h
…}


TLS目录 #define IMAGE_DIRECTORY_ENTRY_TLS 9 (第十个目录)
 
 
 
Tls隐藏的入口点利用
 
 
就是利用Address of Callbacks字段,写入要执行的代码的地址就可以了.
 
 
测试对象:test.exe
 
程序类型:delphi编写
 
 
 
PeEditor检测Tls信息(文件偏移59400H处)如下:
2.jpg
 
TLS信息
 
------------------------------------------
 
 
 
目录表: 0045D000
 
TLS数据: 0045D010
 
索引变量: 004570A0
 
调用返回地址: 0045E010 (调用返回地址)
 
------------------------------------------
 
 
 
我们打算让系统在0045E010处执行我们的代码,就需要在这个地方对应的文件偏移处写入我们的代码。
 
 
 
观察节表信息
 
VA=0045E010,按照文件不需要重定位去计算则RVA=0005E010
 
观察节表信息,这个值处于.rdata节内。
 
.rdata节起始RVA=0005E000,起始Offset为00059400
 
则callback地址对应的Offset=(0005E010 - 0005E000)+ 00059400 =00059410
 
注意在这里(00059410H)应该写入一个函数地址。

打造一个简单的代码:

;----------------------------------------------------------------
 
. 386
 
.model flat,stdcall
 
option casemap:none
 
 
 
include windows.inc
 
include user32.inc
 
 
 
includelib user32.lib
 
 
 
.code
 
start:
 
jmp  @F
 
 
 
db  ' Run thru Tls entry point. ', 0
 
@@: 
 
mov eax,$
 
sub eax, 26
 
call  @delta
 
@delta:
 
pop ebp
 
sub ebp,offset  @delta
 
add eax,ebp
 
invoke MessageBox,NULL,eax,NULL, 0
 
ret
 
end start
 
;----------------------------------------------------------------

编译生成可执行文件,这只是一个简单的弹出对话框的程序。
3.jpg
 
打开16进制工具,载入msgbox.exe,复制代码:
4.jpg
 
注意00402000H处存放的是MessageBox的入口地址,我把它固化下来,动态跟踪发现是8A05D577H。(当然在编程时可以动态搜寻我们需要的API,为简单起见这里Hard-code一下。)
 
打开16进制工具,载入艺术字体2.exe,定位到00059410。
5.jpg
 
我们把代码复制在偏移00059410处,对应的VA=0045E030H,则把0045E030存入偏移00059410。
 
还要注意最后的 MessageBox的入口地址我们使用硬编码的方式,我们把这个地址写入在00059480处了。保存修改,然后运行程序。程序首先弹出两个对话框(一个是TLS模板,一个是主线程创建),结束程序运行还会弹出一个对话框,不过这个对话框太丑了:
 
6.jpg
 
 
说明:我在看一本介绍病毒知识的书籍时看到作者提及到这么一句话,大概意思是说他们公司某人发现了这个秘密,一直没有公布,不过后来由于rgb利用此技术制造了病毒,也就无所谓秘密可言了。由于Tls入口要比OEP先执行,所以在加壳与脱壳中都有利用的价值。
目录
相关文章
|
6天前
|
存储 JSON Go
如何在 Go 项目中隐藏敏感信息,比如避免暴露用户密码?
在Go语言开发中,用户信息管理常涉及敏感数据如密码的处理。为防止这些数据暴露给客户端,本文介绍了三种方法:使用JSON标签忽略字段、自定义序列化逻辑、使用数据传输对象(DTO),以确保用户数据的安全性。通过这些方法,可以有效控制数据输出,避免敏感信息泄露。
18 1
|
5月前
|
安全 Java 网络虚拟化
隐藏 IP 地址调用外部接口:探索与实践
隐藏 IP 地址调用外部接口:探索与实践
93 0
|
3月前
|
Windows
【Azure 应用服务】应用代码中需要使用客户端证书访问服务接口,部署在应用服务后报错不能找到证书(Cannot find the X.509 certificate)
【Azure 应用服务】应用代码中需要使用客户端证书访问服务接口,部署在应用服务后报错不能找到证书(Cannot find the X.509 certificate)
|
6月前
|
算法 Java Android开发
安卓逆向 -- 实现SO层签名验证
安卓逆向 -- 实现SO层签名验证
355 49
|
6月前
|
安全 Windows
win10修改本地host文件,用以增加自定义本地访问域名127.0.0.1
win10修改本地host文件,用以增加自定义本地访问域名127.0.0.1
393 0
|
6月前
|
算法 Android开发
安卓逆向 -- 绕过SO层签名验证
安卓逆向 -- 绕过SO层签名验证
153 1
|
Windows
.Net Framework 0x800b0109 -已处理证书链,但是在不受信任提供程序信任的根证书中终止。
.Net Framework 0x800b0109 -已处理证书链,但是在不受信任提供程序信任的根证书中终止。
1177 0
.Net Framework 0x800b0109 -已处理证书链,但是在不受信任提供程序信任的根证书中终止。
|
存储 API 数据库
c# 如何将程序加密隐藏?
c# 如何将程序加密隐藏?
136 0
c# 如何将程序加密隐藏?
|
JavaScript 前端开发 Java
Nginx location 基础使用、四层访问控制、账户认证及自定义日志路径(二)|学习笔记
快速学习 Nginx location 基础使用、四层访问控制、账户认证及自定义日志路径
211 0
Nginx location 基础使用、四层访问控制、账户认证及自定义日志路径(二)|学习笔记
|
存储 应用服务中间件 开发工具
Nginx location 基础使用、四层访问控制、账户认证及自定义日志路径(四)|学习笔记
快速学习 Nginx location 基础使用、四层访问控制、账户认证及自定义日志路径
179 0
Nginx location 基础使用、四层访问控制、账户认证及自定义日志路径(四)|学习笔记