645 lines
25 KiB
C
645 lines
25 KiB
C
/* Benjamin DELPY `gentilkiwi`
|
|
http://blog.gentilkiwi.com
|
|
benjamin@gentilkiwi.com
|
|
Licence : https://creativecommons.org/licenses/by/4.0/
|
|
*/
|
|
#include "kull_m_process.h"
|
|
|
|
NTSTATUS kull_m_process_NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS informationClass, PVOID buffer, ULONG informationLength)
|
|
{
|
|
NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH;
|
|
DWORD sizeOfBuffer;
|
|
|
|
if(*(PVOID *) buffer)
|
|
{
|
|
status = NtQuerySystemInformation(informationClass, *(PVOID *) buffer, informationLength, NULL);
|
|
}
|
|
else
|
|
{
|
|
for(sizeOfBuffer = 0x1000; (status == STATUS_INFO_LENGTH_MISMATCH) && (*(PVOID *) buffer = LocalAlloc(LPTR, sizeOfBuffer)) ; sizeOfBuffer <<= 1)
|
|
{
|
|
status = NtQuerySystemInformation(informationClass, *(PVOID *) buffer, sizeOfBuffer, NULL);
|
|
if(!NT_SUCCESS(status))
|
|
LocalFree(*(PVOID *) buffer);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS kull_m_process_getProcessInformation(PKULL_M_PROCESS_ENUM_CALLBACK callBack, PVOID pvArg)
|
|
{
|
|
NTSTATUS status;
|
|
PSYSTEM_PROCESS_INFORMATION buffer = NULL, myInfos;
|
|
|
|
status = kull_m_process_NtQuerySystemInformation(SystemProcessInformation, &buffer, 0);
|
|
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
for(myInfos = buffer; callBack(myInfos, pvArg) && myInfos->NextEntryOffset ; myInfos = (PSYSTEM_PROCESS_INFORMATION) ((PBYTE) myInfos + myInfos->NextEntryOffset));
|
|
LocalFree(buffer);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOL CALLBACK kull_m_process_callback_pidForName(PSYSTEM_PROCESS_INFORMATION pSystemProcessInformation, PVOID pvArg)
|
|
{
|
|
if(((PKULL_M_PROCESS_PID_FOR_NAME) pvArg)->isFound = RtlEqualUnicodeString(&pSystemProcessInformation->ImageName, ((PKULL_M_PROCESS_PID_FOR_NAME) pvArg)->name, TRUE))
|
|
*((PKULL_M_PROCESS_PID_FOR_NAME) pvArg)->processId = PtrToUlong(pSystemProcessInformation->UniqueProcessId);
|
|
return !((PKULL_M_PROCESS_PID_FOR_NAME) pvArg)->isFound;
|
|
}
|
|
|
|
BOOL kull_m_process_getProcessIdForName(LPCWSTR name, PDWORD processId)
|
|
{
|
|
BOOL status = FALSE;
|
|
UNICODE_STRING uName;
|
|
KULL_M_PROCESS_PID_FOR_NAME mySearch = {&uName, processId, FALSE};
|
|
|
|
RtlInitUnicodeString(&uName, name);
|
|
if(NT_SUCCESS(kull_m_process_getProcessInformation(kull_m_process_callback_pidForName, &mySearch)))
|
|
status = mySearch.isFound;
|
|
return status;;
|
|
}
|
|
|
|
NTSTATUS kull_m_process_getVeryBasicModuleInformations(PKULL_M_MEMORY_HANDLE memory, PKULL_M_MODULE_ENUM_CALLBACK callBack, PVOID pvArg)
|
|
{
|
|
NTSTATUS status = STATUS_DLL_NOT_FOUND;
|
|
PLDR_DATA_TABLE_ENTRY pLdrEntry;
|
|
PEB Peb; PEB_LDR_DATA LdrData; LDR_DATA_TABLE_ENTRY LdrEntry;
|
|
#ifdef _M_X64
|
|
PLDR_DATA_TABLE_ENTRY_F32 pLdrEntry32;
|
|
PEB_F32 Peb32; PEB_LDR_DATA_F32 LdrData32; LDR_DATA_TABLE_ENTRY_F32 LdrEntry32;
|
|
#endif
|
|
ULONG i;
|
|
KULL_M_MEMORY_ADDRESS aBuffer = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
|
KULL_M_MEMORY_ADDRESS aProcess= {NULL, memory};
|
|
PBYTE aLire, fin;
|
|
PWCHAR moduleNameW;
|
|
UNICODE_STRING moduleName;
|
|
PMINIDUMP_MODULE_LIST pMinidumpModuleList;
|
|
PMINIDUMP_STRING pMinidumpString;
|
|
KULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION moduleInformation;
|
|
PRTL_PROCESS_MODULES modules = NULL;
|
|
BOOL continueCallback = TRUE;
|
|
moduleInformation.DllBase.hMemory = memory;
|
|
switch(memory->type)
|
|
{
|
|
case KULL_M_MEMORY_TYPE_OWN:
|
|
if(kull_m_process_peb(memory, &Peb, FALSE))
|
|
{
|
|
for(pLdrEntry = (PLDR_DATA_TABLE_ENTRY) ((PBYTE) (Peb.Ldr->InMemoryOrderModulevector.Flink) - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
|
|
(pLdrEntry != (PLDR_DATA_TABLE_ENTRY) ((PBYTE) (Peb.Ldr) + FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModulevector))) && continueCallback;
|
|
pLdrEntry = (PLDR_DATA_TABLE_ENTRY) ((PBYTE) (pLdrEntry->InMemoryOrderLinks.Flink ) - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks))
|
|
)
|
|
{
|
|
moduleInformation.DllBase.address = pLdrEntry->DllBase;
|
|
moduleInformation.SizeOfImage = pLdrEntry->SizeOfImage;
|
|
moduleInformation.NameDontUseOutsideCallback = &pLdrEntry->BaseDllName;
|
|
kull_m_process_adjustTimeDateStamp(&moduleInformation);
|
|
continueCallback = callBack(&moduleInformation, pvArg);
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
#ifdef _M_X64
|
|
moduleInformation.NameDontUseOutsideCallback = &moduleName;
|
|
if(continueCallback && NT_SUCCESS(status) && kull_m_process_peb(memory, (PPEB) &Peb32, TRUE))
|
|
{
|
|
status = STATUS_PARTIAL_COPY;
|
|
|
|
for(pLdrEntry32 = (PLDR_DATA_TABLE_ENTRY_F32) ((PBYTE) ULongToPtr(((PEB_LDR_DATA_F32 *) ULongToPtr(Peb32.Ldr))->InMemoryOrderModulevector.Flink) - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY_F32, InMemoryOrderLinks));
|
|
(pLdrEntry32 != (PLDR_DATA_TABLE_ENTRY_F32) ((PBYTE) ULongToPtr(Peb32.Ldr) + FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModulevector))) && continueCallback;
|
|
pLdrEntry32 = (PLDR_DATA_TABLE_ENTRY_F32) ((PBYTE) ULongToPtr(pLdrEntry32->InMemoryOrderLinks.Flink) - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY_F32, InMemoryOrderLinks))
|
|
)
|
|
{
|
|
moduleInformation.DllBase.address = ULongToPtr(pLdrEntry32->DllBase);
|
|
moduleInformation.SizeOfImage = pLdrEntry32->SizeOfImage;
|
|
moduleName.Length = pLdrEntry32->BaseDllName.Length;
|
|
moduleName.MaximumLength = pLdrEntry32->BaseDllName.MaximumLength;
|
|
moduleName.Buffer = (PWSTR) ULongToPtr(pLdrEntry32->BaseDllName.Buffer);
|
|
kull_m_process_adjustTimeDateStamp(&moduleInformation);
|
|
continueCallback = callBack(&moduleInformation, pvArg);
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case KULL_M_MEMORY_TYPE_PROCESS:
|
|
moduleInformation.NameDontUseOutsideCallback = &moduleName;
|
|
if(kull_m_process_peb(memory, &Peb, FALSE))
|
|
{
|
|
aBuffer.address = &LdrData; aProcess.address = Peb.Ldr;
|
|
if(kull_m_memory_copy(&aBuffer, &aProcess, sizeof(LdrData)))
|
|
{
|
|
for(
|
|
aLire = (PBYTE) (LdrData.InMemoryOrderModulevector.Flink) - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks),
|
|
fin = (PBYTE) (Peb.Ldr) + FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModulevector);
|
|
(aLire != fin) && continueCallback;
|
|
aLire = (PBYTE) LdrEntry.InMemoryOrderLinks.Flink - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks)
|
|
)
|
|
{
|
|
aBuffer.address = &LdrEntry; aProcess.address = aLire;
|
|
if(continueCallback = kull_m_memory_copy(&aBuffer, &aProcess, sizeof(LdrEntry)))
|
|
{
|
|
moduleInformation.DllBase.address = LdrEntry.DllBase;
|
|
moduleInformation.SizeOfImage = LdrEntry.SizeOfImage;
|
|
moduleName = LdrEntry.BaseDllName;
|
|
if(moduleName.Buffer = (PWSTR) LocalAlloc(LPTR, moduleName.MaximumLength))
|
|
{
|
|
aBuffer.address = moduleName.Buffer; aProcess.address = LdrEntry.BaseDllName.Buffer;
|
|
if(kull_m_memory_copy(&aBuffer, &aProcess, moduleName.MaximumLength))
|
|
{
|
|
kull_m_process_adjustTimeDateStamp(&moduleInformation);
|
|
continueCallback = callBack(&moduleInformation, pvArg);
|
|
}
|
|
LocalFree(moduleName.Buffer);
|
|
}
|
|
}
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
#ifdef _M_X64
|
|
if(continueCallback && NT_SUCCESS(status) && kull_m_process_peb(memory, (PPEB) &Peb32, TRUE))
|
|
{
|
|
status = STATUS_PARTIAL_COPY;
|
|
aBuffer.address = &LdrData32; aProcess.address = ULongToPtr(Peb32.Ldr);
|
|
if(kull_m_memory_copy(&aBuffer, &aProcess, sizeof(LdrData32)))
|
|
{
|
|
for(
|
|
aLire = (PBYTE) ULongToPtr(LdrData32.InMemoryOrderModulevector.Flink) - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY_F32, InMemoryOrderLinks),
|
|
fin = (PBYTE) ULongToPtr(Peb32.Ldr) + FIELD_OFFSET(PEB_LDR_DATA_F32, InLoadOrderModulevector);
|
|
(aLire != fin) && continueCallback;
|
|
aLire = (PBYTE) ULongToPtr(LdrEntry32.InMemoryOrderLinks.Flink) - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY_F32, InMemoryOrderLinks)
|
|
)
|
|
{
|
|
aBuffer.address = &LdrEntry32; aProcess.address = aLire;
|
|
if(kull_m_memory_copy(&aBuffer, &aProcess, sizeof(LdrEntry32)))
|
|
{
|
|
moduleInformation.DllBase.address = ULongToPtr(LdrEntry32.DllBase);
|
|
moduleInformation.SizeOfImage = LdrEntry32.SizeOfImage;
|
|
|
|
moduleName.Length = LdrEntry32.BaseDllName.Length;
|
|
moduleName.MaximumLength = LdrEntry32.BaseDllName.MaximumLength;
|
|
if(moduleName.Buffer = (PWSTR) LocalAlloc(LPTR, moduleName.MaximumLength))
|
|
{
|
|
aBuffer.address = moduleName.Buffer; aProcess.address = ULongToPtr(LdrEntry32.BaseDllName.Buffer);
|
|
if(kull_m_memory_copy(&aBuffer, &aProcess, moduleName.MaximumLength))
|
|
{
|
|
kull_m_process_adjustTimeDateStamp(&moduleInformation);
|
|
continueCallback = callBack(&moduleInformation, pvArg);
|
|
}
|
|
LocalFree(moduleName.Buffer);
|
|
}
|
|
}
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case KULL_M_MEMORY_TYPE_PROCESS_DMP:
|
|
moduleInformation.NameDontUseOutsideCallback = &moduleName;
|
|
if(pMinidumpModuleList = (PMINIDUMP_MODULE_LIST) kull_m_minidump_stream(memory->pHandleProcessDmp->hMinidump, ModuleListStream))
|
|
{
|
|
for(i = 0; (i < pMinidumpModuleList->NumberOfModules) && continueCallback; i++)
|
|
{
|
|
moduleInformation.DllBase.address = (PVOID) pMinidumpModuleList->Modules[i].BaseOfImage;
|
|
moduleInformation.SizeOfImage = pMinidumpModuleList->Modules[i].SizeOfImage;
|
|
if(pMinidumpString = (PMINIDUMP_STRING) kull_m_minidump_RVAtoPTR(memory->pHandleProcessDmp->hMinidump, pMinidumpModuleList->Modules[i].ModuleNameRva))
|
|
{
|
|
RtlInitUnicodeString(&moduleName, wcsrchr(pMinidumpString->Buffer, L'\\') + 1);
|
|
kull_m_process_adjustTimeDateStamp(&moduleInformation);
|
|
continueCallback = callBack(&moduleInformation, pvArg);
|
|
}
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case KULL_M_MEMORY_TYPE_KERNEL:
|
|
status = kull_m_process_NtQuerySystemInformation(SystemModuleInformation, &modules, 0);
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
moduleInformation.NameDontUseOutsideCallback = &moduleName;
|
|
for(i = 0; (i < modules->NumberOfModules) && continueCallback; i++)
|
|
{
|
|
moduleInformation.DllBase.address = modules->Modules[i].ImageBase;
|
|
moduleInformation.SizeOfImage = modules->Modules[i].ImageSize;
|
|
if(moduleNameW = kull_m_string_qad_ansi_to_unicode((char *) modules->Modules[i].FullPathName + modules->Modules[i].OffsetToFileName))
|
|
{
|
|
RtlInitUnicodeString(&moduleName, moduleNameW);
|
|
moduleInformation.TimeDateStamp = 0;
|
|
continueCallback = callBack(&moduleInformation, pvArg);
|
|
|
|
LocalFree(moduleNameW);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void kull_m_process_adjustTimeDateStamp(PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION information)
|
|
{
|
|
PIMAGE_NT_HEADERS ntHeaders;
|
|
if(kull_m_process_ntheaders(&information->DllBase, &ntHeaders))
|
|
{
|
|
information->TimeDateStamp = ntHeaders->FileHeader.TimeDateStamp;
|
|
LocalFree(ntHeaders);
|
|
}
|
|
else information->TimeDateStamp = 0;
|
|
}
|
|
|
|
BOOL CALLBACK kull_m_process_callback_moduleForName(PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION pModuleInformation, PVOID pvArg)
|
|
{
|
|
if(((PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION_FOR_NAME) pvArg)->isFound = RtlEqualUnicodeString(pModuleInformation->NameDontUseOutsideCallback, ((PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION_FOR_NAME) pvArg)->name, TRUE))
|
|
*((PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION_FOR_NAME) pvArg)->informations = *pModuleInformation;
|
|
return !((PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION_FOR_NAME) pvArg)->isFound;
|
|
}
|
|
|
|
BOOL CALLBACK kull_m_process_callback_moduleFirst(PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION pModuleInformation, PVOID pvArg)
|
|
{
|
|
*(PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION) pvArg = *pModuleInformation;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL kull_m_process_getVeryBasicModuleInformationsForName(PKULL_M_MEMORY_HANDLE memory, PCWSTR name, PKULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION informations)
|
|
{
|
|
BOOL status = FALSE;
|
|
UNICODE_STRING uName;
|
|
KULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION_FOR_NAME mySearch = {&uName, informations, FALSE};
|
|
|
|
if(name)
|
|
{
|
|
RtlInitUnicodeString(&uName, name);
|
|
if(NT_SUCCESS(kull_m_process_getVeryBasicModuleInformations(memory, kull_m_process_callback_moduleForName, &mySearch)))
|
|
status = mySearch.isFound;
|
|
}
|
|
else
|
|
status = NT_SUCCESS(kull_m_process_getVeryBasicModuleInformations(memory, kull_m_process_callback_moduleFirst, informations));
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS kull_m_process_getMemoryInformations(PKULL_M_MEMORY_HANDLE memory, PKULL_M_MEMORY_RANGE_ENUM_CALLBACK callBack, PVOID pvArg)
|
|
{
|
|
NTSTATUS status = STATUS_NOT_FOUND;
|
|
MEMORY_BASIC_INFORMATION memoryInfos;
|
|
PBYTE currentPage, maxPage;
|
|
PMINIDUMP_MEMORY_INFO_LIST maListeInfo = NULL;
|
|
PMINIDUMP_MEMORY_INFO mesInfos = NULL;
|
|
ULONG i;
|
|
BOOL continueCallback = TRUE;
|
|
|
|
if(!NT_SUCCESS(kull_m_process_NtQuerySystemInformation(KIWI_SystemMmSystemRangeStart, &maxPage, sizeof(PBYTE))))
|
|
maxPage = MmSystemRangeStart;
|
|
|
|
switch(memory->type)
|
|
{
|
|
case KULL_M_MEMORY_TYPE_OWN:
|
|
for(currentPage = 0; (currentPage < maxPage) && continueCallback; currentPage += memoryInfos.RegionSize)
|
|
if(VirtualQuery(currentPage, &memoryInfos, sizeof(MEMORY_BASIC_INFORMATION)) == sizeof(MEMORY_BASIC_INFORMATION))
|
|
continueCallback = callBack(&memoryInfos, pvArg);
|
|
else break;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
case KULL_M_MEMORY_TYPE_PROCESS:
|
|
for(currentPage = 0; (currentPage < maxPage) && continueCallback; currentPage += memoryInfos.RegionSize)
|
|
if(VirtualQueryEx(memory->pHandleProcess->hProcess, currentPage, &memoryInfos, sizeof(MEMORY_BASIC_INFORMATION)) == sizeof(MEMORY_BASIC_INFORMATION))
|
|
continueCallback = callBack(&memoryInfos, pvArg);
|
|
else break;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
case KULL_M_MEMORY_TYPE_PROCESS_DMP:
|
|
if(maListeInfo = (PMINIDUMP_MEMORY_INFO_LIST) kull_m_minidump_stream(memory->pHandleProcessDmp->hMinidump, MemoryInfoListStream))
|
|
{
|
|
for(i = 0; (i < maListeInfo->NumberOfEntries) && continueCallback; i++)
|
|
{
|
|
mesInfos = (PMINIDUMP_MEMORY_INFO) ((PBYTE) maListeInfo + maListeInfo->SizeOfHeader + (i * maListeInfo->SizeOfEntry));
|
|
memoryInfos.AllocationBase = (PVOID) mesInfos->AllocationBase;
|
|
memoryInfos.AllocationProtect = mesInfos->AllocationProtect;
|
|
memoryInfos.BaseAddress = (PVOID) mesInfos->BaseAddress;
|
|
memoryInfos.Protect = mesInfos->Protect;
|
|
memoryInfos.RegionSize = (SIZE_T) mesInfos->RegionSize;
|
|
memoryInfos.State = mesInfos->State;
|
|
memoryInfos.Type = mesInfos->Type;
|
|
continueCallback = callBack(&memoryInfos, pvArg);
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
BOOL kull_m_process_peb(PKULL_M_MEMORY_HANDLE memory, PPEB pPeb, BOOL isWOW)
|
|
{
|
|
BOOL status = FALSE;
|
|
PROCESS_BASIC_INFORMATION processInformations;
|
|
HANDLE hProcess = (memory->type == KULL_M_MEMORY_TYPE_PROCESS) ? memory->pHandleProcess->hProcess : GetCurrentProcess();
|
|
KULL_M_MEMORY_ADDRESS aBuffer = {pPeb, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
|
KULL_M_MEMORY_ADDRESS aProcess= {NULL, memory};
|
|
PROCESSINFOCLASS info;
|
|
ULONG szPeb, szBuffer, szInfos;
|
|
LPVOID buffer;
|
|
|
|
#ifdef _M_X64
|
|
if(isWOW)
|
|
{
|
|
info = ProcessWow64Information;
|
|
szBuffer = sizeof(processInformations.PebBaseAddress);
|
|
buffer = &processInformations.PebBaseAddress;
|
|
szPeb = sizeof(PEB_F32);
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
info = ProcessBasicInformation;
|
|
szBuffer = sizeof(processInformations);
|
|
buffer = &processInformations;
|
|
szPeb = sizeof(PEB);
|
|
#ifdef _M_X64
|
|
}
|
|
#endif
|
|
|
|
switch(memory->type)
|
|
{
|
|
#ifndef MIMIKATZ_W2000_SUPPORT
|
|
case KULL_M_MEMORY_TYPE_OWN:
|
|
if(!isWOW)
|
|
{
|
|
*pPeb = *RtlGetCurrentPeb();
|
|
status = TRUE;
|
|
break;
|
|
}
|
|
#endif
|
|
case KULL_M_MEMORY_TYPE_PROCESS:
|
|
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, info, buffer, szBuffer, &szInfos)) && (szInfos == szBuffer) && processInformations.PebBaseAddress)
|
|
{
|
|
aProcess.address = processInformations.PebBaseAddress;
|
|
status = kull_m_memory_copy(&aBuffer, &aProcess, szPeb);
|
|
}
|
|
break;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOL kull_m_process_ntheaders(PKULL_M_MEMORY_ADDRESS pBase, PIMAGE_NT_HEADERS * pHeaders)
|
|
{
|
|
BOOL status = FALSE;
|
|
IMAGE_DOS_HEADER headerImageDos;
|
|
KULL_M_MEMORY_ADDRESS aBuffer = {&headerImageDos, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aRealNtHeaders = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aProcess= {NULL, pBase->hMemory};
|
|
DWORD size;
|
|
|
|
if(kull_m_memory_copy(&aBuffer, pBase, sizeof(IMAGE_DOS_HEADER)) && headerImageDos.e_magic == IMAGE_DOS_SIGNATURE)
|
|
{
|
|
aProcess.address = (PBYTE) pBase->address + headerImageDos.e_lfanew;
|
|
if(aBuffer.address = LocalAlloc(LPTR, sizeof(DWORD) + IMAGE_SIZEOF_FILE_HEADER))
|
|
{
|
|
if(kull_m_memory_copy(&aBuffer, &aProcess, sizeof(DWORD) + IMAGE_SIZEOF_FILE_HEADER) && ((PIMAGE_NT_HEADERS) aBuffer.address)->Signature == IMAGE_NT_SIGNATURE);
|
|
{
|
|
size = (((PIMAGE_NT_HEADERS) aBuffer.address)->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) ? sizeof(IMAGE_NT_HEADERS32) : sizeof(IMAGE_NT_HEADERS64);
|
|
if(aRealNtHeaders.address = (PIMAGE_NT_HEADERS) LocalAlloc(LPTR, size))
|
|
{
|
|
status = kull_m_memory_copy(&aRealNtHeaders, &aProcess, size);
|
|
|
|
if(status)
|
|
*pHeaders = (PIMAGE_NT_HEADERS) aRealNtHeaders.address;
|
|
else
|
|
LocalFree(aRealNtHeaders.address);
|
|
}
|
|
}
|
|
LocalFree(aBuffer.address);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOL kull_m_process_datadirectory(PKULL_M_MEMORY_ADDRESS pBase, DWORD entry, PDWORD pRva, PDWORD pSize, PWORD pMachine, PVOID *pData)
|
|
{
|
|
BOOL status = FALSE;
|
|
KULL_M_MEMORY_ADDRESS aBuffer = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
|
KULL_M_MEMORY_ADDRESS aProcess= *pBase;
|
|
|
|
DWORD rva, size;
|
|
|
|
PIMAGE_NT_HEADERS pNtHeaders;
|
|
if(kull_m_process_ntheaders(pBase, &pNtHeaders))
|
|
{
|
|
if(pMachine)
|
|
*pMachine = pNtHeaders->FileHeader.Machine;
|
|
|
|
if(pNtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
|
{
|
|
rva = ((PIMAGE_NT_HEADERS32) pNtHeaders)->OptionalHeader.DataDirectory[entry].VirtualAddress;
|
|
size = ((PIMAGE_NT_HEADERS32) pNtHeaders)->OptionalHeader.DataDirectory[entry].Size;
|
|
}
|
|
else
|
|
{
|
|
rva = ((PIMAGE_NT_HEADERS64) pNtHeaders)->OptionalHeader.DataDirectory[entry].VirtualAddress;
|
|
size = ((PIMAGE_NT_HEADERS64) pNtHeaders)->OptionalHeader.DataDirectory[entry].Size;
|
|
}
|
|
|
|
if(pRva)
|
|
*pRva = rva;
|
|
if(pSize)
|
|
*pSize = size;
|
|
|
|
if(rva && size && pData)
|
|
{
|
|
if(*pData = LocalAlloc(LPTR, size))
|
|
{
|
|
aProcess.address = (PBYTE) pBase->address + rva;
|
|
aBuffer.address = *pData;
|
|
status = kull_m_memory_copy(&aBuffer, &aProcess, size);
|
|
|
|
if(!status)
|
|
LocalFree(*pData);
|
|
}
|
|
}
|
|
LocalFree(pNtHeaders);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOL kull_m_process_create(KULL_M_PROCESS_CREATE_TYPE type, PCWSTR commandLine, DWORD processFlags, HANDLE hUserToken, DWORD logonFlags, PCWSTR user, PCWSTR domain, PCWSTR password, PPROCESS_INFORMATION pProcessInfos, BOOL autoCloseHandle)
|
|
{
|
|
BOOL status = FALSE;
|
|
DWORD iProcessFlags = CREATE_NEW_CONSOLE | processFlags;
|
|
DWORD iLogonFlags = 0 | logonFlags;
|
|
PWSTR dupCommandLine;
|
|
PPROCESS_INFORMATION ptrProcessInfos;
|
|
STARTUPINFO startupInfo;
|
|
RtlZeroMemory(&startupInfo, sizeof(STARTUPINFO));
|
|
startupInfo.cb = sizeof(STARTUPINFO);
|
|
|
|
ptrProcessInfos = pProcessInfos ? pProcessInfos : (PPROCESS_INFORMATION) LocalAlloc(LPTR, sizeof(PROCESS_INFORMATION));
|
|
|
|
if(dupCommandLine = _wcsdup(commandLine))
|
|
{
|
|
switch(type)
|
|
{
|
|
case KULL_M_PROCESS_CREATE_NORMAL:
|
|
status = CreateProcess(NULL, dupCommandLine, NULL, NULL, FALSE, iProcessFlags, NULL, NULL, &startupInfo, ptrProcessInfos);
|
|
break;
|
|
case KULL_M_PROCESS_CREATE_USER:
|
|
status = CreateProcessAsUser(hUserToken, NULL, dupCommandLine, NULL, NULL, FALSE, iProcessFlags, NULL, NULL, &startupInfo, ptrProcessInfos);
|
|
break;
|
|
/*case KULL_M_PROCESS_CREATE_TOKEN:
|
|
status = CreateProcessWithTokenW(hUserToken, iLogonFlags, NULL, dupCommandLine, iProcessFlags, NULL, NULL, &startupInfo, ptrProcessInfos);
|
|
break;*/
|
|
case KULL_M_PROCESS_CREATE_LOGON:
|
|
status = CreateProcessWithLogonW(user, domain, password, iLogonFlags, NULL, dupCommandLine, iProcessFlags, NULL, NULL, &startupInfo, ptrProcessInfos);
|
|
break;
|
|
}
|
|
|
|
if(autoCloseHandle || !pProcessInfos)
|
|
{
|
|
CloseHandle(ptrProcessInfos->hThread);
|
|
CloseHandle(ptrProcessInfos->hProcess);
|
|
}
|
|
|
|
if(!pProcessInfos)
|
|
LocalFree(ptrProcessInfos);
|
|
free(dupCommandLine);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS kull_m_process_getExportedEntryInformations(PKULL_M_MEMORY_ADDRESS address, PKULL_M_EXPORTED_ENTRY_ENUM_CALLBACK callBack, PVOID pvArg)
|
|
{
|
|
PIMAGE_EXPORT_DIRECTORY pExportDir;
|
|
DWORD rva, size, i, j, rvaFunc;
|
|
KULL_M_PROCESS_EXPORTED_ENTRY exportedEntry;
|
|
BOOL continueCallback = TRUE;
|
|
|
|
if(kull_m_process_datadirectory(address, IMAGE_DIRECTORY_ENTRY_EXPORT, &rva, &size, &exportedEntry.machine, (PVOID *) &pExportDir))
|
|
{
|
|
exportedEntry.function.hMemory = exportedEntry.pRva.hMemory = address->hMemory;
|
|
for(i = 0; (i < pExportDir->NumberOfFunctions) && continueCallback ; i++)
|
|
{
|
|
if(rvaFunc = ((PDWORD) ((PBYTE) pExportDir + (pExportDir->AddressOfFunctions - rva)))[i])
|
|
{
|
|
exportedEntry.pRva.address = (PBYTE) address->address + pExportDir->AddressOfFunctions + (i * sizeof(DWORD));
|
|
exportedEntry.ordinal = i + 1;
|
|
for(j = 0, exportedEntry.hint = 0, exportedEntry.name = NULL; (j < pExportDir->NumberOfNames) && !exportedEntry.name && continueCallback; j++)
|
|
{
|
|
if(i == ((PWORD) ((PBYTE) pExportDir + (pExportDir->AddressOfNameOrdinals - rva)))[j])
|
|
{
|
|
exportedEntry.name = (PSTR) ((PBYTE) pExportDir + (((PDWORD) ((PBYTE) pExportDir + (pExportDir->AddressOfNames - rva)))[j] - rva));
|
|
exportedEntry.hint = j;
|
|
}
|
|
}
|
|
|
|
if((rvaFunc < rva) || (rvaFunc >= (rva + size)))
|
|
{
|
|
exportedEntry.function.address = (PBYTE) address->address + rvaFunc;
|
|
exportedEntry.redirect = NULL;
|
|
}
|
|
else
|
|
{
|
|
exportedEntry.function.address = NULL;
|
|
exportedEntry.redirect = (PSTR) ((PBYTE) pExportDir + (rvaFunc - rva));
|
|
}
|
|
|
|
continueCallback = callBack(&exportedEntry, pvArg);
|
|
}
|
|
}
|
|
LocalFree(pExportDir);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
PSTR kull_m_process_getImportNameWithoutEnd(PKULL_M_MEMORY_ADDRESS base)
|
|
{
|
|
CHAR sEnd = '\0';
|
|
SIZE_T size;
|
|
KULL_M_MEMORY_ADDRESS aStringBuffer = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aNullBuffer = {&sEnd, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
|
KULL_M_MEMORY_SEARCH sMemory = {{{base->address, base->hMemory}, MAX_PATH}, NULL};
|
|
|
|
if(kull_m_memory_search(&aNullBuffer, sizeof(sEnd), &sMemory, FALSE))
|
|
{
|
|
size = (PBYTE) sMemory.result - (PBYTE) base->address + sizeof(char);
|
|
if(aStringBuffer.address = LocalAlloc(LPTR, size))
|
|
if(!kull_m_memory_copy(&aStringBuffer, base, size))
|
|
aStringBuffer.address = LocalFree(aStringBuffer.address);
|
|
}
|
|
return (PSTR) aStringBuffer.address;
|
|
}
|
|
|
|
NTSTATUS kull_m_process_getImportedEntryInformations(PKULL_M_MEMORY_ADDRESS address, PKULL_M_IMPORTED_ENTRY_ENUM_CALLBACK callBack, PVOID pvArg)
|
|
{
|
|
PVOID pLocalBuffer;
|
|
PIMAGE_IMPORT_DESCRIPTOR pImportDir;
|
|
ULONG sizeThunk;
|
|
ULONGLONG OriginalFirstThunk, FirstThunk, ordinalPattern;
|
|
KULL_M_MEMORY_ADDRESS aOriginalFirstThunk = {&OriginalFirstThunk, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aFirstThunk = {&FirstThunk, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
|
KULL_M_MEMORY_ADDRESS aProcOriginalFirstThunk = {NULL, address->hMemory}, aProcName = {NULL, address->hMemory};
|
|
KULL_M_PROCESS_IMPORTED_ENTRY importedEntry;
|
|
BOOL continueCallback = TRUE;
|
|
|
|
importedEntry.pFunction.hMemory = address->hMemory;
|
|
importedEntry.function.hMemory = address->hMemory;
|
|
|
|
if(kull_m_process_datadirectory(address, IMAGE_DIRECTORY_ENTRY_IMPORT, NULL, NULL, &importedEntry.machine, &pLocalBuffer))
|
|
{
|
|
if(importedEntry.machine == IMAGE_FILE_MACHINE_I386)
|
|
{
|
|
sizeThunk = sizeof(IMAGE_THUNK_DATA32);
|
|
ordinalPattern = IMAGE_ORDINAL_FLAG32;
|
|
}
|
|
else
|
|
{
|
|
sizeThunk = sizeof(IMAGE_THUNK_DATA64);
|
|
ordinalPattern = IMAGE_ORDINAL_FLAG64;
|
|
}
|
|
|
|
for(pImportDir = (PIMAGE_IMPORT_DESCRIPTOR) pLocalBuffer ; pImportDir->Characteristics && continueCallback; pImportDir++)
|
|
{
|
|
aProcName.address = (PBYTE) address->address + pImportDir->Name;
|
|
if(importedEntry.libname = kull_m_process_getImportNameWithoutEnd(&aProcName))
|
|
{
|
|
for(
|
|
aProcOriginalFirstThunk.address = ((PBYTE) address->address + pImportDir->OriginalFirstThunk),
|
|
importedEntry.pFunction.address = ((PBYTE) address->address + pImportDir->FirstThunk);
|
|
|
|
(kull_m_memory_copy(&aOriginalFirstThunk, &aProcOriginalFirstThunk, sizeThunk) && kull_m_memory_copy(&aFirstThunk, &importedEntry.pFunction, sizeThunk)) && (OriginalFirstThunk && FirstThunk) ;
|
|
|
|
aProcOriginalFirstThunk.address = ((PBYTE) aProcOriginalFirstThunk.address + sizeThunk), ((PDWORD) &OriginalFirstThunk)[1] = 0,
|
|
importedEntry.pFunction.address = ((PBYTE) importedEntry.pFunction.address + sizeThunk), ((PDWORD) &FirstThunk)[1] = 0
|
|
)
|
|
{
|
|
importedEntry.function.address = (PVOID) FirstThunk;
|
|
if(OriginalFirstThunk & ordinalPattern)
|
|
{
|
|
importedEntry.name = NULL;
|
|
importedEntry.ordinal = IMAGE_ORDINAL(OriginalFirstThunk);
|
|
}
|
|
else
|
|
{
|
|
aProcName.address = ((PIMAGE_IMPORT_BY_NAME) ((PBYTE) address->address + OriginalFirstThunk))->Name;
|
|
importedEntry.name = kull_m_process_getImportNameWithoutEnd(&aProcName);
|
|
importedEntry.ordinal = 0;
|
|
}
|
|
|
|
continueCallback = callBack(&importedEntry, pvArg);
|
|
|
|
if(importedEntry.name)
|
|
LocalFree(importedEntry.name);
|
|
|
|
}
|
|
LocalFree(importedEntry.libname);
|
|
}
|
|
}
|
|
LocalFree(pLocalBuffer);
|
|
}
|
|
return TRUE;
|
|
} |