User Level Hooking을 하다보면 각 Dll 들의 Function Table을 Hooking 하는 경우가 있습니다. 이러한 경우 Hooking 과정에서 Access violation 이 나타나는 경우가 종종 있지요. 예를 들면 Image의 특정 Table Address를 수정한다 던지 하는 경우에 말이죠. 이런 경우 Access violation이 발생했을때는 Image Memory Page의 Protect Mask를 확인해 보시는 것이 좋습니다. 한가지 예를 보여드리죠 .
FAULTING_IP:
XXX!Init+52bd
5ff064ad 8807 mov byte ptr [edi],al
EXCEPTION_RECORD: ffffffff — (.exr 0xffffffffffffffff)
ExceptionAddress: 5ff064ad (XXX!Init+0×000052bd)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000001
Parameter[1]: 76e39e1e
Attempt to write to address 76e39e1e
FAULTING_THREAD: 00001640
위에 표시한 부분은 !analyze -v를 쳤을 때 나타는 일부분입니다. Exception을 발생시킨 Instruction의 인자를 보면 edi와 al을 참조하고 있습니다. al의 경우 단순한 Value 이기 때문에 별로 상관 없지만 edi의 경우 Address Access를 하고 있습니다. 그렇다면 edi의 값이 잘못된 것일까 ??
0:000> r edi
edi=76e39e1e
0:000> dd 76e39e1e
76e39e1e 00000000 00000000 00000000 00000000
76e39e2e 00000000 02430000 00000000 00000000
76e39e3e 00000000 00000000 00000000 021e0000
76e39e4e 00000000 00000000 00000000 00000000
76e39e5e 00000000 00000000 0000007f 00000000
76e39e6e 00000000 00000000 00000000 00000000
76e39e7e 00000029 00000000 00000000 00000000
76e39e8e 00000000 021c0000 00000000 00000000
위에서 볼 수 있듯이 edi의 메모리는 정상적이군요. 그렇다면 왜 76e39e1e에 Write Access가 발생했을때 문제가 되는 것일까요 ? 이것은 생각 보다 단순합니다. 실제로 address 명령을 통해서 76e39e1e Memory의 Protect Mask를 확인해 보면 쉽게 그답을 찾을 수 있습니다.
0:000> !address 76e39e1e
76e30000 : 76e31000 - 0000a000
Type 01000000 MEM_IMAGE
Protect 00000020 PAGE_EXECUTE_READ
State 00001000 MEM_COMMIT
Usage RegionUsageImage
FullPath C:\WINDOWS\system32\rtutils.dll
76e39e1e가 포함된 Memory Page의 경우 현제 PAGE_EXECUTE_READ 가 Protect Mask로 설정되어 있군요. 그리고 Access 하고자 하는 Page에 Write 권한이 없기 때문에 Access violation 발생하게 된것이죠.
실제로 VirtualProtect를 사용해서 Protect Mask를 변경할 경우 Windows는 Memory Page 단위 ( x86기준 0×1000)로 Protect Mask를 변경합니다. 여기서 가장 실수하기 쉬운 것은 VirtualProtect를 이용하여 Memory Page 보다 작은 사이즈로 Write 권한이 없는 Protect Mask로 변경하고 그 다음 Address를 Access 하는 경우인데 이러한 경우는 어김없이 Access violation이 발생합니다.
조심해서 사용하시길…
최근 답글