-
Notifications
You must be signed in to change notification settings - Fork 2
/
bootstrapper.c
134 lines (108 loc) · 5.26 KB
/
bootstrapper.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "dll_injector.h"
void start_of_injectable_code() {
}
// Adjusts and realigns the PE file within the target process memory
void realign_pe(LDLL_INFO dll_info) {
PIMAGE_DOS_HEADER dos_header = NULL;
PIMAGE_NT_HEADERS nt = NULL;
LPVOID base = NULL;
PIMAGE_IMPORT_DESCRIPTOR import = NULL;
PIMAGE_THUNK_DATA original_thunk = NULL;
PIMAGE_THUNK_DATA first_thunk = NULL;
PIMAGE_BASE_RELOCATION relocation_block = NULL;
PIMAGE_TLS_DIRECTORY tls = NULL;
PIMAGE_TLS_CALLBACK *callback = NULL;
// function pointers for dynamic loading
BOOL (*dll_entry)(LPVOID, DWORD, LPVOID);
LPVOID (*load_dll)(LPSTR);
LPVOID (*get_proc)(LPVOID, LPSTR);
// set base addresses and function pointers from DLL_INFO struct
base = dll_info->base; // base address of the DLL in the target process
load_dll = dll_info->load_library_a_addr; // pointer to LoadLibraryA in the target process
get_proc = dll_info->get_process_addr; // pointer to GetProcAddress in the target process
// access the PE headers of the DLL in the target process
dos_header = (PIMAGE_DOS_HEADER)base;
nt = (PIMAGE_NT_HEADERS)(base + dos_header->e_lfanew);
// address of the DLL's entry point
dll_entry = base + nt->OptionalHeader.AddressOfEntryPoint;
// check if base relocation is required (happens if the DLL is loaded at a different address than its preferred one)
if (!dll_info->base_relocation_required) {
goto load_import;
}
// Base Relocation: Adjust addresses in the relocation table
base_relocation:
// check if relocation table exists
if (nt->OptionalHeader.DataDirectory[5].VirtualAddress == 0) {
// no relocation table found
goto load_import;
}
ULONGLONG *relocation_address = NULL;
// calculate the difference between the preferred and actual base addresses
ULONGLONG base_addr_delta = (ULONGLONG)base - nt->OptionalHeader.ImageBase;
relocation_block = (PIMAGE_BASE_RELOCATION)(base + nt->OptionalHeader.DataDirectory[5].VirtualAddress);
// iterate over the relocation table and adjust addresses
while (relocation_block->VirtualAddress) {
LPVOID relocation_target = base + relocation_block->VirtualAddress;
int nEntry = (relocation_block->SizeOfBlock - sizeof(PIMAGE_BASE_RELOCATION)) / 2;
PWORD data = (PWORD)((LPVOID)relocation_block + sizeof(PIMAGE_BASE_RELOCATION));
int i;
for (i = 0; i < nEntry; i++, data++) {
if ((*data) >> 12 == 10) { // type 10 indicates a 64-bit address
relocation_address = (PULONGLONG)(relocation_target + ((*data) &0xfff)); // address to be relocated
*relocation_address += base_addr_delta; // do the relocation
}
}
relocation_block = (PIMAGE_BASE_RELOCATION)((LPVOID)relocation_block + relocation_block->SizeOfBlock);
}
// Load imports: Adjust pointers to imported functions
load_import:
// check if import table exists
if (nt->OptionalHeader.DataDirectory[1].VirtualAddress == 0) {
goto tls_callback;
}
// iterate over the import table and resolve addresses
import = (PIMAGE_IMPORT_DESCRIPTOR)(base + nt->OptionalHeader.DataDirectory[1].VirtualAddress);
while (import->Name) {
LPVOID dll = (*load_dll)(base + import->Name);
original_thunk = (PIMAGE_THUNK_DATA)(base + import->OriginalFirstThunk);
first_thunk = (PIMAGE_THUNK_DATA)(base + import->FirstThunk);
if (!import->OriginalFirstThunk) {
original_thunk = first_thunk;
}
while(original_thunk->u1.AddressOfData) {
if (original_thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) {
// import by ordinal
*(ULONGLONG *)first_thunk = (ULONGLONG)(*get_proc)(dll, (LPSTR)IMAGE_ORDINAL(original_thunk->u1.Ordinal));
} else {
// import by name
PIMAGE_IMPORT_BY_NAME fnm = (PIMAGE_IMPORT_BY_NAME)(base + original_thunk->u1.AddressOfData);
*(PULONGLONG)first_thunk = (ULONGLONG)(*get_proc)(dll, fnm->Name);
}
original_thunk++;
first_thunk++;
}
import++;
}
// TLS Callbacks: Call TLS (Thread Local Storage) callbacks if any
tls_callback:
if(nt->OptionalHeader.DataDirectory[9].VirtualAddress == 0) {
goto execute_entry_point;
}
tls = (PIMAGE_TLS_DIRECTORY)(base + nt->OptionalHeader.DataDirectory[9].VirtualAddress);
if (tls->AddressOfCallBacks == 0) {
goto execute_entry_point;
}
callback = (PIMAGE_TLS_CALLBACK *)(tls->AddressOfCallBacks);
while(*callback) {
(*callback)(base, DLL_PROCESS_ATTACH, NULL); // call the TLS callback
callback++;
}
// Execute Entry Point: Call the DLL's entry
execute_entry_point:
(*dll_entry)(base, DLL_PROCESS_ATTACH, NULL);
}
void end_of_injectable_code() {
}