Windbg – CPU 클럭 인터럽트의 이해 Tick

CPU 클럭 인터럽트 – 이해

특정 스레드가 CPU를 과도하게 사용하는 것을 막기 위해 지정된 클럭 시간 간격으로 클럭 인터럽트가 실행되어, 지정된 시간 동안만 스레드가 CPU를 사용할 수 있게 한다. 이를 진행하는 인터럽트가 클럭 인터럽트로, 시스템 시간을 업데이트하고, 스레드의 실행시간을 업데이트 한다(클럭 주기는 MaximumIncrement, Windbg에서 dd KeTimeIncrement l1명령을 통해 알 수 있다).

클럭 인터럽트가 동작하는 방식은 다음과 같다.

1. Tick(TickOffset)에 MaximumIncrement 값을 더한다.

2. 시스템 시간(nt!KeUpdateSystemTime)에 앞서 TickOffset에 저장한 틱 값을 더한다.

3. Tickcount를 1 증가한다.

4. 스레드 실행시간(nt!KeUpdateRunTime)을 증가시키고, 퀀텀 값을 낮춘다. 만약 퀀텀값이 0이 되면 컨텍스트 전환을 진행한다.

그리고 비스타 이후부터 스레드는 틱 카운터(Tick count)를 이용하여 이용 시간을 계산하고, 시스템에서는 시스템 부팅시 설정된 퀀텀 타겟값(퀀텀 재설정값에 클록 사이클수를 곱한 값)으로 판단하도록 변경되었다(이전 버전은 시스템 시간도 틱 카운터 기준으로 계산하였다). 스레드의 틱 카운터와 퀀텀 재설정값(QuntumReset)은 스레드 명령을 이용해 확인할 수 있다.

CPU 클럭 인터럽트 – 실습

// 스레드 이용 시간은 !thread 명령을 이용하여 확인할 수 있다.

0: kd> !thread -1

THREAD 82d89380 Cid 0000.0000 Teb: 00000000 Win32Thread: 00000000 RUNNING on processor 0

Not impersonating

DeviceMap 88008948

Owning Process 82d89640 Image: Idle

Attached Process 845c49e8 Image: System

Wait Start TickCount 17379 Ticks: 919 (0:00:00:14.336) ß 현재 스레드의 틱 카운터를 알 수 있다.

Context Switch Count 97422 IdealProcessor: 0

UserTime 00:00:00.000

KernelTime 00:04:17.464

Win32 Start Address nt!KiIdleLoop (0x82ccc2c0)

Stack Init 82d7ced0 Current 82d7cc1c Base 82d7d000 Limit 82d7a000 Call 0

Priority 0 BasePriority 0 UnusualBoost 0 ForegroundBoost 0 IoPriority 0 PagePriority 0

ChildEBP RetAddr Args to Child

82d7cb14 82ccee13 00000002 00000002 000000d1 nt!KeUpdateSystemTime

82d7cb14 8ce015d6 00000002 00000002 000000d1 nt!KeUpdateSystemTimeAssist+0x13 (FPO: [0,2] TrapFrame @ 82d7cb28)

WARNING: Stack unwind information not available. Following frames may be wrong.

82d7cc20 82ccc2cd 00000000 0000000e 00000000 intelppm+0x15d6

82d7cc24 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0xd (FPO: [0,0,0])

// 틱 카운터의 시간을 알아보기 위해, 먼저 현재 시스템의 클럭 값을 확인하여 보자. 클럭 값은 KeTimeIncrement에 저장되어 있다.

0: kd> dd KeTimeIncrement l1

82dbe9d0 00026160

// 이 값을 10진수로 변환하여, 밀리 세컨드로 나누어 주면 된다 초단위의 클럭 값을 알 수 있다.

0: kd> ? 00026160

Evaluate expression: 156000 = 00026160

0: kd> ?? 156000.0/10000000.0

double 0.015599999999999999 ß 0.0155초 간력으로 클럭이 설정 되어 있음을 알 수 있다.

0: kd> ?? 1.0 / 0.015599999999999999

double 64.102564102564102 ß 1초에 64번 클럭 인터럽트가 발생한다.

// 이제 시스템 이용 시간 확인을 위하여 시스템 틱 카운터 값을 계산해 보자.

0: kd> dd nt!KeTickCount l1

82d83580 0000477a

0: kd> ? 0000477a

Evaluate expression: 18298 = 0000477a ß 현재 시스템의 틱 카운터

// 그럼 먼저 전체 시스템 사용 시간을 구해보자. 먼저 앞서 구한 클럭 값을 곱한 후에 이를 60초 단위로 나누어 주면 분단위의 사용 시간을 알 수 있다.

0: kd> ?? 18298 * 0.015599999999999999

double 285.44880000000001

0: kd> ?? 285.44880000000001 / 60

double 4.7574800000000002 ß 4분간 사용하였음을 알 수 있다.

// 이렇게 분 단위 사용 시간을 알아 냈다. 이제 이용한 분단위 시간을 60초에 곱하여 남은 초단위 시간값을 알아 내 보자.

0: kd> ?? 285.44880000000001 - 60 * 4

double 45.448800000000006 ß 현재 시스템은 4분 45초 사용하였다.

// 분석한 정보가 실제 시스템 시간과 일치하는지 .time이라는 내부 명령을 이용해 확인해 보면 현재 시스템 시간과 동일함을 알 수 있다.

0: kd> .time

Debug session time: Wed Oct 16 11:12:22.051 2013 (UTC + 9:00)

System Uptime: 0 days 0:04:45.460 ß 4분 45초로 계산한 값과 동일 하다.

// 이를 현재 시스템의 틱 카운터를 값이 저장된 nt!KeTickCount를 확인하고, 앞에서 확인한 스레드 82d89380의 Wait Start TickCount 값을 빼면, 현재 스레드가 이용된 시간이 나오게 된다. 먼저 Wait Start TickCount 값인 17379를 우리가 구한 시스템 틱 카운터에서 빼면 현재 스레드가 이용한 틱 카운터 919를 얻을 수 있다.

0: kd> ?? 18298-17379

int 0n919 ß 스레드 82d89380의 틱카운터 919와 동일하다.

// 추가로 먼저 1초에 필요한 틱 카운터를 계산해 보자.

…중략

https://asecurity.dev/category/post/windows-reverse-2nd/

Facebook Comments

Leave A Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.