Аварийный дамп подразумевает изменение значения регистра между последовательными инструкциями

#windows #winapi #assembly #driver #crash-dumps

#Windows #winapi #сборка #драйвер #аварийные дампы

Вопрос:

В настоящее время я анализирую аварийный дамп от клиента, который произошел в результате BSOD. Я не могу предоставить аварийный дамп по соображениям конфиденциальности, но я зашел в тупик.

Сбой происходит в RtlSetBit функции внутри DDK. Вот запись контекста:

 rax=0000000000000000 rbx=fffff8800282da00 rcx=fffffa8007c10340
rdx=0000000000000000 rsi=0000000000000001 rdi=fffffa8007c102e0
rip=fffff8000168d0b4 rsp=fffff880057478e8 rbp=0000000000000000
 r8=0000000000000000  r9=0000000000000000 r10=fffff88001e5dca0
r11=0000000000000000 r12=0000000000000000 r13=fffffa800812feb0
r14=0000000000000001 r15=fffff88003490af0
iopl=0         nv up ei pl zr na po nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
nt!RtlSetBit 0x4:
fffff800`0168d0b4 0fab10          bts     dword ptr [rax],edx ds:002b:00000000`00000000=????????
  

Вот сборка для RtlSetBit :

 fffff800`0168d0b0 488b4108        mov     rax,qword ptr [rcx 8]
fffff800`0168d0b4 0fab10          bts     dword ptr [rax],edx << Exception
fffff800`0168d0b7 c3              ret
  

Что странно, так это то, что, как вы можете видеть, rax не содержит содержимого rcx 8 :

 2: kd> dq rcx 8
fffffa80`07c10348  fffffa80`07c10338 0000000b`00000014
  

Вместо rax этого отображается значение null.

Как это возможно? Я что-то упускаю?

Ответ №1:

Вероятно, на момент выполнения значение было равно 0 mov rax, qword ptr [rcx 8] . Перед bts выполнением другой поток изменил значение в памяти. Затем происходит сбой bts , и когда вы просматриваете память, вы видите обновленное значение, а не исходное 0.

Ответ №2:

Вы предполагаете, что инструкция перед перемещением выполнена. Но только потому, что оно находится в ассемблере перед ним, это не обязательно означает, что оно выполняется раньше. Переход прямо к bts может привести к такому неправильному поведению.

Причиной этого перехода может быть либо неправильный код (не знаю, есть ли у вас рукописный / оптимизированный ассемблер), либо переполнение стека / буфера / массива, которое изменило адрес возврата в стеке и сделало bts адресом возврата, и другие более неясные ошибки.

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

1. Я думаю, можно с уверенностью предположить, что mov выполняется (или была предпринята попытка выполнить). Предоставленная мной сборка представляет собой полную функцию RtlSetBit. Ничто из того, что я вижу, не указывает на какое-либо переполнение.

2. @ReferentiallySeethru: это не имеет ничего общего с ошибкой функции RtlSetBit. Это может быть целью перехода для всего остального во всей вашей программе, совершенно не связанной с RtlSetBit, это просто случайная цель перехода. Если у вас нет отладчика и вы можете его воспроизвести, такие ошибки ДЕЙСТВИТЕЛЬНО трудно отлаживать. Возможно, вы могли бы получить подсказку, посмотрев на stack и проверив, выглядит ли стек вызовов вменяемым, т. Е. Проверьте, действительно ли функция, находящаяся ранее в стеке вызовов, может вызывать ваш RtlSetBit. Но это не может опровергнуть «ошибку», только докажите, есть ли она у вас.

3. Да, стек вызовов выглядит нормальным, поэтому я не верил, что виновником был «неправильный сброс». Я не отвергаю то, что вы говорите, возможно, просто это кажется очень маловероятным в текущей ситуации. Однако я буду иметь это в виду, если мы не сможем продвинуться дальше.