TLS 处理

简介:
TLS(Thread Local Storage,线程局部存储)是一种便利的编程机制。我们通常不使用,因此并不太关心。但是要压缩的原程序可能会用到它。事实上,Delphi 总是使用它,如果我们打算支持 Delphi 程序,最好兼容它。

TLS 基本上是通过 API 实现。大致过程是,你分配一个“ Index(索引)”并存储在一个全局变量中。通过这个 Index 获得针对每个线程的一个双字值。通常使用这个值保存一个为每个线程分配好的内存块的指针。人们认为这样很乏味,一个特殊机制的出现使得实现它更容易些。因此,你可以这样写代码:

None.gif __declspec ( thread )  int  tls_int_value  =   0 ;
None.gif


每个线程可以通过名称访问它独特的实例,就像访问其他变量一样。我不知道这种 TLS 形式是否有官方名称,所以我叫它“简化 TLS”。这种机制与操作系统兼容,并且 PE 文件中有对应的结构。这些结构包含在数据目录的一个块中:

None.gif origdirinfo[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress
None.gif

问题是, 处理这信息发生在由 OS 在每个线程的创建时刻,在执行到线程开始地址之前。(这句翻译的拗口,原文 The problem is that the processing of this information happens by the OS on the creation of every thread prior to execution being passed to the thread start address. )这通常不牵涉到我们,除了至少一个线程在我们解压数据之前被执行:我们的线程!我们必须设置一个伪 TLS 处理区段捕获 OS 在我们开始之前做的事情,然后在最后一步把这个信息传递给原程序。

为此,我在外部加壳器外部全局结构添加了2个项目:
None.gif GlobalExternVars
ExpandedBlockStart.gif
{
InBlock.gif
//(other stuff we previously described)
InBlock.gif
IMAGE_TLS_DIRECTORY tls_original;
InBlock.gifIMAGE_TLS_DIRECTORY tls_proxy;
ExpandedBlockEnd.gif}
;
None.gif

加壳器将会在运行期复制原始数据到 tls_orginal 为我们所用。tls_proxy 几乎是一个精确的副本,除了2个项目将会被修改:
None.gif tls_proxy.AddressOfIndex
None.giftls_proxy.AddressOfCallBacks

在这个块中我们将要初始化 AddressOfIndex 指向一个正常的全局双字变量,并且我们将初始化 AddressOfCallBacks 指向一个函数指针数组。它是一个线程创建时将会被调用的函数指针列表。用户使用它定义 TLS 对象的初始化。唉,我没见过一个编译器使用它。此外,在 9x 下,这些函数不会被调用。尽管如此,我们还是要支持它以防万一哪天它会被使用。我们令 AddressOfCallbacks 指向一个2个成员的数组,一个试我们将要执行的函数指针,另一个是 NULL 作为列表结束符。

设置一个全局双字存储 TLS slot(槽?)
None.gif DWORD TLS_slot_index;
None.gif

TLS 回调函数必须是这种原型:
None.gif extern   " C "   void  NTAPI TLS_callback ( PVOID DllHandle, DWORD Reason, PVOID Reserved );
None.gif

当然还要添加两个逻辑标志表示是否可以安全地调用原来的回调函数,和是否延期调用。这样初始化它们:
None.gif bool  safe_to_callback_tls  =   false ;
None.gif
bool  delayed_tls_callback  =   false ;
None.gif

再提供一些变量保存延迟调用的数据:
None.gif PVOID TLS_dll_handle  =  NULL;
None.gifDWORD TLS_reason 
=   0 ;
None.gifPVOID TLS_reserved 
=  NULL;
None.gif

编写回调函数:
None.gif extern   " C "   void  NTAPI TLS_callback ( PVOID DllHandle, DWORD Reason, PVOID Reserved )
ExpandedBlockStart.gif
{
InBlock.gif        
if ( safe_to_callback_tls )
ExpandedSubBlockStart.gif        
{
InBlock.gif                PIMAGE_TLS_CALLBACK
* ppfn = g_pkrdat.m_tlsdirOrig.AddressOfCallBacks;
InBlock.gif                
if ( ppfn )
ExpandedSubBlockStart.gif                
{
InBlock.gif                        
while ( *ppfn )
ExpandedSubBlockStart.gif                        
{
InBlock.gif                        (
*ppfn) ( DllHandle, Reason, Reserved );
InBlock.gif                        
++ppfn;
ExpandedSubBlockEnd.gif                        }

ExpandedSubBlockEnd.gif                }

InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif        
else
ExpandedSubBlockStart.gif        
{
InBlock.gif                delayed_tls_callback 
= true;
InBlock.gif                TLS_dll_handle 
= DllHandle;
InBlock.gif                TLS_reason 
= Reason;
InBlock.gif                TLS_reserved 
= Reserved;
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif}

None.gif

这样会为 OS 提供一个存储 slot 信息的地方,我们稍候恢复它,并且如果调用了我们的回调函数我们将捕获参数,在解压缩之后调用原来的回调函数。否则会出错因为 0S 会在我们有机会解压缩之前做这件事情。解压缩之后,我们把参数传递给原来的回调函数。

最后一步是这样的:
None.gif void  FinalizeTLSStuff()
ExpandedBlockStart.gif
{
InBlock.gif        
if ( origdirinfo[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0 )
ExpandedSubBlockStart.gif        
{
InBlock.gif                
*gev.tls_original.AddressOfIndex = TLS_slot_index;
InBlock.gif                
void* TLS_data;
InBlock.gif
InBlock.gif                __asm
ExpandedSubBlockStart.gif                
{
InBlock.gif                mov ecx, DWORD PTR TLS_slot_index;
InBlock.gif                mov edx, DWORD PTR fs:[02ch]
InBlock.gif                mov ecx, DWORD PTR [edx
+ecx*4]
InBlock.gif                mov pvTLSData, ecx
ExpandedSubBlockEnd.gif                }

InBlock.gif
InBlock.gif                
int size = gev.tls_original.EndAddressOfRawData - gev.tls_original.StartAddressOfRawData;
InBlock.gif
InBlock.gif                memcpy ( pvTLSData, (
void*) gev.tls_original.StartAddressOfRawData, size );
InBlock.gif                memset ( (
void*) gev.tls_original.EndAddressOfRawData, 0,
InBlock.gif                gev.tls_original.SizeOfZeroFill );
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        safe_to_callback_tls 
= true;
InBlock.gif        
if ( delayed_tls_callback )
ExpandedSubBlockStart.gif        
{
InBlock.gif                TLSCallbackThunk ( TLS_dll_handle TLS_reason TLS_reserved );
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif}
目录
相关文章
|
7月前
|
算法 网络安全 开发工具
TLS/SSL 协议-非对称加密(RSA)原理
TLS/SSL 协议-非对称加密(RSA)原理
154 0
|
5月前
|
安全 算法 应用服务中间件
TLS SSL
TLS SSL
53 0
EMQ
|
9月前
|
监控 安全 算法
使用 SSL/TLS 加强 MQTT 通信安全
本文将着重介绍 TLS 以及它如何保证 MQTT 通信的完整性、机密性和真实性。
EMQ
546 0
|
Web App开发 移动开发 安全
[ 网络协议篇 ] 一篇文章让你掌握什么是 数字证书 ?什么是SSL ?什么是 TLS ?(下)
[ 网络协议篇 ] 一篇文章让你掌握什么是 数字证书 ?什么是SSL ?什么是 TLS ?(下)
174 0
[ 网络协议篇 ] 一篇文章让你掌握什么是 数字证书 ?什么是SSL ?什么是 TLS ?(下)
|
监控 安全 网络协议
[ 网络协议篇 ] 一篇文章让你掌握什么是 数字证书 ?什么是SSL ?什么是 TLS ?(上)
[ 网络协议篇 ] 一篇文章让你掌握什么是 数字证书 ?什么是SSL ?什么是 TLS ?(上)
157 0
|
Web App开发 网络协议 安全
聊聊HTTPS和SSL/TLS协议
要说清楚 HTTPS 协议的实现原理,至少需要如下几个背景知识。 1. 大致了解几个基本术语(HTTPS、SSL、TLS)的含义 2. 大致了解 HTTP 和 TCP 的关系(尤其是“短连接”VS“长连接”) 3. 大致了解加密算法的概念(尤其是“对称加密与非对称加密”的区别) 考虑到很多技术菜鸟可能不了解上述背景,俺先用最简短的文字描述一下。
1591 0
|
Web App开发 安全 网络安全
SSL/TLS协议漏洞 影响TLS协议1.0及SSL所有版本
9月21日布宜诺斯艾利斯举行的Ekoparty安全会议上,安全研究人员Thai Duong和Juliano Rizzo将演示针对SSL/TLS的概念验证攻击。 研究人员在SSL/TLS协议中发现了严重弱点,能让黑客悄悄破译Web服务器和终端用户浏览器之间传输的加密数据。
2522 0
|
应用服务中间件 网络安全 nginx
|
Web App开发 安全 测试技术
|
存储 安全 算法