
iOS 커널 캐시 분석을 위한 IDA 툴킷.
이 포크는 IDA 9.x / Python 3 / iOS 27.0 beta 1에서 작동하도록 업데이트되었습니다.
ida_kernelcache는 iOS 커널캐시 작업을 더 쉽게 해주는 IDA Pro용 IDAPython 모듈입니다. 이 모듈은 다음 기능을 제공합니다:
__PRELINK_INFO 세그먼트를 파싱하여 Python 딕셔너리로 만듭니다.__got 섹션의 오프셋과 __stubs 섹션의 스텁 함수에 심볼을 추가합니다.주 처리 함수는 수동 분석이나 리버스 엔지니어링 전에 실행되도록 설계되었습니다. 기본 설정에서 IDA는 커널캐시의 많은 유용한 정보를 놓치는 경향이 있습니다. 이 스크립트들은 커널캐시의 알려진 구조를 활용하여 유용한 정보를 자동으로 전파함으로써 IDA를 도와줍니다.
모듈의 기본 기능 외에도 ida_kernelcache에는 iOS 커널캐시 분석을 더 쉽게 해주는 여러 스크립트가 포함되어 있습니다. 예를 들어, 함수가 사용하는 C 구조체를 자동 생성하는 스크립트를 사용할 수 있습니다.
ida_kernelcache에 사용된 많은 기술은 memctl에서 개발되어 직접 차용되었습니다.
ida_kernelcache는 IDA Pro 6.95에서 iOS 10.1.1, 11.0, 11.2, 11.3.1, 12.0 beta의 커널캐시로 테스트되었습니다. 현재 iOS 10 이상의 Arm64 커널캐시만 지원됩니다.
IDA에 이미 압축 해제된 커널캐시 파일이 로드되어 있어야 합니다. Apple의 IPSW를 다운로드할 수 있는 URL은 온라인에서 찾을 수 있으며, 커널캐시를 압축 해제할 수 있는 여러 공개 도구(memctl 포함)가 있습니다.
IDA에서 메뉴 표시줄의 "File" -> "Script file..."을 선택한 다음 메인 디렉토리의 ida_kernelcache.py 스크립트를 선택합니다. 그러면 IDAPython 인터프리터에 ida_kernelcache 모듈이 ida_kernelcache 및 kc라는 이름으로 로드됩니다. IDAPython 프롬프트에서 kc.kernelcache_process()를 입력하고 Enter를 눌러 커널캐시 분석을 시작합니다. 이 함수는 ida_kernelcache에서 지원하는 모든 주요 분석을 수행합니다. IDA가 새 함수를 식별하고 분석하는 동안 함수는 몇 분 동안 실행됩니다.
ida_kernelcache는 주소에 대한 사용자 이름을 덮어쓰지 않으려고 합니다. 즉, kernelcache_process로 초기화하기 전에 커널캐시가 수동으로 분석된 경우 사용자가 지정한 이름이 자동 이름 전파를 차단할 수 있으므로 결과가 완전하지 않을 수 있습니다. 그러나 ida_kernelcache가 이전 분석을 망치지 않을 것이라는 보장도 없으므로 이미 분석한 커널캐시 파일에서 kernelcache_process를 실행하기로 결정했다면 먼저 백업을 만드십시오.
ida_kernelcache는 ida_kernelcache.py를 통해 로드되도록 설계되었습니다. ida_kernelcache 디렉토리 내의 서브모듈은 직접 로드하도록 설계되지 않았습니다. 그러나 ida_kernelcache는 이러한 서브모듈 중 다수의 기능을 노출합니다. 각각의 기능은 다음과 같습니다:
ida_utilities:
이 모듈은 IDA의 일부 함수를 래핑하여 사용하기 쉬운 API를 제공합니다. 특히 유용한 함수는 is_mapped, read_word, read_struct, force_function, ReadWords입니다. is_mapped는 주소가 매핑되었는지 확인하고, 선택적으로 알려진 값을 포함하는지 확인합니다. read_word는 가변 크기의 워드를 주소에서 읽습니다. read_struct는 구조체 타입을 Python 딕셔너리 또는 Python 접근자 객체로 읽어서 데이터 구조체 파싱을 훨씬 쉽게 만듭니다. force_function은 여러 트릭을 시도하여 주소를 IDA의 함수 시작점으로 변환합니다. ReadWords는 범위 내의 데이터 워드와 해당 주소를 반복하는 제너레이터입니다.
build_struct: 이 내부 모듈은 구조체에 대한 일련의 접근을 기반으로 IDA 구조체를 자동으로 채우는 유틸리티를 포함합니다.
class_struct:
이 모듈은 C++ 가상 메서드 테이블과 클래스를 나타내는 IDA 구조체를 생성하는 함수를 제공합니다. initialize_vtable_structs는 (심볼이 추가된) 가상 메서드 테이블을 스캔하고 가상 메서드 포인터를 보유할 IDA 구조체를 만듭니다. initialize_class_structs는 가상 메서드에 대한 데이터 흐름 분석을 수행하여 각 클래스의 필드에 대한 접근을 식별한 다음 클래스를 나타내는 IDA 구조체를 구축합니다. 필드를 참조하는 것으로 보이는 명령어는 구조체 오프셋 참조로 변환됩니다. 자세한 내용은 모듈 문서 문자열을 참조하십시오.
ida_kernelcache_reload.py 스크립트는 ida_kernelcache.py와 동일하지만, ida_kernelcache 모듈과 모든 서브모듈을 강제로 다시 로드합니다. 주로 개발에 유용합니다.
scripts 디렉토리는 ida_kernelcache를 사용하여 어떤 종류의 분석을 수행하는 스크립트를 포함합니다. 이러한 스크립트는 메인 ida_kernelcache 모듈의 일부가 되기에는 너무 구체적이지만, 커널캐시를 리버스 엔지니어링할 때 유용합니다. 포함 내용:
find_virtual_method_overrides.py: 지정된 문자열을 포함하는 가상 메서드를 재정의하는 클래스의 하위 항목을 찾는 스크립트. 일치하는 재정의는 콘솔에 출력됩니다.
populate_struct.py: 현재 주소에서 시작하는 데이터 흐름 분석을 수행하여 C++ 클래스 또는 C 구조체의 필드를 채웁니다.
process_external_methods.py:
IOExternalMethod 또는 IOExternalMethodDispatch 배열을 퍼징 도구에서 사용할 표준 형식으로 처리합니다.
Hex-Rays 디컴파일러를 사용하는 경우 ida_kernelcache의 더 흥미로운 기능 중 하나는 자동 C++ 클래스 재구성입니다. 이는 OSMetaClass 정보와 데이터 흐름 분석을 사용하여 커널캐시에서 발견된 클래스를 나타내는 IDA 구조체를 만듭니다. 이러한 표현은 의사 코드 표현의 가독성을 크게 향상시킬 수 있습니다. 자세한 내용은 Reconstructing C++ classes in the iOS kernelcache using IDA Pro 게시물을 참조하십시오.
iOS 12에서 Apple은 일부 장치에 새로운 커널캐시 형식을 도입했습니다. 변경 사항 중에서 이 새로운 커널캐시의 커널 포인터는 리스트로 연결하기 위해 태그가 지정됩니다. 아마도 iBoot가 프리링크 딕셔너리의 _PrelinkLinkKASLROffsets 데이터 없이 커널을 슬라이드할 수 있도록 하기 위한 것으로 보입니다. 이 형식을 사용하는 스톡 커널캐시를 IDA에서 분석하는 것은 교차 참조가 누락되어 어렵습니다. 자세한 내용은 Analyzing the iOS 12 kernelcache's tagged pointers 문서를 참조하십시오.
추가 처리 없이 커널캐시의 포인터 태그를 제거하려면 kc.tagged_pointers.untag_pointers()를 실행하십시오.
이 기능 중 일부는 Apple 커널캐시보다 더 광범위하게 적용될 가능성이 있습니다(예: vtable 분석 및 심볼 전파, 또는 ida_utilities.py의 대부분의 함수). 그럼에도 불구하고 다른 유형의 바이너리에서 이를 테스트하지 않았으므로 가져오기 범위를 ida_kernelcache 모듈로만 제한했습니다.
ida_kernelcache는 MIT 라이선스로 배포됩니다.
ida_kernelcache의 많은 기능은 memctl에서 차용되었으며, 이 역시 MIT 라이선스로 배포됩니다. 다른 출처는 해당 파일의 주석에 표시되어 있습니다.
Brandon Azad
classes:
이 모듈은 커널캐시의 C++ 클래스에 대한 정보를 보유하는 ClassInfo 타입을 정의하고, 커널캐시에서 클래스를 스캔하고 클래스 이름에서 ClassInfo 객체로의 맵으로 전역 class_info 딕셔너리를 채우는 collect_class_info 함수를 제공합니다. ClassInfo 타입은 각 C++ 클래스에 대해 클래스 이름, OSMetaClass 인스턴스, 가상 메서드 테이블, 슈퍼클래스 이름을 기록합니다. 또한 각 ClassInfo 객체는 슈퍼클래스의 ClassInfo와 모든 직접 서브클래스의 ClassInfo에 대한 참조를 저장하므로 클래스 계층을 검사하고 탐색하기 쉽습니다. collect_class_info는 또한 모든 가상 메서드 테이블의 집합을 전역 vtables 집합에 저장합니다.
data_flow: 이 내부 모듈은 ida_kernelcache의 나머지 부분에서 사용하는 데이터 흐름 연산을 포함합니다.
kernel:
이 모듈은 base 및 prelink_info 전역 변수를 제공합니다. base는 커널 이미지의 기본 주소(커널의 Mach-O 헤더 시작)입니다. prelink_info는 파싱된 __PRELINK_INFO 딕셔너리입니다.
kplist:
이 모듈은 커널 스타일 plist를 파싱하는 kplist_parse 함수를 제공합니다.
metaclass:
이 모듈은 알려진 각 OSMetaClass 인스턴스에 대한 심볼을 추가하는 initialize_metaclass_symbols 함수를 제공합니다.
offset:
이 모듈은 initialize_data_offsets 및 initialize_offset_symbols 함수를 제공합니다. 전자는 세그먼트를 스캔하여 오프셋으로 변환할 수 있는 포인터를 찾습니다. 후자는 오프셋의 대상에 심볼이 있는 경우 각 kext의 __got 섹션에서 오프셋에 심볼을 추가합니다.
segment:
이 모듈은 IDA의 세그먼트 이름을 더 유용하게 변경하는 initialize_segments 함수를 제공합니다. 기본적으로 IDA는 번들 식별자의 추측과 해당 영역을 설명하는 Mach-O 섹션을 결합하여 세그먼트 이름을 만드는 것 같습니다. initialize_segments는 __PRELINK_INFO 딕셔너리에서 실제 번들 식별자를 추출하고 각 세그먼트의 이름을 번들 식별자, Mach-O 세그먼트, Mach-O 섹션을 포함하도록 변경합니다. 예를 들어, __TEXT.__const와 __DATA_CONST.__const를 구별할 수 있습니다. 이 모듈은 또한 지정된 주소를 포함하는 kext를 결정하는 kernelcache_kext 함수(최상위 수준에서 재내보내기됨)를 제공합니다(이전 iOS 11 분할 kext 커널캐시 형식에서만).
stub:
커널캐시의 많은 kext는 커널 본체의 함수로 점프하는 __stubs 섹션에 스텁 함수를 포함합니다. 불행히도 이러한 스텁은 교차 참조와 타입 정보 전파에 장벽을 제공합니다. 이 모듈은 이러한 문제를 해결하지는 않지만, 대상 함수 이름이 보이도록 스텁 함수의 이름을 자동으로 변경하여 스텁을 더 쉽게 살펴볼 수 있게 합니다. 스텁과 그 대상은 IDA에서 강제로 함수로 변환되므로 IDA의 함수가 원본 소스 코드의 함수와 일치하는 데 도움이 됩니다.
tagged_pointers: 새로운 iOS 12 병합 커널캐시 형식은 각 포인터의 상위 2바이트에 오프셋을 태그하여 포인터를 리스트로 체인화합니다. 이 모듈은 해당 태그 포인터를 처리하고 복원하는 함수를 포함합니다.
vtable:
이 모듈은 vtable_length, convert_vtable_to_offsets, vtable_overrides, initialize_vtable_symbols, initialize_vtable_method_symbols를 포함하여 가상 메서드 테이블 작업을 위한 많은 유용한 함수를 제공합니다. vtable_length는 지정된 주소가 vtable일 수 있는지 확인하고 vtable 길이를 반환합니다. 제너레이터 vtable_overrides는 슈퍼클래스가 사용하는 가상 메서드를 재정의하는 클래스의 가상 메서드를 열거합니다. initialize_vtable_symbols 함수는 식별된 각 vtable의 시작에 심볼을 추가합니다. initialize_vtable_method_symbols는 각 vtable에서 재정의된 메서드를 반복하고 슈퍼클래스에서 서브클래스로 심볼을 전파합니다. 이는 IOKit의 대부분의 기본 클래스가 비교적 완전한 심볼 정보로 XNU에 정의되어 있기 때문에 가능합니다. 서브클래스의 vtable에 있는 각 메서드 재정의는 슈퍼클래스의 메서드와 동일한 인터페이스를 준수해야 합니다. 즉, 슈퍼클래스의 가상 메서드 심볼에서 슈퍼클래스 이름을 서브클래스 이름으로 대체하여 재정의에 대한 심볼을 생성할 수 있습니다. 예를 들어, AppleKeyStore 클래스의 인덱스 7에 있는 가상 메서드에 대한 이름이 없지만, 슈퍼클래스 IOService의 인덱스 7에 있는 가상 메서드가 __ZNK9IOService12getMetaClassEv라고 불리는 경우, 인덱스 7은 서브클래스에서 __ZNK13AppleKeyStore12getMetaClassEv라고 불러야 한다고 추론할 수 있습니다. 이 기술은 대부분의 클래스에서 대부분의 가상 메서드에 심볼을 추가하는 데 사용할 수 있습니다.