
힙 메모리 풀 분석 도구
사전 참고: 이 도구는 asatools의 일부로 사용할 것을 권장하지만, 독립적으로도 사용할 수 있습니다.
libmempool은 Python 스크립트이자 GDB 분석 도구로,
Cisco ASA 장치의 다양한 힙 내부에서 발견되는 mempool 관련 데이터 구조를
분석하는 데 도움을 줍니다. 보통 이 정보는 힙 청크에 내장되어 있거나,
dlmalloc mstate 구조와 같은 다른 일반적인 힙 구조의
사용자 지정 확장입니다.
Cisco는 일반 할당, DMA 등 다양한 목적으로 매핑된 메모리 영역을 설명하기 위해 mempool이라는 용어를 사용합니다. 이러한 영역에는 일반적으로 dlmalloc과 같은 자체 힙이 포함됩니다. 이러한 mempool에서의 할당 루틴은 일반적으로 기본 힙 할당자를 감싸는 래퍼를 사용하여 수행되며, 이 래퍼는 결과 할당에 mempool 특정 메타데이터를 주입합니다. 이 메타데이터를 줄여서 mempool 헤더 또는 mh라고 부릅니다. 마찬가지로 mempool을 mp라고 자주 부릅니다. mempool 헤더를 설명하는 데 mh를 사용하는 것은 Cisco ASA lina 바이너리에서 발견되는 다양한 문자열과도 일치합니다.
libmempool은 mempool 헤더 및 데이터 구조와 관련된 일부 항목을 분석하기 위한 독립 실행형 도구로 사용할 수 있지만, 가장 큰 가치는 libdlmalloc이나 libptmalloc과 같은 다른 라이브러리의 콜백으로 사용될 때 발휘됩니다.
사용 중인 청크를 추적하는 데 사용되는 bins와 같은 mempool의 특정 측면은 dlmalloc 2.8.x mstate 구조 내부에 포함되어 있으며 동일한 bin 크기 체계를 따릅니다. 이는 거의 필연적으로 mempool 데이터를 캡슐화하는 mstate를 libdlmalloc을 사용하여 최소한 살펴봐야 함을 의미합니다.
libmempool은 dlmalloc2.8 또는 glibc의 ptmalloc2 기반 할당자를 사용하는 32비트/64비트 Cisco ASA 버전(ASA5500-X 시리즈 및 GNS3 모두)에서 테스트되었습니다. 수많은 8.x.y 및 9.x.y 브랜치를 포함한 여러 ASA 버전에서 테스트되었습니다. 그러나 특정 버전에서는 작동하지 않을 가능성도 충분히 있습니다.
libmempool을 독립 실행형으로 사용하려면 프로젝트에 libmempool.py 파일을
import하기만 하면 됩니다. 이를 통해 mpcallback 객체를 등록하는 등의
몇 가지 제한된 작업을 수행할 수 있습니다. 이는 기록된 힙 기능에 대한
오프라인 분석을 수행할 때 유용할 수 있습니다.
GDB에 import하려면 스크립트에는 Python을 지원하는 GDB만 필요합니다. 대부분의 최신 GDB 버전은 Python 3로 전환했지만 일부는 여전히 2.7을 요구합니다. 이 스크립트는 둘 다에서 테스트되었지만, 주로 개발 및 테스트는 Python 3로 수행됩니다.
(gdb) source libmempool_gdb.py
GDB 관련 로직의 대부분을 libmempool.py에서 분리하여 libmempool_gdb.py에 넣은 이유는 추상화를 테스트하고 GDB 외부에서도 libmempool.py를 쉽게 사용할 수 있도록 하기 위해서입니다. 이는 향후 변경될 가능성이 높습니다. 결국 libheap이나 shadow와 같은 다른 힙 분석 도구에서 사용하는 것과 유사한 디버그 엔진 추상화를 구현하고 싶기 때문입니다.
libmempool의 가치 중 상당수는 노출된 mpcallback 콜백 함수에서 나오지만,
살펴볼 수 있는 여러 기본 제공 GDB 명령이 있습니다.
(gdb) mphelp
[libmempool] mempool commands for gdb
[libmempool] mpheader -v -x <addr> : show chunk contents (-v for verbose, -x for data dump)
[libmempool] mpbinwalk [-v] [-p <addr>] <sz> : walk an mpbin and operate on each chunk in a bin
[libmempool] mpbin <addr> : determine to which bin an mp_header is associated to
[libmempool] mpmstate <addr> : display and cache a mempool mstate address
[libmempool] mphelp
어떤 mempool 헤더의 주소를 알고 있다고 가정하면 해당 데이터를 분석할 수 있습니다. 이 주소는 mempool 헤더 자체의 주소여야 하며, 코어 할당자의 청크 메타데이터 주소가 아니라는 점에 유의하세요. 따라서 다음과 같이 내용을 덤프할 수 있습니다:
(gdb) mpheader 0x7fffbc1c1ca0
struct mp_header @ 0x7fffbc1c1ca0 {
mh_magic = 0xa11c0123
mh_len = 0x3
mh_refcount = 0x10000
mh_unused = 0x0
mh_fd_link = 0x7fffbc1c19e0 (OK)
mh_bk_link = 0x7ffff7ff7540 (-)
alloc_pc = 0x55555849e260 (-)
free_pc = 0x0 (-)
}
-x를 사용하여 청크의 16진수 내용을 덤프할 수도 있습니다.
(gdb) mpheader -x 0x7fffbc1c1ca0
struct mp_header @ 0x7fffbc1c1ca0 {
mh_magic = 0xa11c0123
mh_len = 0x3
mh_refcount = 0x10000
mh_unused = 0x0
mh_fd_link = 0x7fffbc1c19e0 (OK)
mh_bk_link = 0x7ffff7ff7540 (-)
alloc_pc = 0x55555849e260 (-)
free_pc = 0x0 (-)
0x3 bytes of chunk data:
0x7fffbc1c1cd0: 0x55 0x04 0x03
}
mempool에는 bins 개념이 있습니다. bins는 dlmalloc bins와 동일한 크기의
이중 연결 리스트이지만, 해제된(free) 청크가 아니라 사용 중인(inuse) 청크를
추적하는 데 사용됩니다. 이는 Cisco 장치에서 메모리 사용량을 기록하기 위한
것입니다. mempool 헤더를 포함하는 청크를 발견했지만 힙에서 mstate 구조가
어디에 있는지 아직 모르는 경우가 자주 있습니다. 위치를 파악하려면 mpbin
명령을 사용할 수 있습니다. 이 명령은 현재 사용 중인 청크가 들어 있는
mempool bin의 주소를 알려줍니다. 예를 들어:
(gdb) mpbin 0x7fffbc1c1ca0
[libmempool] Found bin start at 0x7ffff7ff7540
[libmempool] Cached new mp_mstate @ 0x7ffff7ff73c0
[libmempool] mp_smallbin[08] - sz: 0x00000040 cnt: 0x00d3, mh_fd_link: 0x7fffbc1c1ca0
이 명령은 mempool mstate 부분의 시작을 찾았을 뿐만 아니라 이를 캐시하고
청크가 존재하는 특정 bin을 나열합니다. 선택적으로 mpbinwalk 명령을 사용하여
이 bin의 모든 0xd3 청크를 나열하거나 특정 개수까지만
나열할 수 있습니다:
(gdb) mpbinwalk 0x40
[libmempool] mp_header @ 0x7ffff7ff7540 - mh_len: 0x00000000, alloc_pc: 0x00000000 [BIN HEAD]
[libmempool] mp_header @ 0x7fffbc1c1ca0 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[libmempool] mp_header @ 0x7fffbc1c19e0 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[libmempool] mp_header @ 0x7fffbc1c1750 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[libmempool] mp_header @ 0x7fffbc1bffa0 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[libmempool] mp_header @ 0x7fffbc1bff60 - mh_len: 0x00000003, alloc_pc: 0x5555584a1288
[libmempool] mp_header @ 0x7fffbc1c0050 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[...]
이제 mstate 구조의 mempool 부분 전체(즉, 모든 bins 및 관련 통계)를 덤프하려면
mpmstate 명령을 사용할 수 있습니다: