双子座流星雨在哪里看:线程局部储存

来源:百度文库 编辑:偶看新闻 时间:2024/04/28 02:13:02
                                                 隐藏的入口点
                                                    64位版
                                                   (Intel)
                                               roy g biv / 29A

29a-8.002  linux2linux翻译于2005-7-9
                                            
关于作者:

从前的 Dos/Win16 病毒编写者,几个病毒家族的作者包括Ginger(参看Coderz #1 杂志的很糟糕有Bug的例子,有好的代码通知我 :)和Rainbow(参看 Virus Bulletin 95/5的描述,他们这么称呼他),世界上第一个使用循环分区技巧的联合病毒作者(Orsam,在1993编写了原型),世界上第一个XMS(扩展内存)交换病毒的发明者(John Galt, 在1995有RT Fishel编写,只有30字节代码存根(stub),其余的都交换出去了),世界上第一个使用线程局部存储用作复制的病毒作者(Shrug, 参看Virus Bulletin 02/6的描述,但他们称它为Chiton),世界上第一个使用Visual Bisic 5/6 语言扩展用作复制的病毒(OU812),世界上第一个本地可执行的病毒(Chthon),世界上第一个使用进程相互协作防止被中止的病毒(Gemini,参看Virus Bulletin 02/9 的描述),世界上第一个使用多态SMTP报头的病毒(JunkMail,参看Virus Bulletin 02/11的描述),世界上第一个能转换任何数据文件到感染对象的病毒(Pretext),世界上第一个32/64位寄生EPO .NET病毒(Croissant),世界上第一个使用自身执行的HTML病毒(JunktmaiL,参看Virus Bulletin 03/7的描述),各种各样的病毒文章的作者(例如 参看Vlad #7 能使你的代码对TBSCAN不可见的字符串),他们都沉睡了多年。这是我第一个Win64病毒。这是世界上第一个在 Intel Itanium 平台上的Win64病毒。

什么是线程局部存储?

这就是Microsoft只好对它解释的内容:

“.tls段为静态线程局部存储(TLS)提供直接的PE/COFF支持。TLS是一种Windows NT支持的特殊的存储类别。为了支持程序的构造,PE/COFF的.tls段详细说明了下面的信息:初始化数据,每一个线程的初始化和中止的回调例程和TLS索引”

所以,为了那些需要在主程序执行开始之前,初始化线程数据的应用程序,Microsoft发明了线程局部存储。为了达到这一点,就有回调指针。这些函数在主函数入口点的代码之前执行!很明显,这是一种让病毒运行的新方法,即使反病毒专家知道它,他们大概也不会支持PE+文件,因为没有病毒使用它。

有一点现在要指出:
我们可以忽略到.tls的引用,因为在PE头中有一字段,它指向在文件中任何地方的这个结构

除了没有什么返回,回调函数具有有相同的参数作为DLL入口点函数,申明看上去像这样:

typedef VOID (NTAPI *PIMAGE_TLS_CALLBACK)
             (PVOID DllHandle, DWORD Reason, PVOID Reserved);

参数Reason可以接受下面的数值:

Setting                 Value   Description
DLL_PROCESS_ATTACH      1       New process has started
DLL_THREAD_ATTACH       2       New thread has been created
DLL_THREAD_DETACH       3       Thread is about to be terminated
DLL_PROCESS_DETACH      0       Process is about to terminate

DLL_PROCESS_ATTACH 和 DLL_PROCESS_DETACH 消息意味着我们因为寄主启动(在CreateProcess之后但在进程入口点之前)和关闭(来自ExitProcess()中)而被调用,DLL_THREAD_ATTACH 和 DLL_THREAD_DETACH 意味着我们因为线程的启动(在CreateThread()之后但在线程入口之前)和关闭(来自于ExitThread()中)。这正发生在EXE和DLL上(只不过DLL使用LoadLibrary加载)。现在再也没有必要挂钩ExitProcess(),因为我们将会被ExitProcess()自动调用。

了解NTDLL.DLL(不是KERNEL32.DLL!)调用回调函数是很重要的。因而,如果你要调用kernel32.dll的API,你需要调用LdrGetDllHandle()去发现kernel32.dll的映像基址。幸运的是导入表已经加载了,所以你能使用寄主的导入表。

TLS看上去像什么?

在PE头偏移0xD0的位置是指向TLS目录的指针,根据Microsoft文档,TLS目录有如下格式:

Offset  Size    Field                   Description
0x00    8       Raw Data Start VA       Starting address of the TLS template
0x04    8       Raw Data End VA         Address of last byte of TLS template
0x08    8       Address of Index        Location to receive the TLS index
0x0C    8       Address of Callbacks    Pointer to array of TLS callbacks
0x10    4       Size of Zero Fill       Size of unused data in TLS template
0x14    4       Characteristics         (reserved but not checked)

注意到指针都是虚地址(VA),不是相对地址(RVA)。这意味着如果我们加上一个TLS目录,我也应该在.reloc段中加入重定位项,或着简单的删去所有的重定位项。这个原因是如果文件被载入到一个不同的基地址,Windows会显示消息框“应用程序正确的初始化失败”并且文件不会在执行。

TLS字段意味着什么?

每当一个线程创建,TLS模板(TLS template)包含的数据就会被复制。这些数据可以是可执行代码(在调用VirtualProtect()后,因为IA64强制了执行位)。如果模板存在(它是可选的并且这个字段可以是空),然后当程序启动时,Windows将为TLS指针分配一个数组,储存这个指针在r13:0x58。对于创建的每一个线程,会从局部堆中分配模板的大小的空间,数据会拷贝到那儿,指针会储存在数组中,而数组的索引储存在TLS index字段中。线程能通过这个公式得到这个指针:

qword at (qword at [r13:[0x58]] + (TLS index * 8))

或者一些代码

add    r30 = 0x58, r13
ld8    r30 = [r30]                      //get pointer to array of TLS pointers
add    r31 = @ltoff(TLSIndex), gp
ld8    r31 = [r31]                      //get TLS index pointer
ld4    r31 = [r31]                      //get TLS index
shladd r30 = r31, 3, r30                //get pointer to TLS data pointer
ld8    r30 = [r30]                      //get pointer to TLS data
then access data at [r30 + offset]

Callbacks 字段的地址包含着一个虚地址,指向一个用来接收ATTACH/DETACH消息的,以null为结束的函数数组。在这个数组中没有入口也是合法的。在这种情况下,该字段假定指向8个0的字节,当然实际字段也能为null。

如何使用TLS?

有几种使用TLS感染文件的简单方法:

在已有的数组中加入一个回调指针(或者创建新数组)
改变寄主回调指针中的一个
改变一个回调函数中代码
创建一个新的TLS目录
劫持TLS模板并且改变文件中某处的一些代码

如果逆向使用TLS的方法感染文件,首先检查是否TLS目录已经存在。如果存在,你可以随机地选择一个回调例程指针,改变它,让其指向你的代码。如果没有存在的TLS目录,在你自己的版本中通过正确设置指针添加一个目录。模板地址能被设为空,索引指针可以指向任何可写的双字(包括Characteristics 字段因为它没有被使用)。回调指针指向回调例程指针数组,其中一个是病毒入口点。但这个入口点接收控制,文件完全载入内存并且输入表会被修正。这意味着我们能做任何我通常所做的事,比如进行常驻或着调用API函数和传播到其他文件。主要的不同在于我们保证被调用至少两次,一次在启动,一次在关闭,并且对于寄主使用的每个线程有会多两次。这就意味着我们必须小心以防止回溯,因为如果我们在病毒代码中使用线程,我门自己也会被调用。

劫持TLS模板是一项仍未使用的技术。想法是做一个TLS模板的拷贝并给它加入病毒代码。当进程启动(或着线程创建),病毒代码将会被Windows拷贝到堆中。这意味着代码自动的放入可写的地址空间中,没有使用任何malloc或者memcopy的调用。在此以后仅需要做的两件事是,标记这段区域为可执行和向在堆中的代码传递控制权。可以通过TLS索引取得堆指针达到这一点。


传递控制的代码看上去像这样:

这段代码在文件中:

fib:
alloc                   loc0 = 0, 4, 4, 0
mov                     loc1 = rp
mov                     loc2 = gp
add                     out0 = 0x58, r13
ld8                     out0 = [out0]
add                     out1 = @ltoff(TLSIndex), gp
ld8                     out1 = [out1]
ld4                     out1 = [out1]
shladd                  out0 = out1, 3, out0
ld8                     out0 = [out0]
mov                     out1 = 1
mov                     out2 = PAGE_EXECUTE_READWRITE
add                     out0 = size of original TLS template, out0
mov                     out3 = sp
mov                     loc3 = out0
br.call.sptk.few        rp = VirtualProtect
fie:
mov                     b1 = loc3
br.cond.sptk.many       b1

这个代码在堆中

mov                     r2 = rp   //get return address
addl                    r2 = fib - fie, r2 //point to first byte of code in file
//rest of code is here.  do not forget to restore host bytes
mov                     ar.pfs = loc0  //restore important registers
mov                     rp = loc1  //restore important registers
mov                     gp = loc2  //restore important registers
mov                     b1 = loc3  //store real return address
br.cond.sptk.many       b1   //return to host

结语

现在你想看我的示例代码并且制作自己的例子。让这种技术变得很有趣可以有多种可能性。当你知道如何做时,这就很简单了,只要发挥一下你的想像力。

TLSDemo3 有一个插入的TLS目录和显示消息框的代码。
这个代码在主程序入口点之前运行。

TLSDemo4 有一个劫持的TLS模板和显示消息框的代码。
这个代码从主程序入口点跳到堆中,没有使用malloc和memcopy函数。

向朋友们问候(A-Z):

Active - Benny - Obleak - Prototype - Ratter - Ronin - RT Fishel -
sars - The Gingerbread Man - Ultras - uNdErX - Vecna - VirusBuster -
Whitehead

rgb/29A 2004年五月
iam_rgb@hotmail.com