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 <iostream>
5
6namespace peconv {
7
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
17 const ULONGLONG img_base = (ULONGLONG)modulePtr;
18 const DWORD img_size = peconv::get_image_size((BYTE*)modulePtr);
19 size_t counter = 0;
20 for (FIELD_T *next_callback = callbacks_list_ptr;
21 validate_ptr(modulePtr, moduleSize, next_callback, sizeof(FIELD_T));
22 next_callback++)
23 {
24 FIELD_T value = *next_callback;
25 if (value == 0) break;
26
27 tls_callbacks.push_back(value);
28 counter++;
29 }
30 return counter;
31 }
32};
33
34
35bool peconv::virtual_addr_to_rva(IN const ULONGLONG img_base, IN const DWORD img_size, IN ULONGLONG callback_addr, OUT DWORD &callback_rva)
36{
37 if (!img_size || !callback_addr) return false;
38
39 //check if VA:
40 if (callback_addr >= img_base && callback_addr < (img_base + img_size)) {
41 callback_rva = MASK_TO_DWORD(callback_addr - img_base);
42 return true;
43 }
44 if (callback_addr < img_size) {
45 callback_rva = MASK_TO_DWORD(callback_addr);
46 return true;
47 }
48 // out of scope address
49 return false;
50}
51
52size_t peconv::list_tls_callbacks(IN PVOID modulePtr, IN size_t moduleSize, OUT std::vector<ULONGLONG> &tls_callbacks)
53{
54 const ULONGLONG img_base = (ULONGLONG)modulePtr;
55 const DWORD img_size = peconv::get_image_size((BYTE*)modulePtr);
56 if (!img_size) return 0; // invalid image
57
58 if (moduleSize == 0) {
59 moduleSize = img_size;
60 }
61 IMAGE_TLS_DIRECTORY* tls_dir = peconv::get_type_directory<IMAGE_TLS_DIRECTORY>((HMODULE)modulePtr, IMAGE_DIRECTORY_ENTRY_TLS);
62 if (!tls_dir) return 0;
63
64 ULONGLONG callbacks_addr = tls_dir->AddressOfCallBacks;
65 if (!callbacks_addr) return 0;
66#ifdef _DEBUG
67 std::cout << "TLS Callbacks Table: " << std::hex << callbacks_addr << std::endl;
68#endif
69 DWORD callbacks_rva = 0;
70 if (!virtual_addr_to_rva(img_base, img_size, callbacks_addr, callbacks_rva)) return 0;
71#ifdef _DEBUG
72 std::cout << "TLS Callbacks RVA: " << std::hex << callbacks_rva << std::endl;
73#endif
74 size_t counter = 0;
75 if (peconv::is64bit((BYTE*)modulePtr)) {
76 counter = fetch_callbacks_list<ULONGLONG>(modulePtr, moduleSize, callbacks_rva, tls_callbacks);
77 }
78 else {
79 counter = fetch_callbacks_list<DWORD>(modulePtr, moduleSize, callbacks_rva, tls_callbacks);
80 }
81 return counter;
82}
83
84size_t peconv::run_tls_callbacks(IN PVOID modulePtr, IN size_t moduleSize, IN DWORD dwReason)
85{
86 const DWORD img_size = peconv::get_image_size((BYTE*)modulePtr);
87 if (moduleSize == 0) {
88 moduleSize = img_size;
89 }
90 std::vector<ULONGLONG> tls_callbacks;
91 if (!peconv::list_tls_callbacks(modulePtr, moduleSize, tls_callbacks)) {
92 return 0;
93 }
94 std::vector<ULONGLONG>::iterator itr;
95 size_t i = 0;
96 for (itr = tls_callbacks.begin(); itr != tls_callbacks.end(); ++itr, i++) {
97 ULONGLONG callback_addr = *itr;
98 DWORD rva = 0; //TLS callback can be defined as RVA or VA, so make sure it is in a consistent format...
99 if (!peconv::virtual_addr_to_rva((ULONG_PTR)modulePtr, img_size, callback_addr, rva)) {
100 // in some cases, TLS callbacks can lead to functions in other modules: we want to skip those,
101 // keeping only addresses that are in the current PE scope
102 continue;
103 }
104#ifdef _DEBUG
105 std::cout << std::hex << "TLS RVA:" << rva << std::endl;
106#endif
107 ULONG_PTR callback_va = rva + (ULONG_PTR)modulePtr;
108 if (!validate_ptr(modulePtr, moduleSize, (BYTE*)callback_va, sizeof(BYTE))) {
109 // make sure that the address is valid
110 continue;
111 }
112 void(NTAPI *callback_func)(PVOID DllHandle, DWORD dwReason, PVOID) = (void(NTAPI *)(PVOID, DWORD, PVOID)) (callback_va);
113#ifdef _DEBUG
114 std::cout << "Calling TLS callback[" << i << "]:" << std::endl;
115#endif
116 callback_func(modulePtr, dwReason, NULL);
117 }
118 return i;
119}
#define MASK_TO_DWORD(val)
Definition buffer_util.h:12
size_t run_tls_callbacks(IN PVOID modulePtr, IN size_t moduleSize=0, IN DWORD dwReason=DLL_PROCESS_ATTACH)
bool validate_ptr(IN const void *buffer_bgn, IN size_t buffer_size, IN const void *field_bgn, IN size_t field_size)
bool virtual_addr_to_rva(IN const ULONGLONG imgBase, IN const DWORD imgSize, IN ULONGLONG virtualAddr, OUT DWORD &outRVA)
IMAGE_TYPE_DIRECTORY * get_type_directory(IN HMODULE modulePtr, IN DWORD dir_id)
DWORD get_image_size(IN const BYTE *payload)
size_t fetch_callbacks_list(IN PVOID modulePtr, IN size_t moduleSize, IN DWORD callbacks_rva, OUT std::vector< ULONGLONG > &tls_callbacks)
bool is64bit(IN const BYTE *pe_buffer)
size_t list_tls_callbacks(IN PVOID modulePtr, IN size_t moduleSize, OUT std::vector< ULONGLONG > &tls_callbacks)
Wrappers over various fields in the PE header. Read, write, parse PE headers.
Functions related to TLS Callbacks.