libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
peb_lookup.cpp
Go to the documentation of this file.
1#include "ntddk.h"
2#include <peconv/util.h>
3#include <peconv/peb_lookup.h>
4
6public:
7 SectionLocker(RTL_CRITICAL_SECTION &_section)
8 : section(_section)
9 {
10 RtlEnterCriticalSection(&section);
11 }
12
14 {
15 RtlLeaveCriticalSection(&section);
16 }
17
18protected:
19 RTL_CRITICAL_SECTION &section;
20};
21
22//here we don't want to use any functions imported form extenal modules
23namespace {
24 typedef struct _LDR_MODULE {
25 LIST_ENTRY InLoadOrderModuleList;// +0x00
26 LIST_ENTRY InMemoryOrderModuleList;// +0x08
27 LIST_ENTRY InInitializationOrderModuleList;// +0x10
28 void* BaseAddress; // +0x18
29 void* EntryPoint; // +0x1c
30 ULONG SizeOfImage;
31 UNICODE_STRING FullDllName;
32 UNICODE_STRING BaseDllName;
33 ULONG Flags;
34 SHORT LoadCount;
35 SHORT TlsIndex;
36 HANDLE SectionHandle;
37 ULONG CheckSum;
38 ULONG TimeDateStamp;
39 } LDR_MODULE, *PLDR_MODULE;
40
41 inline PPEB get_peb()
42 {
43#if defined(_M_AMD64)
44 return (PPEB)__readgsqword(0x60);
45#elif defined(_M_ARM64)
46 const PPEB peb = (PPEB)(*(__getReg(18) + 0x60));
47 return peb;
48#else
49 return (PPEB)__readfsdword(0x30);
50 /*
51 //alternative way to fetch it:
52 LPVOID PEB = NULL;
53 __asm {
54 mov eax, fs:[30h]
55 mov PEB, eax
56 };
57 return (PPEB)PEB;
58
59 or:
60 LPVOID PEB = RtlGetCurrentPeb();
61 */
62#endif
63 }
64
65 inline LPCWSTR find_string_end(LPCWSTR str)
66 {
67 if (!str) return nullptr;
68
69 LPCWSTR curr_end_ptr = str;
70 while (*curr_end_ptr != L'\0') {
71 curr_end_ptr++;
72 }
73 return curr_end_ptr;
74 }
75};
76
77bool is_wanted_module(LPCWSTR curr_name, LPCWSTR wanted_name)
78{
79 if (wanted_name == NULL || curr_name == NULL) return false;
80
81 LPCWSTR curr_end_ptr = find_string_end(curr_name);
82 if (curr_end_ptr == curr_name) return false;
83
84 LPCWSTR wanted_end_ptr = find_string_end(wanted_name);
85 if (wanted_end_ptr == wanted_name) return false;
86
87 // iterate from the last character towards the beginning
88 while (true) {
89 if (peconv::to_lowercase(*wanted_end_ptr) != peconv::to_lowercase(*curr_end_ptr)) {
90 return false;
91 }
92 // if any of the string reached its beginning:
93 if (wanted_end_ptr == wanted_name || curr_end_ptr == curr_name) {
94 break;
95 }
96 wanted_end_ptr--;
97 curr_end_ptr--;
98 }
99 // can be true only if the entire wanted_name was consumed
100 if (wanted_end_ptr == wanted_name) {
101 if (curr_end_ptr == curr_name) return true;
102 curr_end_ptr--;
103 if ((*curr_end_ptr) == L'\\' || (*curr_end_ptr) == L'/') return true;
104 }
105 return false;
106}
107
108HMODULE peconv::get_module_via_peb(IN OPTIONAL LPCWSTR module_name)
109{
110 const PPEB peb = get_peb();
111 if (!peb || !peb->Ldr || !peb->LoaderLock) {
112 return NULL;
113 }
114 SectionLocker locker(*peb->LoaderLock);
115
116 const PLIST_ENTRY list_head = &peb->Ldr->InLoadOrderModuleList;
117 PLDR_MODULE curr_module = (PLDR_MODULE)list_head->Flink;
118 if (!module_name) {
119 return (HMODULE)(curr_module->BaseAddress);
120 }
121
122 // it is a cyclic list, so if the next record links to the initial one, it means we went throught the full loop
123 do {
124 // this should also work as a terminator, because the BaseAddress of the last module in the cycle is NULL
125 if (curr_module == NULL || curr_module->BaseAddress == NULL) {
126 break;
127 }
128 if (is_wanted_module(curr_module->BaseDllName.Buffer, module_name)) {
129 return (HMODULE)(curr_module->BaseAddress);
130 }
131 curr_module = (PLDR_MODULE)curr_module->InLoadOrderModuleList.Flink;
132
133 } while ((PLIST_ENTRY)curr_module != list_head);
134
135 return NULL;
136}
137
138size_t peconv::get_module_size_via_peb(IN OPTIONAL HMODULE hModule)
139{
140 const PPEB peb = get_peb();
141 if (!peb || !peb->Ldr || !peb->LoaderLock) {
142 return 0;
143 }
144 SectionLocker locker(*peb->LoaderLock);
145 const PLIST_ENTRY list_head = &peb->Ldr->InLoadOrderModuleList;
146 PLDR_MODULE curr_module = (PLDR_MODULE)list_head->Flink;
147 if (!hModule) {
148 return (size_t)(curr_module->SizeOfImage);
149 }
150
151 // it is a cyclic list, so if the next record links to the initial one, it means we went throught the full loop
152 do {
153 // this should also work as a terminator, because the BaseAddress of the last module in the cycle is NULL
154 if (curr_module == NULL || curr_module->BaseAddress == NULL) {
155 break;
156 }
157 if (hModule == (HMODULE)(curr_module->BaseAddress)) {
158 return (size_t)(curr_module->SizeOfImage);
159 }
160 curr_module = (PLDR_MODULE)curr_module->InLoadOrderModuleList.Flink;
161
162 } while ((PLIST_ENTRY)curr_module != list_head);
163
164 return 0;
165}
166
167bool peconv::set_main_module_in_peb(HMODULE module_ptr)
168{
169 PPEB peb = get_peb();
170 if (peb == NULL) {
171 return false;
172 }
173 SectionLocker locker(*peb->FastPebLock);
174 peb->ImageBaseAddress = module_ptr;
175 return true;
176}
177
179{
180 PPEB peb = get_peb();
181 if (peb == NULL) {
182 return NULL;
183 }
184 SectionLocker locker(*peb->FastPebLock);
185 return (HMODULE) peb->ImageBaseAddress;
186}
SectionLocker(RTL_CRITICAL_SECTION &_section)
Definition: peb_lookup.cpp:7
RTL_CRITICAL_SECTION & section
Definition: peb_lookup.cpp:19
HMODULE get_main_module_via_peb()
Definition: peb_lookup.cpp:178
HMODULE get_module_via_peb(IN OPTIONAL LPCWSTR module_name=nullptr)
Definition: peb_lookup.cpp:108
bool set_main_module_in_peb(HMODULE hModule)
Definition: peb_lookup.cpp:167
CHAR_T to_lowercase(CHAR_T c1)
Definition: util.h:78
size_t get_module_size_via_peb(IN OPTIONAL HMODULE hModule=nullptr)
Definition: peb_lookup.cpp:138
bool is_wanted_module(LPCWSTR curr_name, LPCWSTR wanted_name)
Definition: peb_lookup.cpp:77
Functions for retrieving process information from PEB.
Miscellaneous utility functions.