当陷阱标志使能时如何创建 INT 1 中断处理程序?

问题描述 投票:0回答:1

下面的 MASM 程序启用了陷阱标志(TF),但它会导致程序过早退出

pushf                   ; Push FLAGS onto the stack
pop     ax              ; Pop FLAGS into AX register
or      ax, 0100h       ; Set the Trap Flag bit 0100h = 0000000100000000
push    ax              ; Push the modified value onto the stack
popf                    ; Pop it back into FLAGS

为了启用处理器的单步执行,x86 架构提供了一位陷阱标志(TF),可以在 标志寄存器。 FLAGS 寄存器是 x86 上的状态寄存器 包含控制或描述的各种位标志的处理器 处理器的状态。如果陷阱标志设置为 true,则 处理器将在每次执行后调用中断 1 (INT 1) 指令被执行。

; +------+--------+-------------+----------------------------------------+
; | Bit #|  Mask  | Abbreviation| Description                            |
; +------+--------+-------------+----------------------------------------+
; |  0   | 0x0001 |     CF      | Carry flag                             |
; |  1   | 0x0002 |     —       | Reserved                               |
; |  2   | 0x0004 |     PF      | Parity flag                            |
; |  3   | 0x0008 |     —       | Reserved                               |
; |  4   | 0x0010 |     AF      | Adjust flag                            |
; |  5   | 0x0020 |     —       | Reserved                               |
; |  6   | 0x0040 |     ZF      | Zero flag                              |
; |  7   | 0x0080 |     SF      | Sign flag                              |
; |  8   | 0x0100 |     TF      | Trap flag                              |
; |  9   | 0x0200 |     IF      | Interrupt flag                         |
; | 10   | 0x0400 |     DF      | Direction flag                         |
; | 11   | 0x0800 |     OF      | Overflow flag                          |
; |12-13 | 0x3000 |    IOPL     | I/O privilege level (286+ only),       |
; |      |        |             | always all-1s on 8086 and 186          |
; | 14   | 0x4000 |     NT      | Nested task flag (286+ only),          |
; |      |        |             | always 1 on 8086 and 186               |
; | 15   | 0x8000 |     MD      | Mode flag (NEC V-series only),         |
; |      |        |             | reserved on all Intel CPUs.            |
; |      |        |             | Always 1 on 8086/186, 0 on 286 and     |
; |      |        |             | later.                                 |
; +------+--------+-------------+----------------------------------------+

option casemap:none

extrn printf:proc

ALIGN_STACK MACRO num_args
    IF (num_args AND 1) EQ 0 OR num_args LT 5
        AND SPL, 0F0h
    ELSE
        OR SPL, 08h
    ENDIF
ENDM

RESTORE_STACK MACRO num_args
    IF num_args LT 5
        LEA RSP, [RSP + 5*8]
    ELSEIF (num_args AND 1) EQ 0
        LEA RSP, [RSP + (num_args + 1)*8]
    ELSE
        LEA RSP, [RSP + num_args*8]
    ENDIF
ENDM

.data  
    strCF   db "Bit # %d, Value  = %d",13,10,0
     
.code

PrintFlagsBit:
    pushfq                  ; Push RFLAGS onto the stack
    pop     r8              ; Load the RFLAGS from the stack into R8
    mov     cl, al          ; Move the lower 8 bits of RAX into CL
    shr     r8, cl          ; Shift right by CL, so the flags bit is now the LSB of R8
    and     r8, 1           ; Zero all other bits, except the LSB
    
    ;; call the printf function
    NUM_ARGS        = 3
    PUSH            RSP
    PUSH            [RSP]
    ALIGN_STACK     NUM_ARGS
    MOV             RDX, RAX
    LEA             RCX,strCF
    SUB             RSP,32
    CALL            printf
    RESTORE_STACK   NUM_ARGS
    POP             RSP    
    
    ret

main proc

    ; Carry flag Bit #1
    ; -----------------
    mov     ax, 0FFFFh      ; 0FFFFh + 1 = 010000h, but since AX is 16 bits,
    add     ax, 1           ; it wraps around the most significant bit into CF                               
    mov     eax, 1          ; Bit #1
    call    PrintFlagsBit
    
    ; Parity flag Bit #2
    ; ------------------    
    mov     al, 00110011b   ; This has 4 set bits - Even Parity
    test    al, al          ; TEST sets the PF = 1 (even parity) based on the value in AL                            
    mov     eax, 2          ; Bit #2
    call    PrintFlagsBit
    
    ; Adjust flag Bit #4
    ; ------------------        
    mov     al, 0Fh         ; 0000 1111 + 0000 0001 = 0001 0000
    add     al, 01h         ; Addition carried 3rd bit to 4th bit
    mov     eax, 4          ; Bit #4
    call    PrintFlagsBit
         
    ; Zero flag Bit #6
    ; -----------------        
    mov     eax, 5          ; Load EAX register with the value 5
    sub     eax, 5          ; Subtract 5 from EAX, result is zero, so ZF is set
    mov     eax, 6          ; Bit #6
    call    PrintFlagsBit        
    
    ; Sign flag Bit #7
    ; -----------------       
    mov     eax, 1          ; Load EAX register with the value 1
    neg     eax             ; Negate the value in EAX, most significant bit is 1, so SF is set
    mov     eax, 7          ; Bit #7
    call    PrintFlagsBit   
    
    ; Trap flag Bit #8
    ; ----------------
    ; Set TF flag
    pushf                   ; Push FLAGS onto the stack
    pop     ax              ; Pop FLAGS into AX register
    or      ax, 0100h       ; Set the Trap Flag bit 0100h = 0000000100000000
    push    ax              ; Push the modified value onto the stack
    popf                    ; Pop it back into FLAGS
    mov     eax, 8          ; Bit #8
    call    PrintFlagsBit  
    ; Unset TF flag
    pushf                   ; Push FLAGS onto the stack
    pop     ax              ; Pop FLAGS into AX register
    and     ax, 0FEFFh      ; Unset the Trap Flag bit 0FEFFh = 1111111011111111
    push    ax              ; Push the modified value onto the stack
    popf                    ; Pop it back into FLAGS    

    ; Interrupt flag Bit #9
    ; ---------------------       
    ;sti                    ; Set Interrupt Flag (already set)
    ;cli                    ; Clear Interrupt Flag
    mov     eax, 9          ; Bit #9
    call    PrintFlagsBit   
    
    ; Direction flag Bit #10
    ; ----------------------       
    std                     ; sets the DF flag, ensuring backward operations.   
    mov     eax, 10         ; Bit #10
    call    PrintFlagsBit   
    cld                     ; clears the DF flag, ensuring forward operations.    
    
    ; Overflow flag Bit #11
    ; ---------------------       
    mov     al, 07Fh        ; AL = 01111111 (unsigned 127, MSB 0)
    add     al, 01h         ; AL = 10000000 (signed -128, MSB 1)
    mov     eax, 11         ; Bit #11
    call    PrintFlagsBit       
    
    RET
main endp

end

当TF设置时,程序输出

Bit # 1, Value  = 1
Bit # 2, Value  = 1
Bit # 4, Value  = 1
Bit # 6, Value  = 1
Bit # 7, Value  = 1
Bit # 8, Value  = 0
Bit # 9, Value  = 1
Bit # 10, Value  = 1
Bit # 11, Value  = 1

当TF设置后,程序输出

Bit # 1, Value  = 1
Bit # 2, Value  = 1
Bit # 4, Value  = 1
Bit # 6, Value  = 1
Bit # 7, Value  = 1

有趣的是,使用 Windbg 单步执行程序时,程序尝试设置 TF=1,但 Windbg 阻止了它?

问题

是否有一种简单的方法来实现 INT 1 处理程序,以便程序可以捕获它?

也许是这样的

INT1handler PROC
    ; ...
    ; ...
    ; ...

    iretd   ; Return from interrupt handler
INT1handler ENDP
windows debugging assembly x86-64 masm64
1个回答
0
投票

添加了向量异常处理以捕获 INT 1。

程序现已正常完成。

; +------+--------+-------------+----------------------------------------+
; | Bit #|  Mask  | Abbreviation| Description                            |
; +------+--------+-------------+----------------------------------------+
; |  0   | 0x0001 |     CF      | Carry flag                             |
; |  1   | 0x0002 |     —       | Reserved                               |
; |  2   | 0x0004 |     PF      | Parity flag                            |
; |  3   | 0x0008 |     —       | Reserved                               |
; |  4   | 0x0010 |     AF      | Adjust flag                            |
; |  5   | 0x0020 |     —       | Reserved                               |
; |  6   | 0x0040 |     ZF      | Zero flag                              |
; |  7   | 0x0080 |     SF      | Sign flag                              |
; |  8   | 0x0100 |     TF      | Trap flag                              |
; |  9   | 0x0200 |     IF      | Interrupt flag                         |
; | 10   | 0x0400 |     DF      | Direction flag                         |
; | 11   | 0x0800 |     OF      | Overflow flag                          |
; |12-13 | 0x3000 |    IOPL     | I/O privilege level (286+ only),       |
; |      |        |             | always all-1s on 8086 and 186          |
; | 14   | 0x4000 |     NT      | Nested task flag (286+ only),          |
; |      |        |             | always 1 on 8086 and 186               |
; | 15   | 0x8000 |     MD      | Mode flag (NEC V-series only),         |
; |      |        |             | reserved on all Intel CPUs.            |
; |      |        |             | Always 1 on 8086/186, 0 on 286 and     |
; |      |        |             | later.                                 |
; +------+--------+-------------+----------------------------------------+

option casemap:none

extrn printf:proc
extrn AddVectoredExceptionHandler:proc
extrn RemoveVectoredExceptionHandler:proc

ALIGN_STACK MACRO num_args
    IF (num_args AND 1) EQ 0 OR num_args LT 5
        AND SPL, 0F0h
    ELSE
        OR SPL, 08h
    ENDIF
ENDM

RESTORE_STACK MACRO num_args
    IF num_args LT 5
        LEA RSP, [RSP + 5*8]
    ELSEIF (num_args AND 1) EQ 0
        LEA RSP, [RSP + (num_args + 1)*8]
    ELSE
        LEA RSP, [RSP + num_args*8]
    ENDIF
ENDM

EXCEPTION_MAXIMUM_PARAMETERS equ 15
EXCEPTION_CONTINUE_EXECUTION equ -1
EXCEPTION_CONTINUE_SEARCH    equ 0
EXCEPTION_SINGLE_STEP        equ 080000004h

EXCEPTION_RECORD STRUCT 8
ExceptionCode                 DWORD ?
ExceptionFlags                DWORD ?
ExceptionRecord               DWORD ?
ExceptionAddress              DWORD ?
NumberParameters              DWORD ?
__unusedAlignment             DWORD ?
ExceptionInformation          QWORD EXCEPTION_MAXIMUM_PARAMETERS DUP(?)
EXCEPTION_RECORD ENDS

.data  
    strCF    db "Bit # %d, Value  = %d",13,10,0
    message db "Single step exception captured! ExceptionCode: %X",13,10,0      
    
.DATA?
    exceptionPointers QWORD EXCEPTION_POINTERS ?
    hHandler          QWORD ?    
     
.code


VectoredHandler PROC
    ; First, obtain the EXCEPTION_RECORD pointer from EXCEPTION_POINTERS
    MOV             R8, [RCX] ; Now, R8 has the EXCEPTION_RECORD pointer
    MOV             EBX, DWORD PTR [R8 + EXCEPTION_RECORD.ExceptionCode]
    
    cmp             EBX, EXCEPTION_SINGLE_STEP
    jne             notOurException

    ; Handle the exception here.
    
    mov             rax, 8          ; Bit #8 (TF)
    call            PrintFlagsBit  
    
    ; Call the printf function
    NUM_ARGS        = 2
    PUSH            RSP
    PUSH            [RSP]
    ALIGN_STACK     NUM_ARGS
    MOV             RDX, RBX
    LEA             RCX,message
    SUB             RSP,32
    CALL            printf
    RESTORE_STACK   NUM_ARGS
    POP             RSP 
    
    pushfq                                   ; Push FLAGS onto the stack
    and             qword ptr [rsp], 0FEFFh  ; Unset the Trap Flag bit 0FEFFh = 1111111011111111
    popfq                                    ; Pop it back into FLAGS          
    
    mov             rax, EXCEPTION_CONTINUE_EXECUTION
    ret

notOurException:
    mov rax, EXCEPTION_CONTINUE_SEARCH
    ret
VectoredHandler ENDP


PrintFlagsBit:
    pushfq                          ; Push RFLAGS onto the stack
    pop             r8              ; Load the RFLAGS from the stack into R8
    mov             cl, al          ; Move the lower 8 bits of RAX into CL
    shr             r8, cl          ; Shift right by CL, so the flags bit is now the LSB of R8
    and             r8, 1           ; Zero all other bits, except the LSB
    
    ;; call the printf function
    NUM_ARGS        = 3
    PUSH            RSP
    PUSH            [RSP]
    ALIGN_STACK     NUM_ARGS
    MOV             RDX, RAX
    LEA             RCX,strCF
    SUB             RSP,32
    CALL            printf
    RESTORE_STACK   NUM_ARGS
    POP             RSP    
    
    ret
    

main proc

    NUM_ARGS        = 2
    PUSH            RSP
    PUSH            [RSP]
    ALIGN_STACK     NUM_ARGS
    LEA             RDX, VectoredHandler
    MOV             RCX,1
    SUB             RSP,32
    CALL            AddVectoredExceptionHandler
    RESTORE_STACK   NUM_ARGS
    POP             RSP       
    
    test            rax, rax
    jz              errorExit
    mov             [hHandler], rax 

    ; Carry flag Bit #1
    ; -----------------
    mov     ax, 0FFFFh      ; 0FFFFh + 1 = 010000h, but since AX is 16 bits,
    add     ax, 1           ; it wraps around the most significant bit into CF                               
    mov     eax, 1          ; Bit #1
    call    PrintFlagsBit
    
    ; Parity flag Bit #2
    ; ------------------    
    mov     al, 00110011b   ; This has 4 set bits - Even Parity
    test    al, al          ; TEST sets the PF = 1 (even parity) based on the value in AL                            
    mov     eax, 2          ; Bit #2
    call    PrintFlagsBit
    
    ; Adjust flag Bit #4
    ; ------------------        
    mov     al, 0Fh         ; 0000 1111 + 0000 0001 = 0001 0000
    add     al, 01h         ; Addition carried 3rd bit to 4th bit
    mov     eax, 4          ; Bit #4
    call    PrintFlagsBit
         
    ; Zero flag Bit #6
    ; -----------------        
    mov     eax, 5          ; Load EAX register with the value 5
    sub     eax, 5          ; Subtract 5 from EAX, result is zero, so ZF is set
    mov     eax, 6          ; Bit #6
    call    PrintFlagsBit        
    
    ; Sign flag Bit #7
    ; -----------------       
    mov     eax, 1          ; Load EAX register with the value 1
    neg     eax             ; Negate the value in EAX, most significant bit is 1, so SF is set
    mov     eax, 7          ; Bit #7
    call    PrintFlagsBit   
    
    ; Trap flag Bit #8
    ; ----------------
    pushfq                   ; Push FLAGS onto the stack
    or qword ptr [rsp], 100h ; Set the Trap Flag bit 0100h = 0000000100000000
    popfq                    ; Pop it back into FLAGS

    ; Interrupt flag Bit #9
    ; ---------------------       
    ;sti                    ; Set Interrupt Flag (already set)
    ;cli                    ; Clear Interrupt Flag
    mov     eax, 9          ; Bit #9
    call    PrintFlagsBit   
    
    ; Direction flag Bit #10
    ; ----------------------       
    std                     ; sets the DF flag, ensuring backward operations.   
    mov     eax, 10         ; Bit #10
    call    PrintFlagsBit   
    cld                     ; clears the DF flag, ensuring forward operations.    
    
    ; Overflow flag Bit #11
    ; ---------------------       
    mov     al, 07Fh        ; AL = 01111111 (unsigned 127, MSB 0)
    add     al, 01h         ; AL = 10000000 (signed -128, MSB 1)
    mov     eax, 11         ; Bit #11
    call    PrintFlagsBit    
    
    NUM_ARGS        = 1
    PUSH            RSP
    PUSH            [RSP]
    ALIGN_STACK     NUM_ARGS
    MOV             RCX,[hHandler]
    SUB             RSP,32
    CALL            RemoveVectoredExceptionHandler
    RESTORE_STACK   NUM_ARGS
    POP             RSP         
    
errorExit:    
    RET
main endp

end

现在输出

Bit # 1, Value  = 1
Bit # 2, Value  = 1
Bit # 4, Value  = 1
Bit # 6, Value  = 1
Bit # 7, Value  = 1
Bit # 8, Value  = 0
Single step exception captured! ExceptionCode: 80000004
Bit # 9, Value  = 1
Bit # 10, Value  = 1
Bit # 11, Value  = 1
© www.soinside.com 2019 - 2024. All rights reserved.