디버거 명령 프로그램 예제
다음 섹션에서는 디버거 명령 프로그램에 대해 설명합니다.
.foreach 토큰 사용
다음 예제에서는 .foreach 토큰을 사용하여 5a4d의 WORD 값을 검색합니다. 발견된 각 5a4d 값에 대해 디버거는 5a4d DWORD가 발견된 주소부터 8개의 DWORD 값을 표시합니다.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place L8 }
다음 예제에서는 .foreach 토큰을 사용하여 5a4d의 WORD 값을 검색합니다. 발견된 각 5a4d 값에 대해 디버거는 5a4d DWORD가 발견된 주소 이전에 4바이트부터 시작하여 8개의 DWORD 값을 표시합니다.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc place -0x4 L8 }
다음 예제에서는 동일한 값을 표시합니다.
0:000> .foreach (place { s-[1]w 77000000 L?4000000 5a4d }) { dc ( place -0x4 ) L8 }
참고 명령의 OutCommands 부분에서 변수 이름에 대해 작업하려면 변수 이름 다음에 공백을 추가해야 합니다. 예를 들어 이전 예제에서는 변수 위치 와 빼기 연산자 사이에 공백이 있습니다.
-[1] 옵션을 s(검색 메모리) 명령과 함께 사용하면 출력에 해당 주소에 있는 값이 아니라 찾은 주소만 포함됩니다.
다음 명령은 0x77000000 0x7F000000 메모리 범위에 있는 모든 모듈에 대한 자세한 모듈 정보를 표시합니다.
0:000> .foreach (place { lm1m }) { .if ((${place} >= 0x77000000) & (${place} <= 0x7f000000)) { lmva place } }
lm(로드된 모듈 나열) 명령과 함께 1m 옵션을 사용하면 출력에 모듈의 전체 설명이 아닌 모듈의 주소만 포함됩니다.
앞의 예제에서는 ${ }(별칭 인터프리터) 토큰을 사용하여 별칭이 다른 텍스트 옆에 있더라도 대체되도록 합니다. 명령에 이 토큰이 포함되지 않은 경우 옆에 있는 여는 괄호로 별칭을 바꿀 수 없습니다. ${} 토큰은 .foreach 및 실제 별칭에 사용되는 변수에서 작동합니다.
프로세스 목록 걷기
다음 예제에서는 커널 모드 프로세스 목록을 살펴보고 목록의 각 항목에 대한 실행 파일을 표시합니다.
이 예제는 텍스트 파일로 저장하고 $$>< (스크립트 파일 실행) 명령을 사용하여 실행해야 합니다. 이 명령은 전체 파일을 로드하고, 모든 캐리지 반환을 세미콜론으로 바꾸고, 결과 블록을 실행합니다. 이 명령을 사용하면 전체 프로그램을 한 줄로 짜내는 대신 여러 줄과 들여쓰기를 사용하여 읽을 수 있는 프로그램을 작성할 수 있습니다.
이 예제에서는 다음 기능을 보여 줍니다.
$t 0, $t 1 및 $t 2 의사 레지스터는 이 프로그램에서 변수로 사용됩니다. 이 프로그램은 Procc 및 $ImageName 별칭도 사용합니다.
이 프로그램은 MASM 식 계산기를 사용합니다. 그러나 @@c++( ) 토큰이 한 번 나타납니다. 이 토큰을 사용하면 프로그램에서 C++ 식 계산기를 사용하여 괄호 내에서 식을 구문 분석합니다. 이 사용을 사용하면 프로그램에서 C++ 구조 토큰을 직접 사용할 수 있습니다.
? 플래그는 r(Registers) 명령과 함께 사용됩니다. 이 플래그는 의사 레지스터 $t 2에 형식화된 값을 할당합니다.
$$ Get process list LIST_ENTRY in $t0.
r $t0 = nt!PsActiveProcessHead
$$ Iterate over all processes in list.
.for (r $t1 = poi(@$t0);
(@$t1 != 0) & (@$t1 != @$t0);
r $t1 = poi(@$t1))
{
r? $t2 = #CONTAINING_RECORD(@$t1, nt!_EPROCESS, ActiveProcessLinks);
as /x Procc @$t2
$$ Get image name into $ImageName.
as /ma $ImageName @@c++(&@$t2->ImageFileName[0])
.block
{
.echo ${$ImageName} at ${Procc}
}
ad $ImageName
ad Procc
}
LDR_DATA_TABLE_ENTRY 목록 걷기
다음 예제에서는 사용자 모드 LDR_DATA_TABLE_ENTRY 목록을 살펴보고 각 목록 항목의 기본 주소와 전체 경로를 표시합니다.
앞의 예제와 마찬가지로 이 프로그램은 파일에 저장되고 $$>< (스크립트 파일 실행) 명령으로 실행되어야 합니다.
이 예제에서는 다음 기능을 보여 줍니다.
이 프로그램은 MASM 식 계산기를 사용합니다. 그러나 두 위치에서 는 @@c++( ) 토큰이 나타납니다. 이 토큰을 사용하면 프로그램에서 C++ 식 계산기를 사용하여 괄호 내에서 식을 구문 분석합니다. 이 사용을 사용하면 프로그램에서 C++ 구조 토큰을 직접 사용할 수 있습니다.
? 플래그는 r(Registers) 명령과 함께 사용됩니다. 이 플래그는 의사 레지스터 $t 0 및 $t1에 형식화된 값을 할당합니다. 루프 본문에서 $t 1 에는 ntdll!_LDR_DATA_TABLE_ENTRY\*형식이 있으므로 프로그램에서 직접 멤버 참조를 만들 수 있습니다.
사용자 이름 별칭 $Base 및 $Mod 이 프로그램에서 사용됩니다. 달러 기호는 이러한 별칭이 현재 디버거 세션에서 이전에 사용되었을 가능성을 줄입니다. 달러 기호는 필요하지 않습니다. ${/v: } 토큰은 별칭을 문자 그대로 해석하므로 스크립트를 실행하기 전에 정의된 경우 대체되지 않습니다. 블록과 함께 이 토큰을 사용하여 블록이 사용되기 전에 별칭 정의를 방지할 수도 있습니다.
.block 토큰은 별칭 대체 단계를 추가하는 데 사용됩니다. 별칭 바꾸기는 전체 스크립트가 로드될 때 한 번, 각 블록이 입력될 때 한 번 발생합니다. .block 토큰과 해당 중괄호가 없으면 .echo 명령은 이전 줄에 할당된 $Mod 및 $Base 별칭의 값을 받지 않습니다.
$$ Get module list LIST_ENTRY in $t0.
r? $t0 = &@$peb->Ldr->InLoadOrderModuleList
$$ Iterate over all modules in list.
.for (r? $t1 = *(ntdll!_LDR_DATA_TABLE_ENTRY**)@$t0;
(@$t1 != 0) & (@$t1 != @$t0);
r? $t1 = (ntdll!_LDR_DATA_TABLE_ENTRY*)@$t1->InLoadOrderLinks.Flink)
{
$$ Get base address in $Base.
as /x ${/v:$Base} @@c++(@$t1->DllBase)
$$ Get full name into $Mod.
as /msu ${/v:$Mod} @@c++(&@$t1->FullDllName)
.block
{
.echo ${$Mod} at ${$Base}
}
ad ${/v:$Base}
ad ${/v:$Mod}
}