TLS学习总结

时间:2021-08-14 23:10:23

我们有知道

Immunity Debugger,OD

调试器,在调试程序时会设断在OEP(修改第一个字节0xcc)。我在想,使用什么编程技术,代码可以在OEP前被执行。在网上找了些资料,在论坛上看到许多大牛,使用静态TLS做了好多有趣的事,今天自己也来终结下,,呵呵

1. 什么是TLS?

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

2. 如何使用TLS编程?

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

__declspec(thread) int g_nData = 0;

3.多线程中使用TLS的例子(动态)
相关API

Windows TLS的API: TlsAlloc, TlsFree, TlsSetValue, TlsGetValue。(动态TLS)

● 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槽时

例子:
#include <windows.h>
#include "stdio.h"

#define ThreadCound 4 //创建线程个数
DWORD dwTlsIndex;

//全局变量
int iNUM_OF_CALL_COMMON=0;   
int iNUM_OF_CALL_THREAD=0;

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))
                exit(0);
       
        // 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))
                exit(0);
       
        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;
}

void main(void)
{
        DWORD dwThreadId;
        HANDLE hThread[ThreadCound];
        int i;
        //Allocate a TLS index
        if ((dwTlsIndex =TlsAlloc()) == TLS_OUT_OF_INDEXES)
        {
                exit(0);
        }
       
        for (i = 0; i<ThreadCound; i++)
        {
                hThread[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFunc, NULL, 0, &dwThreadId);
                if(hThread == NULL)
                {
                        exit(0);
                }
        }
        for (i = 0; i < ThreadCound; i++)
        {
                WaitForSingleObject(hThread, 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);

}

以上是动态TLS在多线程中的使用.
而利用静态线程局部存储可以玩弄调试器甚至可以感染一些pe.
静态线程局部存储是在Windows的PE/COFF可执行文件格式中所支持的静态线程局部存储。即在PE头中数据目录表中的第10项,这一项指向的是Tls目录,Tls目录的结构如下:

IMAGE_TLS_DIRECTORY32  STRUCTStartAddressOfRawData  dd  ?EndAddressOfRawData  dd  ?AddressOfIndex 
  dd  ?AddressOfCallBacks    dd  ?SizeOfZeroFill   
dd  ?Characteristics   
dd  ?IMAGE_TLS_DIRECTORY32  ENDS比较重要的是该结构的第四项,是指向Tls
CallBack的数组,该数组里面存放了一个或多个TLS回调函数.而TLS回调函数要执行大概经历以下三个步骤:1.程序在链接时,连接器要在PE文
件的目录表创建TLS目录2.在创建线程时,PE加载器会从TEB(当前线程环境块,通过FS寄存器获取)中获取指向TLS回调函数数值的指针(TEB偏
移2Ch).3.查看TLS 回调函数数组是否为空,不为空时加载器会依次执行回调函数。
静态TLS代码;
#include "stdio.h"#include <windows.h>//告诉编译器在PE文件中要创建TLS目录#pragma
comment(linker,
"/INCLUDE:__tls_used")//TLS_CallBack()函数,第二个参数决定了函数在那种情况下(DllMain函数一样)
/*        DLL_PROCESS_ATTACH:是指新进程创建时,初始化主线程时执行       
DLL_PROCESS_DETACH: 是指在进程终止时执行       
DLL_THREAD_ATTACH:  是指创建新线程时,但是不包括主线程       
DLL_THREAD_DETACH:  是指在所有线程终止时执行,但是同样不包括主线程*/void go_anit(){       
ExitProcess(0);}void __stdcall my_tls_callback(PVOID h, DWORD reason,
PVOID pv){        //仅在进程初始化创建主线程执行        if (reason ==
DLL_PROCESS_ATTACH)        {                //检查OEP               
IMAGE_DOS_HEADER *DosHeader = (IMAGE_DOS_HEADER*)GetModuleHandle(NULL); 
              IMAGE_NT_HEADERS *NtHeader =
(IMAGE_NT_HEADERS*)(((DWORD)DosHeader)+ (DWORD)DosHeader->e_lfanew); 
              BYTE *ope =
(PBYTE)(NtHeader->OptionalHeader.AddressOfEntryPoint +
(DWORD)DosHeader);                if (*ope == 0xcc)                {     
                  go_anit();                }        }}/*       
下面创建一个TLS段        ".CRT$XLB"的含义是:".CRT"表明是使用C RunTime机制 $后面的XLB中,       
X表示随机的标识        L表示TLS Callback section        B可以被换成B到Y的任意一个字母,.       
$是给连接器的。*/#pragma data_seg(".CRT$XLB")//定义多个TLS_CallBack
PIMAGE_TLS_CALLBACK p_Tls_CallBack[] = {my_Tls_CallBack1,
my_Tls_CallBack2,my_Tls_CallBack3, 0};PIMAGE_TLS_CALLBACK p_Tls_CallBack
= my_tls_callback;#pragma data_seg()void main(){        printf("Hello
TLS\n");        getchar();}
这种方法就能真真的玩弄调试器吗?显然不是的,首先我们来看下创建一个进程的过程1.打开将要在该进程中执行的映像文件。
首先操作系统找到执行的Windows映像然后创建一个内存区对象,以便后面将它映射到新的进程地址空间中。
2.创建Windows执行体进程对象。
接下来操作系统调用内部的系统函数NtCreateProcess来创建一个Windwos执行体进程对象。具体步骤是:
(1)建立EPROCESS
(2)创建初始的进程地址空间(3)初始化内核进程块KPROCESS
(4)结束进程地址空间的创建过程
(5)建立PEB
(6)完成执行体进程对象的创建过程
3.创建初始线程(栈、堆执行环境初始化及执行线程体对象)。
这时候Windows执行体进程对象已经完全建立完成,但它还没有线程所以无法执行,接下来系统调用NtCreateThread来创建一个挂起的新线程它就是进程的主线程体。

4.通知Windows子系统新进程创建了(子系统是操作系统的一部分它是一个协助操作系统内核管理用户态/客户方的一个子系统具体的进程为
Csrss.exe)。
接下来操作系统通过客户态(Kernel32.dll)给Windows子系统(Csrss)发送一个新进程线程创建的数据消息,让子系统建立自己的进程线程管理块。当
Csrss接收到该消息时候执行下面的处理:
*复制一份该进程和线程句柄
*设置进程优先级
*分配Csrss进程块
*把新进程的异常处理端口绑定到Csrss中,这样当该进程发生异常时,Csrss将会接收到异常消息
*分配和初始化Csrss线程块
*把线程插入到进程的线程列表中
*把进程插入到Csrss的线程列表中
*显示进程启动光标
5.开始执行初始线程(如果创建时候指定了线程的CREATE_SUSPENDED状态则线程暂时挂起不执行)。
到这里进程环境已经建立完毕进程中开始创建的主线程到这里获得执行权开始执行线程
6.在新进程和线程环境中完成地址空间的初始化(比如加载必须的DLL和库),然后开始到进程入口执行。
到这步实质是调用ldrInitializeThunk来初始化加载器,堆管理器NLS表TLS数组以及临界区结构,并且加载任何必须要的DLL并且用
DLL_PROCESS_ATTACH功能代码来调用各DLL入口点,最后当加载器初始化例程返回到用户模式APC分发器时进程映像开始在用户模式下执行,然后它调用线程启动函数开始执行。

操作系统会抛出一个CreateProcessEvent事件,早于Tls_CallBack函数,同时ExceptionEvent事件也是早于
Tls_callback的所以我们可以设置调试器第一次断点“系统断点” 本实验我用的Immunity Debugger调试器,
OD相似选项->调试选项->事件->设置第一次暂停于 “系统断点”  单步跟中会发现      对当前进程信息设置

TLS学习总结

file:///C:/Users/asus/AppData/Local/youdao/ynote/images
/C357E1C9D1184437819E2C6A7919ADB8/clipboard.png到此跟进,,,查了好多资料也不知道这个函数是啥
子,,求大牛指导

TLS学习总结

file:///C:/Users/asus/AppData/Local/youdao/ynote/images
/DCE533091FD64FE48C52145B1484E6F6/clipboard.png之后见call跟进,,,到ZwContiune函
数, 继续执行线程,他的一个参数是CONTEXT指针,找到Context->EIP

TLS学习总结

file:///C:/Users/asus/AppData/Local/youdao/ynote/images/2D7F6F8AC69F46B293E3ED5CC47F167E/clipboard.png出现OPE地址

TLS学习总结

file:///C:/Users/asus/AppData/Local/youdao/ynote/images/000F6F5D807640FB92E5BFC4E562AF28/clipboard.png
跟进call eax

TLS学习总结

file:///C:/Users/asus/AppData/Local/youdao/ynote/images/98213D4D5ACD48A3A6C4BF957917E3B1/clipboard.pngcall edx 则进入OEP

TLS学习总结

file:///C:/Users/asus/AppData/Local/youdao/ynote/images/6A1D98036EB64140BAEF6A1F7B67F792/clipboard.png

TLS学习总结

file:///C:/Users/asus/AppData/Local/youdao/ynote/images
/05EAE8B3357D45CCA440A3082C120B11/clipboard.png这个过程真的还很模糊,很多疑问,不知道进入OEP之
前的那些函数具体的干了啥,,,,求指导

7.png
(16.36 KB, 下载次数: 2)

TLS学习总结

8.png
(10.68 KB, 下载次数: 1)

TLS学习总结

TLS学习总结的更多相关文章

  1. 在 ASP&period;NET MVC 中使用 HTTPS &lpar;SSL&sol;TLS&rpar; -- 学习

    在 ASP.NET MVC 中使用 HTTPS (SSL/TLS) IS 7如何实现http重定向https HTTPS 升级指南

  2. Python Web学习笔记之SSL&comma;TLS&comma;HTTPS

    一. SSL 1. SSL简介 SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持.SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可 ...

  3. https、ssl、tls协议学习

    一.知识准备 1.ssl协议:通过认证.数字签名确保完整性:使用加密确保私密性:确保客户端和服务器之间的通讯安全 2.tls协议:在SSL的基础上新增了诸多的功能,它们之间协议工作方式一样 3.htt ...

  4. 常用加密算法学习总结之数字证书与TLS&sol;SSL

    数字证书 对于一个安全的通信,应该有以下特征: 完整性:消息在传输过程中未被篡改 身份验证:确认消息发送者的身份 不可否认:消息的发送者无法否认自己发送了信息 显然,数字签名和消息认证码是不符合要求的 ...

  5. NodeJS学习笔记 &lpar;32&rpar;安全加密-tls

    https://github.com/chyingp/nodejs-learning-guide

  6. 《Django By Example》第二章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:翻译完第一章后,发现翻译第二章的速 ...

  7. tomcat集群学习记录1--初识apache http server

    起因 平时开发的时候我都是用eclipse把代码部署到本地tomcat的,当然只会去跑1台tomcat啦... 偶尔有时候解决问题需要去公司测试环境找日志.连上公司测试环境以后发现竟然有2台weblo ...

  8. SIP学习笔记&lpar;转)

    本文转发自:http://blog.chinaunix.net/uid-20655530-id-1589483.html 学习 SIP 协议最快捷的方法是通过范例来学习, 找到了一个完整的呼叫流程,l ...

  9. Docker学习笔记

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何 ...

随机推荐

  1. &lbrack;原&rsqb;一个针对LVS的压力测试报告

    LVS 测试报告 测试计划 基本功能测试 流量压力测试 响应时间测试 配置正确性测试 灾难恢复测试 测试点 基本功能测试 客户端IP地址正确性 RealServer 访问Internet测试(包括Ip ...

  2. Oracle 创建普通用户,并赋予权限

    采用sys or system / manager as sysdba; 连接数据库. 创建普通用户konglin: create user konglin identified by pwd_ora ...

  3. js判断浏览器

    function myBrowser(){ var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串 ; if (isOpera) { ret ...

  4. 【python cookbook】【字符串与文本】7&period;定义实现最短匹配的正则表达式

    问题:使用正则表达式对文本模式匹配,将识别出来的最长的可能匹配修改为找出最短的可能匹配 解决方法:在匹配模式中的*操作符后加上?修饰符 import re # Sample text text = ' ...

  5. MD5加密(C&num;)

    先来说说Md5 MD5为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护. md5有很多广泛的功能.大家都知道,数据库里面密码不会直接存该密码,而是加密之后的字符串.这时候你就可以把密码 ...

  6. 【LeetCode】232 &amp&semi; 225 - Implement Queue using Stacks &amp&semi; Implement Stack using Queues

    232 - Implement Queue using Stacks Implement the following operations of a queue using stacks. push( ...

  7. Transact-SQL

    Transact-SQL(又称T-SQL),是在Microsoft SQL Server和Sybase SQL Server上的ANSI SQL实现,与Oracle的PL/SQL性质相近(不只是实现A ...

  8. 【转】android 完全退出应用程序

    原文网址:http://www.yoyong.com/archives/199 android退出应用程序会调用android.os.Process.killProcess(android.os.Pr ...

  9. IIS 部署问题 404

    在部署IIS环境中,偶尔会遇到 404 错误,就算以前遇到过,也因为时间久了导致大概知道是什么错了,具体解决方案觉忘了,所以留下一个记录,留给自己,也是给大家一点提醒.(注:错误信息也懒得截图了,希望 ...

  10. CVE-2011-0762环境搭建与EXP利用

    CVE-2011-0762 vsftpd拒绝服务漏洞 危害:通过发送特殊构造的数据包.利用漏洞使应用程序崩溃 条件:连接上vsftpd才能发包 发现时间:2011-03-01 需求:找到EXP运行发送 ...