ProcessGhosting 0.1.0

Process Ghosting technique implementation - Execute PE files from memory without leaving traces on disk
Documentation
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
//! NT API Definitions and Types for ProcessGhosting Library
//! Author: BlackTechX

#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]

use winapi::shared::basetsd::{SIZE_T, PSIZE_T, ULONG_PTR};
use winapi::shared::minwindef::{BOOL, BYTE, DWORD, ULONG, USHORT, PULONG, LPVOID};
use winapi::shared::ntdef::{HANDLE, NTSTATUS, PVOID, LARGE_INTEGER, PLARGE_INTEGER, BOOLEAN};
use winapi::um::winnt::{ACCESS_MASK, PIMAGE_NT_HEADERS};

// ============================================================================
// Constants
// ============================================================================

pub const STATUS_SUCCESS: NTSTATUS = 0;
pub const STATUS_IMAGE_NOT_AT_BASE: NTSTATUS = 0x40000003;
pub const OBJ_CASE_INSENSITIVE: ULONG = 0x00000040;
pub const FILE_SUPERSEDED: ULONG = 0x00000000;
pub const FILE_SYNCHRONOUS_IO_NONALERT: ULONG = 0x00000020;
pub const RTL_USER_PROC_PARAMS_NORMALIZED: ULONG = 0x00000001;
pub const PS_INHERIT_HANDLES: ULONG = 4;
pub const RTL_MAX_DRIVE_LETTERS: usize = 32;

// ============================================================================
// Structures
// ============================================================================

#[repr(C)]
#[derive(Clone, Copy)]
pub struct UNICODE_STRING {
    pub Length: USHORT,
    pub MaximumLength: USHORT,
    pub Buffer: *mut u16,
}

impl Default for UNICODE_STRING {
    fn default() -> Self {
        Self {
            Length: 0,
            MaximumLength: 0,
            Buffer: std::ptr::null_mut(),
        }
    }
}

#[repr(C)]
pub struct OBJECT_ATTRIBUTES {
    pub Length: ULONG,
    pub RootDirectory: HANDLE,
    pub ObjectName: *mut UNICODE_STRING,
    pub Attributes: ULONG,
    pub SecurityDescriptor: PVOID,
    pub SecurityQualityOfService: PVOID,
}

impl OBJECT_ATTRIBUTES {
    pub fn new(object_name: *mut UNICODE_STRING, attributes: ULONG) -> Self {
        Self {
            Length: std::mem::size_of::<OBJECT_ATTRIBUTES>() as ULONG,
            RootDirectory: std::ptr::null_mut(),
            ObjectName: object_name,
            Attributes: attributes,
            SecurityDescriptor: std::ptr::null_mut(),
            SecurityQualityOfService: std::ptr::null_mut(),
        }
    }
}

#[repr(C)]
pub struct IO_STATUS_BLOCK {
    pub Status: NTSTATUS,
    pub Information: ULONG_PTR,
}

impl Default for IO_STATUS_BLOCK {
    fn default() -> Self {
        Self {
            Status: 0,
            Information: 0,
        }
    }
}

#[repr(C)]
pub struct FILE_DISPOSITION_INFORMATION {
    pub DeleteFile: BOOLEAN,
}

#[repr(C)]
pub struct CLIENT_ID {
    pub UniqueProcess: HANDLE,
    pub UniqueThread: HANDLE,
}

#[repr(C)]
pub struct CURDIR {
    pub DosPath: UNICODE_STRING,
    pub Handle: HANDLE,
}

#[repr(C)]
pub struct RTL_DRIVE_LETTER_CURDIR {
    pub Flags: USHORT,
    pub Length: USHORT,
    pub TimeStamp: ULONG,
    pub DosPath: UNICODE_STRING,
}

#[repr(C)]
pub struct RTL_USER_PROCESS_PARAMETERS {
    pub MaximumLength: ULONG,
    pub Length: ULONG,
    pub Flags: ULONG,
    pub DebugFlags: ULONG,
    pub ConsoleHandle: HANDLE,
    pub ConsoleFlags: ULONG,
    pub StandardInput: HANDLE,
    pub StandardOutput: HANDLE,
    pub StandardError: HANDLE,
    pub CurrentDirectory: CURDIR,
    pub DllPath: UNICODE_STRING,
    pub ImagePathName: UNICODE_STRING,
    pub CommandLine: UNICODE_STRING,
    pub Environment: PVOID,
    pub StartingX: ULONG,
    pub StartingY: ULONG,
    pub CountX: ULONG,
    pub CountY: ULONG,
    pub CountCharsX: ULONG,
    pub CountCharsY: ULONG,
    pub FillAttribute: ULONG,
    pub WindowFlags: ULONG,
    pub ShowWindowFlags: ULONG,
    pub WindowTitle: UNICODE_STRING,
    pub DesktopInfo: UNICODE_STRING,
    pub ShellInfo: UNICODE_STRING,
    pub RuntimeData: UNICODE_STRING,
    pub CurrentDirectories: [RTL_DRIVE_LETTER_CURDIR; RTL_MAX_DRIVE_LETTERS],
    pub EnvironmentSize: ULONG_PTR,
    pub EnvironmentVersion: ULONG_PTR,
    pub PackageDependencyData: PVOID,
    pub ProcessGroupId: ULONG,
}

#[repr(C)]
pub struct PEB_LDR_DATA {
    pub Reserved1: [BYTE; 8],
    pub Reserved2: [PVOID; 3],
    pub InMemoryOrderModuleList: LIST_ENTRY,
}

#[repr(C)]
pub struct LIST_ENTRY {
    pub Flink: *mut LIST_ENTRY,
    pub Blink: *mut LIST_ENTRY,
}

#[repr(C)]
pub struct PEB_FREE_BLOCK {
    pub Next: *mut PEB_FREE_BLOCK,
    pub Size: ULONG,
}

pub type PPEBLOCKROUTINE = Option<unsafe extern "system" fn(PebLock: PVOID)>;
pub type PPS_POST_PROCESS_INIT_ROUTINE = Option<unsafe extern "system" fn()>;

#[repr(C)]
pub struct PEB {
    pub InheritedAddressSpace: BOOLEAN,
    pub ReadImageFileExecOptions: BOOLEAN,
    pub BeingDebugged: BOOLEAN,
    pub Spare: BOOLEAN,
    pub Mutant: HANDLE,
    pub ImageBaseAddress: PVOID,
    pub LoaderData: *mut PEB_LDR_DATA,
    pub ProcessParameters: *mut RTL_USER_PROCESS_PARAMETERS,
    pub SubSystemData: PVOID,
    pub ProcessHeap: PVOID,
    pub FastPebLock: PVOID,
    pub FastPebLockRoutine: PPEBLOCKROUTINE,
    pub FastPebUnlockRoutine: PPEBLOCKROUTINE,
    pub EnvironmentUpdateCount: ULONG,
    pub KernelCallbackTable: *mut PVOID,
    pub EventLogSection: PVOID,
    pub EventLog: PVOID,
    pub FreeList: *mut PEB_FREE_BLOCK,
    pub TlsExpansionCounter: ULONG,
    pub TlsBitmap: PVOID,
    pub TlsBitmapBits: [ULONG; 2],
    pub ReadOnlySharedMemoryBase: PVOID,
    pub ReadOnlySharedMemoryHeap: PVOID,
    pub ReadOnlyStaticServerData: *mut PVOID,
    pub AnsiCodePageData: PVOID,
    pub OemCodePageData: PVOID,
    pub UnicodeCaseTableData: PVOID,
    pub NumberOfProcessors: ULONG,
    pub NtGlobalFlag: ULONG,
    pub Spare2: [BYTE; 4],
    pub CriticalSectionTimeout: LARGE_INTEGER,
    pub HeapSegmentReserve: ULONG,
    pub HeapSegmentCommit: ULONG,
    pub HeapDeCommitTotalFreeThreshold: ULONG,
    pub HeapDeCommitFreeBlockThreshold: ULONG,
    pub NumberOfHeaps: ULONG,
    pub MaximumNumberOfHeaps: ULONG,
    pub ProcessHeaps: *mut *mut PVOID,
    pub GdiSharedHandleTable: PVOID,
    pub ProcessStarterHelper: PVOID,
    pub GdiDCAttributeList: PVOID,
    pub LoaderLock: PVOID,
    pub OSMajorVersion: ULONG,
    pub OSMinorVersion: ULONG,
    pub OSBuildNumber: ULONG,
    pub OSPlatformId: ULONG,
    pub ImageSubSystem: ULONG,
    pub ImageSubSystemMajorVersion: ULONG,
    pub ImageSubSystemMinorVersion: ULONG,
    pub GdiHandleBuffer: [ULONG; 0x22],
    pub PostProcessInitRoutine: ULONG,
    pub TlsExpansionBitmap: ULONG,
    pub TlsExpansionBitmapBits: [BYTE; 0x80],
    pub SessionId: ULONG,
}

#[repr(C)]
pub struct PROCESS_BASIC_INFORMATION {
    pub Reserved1: PVOID,
    pub PebBaseAddress: *mut PEB,
    pub Reserved2: [PVOID; 2],
    pub UniqueProcessId: ULONG_PTR,
    pub Reserved3: PVOID,
}

impl Default for PROCESS_BASIC_INFORMATION {
    fn default() -> Self {
        Self {
            Reserved1: std::ptr::null_mut(),
            PebBaseAddress: std::ptr::null_mut(),
            Reserved2: [std::ptr::null_mut(); 2],
            UniqueProcessId: 0,
            Reserved3: std::ptr::null_mut(),
        }
    }
}

// ============================================================================
// Enums
// ============================================================================

#[repr(C)]
pub enum PROCESSINFOCLASS {
    ProcessBasicInformation = 0,
    ProcessDebugPort = 7,
    ProcessWow64Information = 26,
    ProcessImageFileName = 27,
    ProcessBreakOnTermination = 29,
}

#[repr(C)]
pub enum SECTION_INHERIT {
    ViewShare = 1,
    ViewUnmap = 2,
}

#[repr(C)]
pub enum FILE_INFORMATION_CLASS {
    FileDirectoryInformation = 1,
    FileBasicInformation = 4,
    FileStandardInformation = 5,
    FileDispositionInformation = 13,
}

// ============================================================================
// Function Type Definitions
// ============================================================================

pub type FnNtOpenFile = unsafe extern "system" fn(
    FileHandle: *mut HANDLE,
    DesiredAccess: ACCESS_MASK,
    ObjectAttributes: *mut OBJECT_ATTRIBUTES,
    IoStatusBlock: *mut IO_STATUS_BLOCK,
    ShareAccess: ULONG,
    OpenOptions: ULONG,
) -> NTSTATUS;

pub type FnNtSetInformationFile = unsafe extern "system" fn(
    FileHandle: HANDLE,
    IoStatusBlock: *mut IO_STATUS_BLOCK,
    FileInformation: PVOID,
    Length: ULONG,
    FileInformationClass: FILE_INFORMATION_CLASS,
) -> NTSTATUS;

pub type FnNtCreateSection = unsafe extern "system" fn(
    SectionHandle: *mut HANDLE,
    DesiredAccess: ACCESS_MASK,
    ObjectAttributes: *mut OBJECT_ATTRIBUTES,
    MaximumSize: PLARGE_INTEGER,
    SectionPageProtection: ULONG,
    AllocationAttributes: ULONG,
    FileHandle: HANDLE,
) -> NTSTATUS;

pub type FnNtCreateProcessEx = unsafe extern "system" fn(
    ProcessHandle: *mut HANDLE,
    DesiredAccess: ACCESS_MASK,
    ObjectAttributes: *mut OBJECT_ATTRIBUTES,
    ParentProcess: HANDLE,
    Flags: ULONG,
    SectionHandle: HANDLE,
    DebugPort: HANDLE,
    ExceptionPort: HANDLE,
    InJob: BOOLEAN,
) -> NTSTATUS;

pub type FnNtQueryInformationProcess = unsafe extern "system" fn(
    ProcessHandle: HANDLE,
    ProcessInformationClass: PROCESSINFOCLASS,
    ProcessInformation: PVOID,
    ProcessInformationLength: ULONG,
    ReturnLength: PULONG,
) -> NTSTATUS;

pub type FnNtReadVirtualMemory = unsafe extern "system" fn(
    ProcessHandle: HANDLE,
    BaseAddress: PVOID,
    Buffer: PVOID,
    BufferSize: SIZE_T,
    NumberOfBytesRead: PSIZE_T,
) -> NTSTATUS;

pub type FnNtWriteVirtualMemory = unsafe extern "system" fn(
    ProcessHandle: HANDLE,
    BaseAddress: PVOID,
    Buffer: PVOID,
    BufferSize: SIZE_T,
    NumberOfBytesWritten: PSIZE_T,
) -> NTSTATUS;

pub type FnNtAllocateVirtualMemory = unsafe extern "system" fn(
    ProcessHandle: HANDLE,
    BaseAddress: *mut PVOID,
    ZeroBits: ULONG_PTR,
    RegionSize: PSIZE_T,
    AllocationType: ULONG,
    Protect: ULONG,
) -> NTSTATUS;

pub type FnNtCreateThreadEx = unsafe extern "system" fn(
    ThreadHandle: *mut HANDLE,
    DesiredAccess: ACCESS_MASK,
    ObjectAttributes: LPVOID,
    ProcessHandle: HANDLE,
    StartAddress: LPVOID,
    Parameter: LPVOID,
    CreateSuspended: BOOL,
    StackZeroBits: DWORD,
    SizeOfStackCommit: DWORD,
    SizeOfStackReserve: DWORD,
    BytesBuffer: LPVOID,
) -> NTSTATUS;

pub type FnRtlInitUnicodeString = unsafe extern "system" fn(
    DestinationString: *mut UNICODE_STRING,
    SourceString: *const u16,
);

pub type FnRtlImageNtHeader = unsafe extern "system" fn(
    Base: PVOID,
) -> PIMAGE_NT_HEADERS;

pub type FnRtlCreateProcessParametersEx = unsafe extern "system" fn(
    pProcessParameters: *mut *mut RTL_USER_PROCESS_PARAMETERS,
    ImagePathName: *mut UNICODE_STRING,
    DllPath: *mut UNICODE_STRING,
    CurrentDirectory: *mut UNICODE_STRING,
    CommandLine: *mut UNICODE_STRING,
    Environment: PVOID,
    WindowTitle: *mut UNICODE_STRING,
    DesktopInfo: *mut UNICODE_STRING,
    ShellInfo: *mut UNICODE_STRING,
    RuntimeData: *mut UNICODE_STRING,
    Flags: ULONG,
) -> NTSTATUS;

// ============================================================================
// Helper Functions
// ============================================================================

#[inline]
pub fn nt_success(status: NTSTATUS) -> bool {
    status >= 0
}

pub unsafe fn get_ntdll_function<T>(name: &str) -> Result<T, String> {
    use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
    use std::ffi::CString;

    let ntdll = GetModuleHandleA(b"ntdll.dll\0".as_ptr() as *const i8);
    if ntdll.is_null() {
        return Err("[-] Failed to get ntdll.dll handle".to_string());
    }

    let func_name = CString::new(name).map_err(|_| "[-] Invalid function name")?;
    let func = GetProcAddress(ntdll, func_name.as_ptr());
    
    if func.is_null() {
        return Err(format!("[-] Failed to locate {} API", name));
    }

    Ok(std::mem::transmute_copy(&func))
}