18-08-2020, 16:07
Hello,
Si vous surveillez CSGO en ce moment vous avez certainement vu l'implémentation de routines de détections d’exécution de code, que ce soit le grand classique LoadLibrary mais aussi une technique utilisée depuis déjà un long moment, le manual mapping, en checkant les nouveaux threads & en vérifiant s'ils sont legit au sein du module
Du coup je vous partage le code qui était encore utilisé récemment sur Royal Hack afin d'hijack un thread pour faire nos magouilles
Du coup c'est plutôt straightfoward, & compatible 32/64bit automatiquement.
Le concept est ultra simple & facile à implémenter comme vous le voyez.
Si vous surveillez CSGO en ce moment vous avez certainement vu l'implémentation de routines de détections d’exécution de code, que ce soit le grand classique LoadLibrary mais aussi une technique utilisée depuis déjà un long moment, le manual mapping, en checkant les nouveaux threads & en vérifiant s'ils sont legit au sein du module
Du coup je vous partage le code qui était encore utilisé récemment sur Royal Hack afin d'hijack un thread pour faire nos magouilles
Code :
InjectionResult CRemoteAccess::HijackThread(LPCVOID lpAddress, DWORD dwEipOffset, CEvent& event) const
{
InjectionResult result = { InjectionCode::HijackFailure, 0 };
// open the target thread
NTSTATUS ntStatus = 0;
HANDLE hThread = OpenThreadById(
m_dwThreadId,
THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION,
&ntStatus);
if(hThread != NULL)
{
ULONG previousSuspendCount;
// suspend the target thread
ntStatus = Syscall_NtSuspendThread(hThread, &previousSuspendCount);
if(NT_SUCCESS(ntStatus))
{
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
// get the target thread context
ntStatus = Syscall_NtGetContextThread(
hThread,
&context);
if(NT_SUCCESS(ntStatus))
{
// save the old eip
#ifdef _X86_
DWORD_PTR dwOldEip = context.Eip;
#elif defined _AMD64_
DWORD_PTR dwOldEip = context.Rip;
#endif
// write the old eip
ntStatus = Syscall_NtWriteVirtualMemory(
m_hProcess,
MakePtr(PVOID, lpAddress, dwEipOffset),
&dwOldEip,
sizeof(dwOldEip),
NULL);
if(NT_SUCCESS(ntStatus))
{
// redirect the EIP
context.ContextFlags = CONTEXT_CONTROL;
#ifdef _X86_
context.Eip = (DWORD)lpAddress;
#elif defined _AMD64_
context.Rip = (DWORD64)lpAddress;
#endif
// set our modified thread context
ntStatus = Syscall_NtSetContextThread(
hThread,
&context);
if(NT_SUCCESS(ntStatus))
{
result.code = InjectionCode::Injected;
result.error = 0;
}
else
{
result.code = InjectionCode::SetContextFailure;
result.error = ntStatus;
}
}
else
{
result.code = InjectionCode::WriteFailure;
result.error = ntStatus;
}
}
else
{
result.code = InjectionCode::GetContextFailure;
result.error = ntStatus;
}
// resume the target thread
ntStatus = Syscall_NtResumeThread(hThread, &previousSuspendCount);
if(result.code == InjectionCode::Injected && !NT_SUCCESS(ntStatus))
{
result.code = InjectionCode::ResumeFailure;
result.error = ntStatus;
}
}
else
{
result.code = InjectionCode::SuspendFailure;
result.error = ntStatus;
}
// close the target thread
Syscall_NtClose(hThread);
}
else
{
result.code = InjectionCode::OpenFailure;
result.error = ntStatus;
}
if(result.code == InjectionCode::Injected)
{
// wait for the hijack to be done
if(!event.WaitMultiple(m_hProcess))
{
result.code = InjectionCode::WaitEventError;
// read the exit code
g_imports.Modules.Kernel32.GetExitCodeProcess(m_hProcess, &result.error);
}
}
return result;
}
Du coup c'est plutôt straightfoward, & compatible 32/64bit automatiquement.
Le concept est ultra simple & facile à implémenter comme vous le voyez.