您现在的位置是:主页 > news > 彩票网站怎么做/百度搜索资源管理平台

彩票网站怎么做/百度搜索资源管理平台

admin2025/6/19 9:55:12news

简介彩票网站怎么做,百度搜索资源管理平台,全国建设信息网,html简易计算器代码我在之前的博客里并未提及过Tls的底层初始化,现在好好来谈谈。 首先我们要知道Tls的初始化是在入口之前。先从一开始的LdrInitializeThunk说起,在调用LdrPEStartup时,其在修复完导入表后,调用了一次LdrpInitializeTlsForProccess&…

彩票网站怎么做,百度搜索资源管理平台,全国建设信息网,html简易计算器代码我在之前的博客里并未提及过Tls的底层初始化,现在好好来谈谈。 首先我们要知道Tls的初始化是在入口之前。先从一开始的LdrInitializeThunk说起,在调用LdrPEStartup时,其在修复完导入表后,调用了一次LdrpInitializeTlsForProccess&…

我在之前的博客里并未提及过Tls的底层初始化,现在好好来谈谈。
首先我们要知道Tls的初始化是在入口之前。先从一开始的LdrInitializeThunk说起,在调用LdrPEStartup时,其在修复完导入表后,调用了一次LdrpInitializeTlsForProccess,我们看看他是怎样处理的。

static NTSTATUS
LdrpInitializeTlsForProccess(VOID)
{PLIST_ENTRY ModuleListHead;PLIST_ENTRY Entry;PLDR_DATA_TABLE_ENTRY Module;PIMAGE_TLS_DIRECTORY TlsDirectory;PTLS_DATA TlsData;ULONG Size;DPRINT("LdrpInitializeTlsForProccess() called for %wZn", &ExeModule->BaseDllName);if (LdrpTlsCount > 0){LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),0,LdrpTlsCount * sizeof(TLS_DATA));//分配了一个容纳所有Tls变量的空间,基于线程if (LdrpTlsArray == NULL){DPRINT1("Failed to allocate global tls data\n");return STATUS_NO_MEMORY;}ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;Entry = ModuleListHead->Flink;while (Entry != ModuleListHead)//以装载顺序遍历{Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);if (Module->LoadCount == LDRP_PROCESS_CREATION_TIME &&Module->TlsIndex != 0xFFFF){TlsDirectory = (PIMAGE_TLS_DIRECTORY)//获得TLS目录表RtlImageDirectoryEntryToData(Module->DllBase,TRUE,IMAGE_DIRECTORY_ENTRY_TLS,&Size);ASSERT(Module->TlsIndex < LdrpTlsCount);TlsData = &LdrpTlsArray[Module->TlsIndex];//TlsData存放的是记录着该模块Tls信息的指针,其index在TlsIndex里TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;//对该模块的信息进行填充TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;if (TlsDirectory->AddressOfCallBacks)//如果存在TLS回调函数TlsData->TlsAddressOfCallBacks = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks;//放入到其中,TlsAddressOfCallBacks数组是函数指针数组elseTlsData->TlsAddressOfCallBacks = NULL;TlsData->Module = Module;
#if 0DbgPrint("TLS directory for %wZn", &Module->BaseDllName);DbgPrint("StartAddressOfRawData: %xn", TlsDirectory->StartAddressOfRawData);DbgPrint("EndAddressOfRawData:   %xn", TlsDirectory->EndAddressOfRawData);DbgPrint("SizeOfRawData:         %dn", TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData);DbgPrint("AddressOfIndex:        %xn", TlsDirectory->AddressOfIndex);DbgPrint("AddressOfCallBacks:    %xn", TlsDirectory->AddressOfCallBacks);DbgPrint("SizeOfZeroFill:        %dn", TlsDirectory->SizeOfZeroFill);DbgPrint("Characteristics:       %xn", TlsDirectory->Characteristics);
#endif/** FIXME:*   Is this region allways writable ?*/*(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex;}Entry = Entry->Flink;}}DPRINT("LdrpInitializeTlsForProccess() donen");return STATUS_SUCCESS;
}/*
以加载模块的顺序,读取TLS目录,将信息填入到LdrpTlsArray[Module->TlsIndex]指定的索引结构中,其中Module中的索引值起到决定作用,之后内核就可以使用LdrpTlsArray和index来使用TLS
*/

以加载模块的顺序,读取TLS目录,将信息填入到LdrpTlsArray[Module->TlsIndex]指定的索引结构中,其中Module中的索引值起到决定作用,之后内核就可以使用LdrpTlsArray和index来使用TLS。这里就是为内核操作TLS提供了保障,TLS信息被收录到LdrpTlsArray中。

再来看下LdrpAttachThread(),这个是在LdrInitializeThunk中最后被使用的。

NTSTATUS
LdrpAttachThread (VOID)
{PLIST_ENTRY ModuleListHead;PLIST_ENTRY Entry;PLDR_DATA_TABLE_ENTRY Module;NTSTATUS Status;DPRINT("LdrpAttachThread() called for %wZn",&ExeModule->BaseDllName);RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);//加锁Status = LdrpInitializeTlsForThread();//下发到LdrpInitializeTlsForThreadif (NT_SUCCESS(Status)){ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;Entry = ModuleListHead->Flink;while (Entry != ModuleListHead)//以初始化顺序遍历模块{Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&!(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&!(Module->Flags & LDRP_UNLOAD_IN_PROGRESS)){//若DLL_PROCESS_ATTACH被调用了,现在轮到DLL_THREAD_ATTACHTRACE_LDR("%wZ - Calling entry point at %x for thread attachingn",&Module->BaseDllName, Module->EntryPoint);LdrpCallDllEntry(Module, DLL_THREAD_ATTACH, NULL);}Entry = Entry->Flink;}Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);LdrpTlsCallback(Module, DLL_THREAD_ATTACH);}RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);DPRINT("LdrpAttachThread() donen");return Status;
}
/*
LdrpInitializeTlsForThread
LdrpCallDllEntry
LdrpTlsCallback
*/

LdrpAttachThread->LdrpInitializeTlsForThread->LdrpCallDllEntry->LdrpTlsCallback
它将初始化工作交给LdrpInitializeTlsForThread,然后发出dwReason == DLL_THREAD_ATTACH,调用线程的TLS初始化,再来看下LdrpInitializeTlsForThread

static NTSTATUS
LdrpInitializeTlsForThread(VOID)
{PVOID* TlsPointers;PTLS_DATA TlsInfo;PVOID TlsData;ULONG i;PTEB Teb = NtCurrentTeb();DPRINT("LdrpInitializeTlsForThread() called for %wZn", &ExeModule->BaseDllName);Teb->StaticUnicodeString.Length = 0;Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;if (LdrpTlsCount > 0)//若存在线程局部变量{TlsPointers = RtlAllocateHeap(RtlGetProcessHeap(),0,LdrpTlsCount * sizeof(PVOID) + LdrpTlsSize);if (TlsPointers == NULL){DPRINT1("failed to allocate thread tls datan");return STATUS_NO_MEMORY;}TlsData = (PVOID)((ULONG_PTR)TlsPointers + LdrpTlsCount * sizeof(PVOID));//移到离边界还有LdrpTlsSize处Teb->ThreadLocalStoragePointer = TlsPointers;TlsInfo = LdrpTlsArray;//将之前的array赋值给TlsInfo array存放的是指针数组,指向的是每一个模块的目录信息for (i = 0; i < LdrpTlsCount; i++, TlsInfo++)//将对应的每一个模块的TLS目录指定的StartAddressOfRawData开始处的大小为TlsDataSize的数据拷贝到ThreadLocalStoragePointer处{TRACE_LDR("Initialize tls data for %wZn", &TlsInfo->Module->BaseDllName);TlsPointers[i] = TlsData;if (TlsInfo->TlsDataSize){memcpy(TlsData, TlsInfo->StartAddressOfRawData, TlsInfo->TlsDataSize);TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsDataSize);}if (TlsInfo->TlsZeroSize){memset(TlsData, 0, TlsInfo->TlsZeroSize);TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsZeroSize);}}}DPRINT("LdrpInitializeTlsForThread() donen");return STATUS_SUCCESS;
}

真正装载ThreadLocalStoragePointer的是由LdrpInitializeTlsForThread来执行的,可以认为LdrpInitializeTlsForProccess是对LdrpInitializeTlsForThread的初始化,它只是对所有模块TLS目录表的提取。而LdrpInitializeTlsForThread则是对LdrpTlsArray的内容的提取。所以之后只需要NtCurrentTeb()->ThreadLocalStoragePointer来完成Tls变量的存取工作就可以了。

紧接着看下LdrpInitializeTlsForThread初始化ThreadLocalStoragePointer之后LdrpCallDllEntry又干了啥吧

static BOOLEAN LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module, DWORD dwReason, PVOID lpReserved)
{if (!(Module->Flags & LDRP_IMAGE_DLL) ||//如果不是DLL映像,则退出Module->EntryPoint == 0){return TRUE;}LdrpTlsCallback(Module, dwReason);//线程回调函数return  ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->DllBase, dwReason, lpReserved);//对DLL映像发送DLL_THREAD_ATTACH消息
}

这里是专门针对DLL的,用来发送给DLL运行当DLL被线程附加的时候所进行的必要初始化,不过再这之前会调用TLS的回调函数。并且在LdrpAttachThread也调用了LdrpTlsCallback函数,有必要揭晓最后的秘密了。

static __inline VOID LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module, ULONG dwReason)
{PIMAGE_TLS_CALLBACK *TlsCallback;if (Module->TlsIndex != 0xFFFF && Module->LoadCount == LDRP_PROCESS_CREATION_TIME)//若存在TLS变量{TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;//获取该模块相应的回调函数的指针数组if (TlsCallback)//如果该回调有效{while (*TlsCallback)//依次调用所有的回调函数{TRACE_LDR("%wZ - Calling tls callback at %xn",&Module->BaseDllName, *TlsCallback);(*TlsCallback)(Module->DllBase, dwReason, NULL);//调用该回调函数TlsCallback++;}}}
}

这里就很简单了,首先获取TlsCallback的函数指针数组,然后依次调用它们。到此,TLS就分析完了,相比于之前,这次可以是相对简单,只要耐心分析源码,有很大收获