📄 asmmacro.s
字号:
// It should be used for entry into any fast-system call (KiGetTickCount,
// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
// (KiSystemService)
//
// @param Label
// Unique label identifying the name of the caller function; will be
// used to append to the name of the DR helper function, which must
// already exist.
//
// @remark None.
//
.macro SYSCALL_PROLOG Label
/* Create a trap frame */
push 0
push ebp
push ebx
push esi
push edi
push fs
/* Load PCR Selector into fs */
mov ebx, KGDT_R0_PCR
.byte 0x66
mov fs, bx
/* Get a pointer to the current thread */
mov esi, [fs:KPCR_CURRENT_THREAD]
/* Save the previous exception list */
push [fs:KPCR_EXCEPTION_LIST]
/* Set the exception handler chain terminator */
mov dword ptr [fs:KPCR_EXCEPTION_LIST], -1
/* Save the old previous mode */
push [esi+KTHREAD_PREVIOUS_MODE]
/* Skip the other registers */
sub esp, 0x48
/* Set the new previous mode based on the saved CS selector */
mov ebx, [esp+0x6C]
and ebx, 1
mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], bl
/* Go on the Kernel stack frame */
mov ebp, esp
/* Save the old trap frame pointer where EDX would be saved */
mov ebx, [esi+KTHREAD_TRAP_FRAME]
mov [ebp+KTRAP_FRAME_EDX], ebx
/* Flush DR7 */
and dword ptr [ebp+KTRAP_FRAME_DR7], 0
/* Check if the thread was being debugged */
test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
/* Set the thread's trap frame and clear direction flag */
mov [esi+KTHREAD_TRAP_FRAME], ebp
cld
/* Save DR registers if needed */
jnz Dr_&Label
/* Set the trap frame debug header */
3:
SET_TF_DEBUG_HEADER
/* Enable interrupts */
sti
.endm
//
// @name FASTCALL_PROLOG
//
// TODO
//
// @param Label
// Unique label identifying the name of the caller function; will be
// used to append to the name of the DR helper function, which must
// already exist.
//
// @remark None.
//
.macro FASTCALL_PROLOG Label
/* Set FS to PCR */
mov ecx, KGDT_R0_PCR
mov fs, cx
//push KGDT_R0_PCR
//pop fs
/* Set user selector */
mov ecx, KGDT_R3_DATA | RPL_MASK
/* Set DS/ES to User Selector */
mov ds, cx
mov es, cx
/* Set the current stack to Kernel Stack */
mov ecx, [fs:KPCR_TSS]
mov esp, [ecx+KTSS_ESP0]
/* Set up a fake INT Stack. */
push KGDT_R3_DATA + RPL_MASK
push edx /* Ring 3 SS:ESP */
pushf /* Ring 3 EFLAGS */
push 2 /* Ring 0 EFLAGS */
add edx, 8 /* Skip user parameter list */
popf /* Set our EFLAGS */
or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
push KGDT_R3_CODE + RPL_MASK
push dword ptr ds:KUSER_SHARED_SYSCALL_RET
/* Setup the Trap Frame stack */
push 0
push ebp
push ebx
push esi
push edi
push KGDT_R3_TEB + RPL_MASK
/* Save pointer to our PCR */
mov ebx, [fs:KPCR_SELF]
/* Get a pointer to the current thread */
mov esi, [ebx+KPCR_CURRENT_THREAD]
/* Set the exception handler chain terminator */
push [ebx+KPCR_EXCEPTION_LIST]
mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
/* Use the thread's stack */
mov ebp, [esi+KTHREAD_INITIAL_STACK]
/* Push previous mode */
push UserMode
/* Skip the other registers */
sub esp, 0x48
/* Make space for us on the stack */
sub ebp, 0x29C
/* Write the previous mode */
mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
/* Sanity check */
cmp ebp, esp
jnz BadStack
/* Flush DR7 */
and dword ptr [ebp+KTRAP_FRAME_DR7], 0
/* Check if the thread was being debugged */
test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
/* Set the thread's trap frame */
mov [esi+KTHREAD_TRAP_FRAME], ebp
/* Save DR registers if needed */
jnz Dr_&Label
/* Set the trap frame debug header */
3:
SET_TF_DEBUG_HEADER
/* Enable interrupts */
sti
.endm
//
// @name V86_TRAP_PROLOG
//
// This macro creates a V86 Trap entry prologue.
// It should be used for entry into any fast-system call (KiGetTickCount,
// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
// (KiSystemService)
//
// @param Label
// Unique label identifying the name of the caller function; will be
// used to append to the name of the DR helper function, which must
// already exist.
//
// @remark None.
//
.macro V86_TRAP_PROLOG Label
/* Skip everything to the error code */
sub esp, KTRAP_FRAME_ERROR_CODE
/* Clear the error code */
mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
/* Save the registers we'll trample */
mov [esp+KTRAP_FRAME_EBX], ebx
mov [esp+KTRAP_FRAME_EAX], eax
mov [esp+KTRAP_FRAME_EBP], ebp
mov [esp+KTRAP_FRAME_ESI], esi
mov [esp+KTRAP_FRAME_EDI], edi
/* Save PCR and Ring 3 segments */
mov ebx, KGDT_R0_PCR
mov eax, KGDT_R3_DATA + RPL_MASK
/* Save ECX and EDX too */
mov [esp+KTRAP_FRAME_ECX], ecx
mov [esp+KTRAP_FRAME_EDX], edx
/* Set debugging markers */
mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
/* Now set segments (use OVERRIDE, 0x66) */
.byte 0x66
mov fs, bx
.byte 0x66
mov ds, ax
.byte 0x66
mov es, ax
/* Set the trap frame in the stack and clear the direction flag */
mov ebp, esp
cld
/* Save the exception list */
mov eax, [fs:KPCR_EXCEPTION_LIST]
mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
/* Check if we need debugging */
mov eax, dr7
test eax, ~DR7_RESERVED_MASK
mov [esp+KTRAP_FRAME_DR7], eax
// jnz Dr_&Label
.endm
//
// @name V86_TRAP_EPILOG
//
// This macro creates an epilogue for leaving V86 traps
//
// @param None.
//
// @remark None.
//
.macro V86_TRAP_EPILOG
/* Get the current thread and make it unalerted */
ExitBegin:
mov ebx, [fs:KPCR_CURRENT_THREAD]
mov byte ptr [ebx+KTHREAD_ALERTED], 0
/* Check if it has User-mode APCs pending */
cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
jne PendingUserApc
/* It doesn't, pop the frame */
add esp, KTRAP_FRAME_EDX
pop edx
pop ecx
pop eax
/* Check if DR registers should be restored */
test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
//jnz V86DebugRestore
/* Finish popping the rest of the frame, and return to P-mode */
add esp, 12
pop edi
pop esi
pop ebx
pop ebp
add esp, 4
iretd
PendingUserApc:
/* Raise to APC level */
mov ecx, APC_LEVEL
call @KfRaiseIrql@4
/* Save KIRQL and deliver APCs */
push eax
sti
push ebp
push 0
push UserMode
call _KiDeliverApc@12
/* Restore IRQL */
pop ecx
call @KfLowerIrql@4
cli
/* Check if we're not in V86 anymore */
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz ExitBegin
.endm
//
// @name TRAP_EPILOG
//
// This macro creates an epilogue for leaving any system trap.
// It is used for exiting system calls, exceptions, interrupts and generic
// traps.
//
// @param SystemCall
// Specifies whether this trap will exit a system call. If so, special
// code will be assembled to potentially use SYSEXIT instead of IRETD.
//
// @param RestorePreviousMode
// Specifies if the previous mode should be restored.
//
// @param RestoreSegments
// Specifies if the segment registers should be restored.
//
// @param RestoreVolatiles
// Specifies if the volatile registers should be restored.
//
// @param RestoreAllRegs
// Specifies if volatiles and segments should both be restored.
//
// @remark
//
.macro TRAP_EPILOG SystemCall, RestorePreviousMode, RestoreSegments, RestoreVolatiles, RestoreAllRegs
#ifdef DBG
/* Assert the flags */
pushfd
pop edx
test edx, EFLAGS_INTERRUPT_MASK
jnz 6f
/* Assert the stack */
cmp esp, ebp
jnz 6f
/* Assert the trap frame */
#endif
5:
#ifdef DBG
sub dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
jnz 0f
/* Assert FS */
mov bx, fs
cmp bx, KGDT_R0_PCR
jnz 1f
/* Assert exception list */
cmp dword ptr fs:[KPCR_EXCEPTION_LIST], 0
jnz 2f
1:
push -1
call _KeBugCheck@4
#endif
2:
/* Get exception list */
mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
#ifdef DBG
/* Assert the saved exception list */
or edx, edx
jnz 1f
UNHANDLED_PATH
1:
#endif
/* Restore it */
mov [fs:KPCR_EXCEPTION_LIST], edx
.if \RestorePreviousMode
/* Get previous mode */
mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
#ifdef DBG
/* Assert the saved previous mode */
cmp ecx, -1
jnz 1f
UNHANDLED_PATH
1:
#endif
/* Restore the previous mode */
mov esi, [fs:KPCR_CURRENT_THREAD]
mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
.else
#ifdef DBG
/* Assert the saved previous mode */
mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
cmp ecx, -1
jz 1f
UNHANDLED_PATH
1:
#endif
.endif
/* Check for debug registers */
test dword ptr [esp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
//jnz 2f
/* Check for V86 */
4:
test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz V86_Exit
/* Check if the frame was edited */
test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
jz 7f
.if \RestoreAllRegs
/* Check the old mode */
cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
bt word ptr [esp+KTRAP_FRAME_CS], 0
cmc
ja 8f
.endif
.if \RestoreVolatiles
/* Restore volatiles */
mov edx, [esp+KTRAP_FRAME_EDX]
mov ecx, [esp+KTRAP_FRAME_ECX]
mov eax, [esp+KTRAP_FRAME_EAX]
.endif
/* Check if we were called from kernel mode */
cmp dword ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
jz 9f
.if \RestoreSegments
/* Restore segment registers */
lea esp, [ebp+KTRAP_FRAME_GS]
pop gs
pop es
pop ds
.endif
/* Restore FS */
3:
lea esp, [ebp+KTRAP_FRAME_FS]
pop fs
9:
/* Skip debug information and unsaved registers */
lea esp, [ebp+KTRAP_FRAME_EDI]
pop edi
pop esi
pop ebx
pop ebp
/* Check for ABIOS */
cmp word ptr [esp+8], 0x80
ja AbiosExit
/* Pop error code */
add esp, 4
.if \SystemCall
/* Check if previous CS is from user-mode */
test dword ptr [esp+4], 1
/* It is, so use Fast Exit */
jnz FastExit
/* Jump back to stub */
pop edx
pop ecx
popf
jmp edx
.ret:
.endif
iret
.if \SystemCall
FastExit:
/* Is SYSEXIT Supported/Wanted? */
cmp dword ptr ss:[_KiFastSystemCallDisable], 0
jnz .ret
test dword ptr [esp+8], EFLAGS_TF
jnz .ret
/* Restore FS to TIB */
mov ecx, KGDT_R3_TEB + RPL_MASK
mov fs, ecx
/* We will be cleaning up the stack ourselves */
pop edx /* New Ring 3 EIP */
add esp, 4 /* Skip Ring 3 DS */
and dword ptr [esp], 0xfffffdff /* Remove EFLAGS_INTERRUPT_MASK from EFLAGS */
popf /* Restore old EFLAGS */
pop ecx /* Old Ring 3 SS:ESP */
/*
* At this point:
* ECX points to the old User Stack.
* EDX points to the instruction to execute in usermode after the sysenter
*/
sti
sysexit
.endif
.if \RestoreAllRegs
8:
/* Restore EAX */
mov eax, [esp+KTRAP_FRAME_EAX]
/* Skip registers */
add esp, 0x30
/* Restore segments and volatiles */
pop gs
pop es
pop ds
pop edx
pop ecx
/* Jump back to mainline code */
jmp 3b
.endif
#if DBG
0:
/* Fix up the mask */
add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
6:
UNHANDLED_PATH
jmp 5b
#endif
2:
/* Check if this was V86 mode */
test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz 1f
/* Check if it was user mode */
test word ptr [esp+KTRAP_FRAME_CS], MODE_MASK
jz 4b
1:
/* Clear DR7 */
xor ebx, ebx
mov dr7, ebx
/* Get DR0, 1, 2 */
mov esi, [ebp+KTRAP_FRAME_DR0]
mov edi, [ebp+KTRAP_FRAME_DR1]
mov ebx, [ebp+KTRAP_FRAME_DR2]
/* Set them */
mov dr0, esi
mov dr1, edi
mov dr2, ebx
/* Get DR3, 6, 7 */
mov esi, [ebp+KTRAP_FRAME_DR3]
mov edi, [ebp+KTRAP_FRAME_DR6]
mov ebx, [ebp+KTRAP_FRAME_DR7]
/* Set them */
mov dr3, esi
mov dr6, edi
mov dr7, ebx
jmp 4b
7:
/* Restore real CS value */
mov ebx, [esp+KTRAP_FRAME_TEMPCS]
mov [esp+KTRAP_FRAME_CS], ebx
/*
* If ESP was modified, then a special interrupt exit stack
* must be created to "update" ESP's value in a legal manner
*/
mov ebx, [esp+KTRAP_FRAME_TEMPESP]
sub ebx, 0xC
mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
/* Copy Interrupt Stack */
mov esi, [esp+KTRAP_FRAME_EFLAGS]
mov [ebx+8], esi
mov esi, [esp+KTRAP_FRAME_CS]
mov [ebx+4], esi
mov esi, [esp+KTRAP_FRAME_EIP]
mov [ebx], esi
.if \RestoreVolatiles
/* Restore volatiles */
mov eax, [esp+KTRAP_FRAME_EAX]
mov edx, [esp+KTRAP_FRAME_EDX]
mov ecx, [esp+KTRAP_FRAME_ECX]
.endif
/* Return */
add esp, KTRAP_FRAME_EDI
pop edi
pop esi
pop ebx
pop ebp
mov esp, [esp]
iret
.endm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -