
시스템 콜 변조를 통한 깔끔한 간접 시스템 콜.
SyscallRevenant는 깔끔한 간접 시스템 호출을 수행하는 새로운 방법입니다.
주요 구성 요소는 시스템 서비스 번호(SSN)와 syscall 명령어 주소를 동적으로 해석합니다.
이는 실행 중에 트랩 플래그를 활성화함으로써 이루어집니다.
보조 구성 요소는 syscall 이전에 매개변수 교체를 통한 변조입니다.
이 조합은 초기에 제시된 매개변수를 대체하면서 후속 시스템 호출 호출 중에 사용자 영역 후크를 우회하도록 설계되었습니다.
면책 조항: 이는 교육 및 테스트 목적으로만 사용됩니다. 사용 권한이 없는 기기에서는 사용하지 마십시오. 사용 권한이 없는 기기와 연결하거나 통신하는 데 사용하지 마십시오.
간접 시스템 호출은 신뢰할 수 있는 사용자 영역 공간에서 syscall 명령어를 실행하는 방법입니다.
사용자가 syscall 명령어를 발견하면 간접적으로 해당 명령어로 점프할 수 있습니다.
추적 세션 중에 활성화된 이벤트는 명령어 직후의 반환 주소를 드러낼 수 있습니다.
이는 엔드포인트 탐지 및 대응(EDR) 사용자 영역 후크를 고려하지 않습니다.
EDR은 ntdll.dll에 후크를 삽입할 수 있으므로 SSN 및 syscall 명령어에 대한 조회 프로세스가 무효화됩니다.
후크에 진입하면 소유 스레드에 이익이 되며 악성 점수를 높이지 않습니다.
함수 진입을 관찰하는 것과 그로 인한 작업을 관찰하는 것은 다른 일입니다.
RevenantSyscalls는 그 간극을 조사합니다.
다음 섹션에서는 프로젝트의 두 가지 주요 구성 요소를 설명합니다.
첫 번째 구성 요소는 프로세스에 의해 로드된 ntdll.dll에서 함수 주소를 해석합니다.
시스템 호출 정보가 필요한 경우 트랩 워크가 수행될 수 있습니다.
두 번째 구성 요소는 저장된 함수 정보로 간접 점프를 수행합니다.
세그먼트 레지스터에서 읽으면 프로세스 환경 블록(PEB)을 검색할 수 있습니다.
LoaderData는 PEB의 필드로, 각 프로세스와 함께 로드된 데이터를 포함합니다.
LoaderData는 각 프로세스와 함께 로드된 모듈에 대한 정보를 포함합니다.
모듈 이름과 기본 주소는 모듈 항목에 존재합니다.
동적 연결 라이브러리(DLL)의 내보내기 정보는 내보내는 심볼을 설명합니다. 내보내기 메타데이터는 내보낸 심볼을 찾는 것을 지원합니다. 함수의 인덱스는 이름과 이름 서수에만 적용됩니다. 함수 이름을 해싱하는 것이 저메모리 환경에 가장 적합합니다.
벡터 예외 처리기는 프로세스 내 어디에서나 발생하는 예외를 포착하는 예외 처리 메커니즘입니다.
트랩 플래그를 활성화하면 다음에 실행되는 명령어에서 EXCEPTION_SINGLE_STEP 예외가 발생합니다.
사용자 정의 벡터 예외 처리기는 RIP를 검사하고 syscall인지 확인할 수 있습니다.
트랩 플래그를 반복적으로 재설정함으로써 syscall 주소가 발견되고 SSN이 저장됩니다.
시스템 호출 조회
|
시스템 호출 실행
|
각 시스템 호출에는 초기 시스템 호출 정보 조회가 있습니다. 시스템 호출 정보를 검색하기 위해 후크에 진입합니다. 계속 진행하면 시스템 호출로 간접 점프가 이루어집니다. (원래 진입점으로부터의) 관련 RIP 스푸핑이 있을 것입니다. 재진입 시 초기 매개변수가 변조되었습니다.
Windows용 이벤트 추적(ETW) 관점에서 방출될 수 있는 이벤트는 SysEnter, SysExit, 그리고 둘 중 하나에 대한 StackWalk입니다.
EDR이 유사하고 비교 가능한 이벤트를 구축하는 경우, 이들은 거의 동일하게 보일 것입니다.
유일한 차이점은 극적으로 다른 쿼리 성능 카운터(QPC) 타임스탬프에 있을 것입니다.
src/AsmRevenant.asm을 따라가십시오. REAL_RTN: DQ 0
FAKE_RTN: DQ 0
; If a syscall information lookup is in progress, the
; initial entry return address needs to be preserved.
MOV RAX, QWORD PTR [RSP]
MOV QWORD PTR [FAKE_RTN], RAX
; Once the re-entry is made, the real return is saved,
; and the current is spoofed with initial return.
MOV RAX, QWORD PTR [RSP]
MOV QWORD PTR [REAL_RTN], RAX
MOV RAX, QWORD PTR [FAKE_RTN]
MOV QWORD PTR [RSP], RAX
src/Revenant.c를 따라가기LONG VectoredExceptionHandler(EXCEPTION_POINTERS *BreakPoint) {
...
// If a syscall information lookup is being made, the
// syscall instruction address is saved, the SSN is
// saved, and the return is rerouted.
if (LookupInProgress && *(USHORT*)BreakPoint->Address == 0x050F) {
SyscallInstruction = BreakPoint->Address;
SyscallSSN = BreakPoint->Context->Rax;
BreakPoint->Context->Rip = SyscallExit;
}
// When re-entered, if the previous instruction was
// a syscall, reset return address, and exit.
if (!LookupInProgress && *(USHORT*)(BreakPoint->Address - 2) == 0x050F) {
*(VOID**)BreakPoint->Context->Rsp = REAL_RTN;
BreakPoint->Context->Rip = SyscallExit;
}
...
}