среда, 16 марта 2011 г.

Исследуем ASLR

Сегодня неожиданно возник вопрос: одинаков ли адрес загрузки ntdll.dll во всех процессах. Поспорив немного, вопрос разбили на два: влияет ли ASLR на ntdll.dll и как, собственно, работает ASLR: отличаются ли адреса загрузки системных dll в разных процессах. Поскольку практика - мерило истинности, быстренько написали скрипт на питоне и все выяснили. Сам скрипт был написан очень быстро ( по сути, скопипастили пример proclist.py и слегка его модифицировали ). Вот быстрота написания скрипта и сподвигла меня написать этот пост. А заодно хочется продемонстрировать некоторые приемы работы с pykd.

Вот сам код:

import sys
from pykd import *

def moduleBase():

nt = loadModule( "nt" )

processList = typedVarList( nt.PsActiveProcessHead, "nt", "_EPROCESS", "ActiveProcessLinks" )

for process in processList:

dbgCommand( ".process /p %x" % process.getAddress() )
dbgCommand( ".reload /user" )

print "process %x " % process.getAddress(), "".join( [ chr(i) for i in process.ImageFileName.values() ] )

ntdll = loadModule("ntdll")
if ntdll != None: print "\tntdll: %x" % ntdll.begin()

kernel32 = loadModule("kernel32")
if kernel32 != None: print "\tkernel32: %x" % kernel32.begin()

if __name__ == "__main__":

moduleBase()

Запустив данный скрипт в отладчике ядра, мы получим что-то вроде:
process ffffffff859fbbb0   System
process ffffffff8bbf5460   smss.exe
    ntdll: 77d50000
    kernel32: 76b40000
process ffffffff81f6f6a8   csrss.exe
    ntdll: 77d50000
    kernel32: 76b40000
process ffffffff892435a8   wininit.exe
    ntdll: 77d50000
    kernel32: 76b40000
process ffffffff89269b98   csrss.exe
    ntdll: 77d50000
    kernel32: 76b40000
.......
и ответы на свои вопросы. Но не совсем сразу. Перезапустим систему и выполним скрипт еще раз - значения будет другие. Вот теперь уже все ясно. ASLR меняет адреса загрузки при каждом ребуте, в пределах одной загрузки адреса во всех процессах одинаковы.

Хочу обратить внимание на использование функции dbgCommand. Она позволяет выполнять обычные команды windbg. И если какой-то функционал не реализован в pykd, его можно "позаимствовать".

В данном случае, мы позаимстовали команду .process c ключиком /p. Без этого ключика можно было бы использовать функцию setCurrentProcess. Но к сожалению, данная функция не включает неявную трансляцию адресов. В результате, мы не можем получить актуальный список модулей пользовательского режима для каждого процесса. Тут то нам на помощь и  пришла спасительная  функция dbgCommand.

Комментариев нет:

Отправить комментарий