다음을 통해 공유


PEB가 페이징된 경우 기호 매핑

기호를 로드하기 위해 디버거는 운영 체제에서 로드한 모듈 목록을 확인합니다. 사용자 모드 모듈 목록에 대한 포인터는 PEB(프로세스 환경 블록)에 저장된 항목 중 하나입니다.

메모리를 회수하기 위해 메모리 관리자는 다른 프로세스 또는 커널 모드 구성 요소에 대한 공간을 만들기 위해 사용자 모드 데이터를 페이아웃할 수 있습니다. 페이징되는 사용자 모드 데이터에는 PEB 데이터 구조가 포함될 수 있습니다. 이 데이터 구조가 없으면 디버거는 기호를 로드할 이미지를 확인할 수 없습니다.

참고 이는 사용자 모드 모듈의 기호 파일에만 영향을 줍니다. 커널 모드 모듈 및 기호는 다른 목록에서 추적되므로 영향을 받지 않습니다.

사용자 모드 모듈이 현재 프로세스에 매핑되고 해당 모듈의 기호를 수정하려고 하는 경우를 가정해 보겠습니다. 모듈의 가상 주소 범위에서 주소를 찾습니다. 예를 들어 모듈이 주소 7f78e9e000F를 포함하는 가상 주소 범위에 매핑되어 있다고 가정합니다. 다음 명령을 입력합니다.

3: kd> !vad 7f78e9e000F 1

명령 출력은 모듈의 VAD(가상 주소 설명자)에 대한 정보를 표시합니다. 명령 출력에는 모듈의 기호를 로드하는 데 사용할 수 있는 Reload 명령 문자열도 포함됩니다. 다시 로드 명령 문자열에는 메모장 모듈의 시작 주소(000007f7'8e9e0000) 및 크기(32000)가 포함됩니다.

VAD @ fffffa80056fb960
...
Reload command: .reload notepad.exe=000007f7`8e9e0000,32000

기호를 로드하려면 명령 문자열 다시 로드에 지정된 명령을 입력합니다.

.reload notepad.exe=000007f7`8e9e0000,32000

다음은 약간 다른 기술을 사용하는 또 다른 예입니다. 이 예제에서는 PEB를 페이징할 때 !vad 확장을 사용하여 기호를 매핑하는 방법을 보여 줍니다. 기본 개념은 .reload 명령을 사용하여 필요한 기호를 로드할 수 있도록 관련 DLL의 시작 주소와 크기를 찾는 것입니다. 현재 프로세스의 주소가 0xE0000126'01BA0AF0이고 기호를 수정하려는 경우를 가정해 보겠습니다. 먼저 !process 명령을 사용하여 VAD(가상 주소 설명자) 루트 주소를 가져옵니다.

kd> !process e000012601ba0af0 1
PROCESS e000012601ba0af0
    SessionId: 2  Cid: 0b50    Peb: 6fbfffde000  ParentCid: 0efc
    DirBase: 079e8461  ObjectTable: e000000600fbceb0  HandleCount: 360.
    Image: explorer.exe
    VadRoot e000012601a35e70 Vads 201 Clone 0 Private 917. Modified 2198. Locked 0.
...

그런 다음 !vad 확장을 사용하여 프로세스와 연결된 VAD 트리를 나열합니다. "EXECUTE_WRITECOPY"라는 레이블이 지정된 VAD는 코드 모듈에 속합니다.

kd> !vad e000012601a35e70
VAD     level      start      end    commit
...
e0000126019f9790 ( 6)      3fff0    3fff7        -1 Private      READONLY
e000012601be1080 ( 7)   37d9bd30 37d9bd3e         2 Mapped  Exe  EXECUTE_WRITECOPY  <-- these are DLLs
e000012600acd970 ( 5)   37d9bec0 37d9bece         2 Mapped  Exe  EXECUTE_WRITECOPY
e000012601a5cba0 ( 7)   37d9c910 37d9c924         2 Mapped  Exe  EXECUTE_WRITECOPY
...

그런 다음 !vad 확장을 다시 사용하여 관심 있는 DLL을 보유하는 페이징된 메모리의 시작 주소와 크기를 찾습니다. 그러면 올바른 DLL을 찾았음이 확인됩니다.

kd> !vad e000012601be1080 1

VAD @ e000012601be1080
  Start VPN:      37d9bd30  End VPN: 37d9bd3e  Control Area:  e00001260197b8d0
  First ProtoPte: e0000006013e00a0  Last PTE fffffffffffffffc  Commit Charge         2 (2.)
  Secured.Flink          0  Blink           0  Banked/Extend:        0
  File Offset   0
   ImageMap ViewShare EXECUTE_WRITECOPY

...
        File: \Windows\System32\ExplorerFrame.dll

"VPN 시작" 필드(이 경우 0x37D9BD30)는 시작 가상 페이지 번호를 나타냅니다. 이 주소는 페이지 크기를 곱하여 실제 주소로 변환해야 합니다. ?을 사용할 수 있습니다 . (식 평가) 명령을 사용하여 이 값을 0x2000 곱합니다. 이 값은 예제에서 가져온 Itanium 기반 컴퓨터의 페이지 크기입니다.

kd> ? 37d9bd3e*2000 
Evaluate expression: 7676040298496 = 000006fb`37a7c000

그런 다음 범위의 크기를 바이트로 변환할 수 있습니다.

kd> ? 37d9bd3e-37d9bd30+1 <--   computes the number of pages
Evaluate expression: 15 = 00000000`0000000f
kd> ? f*2000
Evaluate expression: 122880 = 00000000`0001e000        

따라서 ExplorerFrame.dll 주소 0x000006Fb'37A7C000에서 시작하며 0x1E000 바이트가 큽니다. 다음을 사용하여 기호를 로드할 수 있습니다.

kd> .reload /f ExplorerFrame.dll=6fb`37a7c000,1e000