libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
tls_parser.cpp
Go to the documentation of this file.
1#include "peconv/tls_parser.h"
2
4#include "peconv/logger.h"
5#include "peconv/relocate.h"
6
7namespace peconv {
8
9 template <typename FIELD_T>
10 size_t fetch_callbacks_list(IN PVOID modulePtr, IN size_t moduleSize, IN DWORD callbacks_rva, OUT std::vector<ULONGLONG> &tls_callbacks)
11 {
12 FIELD_T* callbacks_list_ptr = (FIELD_T*)(callbacks_rva + (BYTE*)modulePtr);
13 if (!validate_ptr(modulePtr, moduleSize, callbacks_list_ptr, sizeof(FIELD_T))) {
14 return 0;
15 }
16 size_t counter = 0;
17 for (FIELD_T *next_callback = callbacks_list_ptr;
18 validate_ptr(modulePtr, moduleSize, next_callback, sizeof(FIELD_T));
19 next_callback++)
20 {
21 FIELD_T value = *next_callback;
22 if (value == 0) break;
23
24 tls_callbacks.push_back(value);
25 counter++;
26 }
27 return counter;
28 }
29
30 template <typename T_IMAGE_TLS_DIRECTORY, typename T_FIELD>
31 size_t _list_tls_callbacks(IN PBYTE modulePtr, IN size_t moduleSize, OUT std::vector<ULONGLONG>& tls_callbacks, IN std::unordered_set<ULONGLONG>* _relocs)
32 {
33 T_IMAGE_TLS_DIRECTORY* tls_dir = peconv::get_type_directory<T_IMAGE_TLS_DIRECTORY>((HMODULE)modulePtr, IMAGE_DIRECTORY_ENTRY_TLS);
34 if (!tls_dir) return 0;
35
36 ULONGLONG callbacks_addr = tls_dir->AddressOfCallBacks;
37 if (!callbacks_addr) return 0;
38 LOG_DEBUG("TLS Callbacks Table: 0x%llx.", (unsigned long long)callbacks_addr);
39 DWORD callbacks_rva = 0;
40 if (!virtual_addr_to_rva((PBYTE)modulePtr, moduleSize, callbacks_addr, callbacks_rva, _relocs)) {
41 return 0;
42 }
43 LOG_DEBUG("TLS Callbacks RVA: 0x%llx.", (unsigned long long)callbacks_rva);
44 return fetch_callbacks_list<T_FIELD>(modulePtr, moduleSize, callbacks_rva, tls_callbacks);
45 }
46};
47
48size_t peconv::list_tls_callbacks(IN PBYTE modulePtr, IN size_t moduleSize, OUT std::vector<ULONGLONG> &tls_callbacks, IN std::unordered_set<ULONGLONG>* _relocs)
49{
50 const DWORD img_size = peconv::get_image_size((BYTE*)modulePtr);
51 if (!img_size) return 0; // invalid image
52
53 if (moduleSize == 0) {
54 moduleSize = img_size;
55 }
56 size_t counter = 0;
57 if (peconv::is64bit((BYTE*)modulePtr)) {
58 counter = _list_tls_callbacks<IMAGE_TLS_DIRECTORY64, ULONGLONG>(modulePtr, moduleSize, tls_callbacks, _relocs);
59 }
60 else {
61 counter = _list_tls_callbacks<IMAGE_TLS_DIRECTORY32, DWORD>(modulePtr, moduleSize, tls_callbacks, _relocs);
62 }
63 return counter;
64}
65
66size_t peconv::run_tls_callbacks(IN PBYTE modulePtr, IN size_t moduleSize, IN DWORD dwReason)
67{
68 const DWORD img_size = peconv::get_image_size((BYTE*)modulePtr);
69 if (moduleSize == 0) {
70 moduleSize = img_size;
71 }
72 // Collect relocations for VA detection
73 std::unordered_set<ULONGLONG> reloc_values;
74 CollectRelocs callback(modulePtr, moduleSize, peconv::is64bit(modulePtr), reloc_values);
75 process_relocation_table(modulePtr, moduleSize, &callback);
76
77 std::vector<ULONGLONG> tls_callbacks;
78 if (!peconv::list_tls_callbacks(modulePtr, moduleSize, tls_callbacks, &reloc_values)) {
79 return 0;
80 }
81
82 std::vector<ULONGLONG>::iterator itr;
83 size_t i = 0;
84 for (itr = tls_callbacks.begin(); itr != tls_callbacks.end(); ++itr, i++) {
85 ULONGLONG callback_addr = *itr;
86 DWORD rva = 0; //TLS callback can be defined as RVA or VA, so make sure it is in a consistent format...
87 if (!peconv::virtual_addr_to_rva((PBYTE)modulePtr, img_size, callback_addr, rva, &reloc_values)) {
88 // in some cases, TLS callbacks can lead to functions in other modules: we want to skip those,
89 // keeping only addresses that are in the current PE scope
90 continue;
91 }
92 LOG_DEBUG("TLS RVA: 0x%llx.", (unsigned long long)rva);
93 ULONG_PTR callback_va = rva + (ULONG_PTR)modulePtr;
94 if (!validate_ptr(modulePtr, moduleSize, (BYTE*)callback_va, sizeof(BYTE))) {
95 // make sure that the address is valid
96 continue;
97 }
98 void(NTAPI *callback_func)(PVOID DllHandle, DWORD dwReason, PVOID) = (void(NTAPI *)(PVOID, DWORD, PVOID)) (callback_va);
99 LOG_INFO("Calling TLS callback[%zu].", i);
100 callback_func(modulePtr, dwReason, NULL);
101 }
102 return i;
103}
Compile-time configurable logging macros for peconv.
#define LOG_DEBUG(fmt,...)
Definition: logger.h:80
#define LOG_INFO(fmt,...)
Definition: logger.h:74
bool virtual_addr_to_rva(IN const PBYTE imgBase, IN const size_t imgSize, IN ULONGLONG virtualAddr, OUT DWORD &outRVA, IN std::unordered_set< ULONGLONG > *relocs=nullptr)
Definition: relocate.cpp:215
size_t list_tls_callbacks(IN PBYTE modulePtr, IN size_t moduleSize, OUT std::vector< ULONGLONG > &tls_callbacks, IN std::unordered_set< ULONGLONG > *relocs)
Definition: tls_parser.cpp:48
bool validate_ptr(IN const void *buffer_bgn, IN size_t buffer_size, IN const void *field_bgn, IN size_t field_size)
Definition: buffer_util.cpp:9
DWORD get_image_size(IN const BYTE *payload)
bool process_relocation_table(IN PVOID modulePtr, IN SIZE_T moduleSize, IN RelocBlockCallback *callback)
Definition: relocate.cpp:111
size_t fetch_callbacks_list(IN PVOID modulePtr, IN size_t moduleSize, IN DWORD callbacks_rva, OUT std::vector< ULONGLONG > &tls_callbacks)
Definition: tls_parser.cpp:10
bool is64bit(IN const BYTE *pe_buffer)
size_t _list_tls_callbacks(IN PBYTE modulePtr, IN size_t moduleSize, OUT std::vector< ULONGLONG > &tls_callbacks, IN std::unordered_set< ULONGLONG > *_relocs)
Definition: tls_parser.cpp:31
size_t run_tls_callbacks(IN PBYTE modulePtr, IN size_t moduleSize=0, IN DWORD dwReason=DLL_PROCESS_ATTACH)
Definition: tls_parser.cpp:66
Wrappers over various fields in the PE header. Read, write, parse PE headers.
Operating on PE file's relocations table.
Functions related to TLS Callbacks.