1. Если вы только начинаете программировать на ассемблере и не знаете с чего начать, тогда попробуйте среду разработки ASM Visual IDE
    (c) на правах рекламы
    Скрыть объявление

Access violation при возврате из 64 битного режима

Тема в разделе "WASM.WIN32", создана пользователем Thetrik, 13 фев 2020 в 01:59.

  1. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    Всем привет.
    Не пойму в чем может быть проблема. В общем есть такой код:
    Код (ASM):
    1. format PE console
    2.  
    3. entry Start
    4.  
    5. include "decl.inc"
    6.  
    7. proc Start
    8.     locals
    9.         tCounters VM_COUNTERS64 ?
    10.         dwWritten dd ?
    11.         pfn dd ?
    12.     endl
    13.  
    14.     cld
    15.  
    16.     stdcall GetNtDllHandle ; Get ntdll64 handle
    17.     stdcall GetProcAddrress64, eax, 'NtQueryInformationProcess' ; get 64 bit fn
    18.  
    19.     .if eax
    20.         mov [pfn], eax
    21.         @@:
    22.         ccall X64Call, [pfn], 5, -1, ProcessVmCounters, addr tCounters, sizeof.VM_COUNTERS64, addr dwWritten
    23.         jmp @b
    24.     .endif
    25.  
    26. endp
    27.  
    28. ; Call 64 bit function
    29. proc X64Call c uses ebx edi, pfn, lNumArgs
    30.  
    31.     jmp far 0x33:@f
    32.  
    33. use64
    34.  
    35.     @@:
    36.  
    37.     push rsi      ; Save stack
    38.     mov rsi, rsp
    39.  
    40.     mov ebx, [lNumArgs]
    41.  
    42.     .if ebx < 4
    43.         mov ebx, 4
    44.     .endif
    45.  
    46.     inc ebx
    47.     and ebx, -2
    48.     and rsp, -16
    49.     neg ebx
    50.     lea esp, [esp + ebx * 8]
    51.  
    52.     mov ebx, [lNumArgs]
    53.     lea eax, [lNumArgs + ebx * 4] ; last arg
    54.  
    55.     .while ebx
    56.  
    57.         dec ebx
    58.  
    59.         .if ebx = 0
    60.             movsxd rcx, dword [eax]
    61.         .elseif ebx = 1
    62.             movsxd rdx, dword [eax]
    63.         .elseif ebx = 2
    64.             movsxd r8, dword [eax]
    65.         .elseif ebx = 3
    66.             movsxd r9, dword [eax]
    67.         .else
    68.             movsxd rdi, dword [eax]
    69.             mov [rsp + rbx*8], rdi
    70.         .endif
    71.  
    72.         sub eax, 4
    73.  
    74.     .endw
    75.  
    76.     mov eax, [pfn]
    77.     call rax
    78.     mov rdx, rax
    79.     shr rdx, 0x20
    80.  
    81.     mov rsp, rsi  ; Restore stack
    82.     pop rsi
    83.  
    84. use32
    85.  
    86.     jmp far [0]
    87.     dd @f
    88.     dw 0x23
    89.     @@:
    90.  
    91.     ret
    92.  
    93. endp
    94.  
    95. ; GetProcAddress64
    96. proc GetProcAddrress64 uses esi edi ebx, hLib, sFuncName
    97.  
    98.     mov ebx, [hLib]
    99.     mov eax, [ebx + 0x3c]
    100.     mov eax, [eax + 0x88 + ebx]  ; Export dir
    101.     add eax, ebx
    102.     mov ecx, [eax + 0x18]  ; Num of functions
    103.     mov edx, [eax + 0x20]  ; Names
    104.  
    105.     @@:
    106.  
    107.         mov edi, [edx + ebx]
    108.  
    109.         .if edi
    110.  
    111.             add edi, ebx
    112.             xchg esi, eax
    113.             push ecx
    114.             xor eax, eax
    115.             lea ecx, [eax - 1]
    116.             repne scasb
    117.             not ecx
    118.             sub edi, ecx
    119.             xchg esi, eax
    120.             mov esi, [sFuncName]
    121.             repe cmpsb
    122.             pop ecx
    123.  
    124.             .if ZERO?
    125.  
    126.                 sub ecx, [eax + 0x18]
    127.                 neg ecx
    128.                 mov edx, [eax + 0x24]
    129.                 add edx, ebx
    130.                 movzx edx, word [edx + ecx * 2]
    131.                 mov eax, [eax + 0x1c]
    132.                 add eax, ebx
    133.                 mov eax, [eax + edx * 4]
    134.                 add eax, ebx
    135.                 jmp .exit_function
    136.  
    137.             .endif
    138.  
    139.         .endif
    140.  
    141.         add edx, 4
    142.  
    143.     loop @b
    144.  
    145.     xor eax, eax
    146.  
    147. .exit_function:
    148.  
    149.     ret
    150.  
    151. endp
    152.  
    153. ; Get 64 bit ntdll base address
    154. proc GetNtDllHandle
    155.     locals
    156.         tPBI PROCESS_BASIC_INFORMATION64 ?
    157.         dwRead dw ?
    158.         pPEBLdr dq ?
    159.     endl
    160.  
    161.     invoke NtWow64QueryInformationProcess64, -1, ProcessBasicInformation, addr tPBI, \
    162.                                              sizeof.PROCESS_BASIC_INFORMATION64, addr dwRead
    163.  
    164.     .if eax < 0
    165.         ret
    166.     .endif
    167.  
    168.     mov eax, dword [tPBI.PebBaseAddress]
    169.     mov eax, [eax + 0x18] ; PEB->Ldr
    170.     mov eax, [eax + 0x10] ; PEB_LDR_DATA.InLoadOrderModuleList.Flink <- exe
    171.     mov eax, [eax] ; <- ntdll
    172.     mov eax, [eax + 0x30] ; <- BaseAddress
    173.  
    174.     ret
    175.  
    176. endp
    Изредка кидает исключение при выходе из X64Call, а именно после переключения в 32 битный режим. Ошибка:
    Код (Text):
    1. 0:000:x86> .exr -1
    2. ExceptionAddress: 00000000004020E7
    3.    ExceptionCode: c0000005 (Access violation)
    4.   ExceptionFlags: 00000000
    5. NumberParameters: 2
    6.    Parameter[0]: 0000000000000003
    7.    Parameter[1]: 0000000000000000
    8. Attempt to execute non-executable address 0000000000000000
    9.  
    Если начать трассировать - то дальше все идет нормально, до следующего исключения. Можно конечно поставить SEH и просто игнорировать исключение, но хотелось бы разобраться в чем причина. Где именно и почему возникает исключение непонятно.

    Файл и код прикреплен в аттаче.
     

    Вложения:

    • HGBug.zip
      Размер файла:
      2,5 КБ
      Просмотров:
      9
  2. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    W8
    1st #AV 402174
    2st #AV 4020F4
     
  3. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    Indy_, сейчас исправлю код, там подразумевалось что 64-битная DLL расположена в пределах 4Гб (по крайней мере так на Win7). Проблема была не в этом.
     
  4. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Thetrik,

    Не понятно что это:

    Код (Text):
    1. jmp far [0]
    2. dd @f
    3. dw 0x23
    4. @@:
    (FF 2D 00 00 00 00) E7 20 40 00 : 23 00

    Должен быть #AV 4020DB с типом R к адресу 0:[0], но адрес 4020E7, тоесть @@ метка, походу отладчик у тебя глючит.
     
  5. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    Исправил код. Сейчас должно корректно работать при размещении за пределами 4ГБ.
    Код (ASM):
    1. format PE console
    2.  
    3. entry Start
    4.  
    5. include "decl.inc"
    6.  
    7. proc Start
    8.     locals
    9.         tCounters VM_COUNTERS64 ?
    10.         dwWritten dd ?
    11.         pfn dq ?
    12.     endl
    13.  
    14.     cld
    15.  
    16.     stdcall GetNtDllHandle ; Get ntdll64 handle
    17.     stdcall GetProcAddrress64, eax, edx, 'NtQueryInformationProcess' ; get 64 bit fn
    18.  
    19.     .if eax
    20.         mov dword [pfn], eax
    21.         mov dword [pfn + 4], edx
    22.         @@:
    23.         ccall X64Call, dword [pfn], dword [pfn + 4], 5, -1, ProcessVmCounters, addr tCounters, sizeof.VM_COUNTERS64, addr dwWritten
    24.         jmp @b
    25.     .endif
    26.  
    27. endp
    28.  
    29. ; Call 64 bit function
    30. proc X64Call c uses ebx edi, pfnL, pfnH, lNumArgs
    31.  
    32.     jmp far 0x33:@f
    33.  
    34. use64
    35.  
    36.     @@:
    37.  
    38.     push rsi      ; Save stack
    39.     mov rsi, rsp
    40.  
    41.     mov ebx, [lNumArgs]
    42.  
    43.     .if ebx < 4
    44.         mov ebx, 4
    45.     .endif
    46.  
    47.     inc ebx
    48.     and ebx, -2
    49.     and rsp, -16
    50.     neg ebx
    51.     lea esp, [esp + ebx * 8]
    52.  
    53.     mov ebx, [lNumArgs]
    54.     lea eax, [lNumArgs + ebx * 4] ; last arg
    55.  
    56.     .while ebx
    57.  
    58.         dec ebx
    59.  
    60.         .if ebx = 0
    61.             movsxd rcx, dword [eax]
    62.         .elseif ebx = 1
    63.             movsxd rdx, dword [eax]
    64.         .elseif ebx = 2
    65.             movsxd r8, dword [eax]
    66.         .elseif ebx = 3
    67.             movsxd r9, dword [eax]
    68.         .else
    69.             movsxd rdi, dword [eax]
    70.             mov [rsp + rbx*8], rdi
    71.         .endif
    72.  
    73.         sub eax, 4
    74.  
    75.     .endw
    76.  
    77.     mov rax, qword [pfnL]
    78.     call rax
    79.     mov rdx, rax
    80.     shr rdx, 0x20
    81.  
    82.     mov rsp, rsi  ; Restore stack
    83.     pop rsi
    84.  
    85. use32
    86.  
    87.     jmp far [0]
    88.     dd @f
    89.     dw 0x23
    90.     @@:
    91.  
    92.     ret
    93.  
    94. endp
    95.  
    96. ; GetProcAddress64
    97. proc GetProcAddrress64 uses esi edi ebx, hLibL, hLibH, sFuncName
    98.  
    99.     jmp far 0x33:@f
    100.  
    101. use64
    102.  
    103.     @@:
    104.  
    105.     mov rbx, qword [hLibL]
    106.     mov eax, [rbx + 0x3c]
    107.     mov eax, [rax + 0x88 + rbx]  ; Export dir
    108.     add rax, rbx
    109.     mov ecx, [rax + 0x18]  ; Num of functions
    110.     mov edx, [rax + 0x20]  ; Names
    111.  
    112.     @@:
    113.  
    114.         mov edi, [rdx + rbx]
    115.  
    116.         .if rdi
    117.  
    118.             add rdi, rbx
    119.             xchg rsi, rax
    120.             push rcx
    121.             xor eax, eax
    122.             lea rcx, [rax - 1]
    123.             repne scasb
    124.             not ecx
    125.             sub rdi, rcx
    126.             xchg rsi, rax
    127.             mov esi, [sFuncName]
    128.             repe cmpsb
    129.             pop rcx
    130.  
    131.             .if ZERO?
    132.  
    133.                 sub ecx, [rax + 0x18]
    134.                 movsxd rcx, ecx
    135.                 neg rcx
    136.                 mov edx, [rax + 0x24]
    137.                 add rdx, rbx
    138.                 movzx edx, word [rdx + rcx * 2]
    139.                 mov eax, [rax + 0x1c]
    140.                 add rax, rbx
    141.                 mov eax, [rax + rdx * 4]
    142.                 add rax, rbx
    143.                 jmp .exit_function
    144.  
    145.             .endif
    146.  
    147.         .endif
    148.  
    149.         add edx, 4
    150.  
    151.     loop @b
    152.  
    153.     xor rax, rax
    154.  
    155. .exit_function:
    156.  
    157.     mov rdx, rax
    158.     shr rdx, 0x20
    159.  
    160. use32
    161.  
    162.     jmp far [0]
    163.     dd @f
    164.     dw 0x23
    165.     @@:
    166.  
    167.     ret
    168.  
    169. endp
    170.  
    171. ; Get 64 bit ntdll base address
    172. proc GetNtDllHandle
    173.     locals
    174.         tPBI PROCESS_BASIC_INFORMATION64 ?
    175.         dwRead dw ?
    176.         pPEBLdr dq ?
    177.     endl
    178.  
    179.     invoke NtWow64QueryInformationProcess64, -1, ProcessBasicInformation, addr tPBI, \
    180.                                              sizeof.PROCESS_BASIC_INFORMATION64, addr dwRead
    181.  
    182.     .if eax < 0
    183.         ret
    184.     .endif
    185.  
    186.     jmp far 0x33:@f
    187.  
    188. use64
    189.  
    190.     @@:
    191.  
    192.     mov rax, [tPBI.PebBaseAddress]
    193.     mov rax, [rax + 0x18] ; PEB->Ldr
    194.     mov rax, [rax + 0x10] ; PEB_LDR_DATA.InLoadOrderModuleList.Flink <- exe
    195.     mov rax, [rax] ; <- ntdll
    196.     mov rax, [rax + 0x30] ; <- BaseAddress
    197.     mov rdx, rax          ; return to EDX:EAX pair
    198.     shr rdx, 0x20
    199.  
    200. use32
    201.  
    202.     jmp far [0]
    203.     dd @f
    204.     dw 0x23
    205.     @@:
    206.  
    207.     ret
    208.  
    209. endp
    Я подозреваю какая-то проблема со стеком, поскольку именно инструкции работы со стеком вызывают креш. К примеру POP/RET как раз и генерируют исключение, если добавить любых других инструкций которые не трогают стек то они корректно выполняются и падает на POP.

    Это переключение в 32 битный режим. В 64 битном режиме RIP адресация, поэтому там 0.

    Скрин с ошибкой.
    err.png

    Заранее спасибо.
     

    Вложения:

    • HGBug_2.rar
      Размер файла:
      1,9 КБ
      Просмотров:
      7
  6. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Thetrik,

    > В 64 битном режиме RIP адресация, поэтому там 0.

    Забыл, точно.

    > Я подозреваю какая-то проблема со стеком

    Вполне возможно, так как стек не переключается на 64(r14) до вызова 64 кода(далее поведение потока не предсказуемо):

    Код (Text):
    1. CpupReturnFromSimulatedCode:
    2.     xchg rsp,r14
    Нужно отладчиком пройти посмотреть что со стеком.
     
  7. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    Да, спасибо, я заметил такое, но обязательно ли переключать стек? Если так то можно ли просто выделить регион памяти и использовать его как стек?
    Отладчиком проходился, не пойму почему падает именно там где падает. В KiUserExceptionDispatcher приходит именно ошибка по этому адресу, контекст валидный (64 битный).
     
  8. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Thetrik,

    У меня на 8 работает без исключений, крутится в цикле. Поставь точку останова 4020EF контекст посмотреть.

    > но обязательно ли переключать стек? Если так то можно ли просто выделить регион памяти

    Не известно, могут быть и в ядре проверки. Лучше перезагрузить как это делает система, стек в r14.
     
  9. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    Код (Text):
    1. Structure CONTEXT at 000CFC0C
    2. Address   Hex dump      Decoded data             Comments
    3. 000CFC0C  /.3F000100    DD 0001003F              ; /ContextFlags = CONTEXT_FULL|CONTEXT_FLOATING_POINT|CONTEXT_DEBUG_REGISTERS|CONTEXT_EXTENDED_REGISTERS
    4. 000CFC10  |.00000000    DD 00000000              ; |Dr0 = 0
    5. 000CFC14  |.00000000    DD 00000000              ; |Dr1 = 0
    6. 000CFC18  |.D0FE6B77    DD 776BFED0              ; |Dr2 = 776BFED0
    7. 000CFC1C  |.00204000    DD 00402000              ; |Dr3 = 402000
    8. 000CFC20  |.F00FFFFF    DD FFFF0FF0              ; |Dr6 = FFFF0FF0
    9. 000CFC24  |.00010000    DD 00000100              ; |Dr7 = 100
    10. 000CFC28  |.7F020000    DD 0000027F              ; |Float_ControlWord = 27F
    11. 000CFC2C  |.00000000    DD 00000000              ; |Float_StatusWord = 0
    12. 000CFC30  |.FFFF0000    DD 0000FFFF              ; |Float_TagWord = 0FFFF
    13. 000CFC34  |.D820320A    DD 0A3220D8              ; |Float_ErrorOffset = 0A3220D8
    14. 000CFC38  |.80F80000    DD 0000F880              ; |Float_ErrorSelector = 0F880
    15. 000CFC3C  |.00000000    DD 00000000              ; |Float_DataOffset = 0
    16. 000CFC40  |.00000000    DD 00000000              ; |Float_DataSelector = 0
    17. 000CFC44  |.00000000 00 DT FLOAT 0.0             ; |ST0 = 0.0
    18. 000CFC4E  |.00000000 00 DT FLOAT 0.0             ; |ST1 = 0.0
    19. 000CFC58  |.00000000 00 DT FLOAT 0.0             ; |ST2 = 0.0
    20. 000CFC62  |.00000000 00 DT FLOAT 0.0             ; |ST3 = 0.0
    21. 000CFC6C  |.00000000 00 DT FLOAT 0.0             ; |ST4 = 0.0
    22. 000CFC76  |.00000000 00 DT FLOAT 0.0             ; |ST5 = 0.0
    23. 000CFC80  |.00000000 00 DT FLOAT 0.0             ; |ST6 = 0.0
    24. 000CFC8A  |.00000000 00 DT FLOAT 0.0             ; |ST7 = 0.0
    25. 000CFC94  |.00000000    DD 00000000              ; |Float_Cr0NpxState = 0
    26. 000CFC98  |.2B000000    DD 0000002B              ; |SegGs = 2B
    27. 000CFC9C  |.53000000    DD 00000053              ; |SegFs = 53
    28. 000CFCA0  |.2B000000    DD 0000002B              ; |SegEs = 2B
    29. 000CFCA4  |.2B000000    DD 0000002B              ; |SegDs = 2B
    30. 000CFCA8  |.7CFF0C00    DD 000CFF7C              ; |Edi = 0CFF7C
    31. 000CFCAC  |.00000000    DD 00000000              ; |Esi = 0
    32. 000CFCB0  |.00000000    DD 00000000              ; |Ebx = 0
    33. 000CFCB4  |.00000000    DD 00000000              ; |Edx = 0
    34. 000CFCB8  |.AA145177    DD 775114AA              ; |Ecx = 775114AA
    35. 000CFCBC  |.00000000    DD 00000000              ; |Eax = 0
    36. 000CFCC0  |.FCFE0C00    DD 000CFEFC              ; |Ebp = 0CFEFC
    37. 000CFCC4  |.EF204000    DD test2.004020EF        ; |Eip = test2.4020EF
    38. 000CFCC8  |.23000000    DD 00000023              ; |SegCs = 23
    39. 000CFCCC  |.56020100    DD 00010256              ; |EFlags = 00010256 D=0,P=1,A=1,Z=1,S=0,T=0,Int=1,D=0,O=0
    40. 000CFCD0  |.F4FE0C00    DD 000CFEF4              ; |Esp = 0CFEF4
    41. 000CFCD4  |.2B000000    DD 0000002B              ; |SegSs = 2B
    42.  
    --- Сообщение объединено, 13 фев 2020 в 12:17 ---
    Я сейчас посмотрю через ядерный отладчик почему это происходит.
     
  10. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Thetrik,

    EFlags = 00010256

    EFLAGS.i16 Resume Flag (RF)

    Не должен он быть взведён. Посмотри 4020EF -> pushfd что там на самом деле что бы исключить отладчик.
     
  11. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    err2.png
     
  12. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Thetrik,

    Я имею ввиду запишу вместо pop edi -> pushfd, за ней точку останова и посмотри на стеке флажки.
     
  13. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    Теперь на ней падает, т.к. она стек меняет, если продолжить то там 0x00000256.
     
  14. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Thetrik,

    Нет видимых причин для исключения, стековая память ведь не изменна, как и указатель. Попробуй прочитать TEB, mov eax,fs:[0] и стек mov eax,esp/mov eax,[eax].
    --- Сообщение объединено, 13 фев 2020 в 13:38 ---
    Тут моя тема есть про подобные переключения модов https://exelab.ru/f/?action=vthread&forum=2&topic=22109&page=1#19

    Там плавающая" ошибка так же без видимых причин, я так и не разобрался тогда.

    Если на 8-ке выполнить следующий код, может показаться что это какая то мистика :umnik2:

    Код (Text):
    1.     push gs
    2.     push gs:[4]
    3.  
    4.     mov ax,gs
    5.     mov gs,ax
    6.  
    7.     push gs:[4]
    - возникает #AV(R, 4) на втором push gs:[]. Первый отрабатывает, на стеке 0, 2B.

    А фишка в том, что есть тн дескрипторный кэш". Пара инструкций mov r,seg/mov seg,r не меняет значение селектора, но перезагружает кэш.

    Вдобавок планировщик фиксит селекторы. Из за переключений между модами может получиться что кэш не обновился. Хотя явная часть контекста будет корректна.
     
  15. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Я немного подумал, получается вот что. Так как у меня нет ос где эту ошибку можно повторить, то я могу лишь теоретически проанализировать.

    Если перезагрузить сегментный регистр на 8-ке, тем самым обновив дескр. кэш(что приведёт к фаулту), но обождав в цикле свапконтекст, то далее выборка не приведёт к исключению. Так как планировщик обновит кэш:

    Код (Text):
    1. .text:0000000140151B5A                 mov     edx, 2Bh
    2. .text:0000000140151B5F                 mov     ds, edx
    3. .text:0000000140151B61                 assume ds:nothing
    4. .text:0000000140151B61                 mov     es, edx
    5. .text:0000000140151B63                 assume es:nothing
    6. .text:0000000140151B63                 cli
    7. .text:0000000140151B64                 swapgs
    8. .text:0000000140151B67                 mov     gs, edx
    9. .text:0000000140151B69                 assume gs:nothing
    10. .text:0000000140151B69                 swapgs
    11. .text:0000000140151B6C                 sti
    В семпле:

    Код (Text):
    1.     mov rax, qword [pfnL]
    2.     call rax
    - сервисный 64 вызов. При этом ядерный возврат через sysret, а она апдейтит дк:

    Получается что после возврата через sysret на код mov rdx,rax дк обновлён, поэтому не может быть мистики как выше. Логически есть лишь единственный вариант, учитывая что крэш не всегда:

    - планировщик не обновляет дк, либо в нём есть какая то проверка на диапазон стека в 64 режиме. Это единственно возможное объяснение, вероятно у меня анстаб был аналогичный. Можно попробовать проверить, зациклив сервисный вызов и обращаться к стеку. В любом случае это ядерный баг, так же как и чтение GS. Найденный спонтанно в этих двух случаях :)
     
  16. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    Indy_, спасибо за ответ. Я еще не смотрел через ядерный отладчик, позже посмотрю, сейчас занят другими делами.

    Вообще баг у меня произошел в другом приложении и я сделал на асме аналогичный код, но этот код намного реже вылетает. Я прикрепил оригинальный код - в нем баг проявляется намного чаще. Нужно запустить и попробовать попермещать окно, перекрывать его другими и т.п. В OllyDbg этот баг у меня сразу почти вылезает.

    Если будет желание отладить и посмотреть в чем баг, уточню что там динамический код формируется для вызова 64 битной функции, чтобы перехватить вызов и посмотреть можно поставить бряк на DispCallFunc, проверять первый параметр - там должен быть 0, во втором указатель на динамический код. Динамический код формируется каждый раз, поэтому там не получится поставить софтверный бряк. Если использовать EXE который в архиве то можно поставить бряк на 004056A9 и смотреть [ESP+4] там будет указатель на динамический код.
     

    Вложения:

  17. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Забыл написать почему такое не происходит на 86. В режиме совместимости(compat mode) набор селекторов как и в 86. В 64 эти регистры не используются, поэтому ядро их в ловушках изменяет напрямую(пример выше SwapContext()). Если там есть какая то ошибка, то она и приводит к анстаб. В 86 же в ловушках сохраняются все селекторы при входе и при возврате перезагружаются, тем самым апдейтится дк и такие ошибки невозможны.
    --- Сообщение объединено, 13 фев 2020 в 20:36 ---
    Thetrik,

    > Я еще не смотрел через ядерный отладчик

    Это бессмысленно, я ведь говорил что так и не смог понять откуда в моём семпле шёл анстаб, это всё планировщик. Просто там очень большой код и крэш был по всему, я приводил линк. Я понял это в данной теме именно по месту с переключением мода; просто повезло что у тебя обнаружилось небольшое место в коде, где происходит аналогичное, можно сказать вот это повезло хоть раз!

    > Если будет желание отладить

    Да, я посмотрю. Но мне больше интересно понять где именно баг. Можно составить тест, просто у меня нет ос где твой семпл падает, на 8 глючит мой, но твой не падает. Хотя тоже не факт, я лишь несколько раз запускал и если это планировочный баг, то нужно сотни раз запускать. Начну с этого.
     
  18. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Thetrik,

    Вот собрал для теста.

    На 10-ке есть в wow64cpu после возврата из sysret этот код:

    Код (Text):
    1. Thunk0Arg:
    2.     call CpupSyscallStub
    3.     mov r14,rsp
    4.     mov dword ptr [rsp+4], 23h
    5.     mov r8d,2Bh
    6.     mov ss,r8d
    7.     mov r9d,[r13+3Ch]
    8.     mov [rsp],r9d
    9.     mov esp,[r13+48h]
    10.     jmp fword ptr [r14]
    11. RunSimulatedCode endp
    - перезагружается SS. При возврате sysret загружает SS из MSR(IA32_STAR), а ядро туда загружает при старте:

    Код (Text):
    1.     mov rax,[r14+8]
    2.     mov ecx,68h
    3.     mov edx,230010h
    4.     mov [rax+66h], cx
    5.     xor eax,eax
    6.     mov ecx,0C0000081h
    7.     wrmsr
    - (23 + 8) | 3 = 2B(KGDT64_R3_DATA | RPL_MASK)

    Тогда нет смысла в загрузке SS, но для чего то она есть :scratch_one-s_head:
     

    Вложения:

    • Wow.7z
      Размер файла:
      11,9 КБ
      Просмотров:
      4
  19. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    512
    Indy_, благодарю! Перезагрузил SS - перестало вылетать. Проблема решена.
    Спасибо!
    Интересно это документировано вообще такое поведение?
     
  20. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    3.084
    Thetrik,

    А на моём семпле как ?
    --- Сообщение объединено, 14 фев 2020 в 17:05 ---
    Thetrik,

    > Интересно это документировано вообще такое поведение?

    Нет конечно, это баг какой то, может даже аппаратный. Получается что из ядра есть только два выхода - sysret и iret. IRET перезагружает SS при переключении стека. Как такое может происходить с дк не понимаю.
    --- Сообщение объединено, 14 фев 2020 в 20:04 ---
    Выяснил что iret не апдейтит дк, по крайней мере при возврате в тот же мод. Проекция GDT в юзермод(x32 os), записываем дескриптор, загружаем его селектор(ES), затем обнуляем дескриптор и выполняем цикл iret(юм). Спустя ~100k итераций срабатывает #AV, это пришло прерывание и при возврате из него из стека перезагружен регистр через pop seg.
    --- Сообщение объединено, 14 фев 2020 в 20:15 ---
    Смена мода через int/iret тоже не обновляет дк. Короче засада, какая то аппаратная фишка :dash1: