首页
论坛
课程
招聘
翻译 TLS 处理
2005-10-23 12:19 8818

翻译 TLS 处理

2005-10-23 12:19
8818
英语又退步了唉,不准就不准吧凑或看。

支持 TLS

原文:Writing Your Own Packer - by BigBoote

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

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

__declspec ( thread ) int tls_int_value = 0;


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

origdirinfo[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress


问题是, 处理这信息发生在由 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个项目:

GlobalExternVars
{
//(other stuff we previously described)
IMAGE_TLS_DIRECTORY tls_original;
IMAGE_TLS_DIRECTORY tls_proxy;
};


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

tls_proxy.AddressOfIndex
tls_proxy.AddressOfCallBacks


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

设置一个全局双字存储 TLS slot(槽?)

DWORD TLS_slot_index;


TLS 回调函数必须是这种原型:

extern "C" void NTAPI TLS_callback ( PVOID DllHandle, DWORD Reason, PVOID Reserved );


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

bool safe_to_callback_tls = false;
bool delayed_tls_callback = false;


再提供一些变量保存延迟调用的数据:

PVOID TLS_dll_handle = NULL;
DWORD TLS_reason = 0;
PVOID TLS_reserved = NULL;


编写回调函数:

extern "C" void NTAPI TLS_callback ( PVOID DllHandle, DWORD Reason, PVOID Reserved )
{
        if ( safe_to_callback_tls )
        {
                PIMAGE_TLS_CALLBACK* ppfn = g_pkrdat.m_tlsdirOrig.AddressOfCallBacks;
                if ( ppfn )
                {
                        while ( *ppfn )
                        {
                        (*ppfn) ( DllHandle, Reason, Reserved );
                        ++ppfn;
                        }
                }

        }
        else
        {
                delayed_tls_callback = true;
                TLS_dll_handle = DllHandle;
                TLS_reason = Reason;
                TLS_reserved = Reserved;
        }
}


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

最后一步是这样的:

void FinalizeTLSStuff()
{
        if ( origdirinfo[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0 )
        {
                *gev.tls_original.AddressOfIndex = TLS_slot_index;
                void* TLS_data;

                __asm
                {
                mov ecx, DWORD PTR TLS_slot_index;
                mov edx, DWORD PTR fs:[02ch]
                mov ecx, DWORD PTR [edx+ecx*4]
                mov pvTLSData, ecx
                }

                int size = gev.tls_original.EndAddressOfRawData - gev.tls_original.StartAddressOfRawData;

                memcpy ( pvTLSData, (void*) gev.tls_original.StartAddressOfRawData, size );
                memset ( (void*) gev.tls_original.EndAddressOfRawData, 0,
                gev.tls_original.SizeOfZeroFill );
        }

        safe_to_callback_tls = true;
        if ( delayed_tls_callback )
        {
                TLSCallbackThunk ( TLS_dll_handle TLS_reason TLS_reserved );
        }
}

看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

收藏
点赞0
打赏
分享
最新回复 (7)
雪    币: 19
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
pendan2001 活跃值 4 2005-10-23 13:50
2
0
不懂!
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:810 )
在线值:
发帖
回帖
粉丝
ForEver 活跃值 20 2005-10-23 18:45
3
0
good!
雪    币: 205
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
南蛮妈妈 活跃值 3 2005-10-24 08:52
4
0
曰:强贴必留名, 我顶
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
k99992002 活跃值 2005-10-24 21:52
5
0
支持下!
雪    币: 159
活跃值: 活跃值 (51)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
gzgzlxg 活跃值 11 2005-10-26 16:16
6
0
forgot 版主为何不将全文翻译,本站外文翻译区有此文前部的部分翻译,但译文不太准确,远不如版主的水平,从译文看译者计算机基本知识或习惯用语不太熟悉,所以有些地方用词不当。
例如:
* Support for code relocation fixups in dlls if you care about packing dlls. Recall ActiveX controls are dlls too, as are other common things you might be interested in packing
支持DLLs加壳,要对代码的偏移修正。同样ActiveX也是DLLs, 假如你感兴趣的话还有其他一般性的东西你需要考虑。
(这里relocation fixups 应该是指重定位表)
* Support for some stuff that must be available even in the compressed form. This includes some of your resources and export names in dlls
支持压缩形式的数据,包括一些资源和DLLs里的输出名。
(这里 export 应该是指输出表)
* Dealing with bound imports
处理被限制的输入。
(这里 imports 应该指输入表)
* Support for stripping out directory entries that will confuse the Windows loader since the decompression won't have happened and they will point to nothing useful, like the IAT and debug info
支持剥除可能使Windows载入器出错的目录项,使解压呈现可以执行,防止代码指向无用的数据,比如图象注释带还有调试信息。
(这里directory entries 应该指 ImageDataDirectoryEntry 表,即节表的地址索引表;这里 IAT 应该指‘输入地址表’(Import Address Table))
雪    币: 5536
活跃值: 活跃值 (56)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
forgot 活跃值 26 2005-10-26 17:34
7
0
好文章不过太长了,我没耐心译完啊。

看这篇文章还是用金山词霸比较好,哈哈。
雪    币: 106
活跃值: 活跃值 (355)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
nbw 活跃值 24 2005-10-26 21:08
8
0
牛x阿。学习
游客
登录 | 注册 方可回帖
返回