Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
Shelter — ROP 기반 슬립 난독화로 메모리 스캐너 우회 | Kitploit
도구/GitHubGitHub/kudaes/shelter
Exploit FrameworksMemory ForensicsRed Teaming
GitHubkudaes/shelter

Shelter

ROP 기반 슬립 난독화로 메모리 스캐너 우회

저장소 보기
3904841년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Shelter

Shelter는 완전한 무장형 수면 난독화 기법으로, ROP를 광범위하게 사용하여 메모리 내 페이로드를 완전히 암호화할 수 있습니다.

이 크레이트는 다음과 같은 특징을 가지고 있습니다:

  • AES-128 암호화.
  • 전체 PE 암호화 기능.
  • 수면 중 실행 권한 제거.
  • APC/HWBP/타이머 미사용, 오직 ROP만을 사용하여 난독화 달성.
  • 호출 스택 스푸핑을 위해 Unwinder 사용 후 ROP 체인 실행.
  • 다양한 상황에 적응할 수 있는 여러 실행 방법.
  • 기타 OPSEC 고려 사항: DInvoke_rs, 간접 시스템 콜, 문자열 리터럴 암호화 등.

내용

  • 사용법
  • 예제
    • fluctuate
    • fluctuate_from_address
    • fluctuate_from_pattern
  • 모듈 테스트
  • TO-DO

사용법

이 크레이트를 프로젝트에 추가하려면 cargo.toml에 다음 줄을 추가하세요:

root@kitploit:~
[dependencies]
shelter = "=0.1.2"

그런 다음 프로젝트를 --release 모드로 컴파일하세요.

이 크레이트의 주요 기능은 세 가지 함수로 래핑되었습니다:

  • fluctuate()는 현재 메모리 영역 또는 전체 PE를 암호화할 수 있습니다. 이 함수는 PE의 MZ 바이트가 메모리에 존재하여 기본 주소를 동적으로 검색해야 합니다.
  • fluctuate_from_address()는 PE를 완전히 암호화합니다. 이 함수는 입력 매개변수로 PE의 기본 주소를 요구합니다.
  • fluctuate_from_pattern()도 PE를 완전히 암호화합니다. 이 함수는 입력 매개변수로 PE의 기본 주소를 결정하는 데 사용할 사용자 정의 2바이트 세트를 요구합니다. 이 사용자 정의 매직 바이트는 기존의 MZ 패턴을 대체합니다.
  • 전체 PE가 암호화될 때, 원래 섹션의 메모리 보호는 힙에 저장되어 나중에 복원됩니다.

    Shelter는 NtWaitForSingleObject를 사용하여 수면합니다. 수면 시간(초)을 지정하는 것 외에도 이벤트 핸들을 전달하여 언제든지 신호를 보내 타임아웃이 만료되기 전에 반환할 수 있습니다 (예: SetEvent 사용). 전체 페이로드가 암호화된 경우(이것이 요점이겠지만), 무기한 수면하는 경우 이벤트에 신호를 보낼 대체 방법이 필요합니다.

    예제

    fluctuate

    이 함수는 다음 매개변수를 요구합니다:

    • 전체 PE를 암호화할지 아니면 현재 메모리 영역만 암호화할지를 나타내는 부울 값. true를 전달하려면 MZ 바이트가 메모리에 존재해야 합니다.
    • 프로그램이 수면할 시간(초). None으로 설정하면 타임아웃이 무한대가 되어, NtWaitForSingleObject에 전달된 이벤트가 신호를 받을 때까지 실행이 반환되지 않습니다.
    • NtWaitForSingleObject에 전달할 이벤트 핸들. 이 매개변수는 None이 될 수 있습니다. 이 매개변수와 타임아웃이 모두 None으로 설정되면 프로그램이 멈춥니다.
    root@kitploit:~
    let time_to_sleep = Some(10); // 10초 동안 수면
    let _ = shelter::fluctuate(false, time_to_sleep, None); // 현재 메모리 영역만 암호화
    
    root@kitploit:~
    let time_to_sleep = Some(10); // 10초 동안 수면
    let _ = shelter::fluctuate(true, time_to_sleep, None); // 전체 PE 암호화
    
    root@kitploit:~
    pub type CreateEventW = unsafe extern "system" fn (*const SECURITY_ATTRIBUTES, i32, i32, *const u16) -> HANDLE;
    
    let k32 = dinvoke_rs::dinvoke::get_module_base_address("kernel32.dll"); 
    let create_event: CreateEventW;
    let event_handle: Option<HANDLE>;
    dinvoke_rs::dinvoke::dynamic_invoke!(k32,"CreateEventW",create_event,event_handle,ptr::null_mut(),0,0,ptr::null());
    let time_to_sleep = None; // 무기한 수면
    let _ = shelter::fluctuate(true, time_to_sleep, event_handle); // 이벤트가 신호를 받을 때까지 전체 PE 암호화
    

    fluctuate_from_address

    이 함수는 다음 매개변수를 요구합니다:

    • 프로그램이 수면할 시간(초). None으로 설정하면 타임아웃이 무한대가 되어, NtWaitForSingleObject에 전달된 이벤트가 신호를 받을 때까지 실행이 반환되지 않습니다.
    • NtWaitForSingleObject에 전달할 이벤트 핸들. 이 매개변수는 None이 될 수 있습니다. 이 매개변수와 타임아웃이 모두 None으로 설정되면 프로그램이 멈춥니다.
    • PE가 매핑된 기본 주소.

    이 함수를 사용하는 한 가지 방법은 Dinvoke_rs로 페이로드를 수동으로 매핑하는 것입니다. 이렇게 하면 로더가 페이로드에 자신의 기본 주소를 보낼 수 있으므로, 페이로드는 필요할 때마다 이를 사용하여 자신을 난독화할 수 있습니다. 또한 로더는 PE 헤더를 안전하게 제거하여 일정 수준의 은밀함을 달성할 수 있습니다.

    로더 예제:

    root@kitploit:~
    let payload: Vec<u8> = your_download_function();
    let mut m = dinvoke_rs::manualmap::manually_map_module(payload.as_ptr(), true).unwrap();
    println!("The dll is loaded at base address 0x{:x}", m.1);
    let dll_exported_function = dinvoke::get_function_address(m.1, "run");
    
    let run: unsafe extern "Rust" fn (usize) = std::mem::transmute(dll_exported_function);
    run(m.1 as usize);
    

    페이로드 예제:

    root@kitploit:~
    #[no_mangle]
    fn run(base_address: usize)
    {
    	...
    	let time_to_sleep = Some(10); // 10초 동안 수면
    	let _ = shelter::fluctuate_from_address(time_to_sleep, None, base_address); // 이 특정 기본 주소에서 전체 PE 암호화
    	...
    }
    

    fluctuate_from_pattern

    이 함수는 다음 매개변수를 요구합니다:

    • 프로그램이 수면할 시간(초). None으로 설정하면 타임아웃이 무한대가 되어, NtWaitForSingleObject에 전달된 이벤트가 신호를 받을 때까지 실행이 반환되지 않습니다.
    • NtWaitForSingleObject에 전달할 이벤트 핸들. 이 매개변수는 None이 될 수 있습니다. 이 매개변수와 타임아웃이 모두 None으로 설정되면 프로그램이 멈춥니다.
    • PE의 기본 주소를 얻기 위해 검색할 사용자 정의 매직 바이트를 포함하는 [u8;2] 배열.

    이 함수를 만든 이유는 로더가 PE 헤더 및 기타 시그니처(기존 MZ 바이트 포함)를 제거할 수 있도록 하기 위함입니다. 이렇게 하면 Shelter가 PE의 기본 주소를 검색하는 데 사용할 사용자 정의 패턴으로 해당 바이트를 대체할 수 있습니다.

    root@kitploit:~
    let time_to_sleep = Some(10); // 10초 동안 수면
    let pattern = [0x29,0x07];
    let _ = shelter::fluctuate_from_pattern(time_to_sleep, None, pattern); // 사용자 정의 패턴을 매직 바이트로 사용하여 전체 PE 암호화
    

    모듈 테스트

    이 기법의 구현을 테스트하기 위해 주로 PE-sieve가 사용되었습니다. 기본적으로 PE-sieve는 실행 가능한 메모리 영역 내에서 임플란트를 찾는데, 이는 현재 메모리 영역 (.text)만 난독화하는 것만으로도 탐지를 피할 수 있음을 의미합니다:

    현재 메모리 영역 난독화. 현재 메모리 영역 난독화 (Process Hacker).

    Unwinder를 사용하고 있기 때문에 호출 스택이 스푸핑되어 /threads 플래그가 매핑된 DLL도 탐지하지 못합니다.

    이제 PE-sieve는 /data 플래그를 사용하여 실행 불가능한 메모리 영역도 검사할 수 있습니다. 공식 문서에 따르면, 이 플래그를 always로 설정하면 "많은 노이즈/거짓 양성"을 생성할 수 있습니다. 그럼에도 불구하고, 우리는 전체 PE 암호화 기능의 효과를 확인하기 위해 이 옵션을 사용하기로 결정했습니다. 이는 메모리 내 임플란트 존재의 지표가 될 수 있는 PE의 데이터 영역을 숨길 수 있기 때문입니다.

    PE-sieve에 의해 탐지된 현재 메모리 영역 난독화. 전체 PE 난독화는 탐지되지 않음.

    보시다시피, 첫 번째 그림에서는 PE-sieve가 실행 불가능한 메모리 페이지를 스캔할 때 .text 섹션만 난독화하는 것으로는 충분하지 않다는 것을 보여줍니다. 일부 영역에는 DLL의 존재를 드러낼 수 있는 문자열 (MZ, DOS 헤더, 섹션 이름 등)이 포함될 수 있기 때문입니다. 반면, 두 번째 그림은 Shelter의 전체 PE 난독화 메커니즘을 사용하여 이 문제를 해결할 수 있음을 보여줍니다. PE-sieve 위키에서 언급했듯이, 이 옵션은 힙에 ".data" 또는 "rdata"와 같은 문자열이 존재하는 것만으로도 가능한 임플란트 PE를 경고하지만 (해당 영역에 실제 PE 내용이 없기 때문에 아무것도 덤프할 수 없음) 수많은 거짓 양성을 초래합니다.

    마지막으로, PE-sieve에는 높은 엔트로피 메모리 영역을 찾아 난독화된 임플란트의 존재를 탐지하는 비교적 새로운 옵션이 있습니다. 이 옵션(/obfusc)과 /data를 함께 사용하면 페이로드가 포함된 메모리 영역의 높은 엔트로피로 인해 페이로드 존재를 탐지할 수 있습니다 (완전히 암호화되어 있어 PE를 검색할 수는 없지만):

    전체 PE 난독화 탐지. 전체 PE 난독화 (Process Hacker).

    TO-DO

    Shelter는 사용할 준비가 되어 있고 OPSEC을 고려하여 개발되었지만, 가까운 미래에 추가될 몇 가지 개선 사항이 있습니다:

    • 전체 PE가 암호화될 때 엔트로피 감소.
    • BCryptEncrypt/BCryptDecrypt를 해당 Nt 함수로 대체.
    • 가젯 선택 과정에 약간의 무작위성 추가.

    이전 작업

    • Gargoyle
    • Ekko
    • Cronos
    도구 다운로드