Skip to content

Commit 929efe8

Browse files
committed
Update the shadow section after relocating
1 parent d36d3a6 commit 929efe8

File tree

4 files changed

+93
-72
lines changed

4 files changed

+93
-72
lines changed

ReflectivePolymorphism/ReflectivePolymorphism.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ typedef struct {
55
WORD type : 4;
66
} IMAGE_RELOC, *PIMAGE_RELOC;
77

8+
DWORD ImageSizeFromHeaders(PDOS_HEADER pDosHeader) {
9+
// Calculate the size of of a PE image from the specified DOS headers.
10+
//
11+
// PDOS_HEADER pDosHeader: The headers to use for the calculation.
12+
// Returns: The size of the PE image.
13+
PIMAGE_NT_HEADERS pImgNtHeaders = NULL;
14+
PIMAGE_SECTION_HEADER pImgSecHeader = NULL;
15+
PIMAGE_SECTION_HEADER pImgSecHeaderLastRaw = NULL;
16+
PIMAGE_SECTION_HEADER pImgSecHeaderCursor = NULL;
17+
DWORD dwCursor = 0;
18+
19+
pImgNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
20+
pImgSecHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pImgNtHeaders + sizeof(IMAGE_NT_HEADERS));
21+
pImgSecHeaderLastRaw = pImgSecHeader;
22+
for (dwCursor = 0; dwCursor < pImgNtHeaders->FileHeader.NumberOfSections; dwCursor++) {
23+
pImgSecHeaderCursor = &pImgSecHeader[dwCursor];
24+
if (pImgSecHeaderLastRaw->PointerToRawData < pImgSecHeaderCursor->PointerToRawData) {
25+
pImgSecHeaderLastRaw = pImgSecHeaderCursor;
26+
}
27+
}
28+
return (pImgSecHeaderLastRaw->PointerToRawData + pImgSecHeaderLastRaw->SizeOfRawData);
29+
}
30+
831
BOOL RebaseImage(PDOS_HEADER pDosHeader, ULONG_PTR uiBaseFrom, ULONG_PTR uiBaseTo) {
932
// Rebase the specified PE image by processing the relocation data as
1033
// necessary.
@@ -60,6 +83,61 @@ BOOL RebaseImage(PDOS_HEADER pDosHeader, ULONG_PTR uiBaseFrom, ULONG_PTR uiBaseT
6083
return TRUE;
6184
}
6285

86+
BOOL ShadowSectionCopy(PDOS_HEADER pDosHeader, BOOL bCopyTo) {
87+
// Copy data to or from the shadow section. Copying data from the shadow
88+
// section effectively restores content from the backup. Copying data to the
89+
// shadow section effectively updates backup content.
90+
//
91+
// PDOS_HEADER pDosHeader: Pointer to the DOS header of the blob to patch.
92+
// Returns: TRUE on success.
93+
PIMAGE_SECTION_HEADER pImgSecHeaderCopy = NULL;
94+
PIMAGE_SECTION_HEADER pImgSecHeaderCursor = NULL;
95+
PIMAGE_SECTION_HEADER pImgSecHeader1 = NULL;
96+
PIMAGE_SECTION_HEADER pImgSecHeader2 = NULL;
97+
DWORD dwImageSize = 0;
98+
99+
pImgSecHeaderCopy = SectionHeaderFromName(pDosHeader, SHADOW_SECTION_NAME);
100+
if (!pImgSecHeaderCopy) {
101+
return FALSE;
102+
}
103+
if (!pImgSecHeaderCopy->SizeOfRawData) {
104+
return FALSE;
105+
}
106+
107+
dwImageSize = ImageSizeFromHeaders(pDosHeader);
108+
pImgSecHeaderCursor = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pDosHeader + pImgSecHeaderCopy->PointerToRawData);
109+
while (memcmp(pImgSecHeaderCursor->Name, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) {
110+
pImgSecHeader2 = pImgSecHeaderCursor;
111+
pImgSecHeaderCursor += 1;
112+
113+
if (!pImgSecHeader2->SizeOfRawData) {
114+
continue;
115+
}
116+
pImgSecHeader1 = SectionHeaderFromName(pDosHeader, pImgSecHeader2->Name);
117+
if (!pImgSecHeader1) {
118+
return FALSE;
119+
}
120+
if (pImgSecHeader1->SizeOfRawData != pImgSecHeader2->SizeOfRawData) {
121+
return FALSE;
122+
}
123+
if (dwImageSize < (pImgSecHeaderCursor->PointerToRawData + pImgSecHeaderCursor->SizeOfRawData)) {
124+
return FALSE;
125+
}
126+
if (bCopyTo) {
127+
// swap the pointers if we're copying to the shadow section
128+
(ULONG_PTR)pImgSecHeader1 ^= (ULONG_PTR)pImgSecHeader2;
129+
(ULONG_PTR)pImgSecHeader2 ^= (ULONG_PTR)pImgSecHeader1;
130+
(ULONG_PTR)pImgSecHeader1 ^= (ULONG_PTR)pImgSecHeader2;
131+
}
132+
CopyMemory(
133+
(PVOID)((ULONG_PTR)pDosHeader + pImgSecHeader1->PointerToRawData),
134+
(PVOID)((ULONG_PTR)pDosHeader + pImgSecHeader2->PointerToRawData),
135+
pImgSecHeader1->SizeOfRawData
136+
);
137+
}
138+
return TRUE;
139+
}
140+
63141
PIMAGE_SECTION_HEADER SectionHeaderFromRVA(PDOS_HEADER pDosHeader, ULONG_PTR pVirtualAddress) {
64142
// Retrieve the section header for the specified Relative Virtual Address
65143
// (RVA).

ReflectivePolymorphism/ReflectivePolymorphism.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#define IMAGE_BASE_EXE 0x400000
4747
#endif
4848

49+
#define SHADOW_SECTION_NAME ".restore"
50+
4951
typedef struct {
5052
// short is 2 bytes, long is 4 bytes
5153
WORD signature;
@@ -69,8 +71,14 @@ typedef struct {
6971
DWORD e_lfanew;
7072
} DOS_HEADER, *PDOS_HEADER;
7173

74+
DWORD ImageSizeFromHeaders(PDOS_HEADER pDosHeader);
7275
BOOL RebaseImage(PDOS_HEADER pDosHeader, ULONG_PTR uiBaseFrom, ULONG_PTR uiBaseTo);
7376

77+
// Shadow section functions
78+
BOOL ShadowSectionCopy(PDOS_HEADER pDosHeader, BOOL bCopyTo);
79+
#define ShadowSectionRestore(pDosHeader) ShadowSectionCopy(pDosHeader, FALSE)
80+
#define ShadowSectionUpdate(pDosHeader) ShadowSectionCopy(pDosHeader, TRUE)
81+
7482
// Section Header retrieval functions
7583
PIMAGE_SECTION_HEADER SectionHeaderFromName(PDOS_HEADER pDosHeader, PVOID pName);
7684
PIMAGE_SECTION_HEADER SectionHeaderFromRVA(PDOS_HEADER pDosHeader, ULONG_PTR pVirtualAddress);

ReflectivePolymorphism/ReflectiveTransformer.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ BOOL ReflectiveTransformerToDLL(PDOS_HEADER pDosHeader, DWORD dwAddressOfEntryPo
6969
return FALSE;
7070
}
7171

72-
RebaseImage(pDosHeader, (ULONG_PTR)(pImgNtHeaders->OptionalHeader.ImageBase), IMAGE_BASE_DLL);
72+
if (RebaseImage(pDosHeader, (ULONG_PTR)(pImgNtHeaders->OptionalHeader.ImageBase), IMAGE_BASE_DLL)) {
73+
ShadowSectionUpdate(pDosHeader);
74+
}
7375

7476
pImgNtHeaders->FileHeader.Characteristics |= IMAGE_FILE_DLL;
7577
pImgNtHeaders->FileHeader.Characteristics |= IMAGE_FILE_EXECUTABLE_IMAGE;
@@ -94,7 +96,9 @@ BOOL ReflectiveTransformerToEXE(PDOS_HEADER pDosHeader, DWORD dwAddressOfEntryPo
9496
return FALSE;
9597
}
9698

97-
RebaseImage(pDosHeader, (ULONG_PTR)(pImgNtHeaders->OptionalHeader.ImageBase), IMAGE_BASE_EXE);
99+
if (RebaseImage(pDosHeader, (ULONG_PTR)(pImgNtHeaders->OptionalHeader.ImageBase), IMAGE_BASE_EXE)) {
100+
ShadowSectionUpdate(pDosHeader);
101+
}
98102

99103
pImgNtHeaders->FileHeader.Characteristics &= ~IMAGE_FILE_DLL;
100104
pImgNtHeaders->FileHeader.Characteristics |= IMAGE_FILE_EXECUTABLE_IMAGE;

ReflectivePolymorphism/ReflectiveUnloader.c

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,5 @@
11
#include "ReflectiveUnloader.h"
22

3-
static DWORD ImageSizeFromHeaders(PDOS_HEADER pDosHeader) {
4-
PIMAGE_NT_HEADERS pImgNtHeaders = NULL;
5-
PIMAGE_SECTION_HEADER pImgSecHeader = NULL;
6-
PIMAGE_SECTION_HEADER pImgSecHeaderLastRaw = NULL;
7-
PIMAGE_SECTION_HEADER pImgSecHeaderCursor = NULL;
8-
DWORD dwCursor = 0;
9-
10-
pImgNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
11-
pImgSecHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pImgNtHeaders + sizeof(IMAGE_NT_HEADERS));
12-
pImgSecHeaderLastRaw = pImgSecHeader;
13-
for (dwCursor = 0; dwCursor < pImgNtHeaders->FileHeader.NumberOfSections; dwCursor++) {
14-
pImgSecHeaderCursor = &pImgSecHeader[dwCursor];
15-
if (pImgSecHeaderLastRaw->PointerToRawData < pImgSecHeaderCursor->PointerToRawData) {
16-
pImgSecHeaderLastRaw = pImgSecHeaderCursor;
17-
}
18-
}
19-
return (pImgSecHeaderLastRaw->PointerToRawData + pImgSecHeaderLastRaw->SizeOfRawData);
20-
}
21-
223
static BOOL ReflectiveUnloaderUnimport(PDOS_HEADER pDosHeader) {
234
// PDOS_HEADER pDosHeader: Pointer to the DOS header of the blob to patch.
245
// Returns: TRUE on success.
@@ -64,56 +45,6 @@ static BOOL ReflectiveUnloaderUnrelocate(PDOS_HEADER pDosHeader, ULONG_PTR pBase
6445
return RebaseImage(pDosHeader, pBaseAddress, (ULONG_PTR)(pImgNtHeaders->OptionalHeader.ImageBase));
6546
}
6647

67-
static BOOL ReflectiveUnloaderRestoreWritable(PDOS_HEADER pDosHeader) {
68-
// Restore the sections that were backed up in the ".restore" section if it
69-
// is present. If the ".restore" section is not present, this function will
70-
// return FALSE and the resulting PE image will probably be corrupted due to
71-
// changes made to writeable sections persisting in the unloaded copy.
72-
//
73-
// PDOS_HEADER pDosHeader: Pointer to the DOS header of the blob to patch.
74-
// Returns: TRUE on success.
75-
PIMAGE_SECTION_HEADER pImgSecHeaderCopy = NULL;
76-
PIMAGE_SECTION_HEADER pImgSecHeaderCursor = NULL;
77-
PIMAGE_SECTION_HEADER pImgSecHeaderDst = NULL;
78-
PIMAGE_SECTION_HEADER pImgSecHeaderSrc = NULL;
79-
DWORD dwImageSize = 0;
80-
81-
pImgSecHeaderCopy = SectionHeaderFromName(pDosHeader, ".restore");
82-
if (!pImgSecHeaderCopy) {
83-
return FALSE;
84-
}
85-
if (!pImgSecHeaderCopy->SizeOfRawData) {
86-
return FALSE;
87-
}
88-
89-
dwImageSize = ImageSizeFromHeaders(pDosHeader);
90-
pImgSecHeaderCursor = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pDosHeader + pImgSecHeaderCopy->PointerToRawData);
91-
while (memcmp(pImgSecHeaderCursor->Name, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) {
92-
pImgSecHeaderSrc = pImgSecHeaderCursor;
93-
pImgSecHeaderCursor += 1;
94-
95-
if (!pImgSecHeaderSrc->SizeOfRawData) {
96-
continue;
97-
}
98-
pImgSecHeaderDst = SectionHeaderFromName(pDosHeader, pImgSecHeaderSrc->Name);
99-
if (!pImgSecHeaderDst) {
100-
return FALSE;
101-
}
102-
if (pImgSecHeaderDst->SizeOfRawData != pImgSecHeaderSrc->SizeOfRawData) {
103-
return FALSE;
104-
}
105-
if (dwImageSize < (pImgSecHeaderCursor->PointerToRawData + pImgSecHeaderCursor->SizeOfRawData)) {
106-
return FALSE;
107-
}
108-
CopyMemory(
109-
(PVOID)((ULONG_PTR)pDosHeader + pImgSecHeaderDst->PointerToRawData),
110-
(PVOID)((ULONG_PTR)pDosHeader + pImgSecHeaderSrc->PointerToRawData),
111-
pImgSecHeaderDst->SizeOfRawData
112-
);
113-
}
114-
return TRUE;
115-
}
116-
11748
VOID ReflectiveUnloaderFree(PVOID pAddress, SIZE_T dwSize) {
11849
// Free memory that was previously allocated by ReflectiveUnloader().
11950
//
@@ -198,7 +129,7 @@ PVOID ReflectiveUnloader(HINSTANCE hInstance, PSIZE_T pdwSize) {
198129
ReflectiveUnloaderUnrelocate(pDosHeader, pBaseAddress);
199130
ReflectiveUnloaderUnimport(pDosHeader);
200131
// This step is optional
201-
ReflectiveUnloaderRestoreWritable(pDosHeader);
132+
ShadowSectionRestore(pDosHeader);
202133

203134
if (pdwSize) {
204135
*pdwSize = dwImageSize;

0 commit comments

Comments
 (0)