PE结构-3

PE结构-3

9. TLS

数据目录表索引:#define IMAGE_DIRECTORY_ENTRY_TLS 9,我查看了一下位于rdata段,不知道是不是固定的。

  • 为了解决多线程变量同步问题
  • 声明为TLS变量后,当线程去访问这个全局变量是,会将这个变量拷贝到自己线程中的TLS空间中。线程只能修改自己的空间tls变量,不会修改到全局变量
  • TLS经常会用于反调试,抢占式执行。
__declspec (thread) int g_nNum;

正常用法:定义一个线程内的全局数据,回调函数做初始化工作。

非正常用法:安全上,将反调试代码写在回调函数里。抢占执行等。

另外,还可以提高壳的兼容性。

typedef struct _IMAGE_TLS_DIRECTORY32 {
    DWORD   StartAddressOfRawData;
    DWORD   EndAddressOfRawData;
    DWORD   AddressOfIndex;             // PDWORD
    DWORD   AddressOfCallBacks;         // PIMAGE_TLS_CALLBACK *
    DWORD   SizeOfZeroFill;
    union {
        DWORD Characteristics;
        struct {
            DWORD Reserved0 : 20;
            DWORD Alignment : 4;
            DWORD Reserved1 : 8;
        } DUMMYSTRUCTNAME;
    } DUMMYUNIONNAME;

} IMAGE_TLS_DIRECTORY32;
  • StartAddressOfRawData:数据起始位置,在TLS节;
  • EndAddressOfRawData:数据结束位置,在TLS节;
  • AddressOfCallBacks:回调函数地址表位置,在rdata节。

数据起始位置和结束位置中间是TLS数据初始值。

回调函数触发事件:

  • DLL_PROCESS_ATTACH 1
  • DLL_THREAD_ATTACH 2
  • DLL_THREAD_DETACH 3
  • DLL_PROCESS_DETACH 0

注册TLS回调函数,".CRT$XLB"的含义是:

  • CRT表明使用C RunTime机制
  • X表示标识名随机
  • L表示TLS callback section
  • B其实也可以为B-Y的任意一个字母

TLS回调函数在.text段中,但回调函数地址保存在.tls段。

#include<iostream>
#include<windows.h>
#pragma comment(linker, "/INCLUDE:__tls_used")

__declspec (thread) int g_nNum = 0xdeadbeef;
__declspec (thread) char g_szStr[] = "TLS g_nNum : 0x%x at 0x%p ... \n";

void NTAPI tTlsCallBack_A(PVOID DllHandle, DWORD Reason, PVOID red)
{
	if (DLL_THREAD_DETACH == Reason) // 如果线程退出则打印信息
		printf("tTlsCallBack_A -> ThreadDetach!\r\n");
	return;
}

void NTAPI tTlsCallBack_B(PVOID DllHandle, DWORD Reason, PVOID red)
{
	if (DLL_THREAD_DETACH == Reason) // 如果线程退出则打印信息
		printf("tTlsCallBack_B -> ThreadDetach!\r\n");
	return;
}

#pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK pThreadCallBack[] =
{
	tTlsCallBack_A,
	tTlsCallBack_B,
	NULL
};
#pragma data_seg()

DWORD WINAPI t_ThreadFun(PVOID pParam) {
	printf("t_Thread ->  first printf:");
	printf(g_szStr, g_nNum);

	g_nNum = 0x22222222; // 注意这里
	printf("t_Thread -> second printf:");
	printf(g_szStr, g_nNum);
	return 0;
}


int main()
{
	CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0);
	Sleep(100);
	printf("\n");
	CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0);
	system("pause");
	return 0;
}

10. 异常

PE文件的异常目录位于.pdata区段,数据目录中的IMAGE_DIRECTORY_ENTRY_EXCEPTION指向此结构。

平台不同,异常结构也不同。x64的异常结构如下:

typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
    DWORD BeginAddress;
    DWORD EndAddress;
    union {
        DWORD UnwindInfoAddress;
        DWORD UnwindData;
    } DUMMYUNIONNAME;
} _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;

typedef  _IMAGE_RUNTIME_FUNCTION_ENTRY  IMAGE_IA64_RUNTIME_FUNCTION_ENTRY;
typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY;

BeginAddressEndAddress是SEH相关代码的起始和末尾偏移地址,这一部分的代码差异属性由UNWIND_INFO结构描述。

这个结构可以译为展开处理程序(unwind handler)结构,记录函数对堆栈指针的影响以及非易失寄存器在堆栈中的保存位置。

typedef struct _UNWIND_INFO {
    UBYTE Version       : 3;
    UBYTE Flags         : 5;
    UBYTE SizeOfProlog;
    UBYTE CountOfCodes;
    UBYTE FrameRegister : 4;
    UBYTE FrameOffset   : 4;
    UNWIND_CODE UnwindCode[1];
    union {
        OPTIONAL ULONG ExceptionHandler;
        OPTIONAL ULONG FunctionEntry;
    };
    OPTIONAL ULONG ExceptionData[]; 
} UNWIND_INFO, *PUNWIND_INFO;

11. 安全

数据目录的IMAGE_DIRECTORY_ENTRY_SECURITY指向安全目录结构,该结构一般存有映像文件的数字签名。

该结构位于wintrust.h,已经弃用。

//
//
//  support for old calling convention: *** DO NOT USE ***
//
#ifdef WT_DEFINE_ALL_APIS

typedef struct _WIN_CERTIFICATE
{
    DWORD       dwLength;
    WORD        wRevision;
    WORD        wCertificateType;   // WIN_CERT_TYPE_xxx
    BYTE        bCertificate[ANYSIZE_ARRAY];

} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;

12. 调试

数据目录表的 IMAGE_DIRECTORY_ENTRY_DEBUG指向调试目录结构,该结构位于.debug区段,主要协助第三方应用调试本程序,如提供调试数据块的位置与大小。

//
// Debug Format
//

typedef struct _IMAGE_DEBUG_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Type;
    DWORD   SizeOfData;
    DWORD   AddressOfRawData;	//RVA in memory, 0 means no mapping
    DWORD   PointerToRawData;
} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;

//Type
#define IMAGE_DEBUG_TYPE_UNKNOWN          0
#define IMAGE_DEBUG_TYPE_COFF             1
#define IMAGE_DEBUG_TYPE_CODEVIEW         2		//vc++
#define IMAGE_DEBUG_TYPE_FPO              3		//框架指针忽略信息,引导调试器解释非标准框架结构
#define IMAGE_DEBUG_TYPE_MISC             4		//dbg文件位置
#define IMAGE_DEBUG_TYPE_EXCEPTION        5		//copy of .pdata
#define IMAGE_DEBUG_TYPE_FIXUP            6		//保留
#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC      7		//将此映像的RVA映射到源映像的RVA
#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC    8		//将源映像的RVA映射到此映像的RVA
#define IMAGE_DEBUG_TYPE_BORLAND          9		//为Borland公司保留
#define IMAGE_DEBUG_TYPE_RESERVED10       10	//保留
#define IMAGE_DEBUG_TYPE_CLSID            11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值