📄 process.c
字号:
if (! NT_SUCCESS(status))
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: ZwQueryInformationProcess failed with status %x\n", FunctionName, status));
goto done;
}
ProcessId = ProcessBasicInfo.UniqueProcessId;
/*
* if ProcessId is 0 then the pid has not been assigned yet and we are the primary thread.
* in that case pass our pid (we are still running in the context of the parent process) as the ParentId
* to make sure we find the right process (since theoretically there can be more than one process with a
* pid of 0)
*/
p = FindImagePidEntry(ProcessId, ProcessId == 0 ? CURRENT_PROCESS_PID : 0);
if (p == NULL)
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d %s: FindImagePidEntry(%d) failed\n", CURRENT_PROCESS_PID, FunctionName, ProcessId));
goto done;
}
/*
* Stack Buffer Overflow Protection (Part 3).
*
* Allocate/reserve a random (< 1024 bytes) part of a thread's stack space.
* This causes the least significant 10 bits to be randomized as well.
* (without this, the least significant 16 bits are always the same).
*/
/* save the stackoffset for now since we are holding a spinlock and cannot touch pageable memory */
//XXX we are not holding the spinlock here but are still accessing various p-> fields
if (IS_OVERFLOW_PROTECTION_ON(gSecPolicy) && IS_OVERFLOW_PROTECTION_ON(p->SecPolicy))
StackOffset = (USHORT) (16 + (rand(ThreadContext->Eax) % 63) * 16);
if (! IS_USERLAND_PROTECTION_ON(gSecPolicy) || ! IS_USERLAND_PROTECTION_ON(p->SecPolicy))
goto done;
/* Userland DLL needs to be loaded only once (by the first/main thread) */
if (p->FirstThread != TRUE)
goto done;
p->FirstThread = FALSE;
//XXX investigate MEM_WRITE_WATCH (supported on i386?)
/*
* Inject the userland DLL into the process.
*
* This is achieved by allocating 1 page of memory in the address space of a "victim" process.
* Then the LdrLoadDll(our_dll) code is written to the allocated page and victim's thread EIP
* is changed to point to our code.
* As soon as the thread executes, it will load our DLL and then jump to the original entry point.
*
* When not given explicit directions, the Microsoft linker creates each DLL with a
* preferred load address of 0x10000000. By loading our DLL first, we cause the rest of
* the application DLLs to load at a different address.
*/
/* allocate 1 page of commited rwx memory */
Size = PAGE_SIZE;
Base = NULL;
status = ZwAllocateVirtualMemory(ProcessHandle, &Base, 0L, &Size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (! NT_SUCCESS(status))
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: ZwAllocateVirtualMemory(%x, %x) failed with status %x\n", FunctionName, Base, Size, status));
goto done;
}
status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_ALL_ACCESS, 0, KernelMode, &proc, NULL);
if (! NT_SUCCESS(status))
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: ObReferenceObjectByHandle(ProcessHandle) failed with status %x\n", FunctionName, status));
goto done;
}
try
{
ULONG CodeAddress, DllPathAddress;
ULONG ThreadEntryPoint = ThreadContext->Eax; /* thread entry point is stored in the EAX register */
PWSTR InjectDllName = L"ozoneusr.dll";
USHORT InjectDllNameSize = (wcslen(InjectDllName) + 1) * sizeof(WCHAR);
/*
* Execute the DLL inject in the memory context of a "victim" process
*/
KeAttachProcess(proc);
{
/* probe the memory, just in case */
ProbeForRead(Base, PAGE_SIZE, 1);
ProbeForWrite(Base, PAGE_SIZE, 1);
/*
* Memory Layout used for DLL injection
*
* Byte Value
*
* 0..4 Original EIP
* 4..8 LdrLoadDll() output handle
* 8..16 LdrLoadDll() DllName UNICODE_STRING structure
* 16..? DllName.Buffer WCHAR string
* ?..? DllPath WCHAR string
* .... assembler code (to call LdrLoadDll() and then jmp to the original EIP)
*/
#define BASE_PTR Base
#define ADDRESS_ORIGINAL_EIP (BASE_PTR + 0)
#define ADDRESS_DLL_HANDLE (BASE_PTR + 4)
#define ADDRESS_DLL_NAME (BASE_PTR + 8)
/* save the original thread entry point */
* (PULONG) ADDRESS_ORIGINAL_EIP = ThreadEntryPoint;
/* skip past eip and output handle (8 bytes) */
InstructionAddress = ADDRESS_DLL_NAME;
/*
* Create a UNICODE_STRING structure
*/
* ((PUSHORT) InstructionAddress)++ = InjectDllNameSize; /* UNICODE_STRING.Length */
* ((PUSHORT) InstructionAddress)++ = InjectDllNameSize; /* UNICODE_STRING.MaximumLength */
/* UNICODE_STRING.Buffer (points to unicode string directly following the buffer) */
* ((PULONG) InstructionAddress)++ = (ULONG) (InstructionAddress + sizeof(PWSTR));
/* the actual DllName.Buffer value */
wcscpy((PWSTR) InstructionAddress, InjectDllName);
InstructionAddress += InjectDllNameSize;
/* DllPathValue value */
DllPathAddress = (ULONG) InstructionAddress;
wcscpy((PWSTR) InstructionAddress, OzoneInstallPath);
InstructionAddress += OzoneInstallPathSize;
CodeAddress = (ULONG) InstructionAddress;
/*
* Generate code that will call LdrLoadDll and then jmp to the original entry point.
*/
/*
* NTSTATUS
* LdrLoadDll (
* IN PWSTR DllPath OPTIONAL,
* IN PULONG DllCharacteristics OPTIONAL,
* IN PUNICODE_STRING DllName,
* OUT PVOID *DllHandle
* );
*
* Save LdrLoadDll parameters on stack (last to first).
*/
ASM_PUSH(InstructionAddress, ADDRESS_DLL_HANDLE); /* DllHandle */
ASM_PUSH(InstructionAddress, ADDRESS_DLL_NAME); /* DllName */
ASM_PUSH(InstructionAddress, 0); /* DllCharacteristics */
// ASM_PUSH(InstructionAddress, NULL); /* DllPath */
ASM_PUSH(InstructionAddress, DllPathAddress); /* DllPath */
ASM_CALL(InstructionAddress, FindFunctionBase(NTDLL_Base, "LdrLoadDll"));
//XXX now clear out all the data up to this instruction
//be careful first 4 bytes are used by the next instruction
/*
mov ecx, 16
lea edi, Base + 4
rep stosw
*/
ASM_JMP(InstructionAddress, Base);
}
KeDetachProcess();
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d %s: Replacing original thread entry point %x with %x\n", CURRENT_PROCESS_PID, FunctionName, ThreadContext->Eax, CodeAddress));
/* hijack the thread instruction pointer (saved in EAX) */
// LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("eip %x eax %x\n", ThreadContext->Eip, ThreadContext->Eax));
ThreadContext->Eax = (ULONG) CodeAddress;
ThreadContext->Eip = ThreadContext->Eax;
ObDereferenceObject(proc);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
NTSTATUS status = GetExceptionCode();
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%s: caught an exception. status = 0x%x\n", FunctionName, status));
KeDetachProcess();
ObDereferenceObject(proc);
}
}
done:
/*
* finally adjust the stack.
* could not have done it before since we were holding a spinlock and weren't allowed to access pageable memory
*/
if (StackOffset)
ThreadContext->Esp -= StackOffset;
ASSERT(OriginalNtCreateThread);
rc = OriginalNtCreateThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle,
ClientId, ThreadContext, UserStack, CreateSuspended);
HOOK_ROUTINE_EXIT(rc);
}
/*
* HookedNtOpenThread()
*
* Description:
* This function mediates the NtOpenThread() system service in order to XXX
* .
*
* NOTE: ZwOpenThread opens a thread object. [NAR]
*
* Parameters:
* Those of NtOpenThread().
*
* Returns:
* NTSTATUS returned by NtOpenThread().
*/
NTSTATUS
NTAPI
HookedNtOpenThread
(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId
)
{
CHAR THREADNAME[MAX_PATH];
HOOK_ROUTINE_ENTER();
if (LearningMode == FALSE && GetPathFromOA(ObjectAttributes, THREADNAME, MAX_PATH, RESOLVE_LINKS))
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d HookedNtOpenThread: %s\n", (ULONG) PsGetCurrentProcessId(), THREADNAME));
}
if (! IS_BIT_SET(DesiredAccess, THREAD_QUERY_INFORMATION))
{
// ClientId->UniqueProcess = 0 if process opens a thread in the same process (wmplayer.exe)
if (ClientId)
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d HookedNtOpenThread(%d %d): %x\n", (ULONG) PsGetCurrentProcessId(), ClientId->UniqueProcess, ClientId->UniqueThread, DesiredAccess));
else
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("%d HookedNtOpenThread(): %x\n", (ULONG) PsGetCurrentProcessId(), DesiredAccess));
}
ASSERT(OriginalNtOpenThread);
rc = OriginalNtOpenThread(ThreadHandle, DesiredAccess, ObjectAttributes, ClientId);
HOOK_ROUTINE_EXIT(rc);
}
/*
* ProcessPostBootup()
*
* Description:
* Find out where userland Ozone files are installed once the bootup process is complete.
* We are unable to read some parts of the registry before the bootup is complete since
* they have not been initialized yet.
*
* ProcessPostBootup() might run even before bootup is complete in order to setup up the
* default values. When ProcessPostBootup() runs again after bootup, the default values
* will be overwritten with the correct ones.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*/
VOID
ProcessPostBootup()
{
if (ReadStringRegistryValueW(L"\\Registry\\Machine\\Software\\Security Architects\\Ozone Agent", L"InstallPath", OzoneInstallPath, MAX_PATH) == FALSE)
{
LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("ProcessPostBootup: Failed to open InstallPath registry key\n"));
// use the default path
wcscpy(OzoneInstallPath, L"C:\\Program Files\\Security Architects\\Ozone Agent");
}
OzoneInstallPathSize = (wcslen(OzoneInstallPath) + 1) * sizeof(WCHAR);
}
/*
* InitProcessEntries()
*
* Description:
* Initializes all the mediated process operation pointers. The "OriginalFunction" pointers
* are initialized by InstallSyscallsHooks() that must be called prior to this function.
*
* NOTE: Called once during driver initialization (DriverEntry()).
*
* Parameters:
* None.
*
* Returns:
* TRUE to indicate success, FALSE if failed.
*/
/*
VOID
LoadImageNotifyProc
(
IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId, // where image is mapped
IN PIMAGE_INFO ImageInfo
)
{
if (FullImageName && ImageInfo)
{
KdPrint(("LoadImageNotifyProc: %d %S %x %x\n", ProcessId, FullImageName->Buffer, ImageInfo->ImageBase, ImageInfo->ImageSize));
}
else
{
KdPrint(("LoadImageNotifyProc: NULL Pointer %x %x\n", FullImageName, ImageInfo));
}
}
*/
BOOLEAN
InitProcessEntries()
{
// PsSetLoadImageNotifyRoutine(LoadImageNotifyProc);
if ( (OriginalNtCreateProcess = (fpZwCreateProcess) ZwCalls[ZW_CREATE_PROCESS_INDEX].OriginalFunction) == NULL)
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtCreateProcess is NULL\n"));
return FALSE;
}
if ( (OriginalNtCreateProcessEx = (fpZwCreateProcessEx) ZwCalls[ZW_CREATE_PROCESSEX_INDEX].OriginalFunction) == NULL)
{
/* does not exist on Win2K */
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtCreateProcessEx is NULL\n"));
}
if ( (OriginalNtOpenProcess = (fpZwOpenProcess) ZwCalls[ZW_OPEN_PROCESS_INDEX].OriginalFunction) == NULL)
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtOpenProcess is NULL\n"));
return FALSE;
}
if ( (OriginalNtCreateThread = (fpZwCreateThread) ZwCalls[ZW_CREATE_THREAD_INDEX].OriginalFunction) == NULL)
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtCreateThread is NULL\n"));
return FALSE;
}
if ( (OriginalNtOpenThread = (fpZwOpenThread) ZwCalls[ZW_OPEN_THREAD_INDEX].OriginalFunction) == NULL)
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("InitProcessEntries: OriginalNtOpenThread is NULL\n"));
return FALSE;
}
/*
* run ProcessPostBootup() even if we are still booting up, this way we will at least setup
* the default values. When ProcessPostBootup() runs again after bootup, the default values
* will be overwritten with the correct ones.
*/
ProcessPostBootup();
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -