朋友遇到个环境:命令行程序被杀软注入dll到自身的conhost中(猜测是年初火眼公开的命令行输出监控?),需要对远程进程调用FreeLibrary,简单封装了个函数,勉强能用。
typedef NTSTATUS(WINAPI * _RtlCreateUserThread)( HANDLE ProcessHandle, PSECURITY_DESCRIPTOR SecurityDescriptor, BOOL CreateSuspended, ULONG StackZeroBits, PULONG StackReserved, PULONG StackCommit, LPVOID StartAddress, LPVOID StartParameter, PHANDLE ThreadHandle, LPVOID ClientID ); typedef ULONG(WINAPI * _RtlNtStatusToDosError)( NTSTATUS Status ); BOOL RemoteFreeLibrary(HANDLE hProc, LPWSTR pwszModule) { if (!hProc) { return false; } if (!pwszModule) { return false; } HMODULE hm = LoadLibraryW(pwszModule); if (!hm) { return false; } HANDLE ht = 0; HMODULE hmNtdll = GetModuleHandle(L"ntdll.dll"); _RtlCreateUserThread RtlCreateUserThread = (_RtlCreateUserThread)GetProcAddress(hmNtdll, "RtlCreateUserThread"); _RtlNtStatusToDosError RtlNtStatusToDosError= (_RtlNtStatusToDosError)GetProcAddress(hmNtdll, "RtlNtStatusToDosError"); if (!RtlCreateUserThread || !RtlNtStatusToDosError){ return false; } NTSTATUS status = RtlCreateUserThread(hProc, 0, false, 0, 0, 0, FreeLibrary, hm, &ht, 0); if (!NT_SUCCESS(status)) { SetLastError(RtlNtStatusToDosError(status)); return false; } CloseHandle(ht); return true; }
调用:
EnablePrivilge(SE_DEBUG_NAME); HANDLE hProc = OpenProcess(MAXIMUM_ALLOWED, false, pid); if(hProc) { RemoteFreeLibrary(L"dbgeng.dll"); }
测试程序:
#include <Windows.h> int main() { LoadLibraryW(L"dbgeng.dll"); printf("%d\n",GetCurrentProcessId()); while (true) { printf("hm= %#p\n",GetModuleHandleW(L"dbgeng.dll")); Sleep(1000); } return 0; }
实战使用时需要注意的几点:
1.没加入wow64到x64的切换。考虑到实战中x64环境以及工具居多,遇到再说吧。
2.同Session用CreateRemoteThread也可以,不过无论是CreateRemoteThread或是RtlCreateUserThread基本属于会被监控的API范畴,比如大规模部署的sysmon……最好的方法还是手动加载ntdll,构造NtCreateThread的stub,必要时候切换到x64,最后调用。这样至少能规避r3层面的监控吧……
3.OpenProcess也较为敏感,找一些黑科技代替吧。