
탐지 회피형 Windows 개발을 위한 헤더 전용 C++17 라이브러리: 컴파일 타임 API 해싱, DLL 언후킹, 하드웨어 브레이크포인트 해제, VEH 제거, EDR 후크 회피를 위한 DLL 알림 콜백 억제.
이것은 제 원래 프로젝트인 WTSRM과 해당 발표의 연장선입니다.
이 프로젝트는 C++17을 활용하여 컴파일 타임에 필요한 기능을 쉽게 변경할 수 있는 템플릿을 만들기 위해 재작성되었습니다! 헤더 전용 파일로 구현되어 있으므로 자신의 프로젝트에 쉽게 추가할 수 있습니다.
현재 구현된 일부 기능은 다음과 같습니다:
이 동작은 다음과 같이 구성할 수 있습니다
#define HASHING_ALGORITHM hash_string_fnv1a // constexpr 알고리즘
namespace config
{
...
//
// 동작 구성
//
inline constexpr unsigned unhooking = system32 | write_process_memory;
inline constexpr auto work_item_load_library = true; // LL에 작업 항목 사용
//
// 회피 기능 구성
//
inline constexpr auto clear_and_restore_veh = true; // veh 지우기 및 복원
inline constexpr auto unregister_dll_notifs = true; // LdrRegisterDllNotification
inline constexpr auto clear_thread_hwbps = true; // hwbps 지우기
}
constexpr을 활용하므로 사용하지 않는 기능은 죽은 코드로 간주되어 프로그램에서 최적화되므로 비용이 들지 않습니다.
DLL을 가져오려면 먼저 DLL_HASH 매크로를 사용하여 해시를 만들어야 합니다
DLL_HASH(DBGHELP, L"DBGHELP.DLL")
그런 다음 내부 IAT 역할을 하는 module_address_table에 추가해야 합니다. hash_ 상수는 DLL_HASH 매크로에 의해 생성됩니다. 항상 로드되지 않는 비공용 DLL의 경우 로드할 수 있도록 이름을 지정해야 합니다.
inline addr_struct<decltype(HASHING_ALGORITHM(TOKENIZEA(T))), wchar_t> module_address_table[] =
{
{hash_NTDLL, nullptr,},
{hash_KERNEL32, nullptr,},
{hash_DBGHELP, nullptr, L"DBGHELP.DLL"}
};
함수를 가져오려면 먼저 HASH_FUNC 매크로를 사용하여 함수 이름 해시와 typedef를 만들어야 합니다
HASH_FUNC(NtUnmapViewOfSection, NTSTATUS, HANDLE, PVOID)
첫 번째 매개변수는 함수 이름, 다음은 반환 타입, 그 다음은 함수의 인수입니다. 그런 다음 현재 함수 주소로 채워질 api_address_table에 추가해야 합니다
inline addr_struct<decltype(HASHING_ALGORITHM(TOKENIZEA(T))), void> api_address_table[] =
{
{hash_GetProcAddress, nullptr},
{hash_NtUnmapViewOfSection, nullptr},
이 함수를 이 테이블에 추가하지 못해도 프로그램은 충돌하지 않지만 안정성을 높이기 위해 -1을 반환합니다.
API를 사용하려면 다음과 같이 API()() 매크로를 사용합니다
API(NtWaitForSingleObject)(NtCurrentProcess(), FALSE, &timeout);
자체 API 해싱 함수를 추가하려면 필요한 타입과 호환되도록 이 템플릿을 사용해야 합니다.
template <typename T>
constexpr auto hash_string_(const T* buffer)
{
TRIVIAL_TYPE_CHECK()
}
아이디어와 기여를 제공해 주신 다음 분들께 특별한 순서 없이 감사드립니다 @peterwintrsmith @modexpblog @jonaslyk @JustasMasiulis