V>теперь при APC_LEVEL в эту ветку вообще не попадаю.
Разумеется, ты ж из таймера это делаешь (функция KiProcessTimerDpcTable в стеке), они на DISPATCH_LEVEL выполняются. Итого тебе: читать про DPC/таймеры в документации и думать, как перепроектировать драйвер (если возможно), потому что если будешь делать по варианту 2
, то работать-то оно будет, но нужно будет ещё синхронизацию правильную навесить, т.е. нельзя будет завершить процесс, страницы которого проецируешь, пока выполняется DPC/таймер. Вкратце, в момент завершения процесса (как ловить — тут есть варианты) ждать, пока не закончится работа с памятью (можно сам таймер ждать, можно событие, ...) и затем только отпускать процесс в вечный путь. Зачем это нужно — процесс может быть убит в любой момент, ты не контролируешь это.
x64>Да, но зачем же недокументированное предлагать при наличии правильной альтернативы (MmGetSystemAddressForMdlSafe)?
Ну хотя бы потому, что юзермодный код может подкозлить пока там драйвер чухается — а именно отмапить адреса которые драйвер получил от ZwMapViewOfSection и подсунуть что-нить свое. А с точки зрения драйвера весь юзермод населен козлами. Исключая юзермод, имеющий включенную Administrators группу в токене — он тоже населен козлами, но этим можно доверять.
Как много веселых ребят, и все делают велосипед...
Креш ОС при обращении к шаровой памяти
От:
Аноним
Дата:
23.04.13 12:52
Оценка:
В приложении создаю шаровую память для передачи информации с приложения в драйвер:
#define VIDEO_DRV_SIZE 2048 * 1536 * 3 + 3 * sizeof(int) // прошу не ругать , поставил этого крокодила временно
......
//create a memory share
m_hMemoryShareDrv = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
VIDEO_DRV_SIZE,
L"Global\\Restricted\\SplitCamDrvData");
if (!m_hMemoryShareDrv)
{
return;
}
m_pBufMemoryShareDrv = (uint8_t*)MapViewOfFile(m_hMemoryShareDrv,
FILE_MAP_ALL_ACCESS,
0,
0,
VIDEO_DRV_SIZE);
...............
далее записываю в эту память инфу
if (m_pBufMemoryShareDrv)
{
uint8_t* pBuf;
uint32_t bufSz = win32::Bmp24GetBufferSize(iWidth, iHeight);
memset(m_pBufMemoryShareDrv, 0, VIDEO_DRV_SIZE);
memcpy(m_pBufMemoryShareDrv, &bufSz, sizeof(uint32_t));
int i = sizeof(uint32_t);
memcpy(m_pBufMemoryShareDrv + i, &iWidth, sizeof(uint32_t));
i += sizeof(uint32_t);
memcpy(m_pBufMemoryShareDrv + i, &iHeight, sizeof(uint32_t));
i += sizeof(uint32_t);
}
Все ок!
Теперь в драйвере подключаюсь к этой памяти
А>На последней строке Вин7 32 крешится. Что сделал не так?
В контексте какого процесса зовётся ZwMapViewOfSection() и в каком контексте потом происходит обращение к памяти? Если, например, проецируешь в контексте вызывающего процесса, а читать потом пытаешься в потоке ядра, — получишь падение, естественно.
x64>В контексте какого процесса зовётся ZwMapViewOfSection() и в каком контексте потом происходит обращение к памяти? Если, например, проецируешь в контексте вызывающего процесса, а читать потом пытаешься в потоке ядра, — получишь падение, естественно.
В драйвере есть функция, которая вызывается периодически, когда надо прочитать кадр. При первом ее вызове я вызываю
status = ZwMapViewOfSection(m_SectionHandle, ZwCurrentProcess(),
Теперь в драйвере пробую почитать данный с приложения, используя m_pAddrMap
m_pAddrMap — usermode адрес и валидный только в контексте процеса, где была вызвана ZwMapViewOfSection, если обратиться по этому адресу в контексте другого процесса естественно KMODE_EXCEPTION_NOT_HANDLED(STATUS_ACCESS_VIOLATION)
Короче, слушай внимательно. Про контексты и адресные пространства тебе уже объяснили. Далее, если тебе реально необходим доступ к проекции в любом контексте, то для решения проблемы варианта у тебя два: 1. [попроще] создать проекцию через ZwMapViewOfSection(), а при каждом обращении к памяти аттачиться к а.п. исходного процесса через KeStackAttachProcess(), однако доступ к такой памяти можно будет выполнять только на IRQL <= APC_LEVEL, или 2. [посложнее] сразу спроецировать память процесса в верхние адреса, которые "всегда доступны" в ядре, т.к. общие для всех процессов, это делается вызовами MmAllocateMdl(), MmProbeAndLockPages() и MmGetSystemAddressForMdlSafe(), — плюс в том, что память будет зафиксирована в физической памяти и к ней можно будет обращаться в прямом смысле отовсюду, включая повышенный IRQL, однако минус в том, что придётся тем или иным способом следить за уничтожением процесса, чтобы вовремя разблокировать страницы и удалить проекцию, иначе получишь сюрпризы типа такого.
x64>Короче, слушай внимательно. Про контексты и адресные пространства тебе уже объяснили. Далее, если тебе реально необходим доступ к проекции в любом контексте, то для решения проблемы варианта у тебя два: 1. [попроще] создать проекцию через ZwMapViewOfSection(), а при каждом обращении к памяти аттачиться к а.п. исходного процесса через KeStackAttachProcess(), однако доступ к такой памяти можно будет выполнять только на IRQL <= APC_LEVEL, или 2. о[/url].
что-то не выходит, взял первый вариант.
1. В конструкторе главного процесса запускаю поток
status = PsCreateSystemThread(
&hThread,
THREAD_ALL_ACCESS,
NULL, NULL, NULL,
Thread_proc, NULL);
2. в Thread_proc() подключаюсь к памяти приложения
V>> if ( KeGetCurrentIrql() <= 2) x64>Во-первых, не 2, а DISPATCH_LEVEL. x64>Во-вторых, какой ещё DISPATCH_LEVEL?! x64>Максимум, APC_LEVEL здесь можно, я ж писал.
я смотрел по логу, функция вызывается с Irql == 2 (DISPATCH),
т.е в APC_LEVEL вообще я попасть не могу?
O>>...весь юзермод населен козлами. x64>Иногда твоё образное мышление доставляет =)))
Профессиональная деформация секурити разработчика. Добавлю что если уж юзать ZwMap* и аттачиться к процессу — то лучше это городить в системном процессе — KeStackAttachProcess( PsInitialSystemProcess().. ) и вперед...
Как много веселых ребят, и все делают велосипед...
O>Добавлю что если уж юзать ZwMap* и аттачиться к процессу — то лучше это городить в системном процессе — KeStackAttachProcess( PsInitialSystemProcess().. ) и вперед...
Так ему ж память с процессом шарить надобно.
Предлагаешь а.п. ядра проецировать в процесс, что ли?
O>>Добавлю что если уж юзать ZwMap* и аттачиться к процессу — то лучше это городить в системном процессе — KeStackAttachProcess( PsInitialSystemProcess().. ) и вперед... x64>Так ему ж память с процессом шарить надобно.
Ну процесс у него создает секцию сам (CreateFileMapping'ом) и сам же отображает себе в АП, а драйаер открывает по имени ту же секцию и отображает в АП системного процесса во избежание несчастных случаев. Все шарится и в тоже время все безопасно как Contex Classic. Вообще секция — это конечно не самый лучший и уж точно не самый простой способ обмениваться данными с драйверами, но раз уж ТС хочет именно так.. Может у него есть какие нить свои скрытые мотивы.
x64>Предлагаешь а.п. ядра проецировать в процесс, что ли?
Ась?
Как много веселых ребят, и все делают велосипед...
O>>Может у него есть какие нить свои скрытые мотивы. x64>Возможно, скорость? x64>LPC ведь недокументировано. x64>А через I/O Control медленнее будет. x64>Хотя, на современном железе уже не так важно, наверное...
Я бы сделал так — слал бы драйверу IOCTL со структуркой в которой поинтер на юзермодный буфер и вспомогательную инфу (как пить дать ему еще ивенты понадобятся и все такое). Драйвер бы буфер лочил/отображал бы все это добро к себе в кернелмод при помощи этого
и ObReference*** (для ивентов etc) и далее всегда имел бы все под рукой "тепленьким". Минусы — надо содержать постоянно в кернеловском АП буфер (хз какого размера) — в ведь нехорошо его занимать без надобности.
Как много веселых ребят, и все делают велосипед...