Skip to content

Commit

Permalink
fix for DarthTon#27: safely call Dynamically imported functions
Browse files Browse the repository at this point in the history
  • Loading branch information
DarthTon committed May 12, 2015
1 parent 29b3222 commit 61f115d
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 93 deletions.
26 changes: 15 additions & 11 deletions src/BlackBone/DriverControl/DriverControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ namespace blackbone

DriverControl::DriverControl()
{
DynImport::load( "NtLoadDriver", GetModuleHandleW( L"ntdll.dll" ) );
DynImport::load( "NtUnloadDriver", GetModuleHandleW( L"ntdll.dll" ) );
DynImport::load( "RtlDosPathNameToNtPathName_U", GetModuleHandleW( L"ntdll.dll" ) );
HMODULE ntdll = GetModuleHandleW( L"ntdll.dll" );

DynImport::load( "NtLoadDriver", ntdll );
DynImport::load( "NtUnloadDriver", ntdll );
DynImport::load( "RtlDosPathNameToNtPathName_U", ntdll );
DynImport::load( "RtlInitUnicodeString", ntdll );
DynImport::load( "RtlFreeUnicodeString", ntdll );
}


Expand Down Expand Up @@ -546,9 +550,9 @@ NTSTATUS DriverControl::MmapDll(
UNICODE_STRING ustr = { 0 };

// Convert path to native format
GET_IMPORT( RtlDosPathNameToNtPathName_U )(path.c_str(), &ustr, NULL, NULL);
SAFE_NATIVE_CALL( RtlDosPathNameToNtPathName_U, path.c_str(), &ustr, nullptr, nullptr );
wcscpy_s( data.FullDllPath, ustr.Buffer );
GET_IMPORT( RtlFreeUnicodeString )(&ustr);
SAFE_CALL( RtlFreeUnicodeString, &ustr );

wcscpy_s( data.initArg, initArg.c_str() );

Expand Down Expand Up @@ -628,9 +632,9 @@ NTSTATUS DriverControl::MMapDriver( const std::wstring& path )
return STATUS_DEVICE_DOES_NOT_EXIST;

// Convert path to native format
GET_IMPORT( RtlDosPathNameToNtPathName_U )(path.c_str(), &ustr, NULL, NULL);
SAFE_NATIVE_CALL( RtlDosPathNameToNtPathName_U, path.c_str(), &ustr, nullptr, nullptr);
wcscpy_s( data.FullPath, ustr.Buffer );
GET_IMPORT( RtlFreeUnicodeString )(&ustr);
SAFE_CALL( RtlFreeUnicodeString, &ustr);

if (!DeviceIoControl( _hDriver, IOCTL_BLACKBONE_MAP_DRIVER, &data, sizeof( data ), nullptr, 0, &bytes, NULL ))
return LastNtStatus();
Expand Down Expand Up @@ -703,9 +707,9 @@ NTSTATUS DriverControl::LoadDriver( const std::wstring& svcName, const std::wstr
return LastNtStatus();

std::wstring regPath = L"\\registry\\machine\\SYSTEM\\CurrentControlSet\\Services\\" + svcName;
GET_IMPORT( RtlInitUnicodeString )(&Ustr, regPath.c_str());
SAFE_CALL( RtlInitUnicodeString, &Ustr, regPath.c_str() );

return GET_IMPORT( NtLoadDriver )(&Ustr);
return SAFE_NATIVE_CALL( NtLoadDriver, &Ustr );
}


Expand All @@ -719,10 +723,10 @@ NTSTATUS DriverControl::UnloadDriver( const std::wstring& svcName )
UNICODE_STRING Ustr = { 0 };

std::wstring regPath = L"\\registry\\machine\\SYSTEM\\CurrentControlSet\\Services\\" + svcName;
GET_IMPORT( RtlInitUnicodeString )(&Ustr, regPath.c_str());
SAFE_CALL( RtlInitUnicodeString, &Ustr, regPath.c_str() );

// Remove previously loaded instance, if any
NTSTATUS status = GET_IMPORT( NtUnloadDriver )(&Ustr);
NTSTATUS status = SAFE_NATIVE_CALL( NtUnloadDriver, &Ustr );
RegDeleteTreeW( HKEY_LOCAL_MACHINE, (L"SYSTEM\\CurrentControlSet\\Services\\" + svcName).c_str() );

return status;
Expand Down
46 changes: 26 additions & 20 deletions src/BlackBone/ManualMap/Native/NtLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ _LDR_DATA_TABLE_ENTRY_W8* NtLdr::InitW8Node(
_process.memory().Write( GET_FIELD_PTR( pEntry, EntryPoint ), entryPoint );

// Dll name and name hash
GET_IMPORT( RtlInitUnicodeString )( &strLocal, dllname.c_str() );
SAFE_CALL( RtlInitUnicodeString, &strLocal, dllname.c_str() );
outHash = HashString( dllname );

// Write into buffer
Expand All @@ -409,7 +409,7 @@ _LDR_DATA_TABLE_ENTRY_W8* NtLdr::InitW8Node(
_process.memory().Write( GET_FIELD_PTR( pEntry, BaseDllName ), strLocal );

// Dll full path
GET_IMPORT( RtlInitUnicodeString )( &strLocal, dllpath.c_str() );
SAFE_CALL( RtlInitUnicodeString, &strLocal, dllpath.c_str() );
strLocal.Buffer = reinterpret_cast<PWSTR>(StringBuf.ptr<uint8_t*>( ) + 0x800);
StringBuf.Write( 0x800, dllpath.length() * sizeof(wchar_t) + 2, dllpath.c_str() );

Expand Down Expand Up @@ -516,7 +516,7 @@ _LDR_DATA_TABLE_ENTRY_W7* NtLdr::InitW7Node(
_process.memory().Write( GET_FIELD_PTR( pEntry, LoadCount ), -1 );

// Dll name
GET_IMPORT( RtlInitUnicodeString )( &strLocal, dllname.c_str() );
SAFE_CALL( RtlInitUnicodeString, &strLocal, dllname.c_str() );

// Name hash
outHash = HashString( dllname );
Expand All @@ -529,7 +529,7 @@ _LDR_DATA_TABLE_ENTRY_W7* NtLdr::InitW7Node(
_process.memory().Write( GET_FIELD_PTR( pEntry, BaseDllName ), strLocal );

// Dll full path
GET_IMPORT( RtlInitUnicodeString )( &strLocal, dllpath.c_str() );
SAFE_CALL( RtlInitUnicodeString, &strLocal, dllpath.c_str() );
strLocal.Buffer = reinterpret_cast<PWSTR>(StringBuf.ptr<uint8_t*>() + 0x800);
StringBuf.Write( 0x800, dllpath.length() * sizeof(wchar_t) + 2, dllpath.c_str() );

Expand Down Expand Up @@ -699,13 +699,13 @@ ULONG NtLdr::HashString( const std::wstring& str )
if (IsWindows8OrGreater())
{
UNICODE_STRING ustr;
GET_IMPORT( RtlInitUnicodeString )(&ustr, str.c_str( ));
GET_IMPORT( RtlHashUnicodeString )(&ustr, TRUE, 0, &hash);
SAFE_CALL( RtlInitUnicodeString, &ustr, str.c_str() );
SAFE_NATIVE_CALL( RtlHashUnicodeString, &ustr, (BOOLEAN)TRUE, 0, &hash );
}
else
{
for (auto& ch : str)
hash += 0x1003F * static_cast<unsigned short>(GET_IMPORT( RtlUpcaseUnicodeChar )(ch));
hash += 0x1003F * static_cast<unsigned short>(SAFE_CALL( RtlUpcaseUnicodeChar, ch ));
}

return hash;
Expand All @@ -723,7 +723,7 @@ bool NtLdr::FindLdrpHashTable( )
reinterpret_cast<TEB_T*>(NtCurrentTeb())->ProcessEnvironmentBlock)->Ldr);

LDR_DATA_TABLE_ENTRY_BASE_T *Ntdll = CONTAINING_RECORD( Ldr->InInitializationOrderModuleList.Flink,
LDR_DATA_TABLE_ENTRY_BASE_T, InInitializationOrderLinks );
LDR_DATA_TABLE_ENTRY_BASE_T, InInitializationOrderLinks );

ULONG NtdllHashIndex = HashString( reinterpret_cast<wchar_t*>(Ntdll->BaseDllName.Buffer) ) & 0x1F;

Expand Down Expand Up @@ -1101,22 +1101,28 @@ ptr_t NtLdr::UnlinkFromLdr( ptr_t baseAddress, const std::wstring& name )
ptr_t ldrEntry = 0;

// InLoadOrderModuleList
ldrEntry |= UnlinkListEntry( ldr.InLoadOrderModuleList,
peb.Ldr + FIELD_OFFSET( _PEB_LDR_DATA2<T>, InLoadOrderModuleList ),
FIELD_OFFSET( _LDR_DATA_TABLE_ENTRY_BASE<T>, InLoadOrderLinks ),
baseAddress );
ldrEntry |= UnlinkListEntry(
ldr.InLoadOrderModuleList,
peb.Ldr + FIELD_OFFSET( _PEB_LDR_DATA2<T>, InLoadOrderModuleList ),
FIELD_OFFSET( _LDR_DATA_TABLE_ENTRY_BASE<T>, InLoadOrderLinks ),
baseAddress
);

// InMemoryOrderModuleList
ldrEntry |= UnlinkListEntry( ldr.InMemoryOrderModuleList,
peb.Ldr + FIELD_OFFSET( _PEB_LDR_DATA2<T>, InMemoryOrderModuleList ),
FIELD_OFFSET( _LDR_DATA_TABLE_ENTRY_BASE<T>, InMemoryOrderLinks ),
baseAddress );
ldrEntry |= UnlinkListEntry(
ldr.InMemoryOrderModuleList,
peb.Ldr + FIELD_OFFSET( _PEB_LDR_DATA2<T>, InMemoryOrderModuleList ),
FIELD_OFFSET( _LDR_DATA_TABLE_ENTRY_BASE<T>, InMemoryOrderLinks ),
baseAddress
);

// InInitializationOrderModuleList
ldrEntry |= UnlinkListEntry( ldr.InInitializationOrderModuleList,
peb.Ldr + FIELD_OFFSET( _PEB_LDR_DATA2<T>, InInitializationOrderModuleList ),
FIELD_OFFSET( _LDR_DATA_TABLE_ENTRY_BASE<T>, InInitializationOrderLinks ),
baseAddress );
ldrEntry |= UnlinkListEntry(
ldr.InInitializationOrderModuleList,
peb.Ldr + FIELD_OFFSET( _PEB_LDR_DATA2<T>, InInitializationOrderModuleList ),
FIELD_OFFSET( _LDR_DATA_TABLE_ENTRY_BASE<T>, InInitializationOrderLinks ),
baseAddress
);

// Hash table
if (ldrEntry == 0)
Expand Down
30 changes: 30 additions & 0 deletions src/BlackBone/Misc/DynImport.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,34 @@ class DynImport
return nullptr;
}

/// <summary>
/// Safely call import
/// If import not found - return STATUS_ORDINAL_NOT_FOUND
/// </summary>
/// <param name="name">Import name.</param>
/// <param name="...args">Function args</param>
/// <returns>Function result or STATUS_ORDINAL_NOT_FOUND if import not found</returns>
template<typename T, typename... Args>
inline static NTSTATUS safeNativeCall( const std::string& name, Args... args )
{
auto pfn = DynImport::get<T>( name );
return pfn ? pfn( std::forward<Args>( args )... ) : STATUS_ORDINAL_NOT_FOUND;
}

/// <summary>
/// Safely call import
/// If import not found - return 0
/// </summary>
/// <param name="name">Import name.</param>
/// <param name="...args">Function args</param>
/// <returns>Function result or 0 if import not found</returns>
template<typename T, typename... Args>
inline static auto safeCall( const std::string& name, Args... args ) -> typename std::result_of<T(Args...)>::type
{
auto pfn = DynImport::get<T>( name );
return pfn ? pfn( std::forward<Args>( args )... ) : (std::result_of<T( Args... )>::type )(0);
}

/// <summary>
/// Load function into database
/// </summary>
Expand All @@ -55,5 +83,7 @@ class DynImport

// Syntax sugar
#define GET_IMPORT(name) (DynImport::get<fn ## name>( #name ))
#define SAFE_NATIVE_CALL(name, ...) (DynImport::safeNativeCall<fn ## name>( #name, __VA_ARGS__ ))
#define SAFE_CALL(name, ...) (DynImport::safeCall<fn ## name>( #name, __VA_ARGS__ ))

}
12 changes: 7 additions & 5 deletions src/BlackBone/Misc/NameResolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ NTSTATUS NameResolve::ProbeSxSRedirect( std::wstring& path, HANDLE actx /*= INVA
if (GET_IMPORT( RtlDosApplyFileIsolationRedirection_Ustr ) == nullptr)
return STATUS_ORDINAL_NOT_FOUND;

GET_IMPORT( RtlInitUnicodeString )( &OriginalName, path.c_str()) ;
SAFE_CALL( RtlInitUnicodeString, &OriginalName, path.c_str() );

DllName1.Buffer = wBuf;
DllName1.Length = NULL;
Expand All @@ -324,9 +324,11 @@ NTSTATUS NameResolve::ProbeSxSRedirect( std::wstring& path, HANDLE actx /*= INVA
ActivateActCtx( actx, &cookie );

// SxS resolve
NTSTATUS status = GET_IMPORT( RtlDosApplyFileIsolationRedirection_Ustr )( TRUE, &OriginalName, NULL,
&DllName1, &DllName2, &pPath,
NULL, NULL, NULL );
NTSTATUS status = SAFE_NATIVE_CALL(
RtlDosApplyFileIsolationRedirection_Ustr, TRUE, &OriginalName, (PUNICODE_STRING)NULL,
&DllName1, &DllName2, &pPath,
nullptr, nullptr, nullptr
);

if (cookie != 0 && actx != INVALID_HANDLE_VALUE)
DeactivateActCtx( 0, cookie );
Expand All @@ -338,7 +340,7 @@ NTSTATUS NameResolve::ProbeSxSRedirect( std::wstring& path, HANDLE actx /*= INVA
else
{
if (DllName2.Buffer)
GET_IMPORT( RtlFreeUnicodeString )( &DllName2 );
SAFE_CALL( RtlFreeUnicodeString, &DllName2);
}

return LastNtStatus( status );
Expand Down
18 changes: 9 additions & 9 deletions src/BlackBone/Process/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,14 @@ NTSTATUS Process::EnumHandles( std::vector<HandleInfo>& handles )
ULONG returnLength = 0;

// Query handle list
NTSTATUS status = GET_IMPORT( NtQuerySystemInformation )(SystemHandleInformation, buffer, bufSize, &returnLength);
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 = GET_IMPORT( NtQuerySystemInformation )(SystemHandleInformation, buffer, bufSize, &returnLength);
status = SAFE_NATIVE_CALL( NtQuerySystemInformation, SystemHandleInformation, buffer, bufSize, &returnLength);
}

if (!NT_SUCCESS( status ))
Expand All @@ -227,15 +227,15 @@ NTSTATUS Process::EnumHandles( std::vector<HandleInfo>& handles )
continue;

// Get local handle copy
status = GET_IMPORT( NtDuplicateObject )(_core._hProcess, reinterpret_cast<HANDLE>(handleInfo->Handles[i].Handle), GetCurrentProcess(), &hLocal, 0, 0, DUPLICATE_SAME_ACCESS);
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 = GET_IMPORT( NtQueryObject )(hLocal, ObjectTypeInformation, pTypeInfo, 0x1000, NULL);
status = SAFE_NATIVE_CALL( NtQueryObject, hLocal, ObjectTypeInformation, pTypeInfo, 0x1000, nullptr );
if (!NT_SUCCESS( status ))
{
CloseHandle( hLocal );
Expand All @@ -246,11 +246,11 @@ NTSTATUS Process::EnumHandles( std::vector<HandleInfo>& handles )
// Obtain object name
//
pNameInfo = malloc( 0x1000 );
status = GET_IMPORT( NtQueryObject )(hLocal, ObjectNameInformation, pNameInfo, 0x1000, &returnLength);
status = SAFE_NATIVE_CALL( NtQueryObject, hLocal, ObjectNameInformation, pNameInfo, 0x1000, &returnLength);
if (!NT_SUCCESS( status ))
{
pNameInfo = realloc( pNameInfo, returnLength );
status = GET_IMPORT( NtQueryObject )(hLocal, ObjectNameInformation, pNameInfo, returnLength, NULL);
status = SAFE_NATIVE_CALL( NtQueryObject, hLocal, ObjectNameInformation, pNameInfo, returnLength, nullptr );
if (!NT_SUCCESS( status ))
{
free( pTypeInfo );
Expand Down Expand Up @@ -283,7 +283,7 @@ NTSTATUS Process::EnumHandles( std::vector<HandleInfo>& handles )
{
SECTION_BASIC_INFORMATION_T secInfo = { 0 };

status = GET_IMPORT( NtQuerySection )(hLocal, SectionBasicInformation, &secInfo, sizeof( secInfo ), NULL);
status = SAFE_NATIVE_CALL( NtQuerySection, hLocal, SectionBasicInformation, &secInfo, (ULONG)sizeof( secInfo ), nullptr );
if (NT_SUCCESS( status ))
{
info.section.reset( new SectionInfo() );
Expand Down Expand Up @@ -394,12 +394,12 @@ NTSTATUS Process::EnumByNameOrPID(
found.clear();

// Query process info
NTSTATUS status = GET_IMPORT( NtQuerySystemInformation )((SYSTEM_INFORMATION_CLASS)57, buffer, bufSize, &returnLength);
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 = GET_IMPORT( NtQuerySystemInformation )((SYSTEM_INFORMATION_CLASS)57, buffer, bufSize, &returnLength);
status = SAFE_NATIVE_CALL( NtQuerySystemInformation, (SYSTEM_INFORMATION_CLASS)57, buffer, bufSize, &returnLength );
if (!NT_SUCCESS( status ))
{
VirtualFree( buffer, 0, MEM_RELEASE );
Expand Down
2 changes: 1 addition & 1 deletion src/BlackBone/Process/ProcessCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ NTSTATUS ProcessCore::Init()
DWORD flags = 0;
BOOL perm = 0;

if (GET_IMPORT( GetProcessDEPPolicy )(_hProcess, &flags, &perm))
if (SAFE_CALL( GetProcessDEPPolicy, _hProcess, &flags, &perm ))
_dep = (flags & PROCESS_DEP_ENABLE) != 0;
}

Expand Down
2 changes: 1 addition & 1 deletion src/BlackBone/Process/RPC/RemoteExec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID )
obAttr.ObjectName = &ustr;

// Open created event
status = GET_IMPORT( NtOpenEvent )( &_hWaitEvent, SYNCHRONIZE | EVENT_MODIFY_STATE, &obAttr );
status = SAFE_NATIVE_CALL( NtOpenEvent, &_hWaitEvent, SYNCHRONIZE | EVENT_MODIFY_STATE, &obAttr );
}

return status;
Expand Down
10 changes: 5 additions & 5 deletions src/BlackBone/Process/Threads/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ bool Thread::Suspend()

// Target process is x86 and not running on x86 OS
if (_core->isWow64() && !_core->native()->GetWow64Barrier().x86OS)
return (GET_IMPORT(Wow64SuspendThread)( _handle ) != -1);
return (SAFE_CALL(Wow64SuspendThread, _handle ) != -1);
else
return (SuspendThread( _handle ) != -1);
}
Expand All @@ -90,8 +90,8 @@ bool Thread::Resume()
/// <returns>true if suspended</returns>
bool Thread::Suspended()
{
auto count = (_core->isWow64() && !_core->native()->GetWow64Barrier().x86OS)
? GET_IMPORT( Wow64SuspendThread )(_handle)
auto count = (_core->isWow64() && !_core->native()->GetWow64Barrier().x86OS)
? SAFE_CALL( Wow64SuspendThread, _handle )
: SuspendThread( _handle );

ResumeThread( _handle );
Expand Down Expand Up @@ -399,8 +399,8 @@ DWORD Thread::GetThreadIdT( HANDLE hThread )
{
_THREAD_BASIC_INFORMATION_T<DWORD> tbi = { 0 };
ULONG bytes = 0;

if (NT_SUCCESS( GET_IMPORT( NtQueryInformationThread )(hThread, (THREADINFOCLASS)0, &tbi, sizeof( tbi ), &bytes) ))
if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueryInformationThread, hThread, (THREADINFOCLASS)0, &tbi, (ULONG)sizeof( tbi ), &bytes ) ))
return tbi.ClientID.UniqueThread;

return 0;
Expand Down
Loading

0 comments on commit 61f115d

Please sign in to comment.