windows-nt/Source/XPSP1/NT/com/svcdlls/trksvcs/dltadmin/procact.cxx
2020-09-26 16:20:57 +08:00

440 lines
14 KiB
C++

#include <pch.cxx>
#pragma hdrstop
#include <ole2.h>
#include "trkwks.hxx"
#include "dltadmin.hxx"
typedef HINSTANCE (WINAPI *PFNLoadLibrary)(LPCTSTR);
typedef HMODULE (WINAPI *PFNGetModuleHandle)(LPCTSTR);
typedef BOOL (WINAPI *PFNFreeLibrary)(HINSTANCE);
typedef LONG (WINAPI *PFNGetLastError)();
typedef VOID (WINAPI *PFNDebugBreak)();
typedef VOID (WINAPI *PFNOutputDebugStringW)( LPCTSTR );
typedef BOOL (WINAPI *PFNCreateProcessW)(
IN LPCWSTR lpApplicationName,
IN LPWSTR lpCommandLine,
IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
IN BOOL bInheritHandles,
IN DWORD dwCreationFlags,
IN LPVOID lpEnvironment,
IN LPCWSTR lpCurrentDirectory,
IN LPSTARTUPINFOW lpStartupInfo,
OUT LPPROCESS_INFORMATION lpProcessInformation
);
typedef struct
{
EProcessAction eAction;
PFNGetModuleHandle pfnGetModuleHandleW;
PFNFreeLibrary pfnFreeLibrary;
PFNLoadLibrary pfnLoadLibraryW;
PFNGetLastError pfnGetLastError;
PFNDebugBreak pfnDebugBreak;
PFNOutputDebugStringW pfnOutputDebugStringW;
PFNCreateProcessW pfnCreateProcessW;
WCHAR wsz[ 4*MAX_PATH + 1 ];
WCHAR wszMessage[ 2*MAX_PATH + 1 ];
} THREADFNSTRUCT;
extern "C"
{
// Turn off stack-probing.
#pragma check_stack (off)
// Also turn off optimizations, to ensure that the compiler doesn't
// consolidate any of this code with that from another function.
#pragma optimize( "", off )
static void BeforeThreadFunc (void)
{
// Prevent optimizations
int i = rand();
}
static DWORD WINAPI
RemoteThreadFunc( THREADFNSTRUCT *pStruct )
{
pStruct->pfnOutputDebugStringW( pStruct->wszMessage );
if( FREE_LIBRARY == pStruct->eAction )
{
HINSTANCE hinst = NULL;
hinst = pStruct->pfnGetModuleHandleW( pStruct->wsz );
if( NULL == hinst )
return( pStruct->pfnGetLastError() );
if( !pStruct->pfnFreeLibrary( hinst ))
return( pStruct->pfnGetLastError() );
else
return( ERROR_SUCCESS );
}
else if( LOAD_LIBRARY == pStruct->eAction )
{
if( NULL == pStruct->pfnLoadLibraryW( pStruct->wsz ))
return( pStruct->pfnGetLastError() );
else
return( ERROR_SUCCESS );
}
else if( DEBUG_BREAK == pStruct->eAction )
{
pStruct->pfnDebugBreak();
return( ERROR_SUCCESS );
}
else if( CREATE_PROCESS == pStruct->eAction )
{
if( !pStruct->pfnCreateProcessW( NULL, pStruct->wsz,
NULL, NULL,
FALSE, NORMAL_PRIORITY_CLASS,
NULL, NULL, NULL, NULL ))
{
return GetLastError();
}
else
return ERROR_SUCCESS;
}
else
{
pStruct->pfnOutputDebugStringW( L"Invalid action to RemoteThreadFunc" );
return ERROR_INVALID_PARAMETER;
}
}
static void AfterThreadFunc (void)
{
// Prevent optimziations
int i = 2 * rand();
}
#pragma optimize ("", on ) // Restore to default
#pragma check_stack // Restore to default
}
BOOL
RemoteProcessAction( HANDLE hProcess,
EProcessAction eAction,
const WCHAR *pwsz )
{
int cbCodeSize = 0;
const DWORD cbMemSize = cbCodeSize + sizeof(THREADFNSTRUCT) + 3;
DWORD *pdwCodeRemote = NULL;
THREADFNSTRUCT ThreadFnStruct;
THREADFNSTRUCT *pRemoteThreadFnStruct = NULL;
HANDLE hThread = NULL;
DWORD dwThreadID = 0;
BOOL fSuccess = FALSE;
__try {
// Determine the size of RemoteThreadFunc. Assume the functions
// either in order or in reverse order.
if( (LPBYTE) AfterThreadFunc > (LPBYTE) RemoteThreadFunc )
cbCodeSize = (int)( (LPBYTE) AfterThreadFunc - (LPBYTE) RemoteThreadFunc );
else if( (LPBYTE) BeforeThreadFunc > (LPBYTE) RemoteThreadFunc )
cbCodeSize = (int)( (LPBYTE) BeforeThreadFunc - (LPBYTE) RemoteThreadFunc );
else
{
printf( "Can't determine size of code to inject (%p, %p, %p)\n",
BeforeThreadFunc, AfterThreadFunc, RemoteThreadFunc );
__leave;
}
// Allocate memory in the remote process's address space large
// enough to hold our RemoteThreadFunc function and a THREADFNSTRUCT structure.
pdwCodeRemote = (DWORD*) VirtualAllocEx( hProcess, NULL, cbMemSize,
MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( NULL == pdwCodeRemote )
{
printf( "VirtualAllocEx failed: %d\n", GetLastError() );
__leave;
}
// Write a copy of RemoteThreadFunc to the remote process.
if( !WriteProcessMemory( hProcess, pdwCodeRemote,
(LPVOID) RemoteThreadFunc,
cbCodeSize, NULL ))
{
printf( "WriteProcessMemory failed: %d\n", GetLastError() );
__leave;
}
// Write a copy of ThreadFnStruct to the remote process
// (the structure MUST start on an even 32-bit bourdary).
pRemoteThreadFnStruct = reinterpret_cast<THREADFNSTRUCT *>
( (BYTE*)pdwCodeRemote + ((cbCodeSize + 4) & ~3) );
memset( &ThreadFnStruct, 0, sizeof(ThreadFnStruct) );
ThreadFnStruct.eAction = eAction;
//wcscpy( ThreadFnStruct.wszMessage, L"*** Remote thread from dltadmin.exe ***\n" );
if( LOAD_LIBRARY == eAction )
{
wcscpy( ThreadFnStruct.wsz, pwsz );
wsprintf( ThreadFnStruct.wszMessage,
L"Received request from dltadmin to load \"%s\"\n",
pwsz );
ThreadFnStruct.pfnLoadLibraryW = (PFNLoadLibrary)
GetProcAddress( GetModuleHandle( L"kernel32.dll" ),
"LoadLibraryW" );
if( NULL == ThreadFnStruct.pfnLoadLibraryW )
{
printf( "Couldn't load LoadLibraryW (%d)\n", GetLastError() );
__leave;
}
}
else if( FREE_LIBRARY == eAction )
{
wcscpy( ThreadFnStruct.wsz, pwsz );
wsprintf( ThreadFnStruct.wszMessage,
L"Received request from dltadmin to free \"%s\"\n",
pwsz );
ThreadFnStruct.pfnFreeLibrary = (PFNFreeLibrary)
GetProcAddress( GetModuleHandleA("kernel32.dll"),
"FreeLibrary" );
if( NULL == ThreadFnStruct.pfnFreeLibrary )
{
printf( "Couldn't load FreeLibrary (%d)\n", GetLastError() );
__leave;
}
ThreadFnStruct.pfnGetModuleHandleW = (PFNGetModuleHandle)
GetProcAddress( GetModuleHandle(L"kernel32.dll"),
"GetModuleHandleW" );
if( NULL == ThreadFnStruct.pfnFreeLibrary )
{
printf( "Couldn't load FreeLibrary (%d)\n", GetLastError() );
__leave;
}
}
else if( CREATE_PROCESS == eAction )
{
wcscpy( ThreadFnStruct.wsz, pwsz );
wsprintf( ThreadFnStruct.wszMessage,
L"Received request from dltadmin to create \"%s\"\n",
pwsz );
ThreadFnStruct.pfnCreateProcessW = (PFNCreateProcessW)
GetProcAddress( GetModuleHandleA("kernel32.dll"),
"CreateProcessW" );
if( NULL == ThreadFnStruct.pfnCreateProcessW )
{
printf( "Couldn't load CreateProcess (%d)\n", GetLastError() );
__leave;
}
}
else // DEBUG_BREAK
{
wsprintf( ThreadFnStruct.wszMessage,
L"Received request from dltadmin to DebugBreak\n" );
ThreadFnStruct.pfnDebugBreak = (PFNDebugBreak)
GetProcAddress( GetModuleHandleA("kernel32.dll"),
"DebugBreak" );
if( NULL == ThreadFnStruct.pfnDebugBreak )
{
printf( "Couldn't load DebugBreak (%d)\n", GetLastError() );
__leave;
}
}
ThreadFnStruct.pfnGetLastError = (PFNGetLastError)
GetProcAddress( GetModuleHandle( L"kernel32.dll" ),
"GetLastError" );
if( NULL == ThreadFnStruct.pfnGetLastError )
{
printf( "Couldn't load GetLastError (%d)\n", GetLastError() );
__leave;
}
ThreadFnStruct.pfnOutputDebugStringW = (PFNOutputDebugStringW)
GetProcAddress( GetModuleHandle( L"kernel32.dll" ),
"OutputDebugStringW" );
if( NULL == ThreadFnStruct.pfnOutputDebugStringW )
{
printf( "Couldn't load OutputDebugStringW (%d)\n", GetLastError() );
__leave;
}
// Write the struct into the remote thread's memory block.
if( !WriteProcessMemory( hProcess, pRemoteThreadFnStruct,
&ThreadFnStruct, sizeof(THREADFNSTRUCT), NULL ))
{
printf( "Couldn't write ThreadFnStruct to remote thread: %d\n", GetLastError() );
__leave;
}
hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) pdwCodeRemote,
pRemoteThreadFnStruct, 0, &dwThreadID );
if( NULL == hThread )
{
printf( "Couldn't create remote thread: %d\n", GetLastError() );
__leave;
}
DWORD dwWait = WaitForSingleObject( hThread, INFINITE );
if( WAIT_OBJECT_0 != dwWait )
printf( "Wait failed: %d, %d\n", dwWait, GetLastError() );
} // __try
__finally
{
if( NULL != hThread )
{
DWORD dwError;
if( !AbnormalTermination() )
{
if( !GetExitCodeThread( hThread, &dwError ))
printf( "Couldn't get remote thread exit code: %d\n", GetLastError() );
else if( ERROR_MOD_NOT_FOUND == dwError )
{
if( LOAD_LIBRARY == eAction )
wprintf( L"DLL \"%s\" not found\n", pwsz );
else if( FREE_LIBRARY == eAction )
wprintf( L"DLL \"%s\" not already loaded\n", pwsz );
}
else if( ERROR_SUCCESS != dwError )
printf( "Failed: 0x%x\n", dwError );
else
fSuccess = TRUE;
}
CloseHandle(hThread);
}
if( NULL != pdwCodeRemote )
{
if( !VirtualFreeEx( hProcess, pdwCodeRemote, 0, MEM_RELEASE ))
printf( "Couldn't free remote memory: 0x%x\n", GetLastError() );
}
} // __finally
if( fSuccess )
printf( "Succeeded\n" );
return( fSuccess );
}
BOOL
DltAdminProcessAction( EProcessAction eAction, ULONG cArgs, TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
BOOL fSuccess = FALSE;
*pcEaten = 0;
if( 0 == cArgs
||
1 <= cArgs && IsHelpArgument(rgptszArgs[0]) )
{
*pcEaten = 1;
if( LOAD_LIBRARY == eAction )
{
printf( "\nOption LoadLib\n"
" Purpose: Load a dll into a process with LoadLibrary\n"
" Usage: -LoadLib -p <process ID> <library name>\n"
" E.g.: -LoadLib -p 182 shell32.dll\n" );
}
else if( FREE_LIBRARY == eAction )
{
printf( "\nOption FreeLib\n"
" Purpose: Unload a dll from a process with FreeLibrary\n"
" Usage: -FreeLib -p <process ID> <library name>\n"
" E.g.: -FreeLib -p 182 shell32.dll\n" );
}
else
{
printf( "\nOption DebugBreak\n"
" Purpose: Execute DebugBreak within a process\n"
" Usage: -DebugBreak -p <process ID>\n"
" E.g.: -DebugBreak -p 182\n" );
}
return( TRUE );
}
ULONG iArgs = 0;
if( 2 > cArgs
||
TEXT('-') != rgptszArgs[0][0]
&&
TEXT('/') != rgptszArgs[0][0]
||
TEXT('P') != rgptszArgs[0][1]
&&
TEXT('p') != rgptszArgs[0][1] )
{
printf( "Argument error. Use -? for usage info.\n" );
return( FALSE );
}
HANDLE hProcess = NULL;
__try
{
DWORD dwProcessID = 0;
_stscanf( rgptszArgs[1], TEXT("%d"), &dwProcessID );
if( 0 == dwProcessID )
{
printf( "Failed to open system process\n" );
__leave;
}
EnablePrivilege(SE_DEBUG_NAME);
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwProcessID );
if( NULL == hProcess )
{
printf( "Failed to open process %d (%lu)\n", dwProcessID, GetLastError() );
__leave;
}
if( RemoteProcessAction( hProcess, eAction,
DEBUG_BREAK == eAction ? NULL : rgptszArgs[2] ))
fSuccess = TRUE;
if( DEBUG_BREAK == eAction )
*pcEaten = 2;
else
*pcEaten = 3;
}
__finally
{
if( NULL != hProcess )
CloseHandle( hProcess );
}
return( fSuccess );
}