/// <summary> /// NtQueueApcThread /// </summary> /// <param name="hThread">Thread handle.</param> /// <param name="func">APC function</param> /// <param name="arg">APC argument</param> /// <returns>Status code</returns> NTSTATUS Native::QueueApcT( HANDLE hThread, ptr_t func, ptr_t arg ) { if (_wowBarrier.type == wow_64_32) { return SAFE_NATIVE_CALL( RtlQueueApcWow64Thread, hThread, reinterpret_cast<PVOID>(func), reinterpret_cast<PVOID>(arg), nullptr, nullptr ); //func = (~func) << 2; } return SAFE_NATIVE_CALL( NtQueueApcThread, hThread, reinterpret_cast<PVOID>(func), reinterpret_cast<PVOID>(arg), nullptr, nullptr ); }
/// <summary> /// Get native PEB /// </summary> /// <param name="ppeb">Retrieved PEB</param> /// <returns>PEB pointer</returns> ptr_t NativeWow64::getPEB( _PEB64* ppeb ) { _PROCESS_BASIC_INFORMATION_T<DWORD64> info = { 0 }; ULONG bytes = 0; SAFE_NATIVE_CALL( NtWow64QueryInformationProcess64, _hProcess, ProcessBasicInformation, &info, (ULONG)sizeof( info ), &bytes ); if (bytes > 0 && NT_SUCCESS( SAFE_NATIVE_CALL( NtWow64ReadVirtualMemory64, _hProcess, info.PebBaseAddress, ppeb, (ULONG)sizeof( _PEB64 ), nullptr ) )) return info.PebBaseAddress; return 0; }
ptr_t x86Native::GetTEB(HANDLE hThread, _TEB32* pteb) { _THREAD_BASIC_INFORMATION_T<DWORD> tbi = {0}; ULONG bytes = 0; if(NT_SUCCESS(SAFE_NATIVE_CALL(NtQueryInformationThread, hThread, (THREADINFOCLASS)0, &tbi, (ULONG)sizeof(tbi), &bytes)) && pteb) ReadProcessMemory(_hProcess, (LPCVOID)((uintptr_t)tbi.TebBaseAddress), pteb, sizeof(_TEB32), NULL); return tbi.TebBaseAddress; }
ptr_t x86Native::GetPEB(_PEB32* ppeb) { PROCESS_BASIC_INFORMATION pbi = {0}; ULONG bytes = 0; if(NT_SUCCESS(SAFE_NATIVE_CALL(NtQueryInformationProcess, _hProcess, ProcessBasicInformation, &pbi, (ULONG)sizeof(pbi), &bytes)) && ppeb) ReadProcessMemory(_hProcess, pbi.PebBaseAddress, ppeb, sizeof(_PEB32), NULL); return reinterpret_cast<ptr_t>(pbi.PebBaseAddress); }
/// <summary> /// Manually map PE image /// </summary> /// <param name="pid">Target PID</param> /// <param name="path">Full qualified image path</param> /// <param name="flags">Mapping flags</param> /// <param name="initRVA">Init routine RVA</param> /// <param name="initArg">Init routine argument</param> /// <returns>Status code</returns> NTSTATUS DriverControl::MmapDll( DWORD pid, const std::wstring& path, KMmapFlags flags, uint32_t initRVA /*= 0*/, const std::wstring& initArg /*= L"" */ ) { DWORD bytes = 0; INJECT_DLL data = { IT_MMap }; UNICODE_STRING ustr = { 0 }; // Convert path to native format SAFE_NATIVE_CALL( RtlDosPathNameToNtPathName_U, path.c_str(), &ustr, nullptr, nullptr ); wcscpy_s( data.FullDllPath, ustr.Buffer ); SAFE_CALL( RtlFreeUnicodeString, &ustr ); wcscpy_s( data.initArg, initArg.c_str() ); data.pid = pid; data.initRVA = initRVA; data.wait = true; data.unlink = false; data.erasePE = false; data.flags = flags; data.imageBase = 0; data.imageSize = 0; data.asImage = false; if (!DeviceIoControl( _hDriver, IOCTL_BLACKBONE_INJECT_DLL, &data, sizeof( data ), nullptr, 0, &bytes, NULL )) return LastNtStatus(); return STATUS_SUCCESS; }
/// <summary> /// Write virtual memory /// </summary> /// <param name="lpBaseAddress">Memory address</param> /// <param name="lpBuffer">Buffer to write</param> /// <param name="nSize">Number of bytes to read</param> /// <param name="lpBytes">Mumber of bytes read</param> /// <returns>Status code</returns> NTSTATUS NativeWow64::WriteProcessMemoryT( ptr_t lpBaseAddress, LPCVOID lpBuffer, size_t nSize, DWORD64 *lpBytes /*= nullptr */ ) { DWORD64 junk = 0; if (lpBytes == nullptr) lpBytes = &junk; return SAFE_NATIVE_CALL( NtWow64WriteVirtualMemory64, _hProcess, lpBaseAddress, (LPVOID)lpBuffer, nSize, lpBytes ); }
/// <summary> /// Get native TEB /// </summary> /// <param name="ppeb">Retrieved TEB</param> /// <returns>TEB pointer</returns> ptr_t Native::getTEB( HANDLE hThread, _TEB64* pteb ) { _THREAD_BASIC_INFORMATION_T<DWORD64> tbi = { 0 }; ULONG bytes = 0; if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationThread, hThread, (THREADINFOCLASS)0, &tbi, (ULONG)sizeof( tbi ), &bytes ) ) && pteb) ReadProcessMemory( _hProcess, reinterpret_cast<LPCVOID>(tbi.TebBaseAddress), pteb, sizeof(_TEB64), NULL ); return tbi.TebBaseAddress; }
/// <summary> /// Query virtual memory /// </summary> /// <param name="lpAddress">Address to query</param> /// <param name="lpBuffer">Retrieved memory info</param> /// <returns>Status code</returns> NTSTATUS Native::VirtualQueryExT( ptr_t lpAddress, MEMORY_INFORMATION_CLASS infoClass, LPVOID lpBuffer, size_t bufSize ) { SIZE_T retLen = 0; SetLastNtStatus( STATUS_SUCCESS ); return SAFE_NATIVE_CALL( NtQueryVirtualMemory, _hProcess, reinterpret_cast<LPVOID>(lpAddress), infoClass, lpBuffer, bufSize, &retLen ); }
/// <summary> /// Unload arbitrary driver /// </summary> /// <param name="svcName">Driver service name</param> /// <returns>Status</returns> NTSTATUS DriverControl::UnloadDriver( const std::wstring& svcName ) { UNICODE_STRING Ustr = { 0 }; std::wstring regPath = L"\\registry\\machine\\SYSTEM\\CurrentControlSet\\Services\\" + svcName; SAFE_CALL( RtlInitUnicodeString, &Ustr, regPath.c_str() ); // Remove previously loaded instance, if any NTSTATUS status = SAFE_NATIVE_CALL( NtUnloadDriver, &Ustr ); RegDeleteTreeW( HKEY_LOCAL_MACHINE, (L"SYSTEM\\CurrentControlSet\\Services\\" + svcName).c_str() ); return status; }
/// <summary> /// Load arbitrary driver /// </summary> /// <param name="svcName">Driver service name</param> /// <param name="path">Driver file path</param> /// <returns>Status</returns> NTSTATUS DriverControl::LoadDriver( const std::wstring& svcName, const std::wstring& path ) { UNICODE_STRING Ustr; // If no file provided, try to start existing service if (!path.empty() && PrepareDriverRegEntry( svcName, path ) != 0) return LastNtStatus(); std::wstring regPath = L"\\registry\\machine\\SYSTEM\\CurrentControlSet\\Services\\" + svcName; SAFE_CALL( RtlInitUnicodeString, &Ustr, regPath.c_str() ); return SAFE_NATIVE_CALL( NtLoadDriver, &Ustr ); }
/// <summary> /// Get WOW64 PEB /// </summary> /// <param name="ppeb">Retrieved PEB</param> /// <returns>PEB pointer</returns> ptr_t Native::getPEB( _PEB32* ppeb ) { // Target process is x64. PEB32 is not available. if (_wowBarrier.targetWow64 == false) { return 0; } else { ptr_t ptr = 0; if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationProcess, _hProcess, ProcessWow64Information, &ptr, (ULONG)sizeof( ptr ), nullptr ) ) && ppeb) ReadProcessMemory( _hProcess, reinterpret_cast<LPCVOID>(ptr), ppeb, sizeof(_PEB32), NULL ); return ptr; } }
/// <summary> /// Get WOW64 TEB /// </summary> /// <param name="ppeb">Retrieved TEB</param> /// <returns>TEB pointer</returns> ptr_t NativeWow64::getTEB( HANDLE hThread, _TEB32* pteb ) { // Target process is x64. TEB32 is not available. if (_wowBarrier.targetWow64 == false) { return 0; } else { _THREAD_BASIC_INFORMATION_T<DWORD> tbi = { 0 }; ULONG bytes = 0; if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationThread, hThread, (THREADINFOCLASS)0, &tbi, (ULONG)sizeof( tbi ), &bytes ) ) && pteb) ReadProcessMemory( _hProcess, (LPCVOID)((uintptr_t)tbi.TebBaseAddress), pteb, sizeof( _TEB32 ), nullptr ); return static_cast<ptr_t>(tbi.TebBaseAddress); } }
/// <summary> /// Gets WOW64 PEB /// </summary> /// <param name="ppeb">Retrieved PEB</param> /// <returns>PEB pointer</returns> ptr_t NativeWow64::getPEB( _PEB32* ppeb ) { // Target process is x64. PEB32 is not available. if (_wowBarrier.targetWow64 == false) { return 0; } else { PROCESS_BASIC_INFORMATION pbi = { 0 }; ULONG bytes = 0; if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationProcess, _hProcess, ProcessBasicInformation, &pbi, (ULONG)sizeof( pbi ), &bytes ) ) && ppeb) ReadProcessMemory( _hProcess, pbi.PebBaseAddress, ppeb, sizeof(_PEB32), NULL ); return reinterpret_cast<ptr_t>(pbi.PebBaseAddress); } }
/// <summary> /// GetThreadId support for XP /// </summary> /// <param name="hThread">Thread handle</param> /// <returns>Thread ID</returns> DWORD Thread::GetThreadIdT( HANDLE hThread ) { static auto pGetThreadId = (decltype(&GetThreadId))GetProcAddress( GetModuleHandleW( L"kernel32.dll" ), "GetThreadId" ); if (pGetThreadId != nullptr) { return pGetThreadId( hThread ); } // XP version else { _THREAD_BASIC_INFORMATION_T<DWORD> tbi = { 0 }; ULONG bytes = 0; if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationThread, hThread, (THREADINFOCLASS)0, &tbi, (ULONG)sizeof( tbi ), &bytes ) )) return tbi.ClientID.UniqueThread; return 0; } }
NTSTATUS x86Native::VirtualQueryExT(ptr_t lpAddress, PMEMORY_BASIC_INFORMATION64 lpBuffer) { MEMORY_BASIC_INFORMATION tmp = {0}; NTSTATUS status = SAFE_NATIVE_CALL( NtQueryVirtualMemory, _hProcess, reinterpret_cast<PVOID>(lpAddress), MemoryBasicInformation, &tmp, sizeof(tmp), nullptr ); if(status != STATUS_SUCCESS) return status; // Map values lpBuffer->AllocationBase = reinterpret_cast<ULONGLONG>(tmp.AllocationBase); lpBuffer->AllocationProtect = tmp.AllocationProtect; lpBuffer->BaseAddress = reinterpret_cast<ULONGLONG>(tmp.BaseAddress); lpBuffer->Protect = tmp.Protect; lpBuffer->RegionSize = tmp.RegionSize; lpBuffer->State = tmp.State; lpBuffer->Type = tmp.Type; return status; }
/// <summary> /// Manually map another system driver into system space /// </summary> /// <param name="path">Fully quialified path to the drver</param> /// <returns>Status code</returns> NTSTATUS DriverControl::MMapDriver( const std::wstring& path ) { DWORD bytes = 0; MMAP_DRIVER data = { { 0 } }; UNICODE_STRING ustr = { 0 }; // Not loaded if (_hDriver == INVALID_HANDLE_VALUE) return STATUS_DEVICE_DOES_NOT_EXIST; // Convert path to native format SAFE_NATIVE_CALL( RtlDosPathNameToNtPathName_U, path.c_str(), &ustr, nullptr, nullptr); wcscpy_s( data.FullPath, ustr.Buffer ); SAFE_CALL( RtlFreeUnicodeString, &ustr); if (!DeviceIoControl( _hDriver, IOCTL_BLACKBONE_MAP_DRIVER, &data, sizeof( data ), nullptr, 0, &bytes, NULL )) return LastNtStatus(); return STATUS_SUCCESS; }
/// <summary> /// Get native TEB /// </summary> /// <param name="ppeb">Retrieved TEB</param> /// <returns>TEB pointer</returns> ptr_t NativeWow64::getTEB( HANDLE hThread, _TEB64* pteb ) { _THREAD_BASIC_INFORMATION_T<DWORD64> info = { 0 }; ULONG bytes = 0; static ptr_t ntQit = _local.GetProcAddress64( _local.getNTDLL64(), "NtQueryInformationThread" ); if (ntQit == 0) { LastNtStatus( STATUS_ORDINAL_NOT_FOUND ); return 0; } _local.X64Call( ntQit, hThread, 0, &info, sizeof(info), &bytes ); if (bytes > 0 && NT_SUCCESS( SAFE_NATIVE_CALL( NtWow64ReadVirtualMemory64, _hProcess, info.TebBaseAddress, pteb, sizeof( _TEB64 ), nullptr ) )) return static_cast<ptr_t>(info.TebBaseAddress); return 0; }
/// <summary> /// Get WOW64 TEB /// </summary> /// <param name="ppeb">Retrieved TEB</param> /// <returns>TEB pointer</returns> ptr_t Native::getTEB( HANDLE hThread, _TEB32* pteb ) { // Target process is x64. TEB32 is not available. if (_wowBarrier.targetWow64 == false) { return 0; } // Retrieving TEB32 from x64 process. else { _THREAD_BASIC_INFORMATION_T<DWORD64> tbi = { 0 }; ULONG bytes = 0; if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationThread, hThread, (THREADINFOCLASS)0, &tbi, (ULONG)sizeof( tbi ), &bytes ) ) && pteb) ReadProcessMemory( _hProcess, (const uint8_t*)tbi.TebBaseAddress + 0x2000, pteb, sizeof(_TEB32), NULL ); return tbi.TebBaseAddress + 0x2000; } }
/// <summary> /// Call NtQueryInformationProcess for underlying process /// </summary> /// <param name="infoClass">Information class</param> /// <param name="lpBuffer">Output buffer</param> /// <param name="bufSize">Buffer size</param> /// <returns>Status code</returns> NTSTATUS Native::QueryProcessInfoT( PROCESSINFOCLASS infoClass, LPVOID lpBuffer, uint32_t bufSize ) { ULONG length = 0; return SAFE_NATIVE_CALL( NtQueryInformationProcess, _hProcess, infoClass, lpBuffer, bufSize, &length ); }
/// <summary> /// Search for process by executable name or by process ID /// </summary> /// <param name="pid">Target process ID. rocess name. If empty - function will retrieve all existing processes</param> /// <param name="name">Process executable name. If empty - function will retrieve all existing processes</param> /// <param name="found">Found processses</param> /// <param name="includeThreads">If set to true, function will retrieve info ablout process threads</param> /// <returns>Status code</returns> NTSTATUS Process::EnumByNameOrPID( uint32_t pid, const std::wstring& name, std::vector<ProcessInfo>& found, bool includeThreads /*= false*/ ) { ULONG bufSize = 0x100; uint8_t tmpbuf[0x100]; uint8_t* buffer = tmpbuf; ULONG returnLength = 0; found.clear(); // Query process info NTSTATUS status = SAFE_NATIVE_CALL( NtQuerySystemInformation, (SYSTEM_INFORMATION_CLASS)57, buffer, bufSize, &returnLength ); if (!NT_SUCCESS( status )) { bufSize = returnLength; buffer = (uint8_t*)VirtualAlloc( NULL, bufSize, MEM_COMMIT, PAGE_READWRITE ); status = SAFE_NATIVE_CALL( NtQuerySystemInformation, (SYSTEM_INFORMATION_CLASS)57, buffer, bufSize, &returnLength ); if (!NT_SUCCESS( status )) { VirtualFree( buffer, 0, MEM_RELEASE ); return status; } } // Parse info for (auto pInfo = reinterpret_cast<_SYSTEM_PROCESS_INFORMATION_T<DWORD_PTR>*>(buffer);;) { // Skip idle process, compare name or compare pid if (pInfo->UniqueProcessId != 0 && ((name.empty() && pid == 0) || _wcsicmp( name.c_str(), (wchar_t*)pInfo->ImageName.Buffer ) == 0 || pid == pInfo->UniqueProcessId)) { ProcessInfo info; info.pid = static_cast<uint32_t>(pInfo->UniqueProcessId); if (pInfo->ImageName.Buffer) info.imageName = reinterpret_cast<wchar_t*>(pInfo->ImageName.Buffer); // Get threads info if (includeThreads) { int64_t minTime = 0xFFFFFFFFFFFFFFFF; ULONG mainIdx = 0; for (ULONG i = 0; i < pInfo->NumberOfThreads; i++) { ThreadInfo tinfo; auto& thd = pInfo->Threads[i]; tinfo.tid = static_cast<uint32_t>(thd.ThreadInfo.ClientId.UniqueThread); tinfo.startAddress = static_cast<uintptr_t>(thd.ThreadInfo.StartAddress); // Check for main thread if (thd.ThreadInfo.CreateTime.QuadPart < minTime) { minTime = thd.ThreadInfo.CreateTime.QuadPart; mainIdx = i; } info.threads.emplace_back( tinfo ); info.threads[mainIdx].mainThread = true; } } found.emplace_back( info ); } if (pInfo->NextEntryOffset) pInfo = reinterpret_cast<_SYSTEM_PROCESS_INFORMATION_T<DWORD_PTR>*>((uint8_t*)pInfo + pInfo->NextEntryOffset); else break; } // Sort results std::sort( found.begin(), found.end() ); VirtualFree( buffer, 0, MEM_RELEASE ); return status; }
/// <summary> /// Enumerate all open handles /// </summary> /// <param name="handles">Found handles</param> /// <returns>Status code</returns> NTSTATUS Process::EnumHandles( std::vector<HandleInfo>& handles ) { ULONG bufSize = 0x10000; uint8_t* buffer = (uint8_t*)VirtualAlloc( NULL, bufSize, MEM_COMMIT, PAGE_READWRITE ); ULONG returnLength = 0; // Query handle list NTSTATUS status = SAFE_NATIVE_CALL( NtQuerySystemInformation, SystemHandleInformation, buffer, bufSize, &returnLength); while (status == STATUS_INFO_LENGTH_MISMATCH) { bufSize *= 2; VirtualFree( buffer, 0, MEM_RELEASE ); buffer = (uint8_t*)VirtualAlloc( NULL, bufSize, MEM_COMMIT, PAGE_READWRITE ); status = SAFE_NATIVE_CALL( NtQuerySystemInformation, SystemHandleInformation, buffer, bufSize, &returnLength); } if (!NT_SUCCESS( status )) { VirtualFree( buffer, 0, MEM_RELEASE ); return status; } SYSTEM_HANDLE_INFORMATION_T* handleInfo = (SYSTEM_HANDLE_INFORMATION_T*)buffer; for (ULONG i = 0; i < handleInfo->HandleCount; i++) { HandleInfo info; HANDLE hLocal = NULL; OBJECT_TYPE_INFORMATION_T* pTypeInfo = nullptr; PVOID pNameInfo = nullptr; UNICODE_STRING objectName = { 0 }; ULONG returnLength = 0; // Filter process if (handleInfo->Handles[i].ProcessId != _core._pid) continue; // Get local handle copy status = SAFE_NATIVE_CALL( NtDuplicateObject, _core._hProcess, reinterpret_cast<HANDLE>(handleInfo->Handles[i].Handle), GetCurrentProcess(), &hLocal, 0, 0, DUPLICATE_SAME_ACCESS); if (!NT_SUCCESS( status )) continue; // // Get type information // pTypeInfo = (OBJECT_TYPE_INFORMATION_T*)malloc( 0x1000 ); status = SAFE_NATIVE_CALL( NtQueryObject, hLocal, ObjectTypeInformation, pTypeInfo, 0x1000, nullptr ); if (!NT_SUCCESS( status )) { CloseHandle( hLocal ); continue; } // // Obtain object name // pNameInfo = malloc( 0x1000 ); status = SAFE_NATIVE_CALL( NtQueryObject, hLocal, ObjectNameInformation, pNameInfo, 0x1000, &returnLength); if (!NT_SUCCESS( status )) { pNameInfo = realloc( pNameInfo, returnLength ); status = SAFE_NATIVE_CALL( NtQueryObject, hLocal, ObjectNameInformation, pNameInfo, returnLength, nullptr ); if (!NT_SUCCESS( status )) { free( pTypeInfo ); free( pNameInfo ); CloseHandle( hLocal ); continue; } } objectName = *(PUNICODE_STRING)pNameInfo; // // Fill handle info structure // info.handle = reinterpret_cast<HANDLE>(handleInfo->Handles[i].Handle); info.access = handleInfo->Handles[i].GrantedAccess; info.flags = handleInfo->Handles[i].Flags; info.pObject = handleInfo->Handles[i].Object; if (pTypeInfo->Name.Length) info.typeName = (wchar_t*)pTypeInfo->Name.Buffer; if (objectName.Length) info.name = objectName.Buffer; // // Type-specific info // if (_wcsicmp( info.typeName.c_str(), L"Section" ) == 0) { SECTION_BASIC_INFORMATION_T secInfo = { 0 }; status = SAFE_NATIVE_CALL( NtQuerySection, hLocal, SectionBasicInformation, &secInfo, (ULONG)sizeof( secInfo ), nullptr ); if (NT_SUCCESS( status )) { info.section.reset( new SectionInfo() ); info.section->size = secInfo.Size.QuadPart; info.section->attrib = secInfo.Attributes; } } handles.emplace_back( info ); free( pTypeInfo ); free( pNameInfo ); CloseHandle( hLocal ); } VirtualFree( buffer, 0, MEM_RELEASE ); return status; }
/// <summary> /// Call NtSetInformationProcess for underlying process /// </summary> /// <param name="infoClass">Information class</param> /// <param name="lpBuffer">Input buffer</param> /// <param name="bufSize">Buffer size</param> /// <returns>Status code</returns> NTSTATUS Native::SetProcessInfoT( PROCESSINFOCLASS infoClass, LPVOID lpBuffer, uint32_t bufSize ) { return SAFE_NATIVE_CALL( NtSetInformationProcess, _hProcess, infoClass, lpBuffer, bufSize ); }
/// <summary> /// Suspend process /// </summary> /// <returns>Status code</returns> NTSTATUS Process::Suspend() { return SAFE_NATIVE_CALL( NtSuspendProcess, _core._hProcess ); }
/// <summary> /// Create event to synchronize APC procedures /// </summary> /// <param name="threadID">The thread identifier.</param> /// <returns>Status code</returns> NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID ) { NTSTATUS status = STATUS_SUCCESS; if(_hWaitEvent == NULL) { AsmJitHelper a; wchar_t pEventName[128] = { 0 }; uint64_t dwResult = NULL; size_t len = sizeof(pEventName); OBJECT_ATTRIBUTES obAttr = { 0 }; UNICODE_STRING ustr = { 0 }; // Detect ntdll type eModType mt = mt_default; if (_memory.core().native()->GetWow64Barrier().type == wow_64_32) mt = mt_mod64; // Event name swprintf_s( pEventName, ARRAYSIZE( pEventName ), L"\\BaseNamedObjects\\_MMapEvent_0x%x_0x%x", threadID, GetTickCount() ); // Prepare Arguments ustr.Length = static_cast<USHORT>(wcslen( pEventName ) * sizeof(wchar_t)); ustr.MaximumLength = static_cast<USHORT>(sizeof(pEventName)); ustr.Buffer = reinterpret_cast<PWSTR>(_userData.ptr<size_t>() + ARGS_OFFSET + sizeof(obAttr) + sizeof(ustr)); obAttr.ObjectName = reinterpret_cast<PUNICODE_STRING>(_userData.ptr<size_t>() + ARGS_OFFSET + sizeof(obAttr)); obAttr.Length = sizeof(obAttr); auto pCreateEvent = _mods.GetExport( _mods.GetModule( L"ntdll.dll", Sections, mt ), "NtCreateEvent" ).procAddress; if (pCreateEvent == 0) return false; a.GenCall( static_cast<size_t>(pCreateEvent), { _userData.ptr<size_t>() + EVENT_OFFSET, EVENT_ALL_ACCESS, _userData.ptr<size_t>() + ARGS_OFFSET, 0, FALSE } ); // Save status a->mov( a->zdx, _userData.ptr<size_t>() + ERR_OFFSET ); a->mov( asmjit::host::dword_ptr( a->zdx ), asmjit::host::eax ); a->ret(); status = _userData.Write( ARGS_OFFSET, obAttr ); status |= _userData.Write( ARGS_OFFSET + sizeof(obAttr), ustr ); status |= _userData.Write( ARGS_OFFSET + sizeof(obAttr) + sizeof(ustr), len, pEventName ); if (!NT_SUCCESS( status )) return LastNtStatus( status ); ExecInNewThread( a->make(), a->getCodeSize(), dwResult ); status = _userData.Read<NTSTATUS>( ERR_OFFSET, -1 ); if (!NT_SUCCESS( status )) return LastNtStatus( status ); ustr.Buffer = pEventName; obAttr.ObjectName = &ustr; // Open created event status = SAFE_NATIVE_CALL( NtOpenEvent, &_hWaitEvent, SYNCHRONIZE | EVENT_MODIFY_STATE, &obAttr ); } return status; }
/// <summary> /// Resume process /// </summary> /// <returns>Status code</returns> NTSTATUS Process::Resume() { return SAFE_NATIVE_CALL( NtResumeProcess, _core._hProcess ); }