-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathReflectiveUnloader.c
138 lines (123 loc) · 5.1 KB
/
ReflectiveUnloader.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
135
136
137
138
#include "ReflectiveUnloader.h"
static BOOL ReflectiveUnloaderUnimport(PDOS_HEADER pDosHeader) {
// PDOS_HEADER pDosHeader: Pointer to the DOS header of the blob to patch.
// Returns: TRUE on success.
PIMAGE_NT_HEADERS pImgNtHeaders = NULL;
PIMAGE_DATA_DIRECTORY pImgDataDirectory = NULL;
PIMAGE_IMPORT_DESCRIPTOR pImgImpDesc = NULL;
ULONG_PTR uiValueA;
ULONG_PTR uiValueD;
pImgNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
pImgDataDirectory = &pImgNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (!pImgDataDirectory->Size) {
return FALSE;
}
pImgImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)pDosHeader + PAFromRVA(pDosHeader, pImgDataDirectory->VirtualAddress));
while (pImgImpDesc->Name) {
uiValueD = VAFromRVA(pDosHeader, pImgImpDesc->OriginalFirstThunk);
uiValueA = VAFromRVA(pDosHeader, pImgImpDesc->FirstThunk);
while (DEREF(uiValueA) && DEREF(uiValueD)) {
DEREF(uiValueA) = DEREF(uiValueD);
uiValueA += sizeof(ULONG_PTR);
uiValueD += sizeof(ULONG_PTR);
}
pImgImpDesc += 1;
}
return TRUE;
}
static BOOL ReflectiveUnloaderUnrelocate(PDOS_HEADER pDosHeader, ULONG_PTR pBaseAddress) {
// PDOS_HEADER pDosHeader: Pointer to the DOS header of the blob to patch.
// ULONG_PTR pBaseAddress: Pointer to the original loaded PE blob.
// Returns: TRUE on success.
PIMAGE_NT_HEADERS pImgNtHeaders = NULL;
PIMAGE_DATA_DIRECTORY pImgDataDirectory = NULL;
pImgNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
pImgDataDirectory = &pImgNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (!pImgDataDirectory->Size) {
return FALSE;
}
return RebaseImage(pDosHeader, pBaseAddress, (ULONG_PTR)(pImgNtHeaders->OptionalHeader.ImageBase));
}
VOID ReflectiveUnloaderFree(PVOID pAddress, SIZE_T dwSize) {
// Free memory that was previously allocated by ReflectiveUnloader().
//
// PVOID pAddress: Pointer to the blob returned by ReflectiveUnloader.
// SIZE_T dwSize: Size of the blob returned by ReflectiveUnloader.
SecureZeroMemory(pAddress, dwSize);
#ifdef DEBUG
VirtualFree(pAddress, dwSize, MEM_DECOMMIT | MEM_RELEASE);
#else
HeapFree(GetProcessHeap(), 0, pAddress);
#endif
return;
}
PVOID ReflectiveUnloader(HINSTANCE hInstance, PSIZE_T pdwSize) {
// Unload the module indicated by hInstance and return a pointer to it's
// location in memory. If this function fails, NULL is returned.
//
// HINSTANCE hInstance: Handle to the module instance to unload from memory.
// PSIZE_T pdwSize: The size of the returned PE image.
// Returns: A pointer to a blob of the unloaded PE image.
PDOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pImgNtHeaders = NULL;
PIMAGE_SECTION_HEADER pImgSecHeader = NULL;
PIMAGE_SECTION_HEADER pImgSecHeaderCursor = NULL;
ULONG_PTR pBaseAddress = 0;
SIZE_T dwImageSize = 0;
DWORD dwCursor = 0;
PVOID pCursor = NULL;
if (pdwSize) {
*pdwSize = 0;
}
pDosHeader = (PDOS_HEADER)hInstance;
if (DEREF_32(pDosHeader) != 0x00905a4d) {
return NULL;
}
pImgNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
if (pImgNtHeaders->Signature != 0x4550) {
return NULL;
}
dwImageSize = ImageSizeFromHeaders(pDosHeader);
#ifdef DEBUG
pBaseAddress = (ULONG_PTR)VirtualAlloc(NULL, dwImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
pBaseAddress = (ULONG_PTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwImageSize);
#endif
if (!pBaseAddress) {
return NULL;
}
CopyMemory((PVOID)pBaseAddress, (PVOID)pDosHeader, dwImageSize);
pCursor = pDosHeader;
pDosHeader = (PDOS_HEADER)pBaseAddress;
pBaseAddress = (ULONG_PTR)pCursor;
pImgNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
pImgSecHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pImgNtHeaders + sizeof(IMAGE_NT_HEADERS));
// 0x00400000 for EXEs and 0x10000000 for DLLs
// see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
if (pImgNtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) {
pImgNtHeaders->OptionalHeader.ImageBase = IMAGE_BASE_DLL;
}
else if (pImgNtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) {
pImgNtHeaders->OptionalHeader.ImageBase = IMAGE_BASE_EXE;
}
for (dwCursor = 0; dwCursor < pImgNtHeaders->FileHeader.NumberOfSections; dwCursor++) {
pImgSecHeaderCursor = &pImgSecHeader[dwCursor];
if (!pImgSecHeaderCursor->SizeOfRawData) {
continue;
}
pCursor = (PVOID)((ULONG_PTR)pDosHeader + pImgSecHeaderCursor->PointerToRawData);
if (dwImageSize < (pImgSecHeaderCursor->PointerToRawData + pImgSecHeaderCursor->SizeOfRawData)) {
ReflectiveUnloaderFree((PVOID)pDosHeader, dwImageSize);
return NULL;
}
CopyMemory(pCursor, (PVOID)(pBaseAddress + pImgSecHeaderCursor->VirtualAddress), pImgSecHeaderCursor->SizeOfRawData);
}
ReflectiveUnloaderUnrelocate(pDosHeader, pBaseAddress);
ReflectiveUnloaderUnimport(pDosHeader);
// This step is optional
ShadowSectionRestore(pDosHeader);
if (pdwSize) {
*pdwSize = dwImageSize;
}
return pDosHeader;
}