[原创]EFER hook
2022-11-5 12:44:16 Author: bbs.pediy.com(查看原文) 阅读量:15 收藏

最近在看HyperDbg这个项目,看到了一种基于VT的syscall挂钩方法,记录一下。EFER(Extended Feature Enable Register)是MSR寄存器的一种,相关功能可以在intel白皮书卷3A,第2.2.1节中找到。

EFER寄存器的SCE位用来控制对SYSCALL/SYSRET的支持。
在卷2B,第4.3节可以找到SYSCALL指令的操作

可以看出当EFER寄存器的SCE位为0时会产生#UD异常,如果我们手动将SCE清零,那么就会导致#UD异常,再通过设置VT中对#UD异常的响应事件就可以拦截SYSCALL。
用代码模拟SYSCALL:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

_Use_decl_annotations_

BOOLEAN

SyscallHookHandleUD(PGUEST_REGS Regs, UINT32 CoreIndex)

{

    CR3_TYPE                GuestCr3;

    UINT64                  OriginalCr3;

    UINT64                  Rip;

    VIRTUAL_MACHINE_STATE * CurrentVmState = &g_GuestState[CoreIndex];

    //

    // Reading guest's RIP

    //

    __vmx_vmread(VMCS_GUEST_RIP, &Rip);

    if (g_IsUnsafeSyscallOrSysretHandling)

    {

        //

        // In some computers, we realized that safe accessing to memory

        // is problematic. It means that our syscall approach might not

        // working properly.

        // Based on our tests, we realized that system doesn't generate

        // regularly. So, we can imagine that only kernel addresses are SYSRET

        // instruction and SYSCALL is on a user-mode RIP.

        // It's faster than our safe methods but if the system generates a

        // then a BSOD will happen. But if the system is working regularly, then

        // no BSOD happens. For more information, see documentation at !syscall2

        // or !sysret2 commands

        //

        if (Rip & 0xff00000000000000)

        {

            goto EmulateSYSRET;

        }

        else

        {

            goto EmulateSYSCALL;

        }

    }

    else

    {

        //

        // Get the guest's running process's cr3

        //

        GuestCr3.Flags = GetRunningCr3OnTargetProcess().Flags;

        //

        // No, longer needs to be checked because we're sticking to system process

        // and we have to change the cr3

        //

        // if ((GuestCr3.Flags & PCID_MASK) != PCID_NONE)

        OriginalCr3 = __readcr3();

        __writecr3(GuestCr3.Flags);

        //

        // Read the memory

        //

        UCHAR InstructionBuffer[3] = {0};

        if (MemoryMapperCheckIfPageIsPresentByCr3(Rip, GuestCr3))

        {

            //

            // The page is safe to read (present)

            // It's not necessary to use MemoryMapperReadMemorySafeOnTargetProcess

            // because we already switched to the process's cr3

            //

            MemoryMapperReadMemorySafe(Rip, InstructionBuffer, 3);

        }

        else

        {

            //

            // The page is not present, we have to inject a

            //

            CurrentVmState->IncrementRip = FALSE;

            //

            // For testing purpose

            //

            // LogInfo("#PF Injected");

            //

            // Inject

            //

            EventInjectPageFault(Rip);

            //

            // We should not inject

            //

            return FALSE;

        }

        __writecr3(OriginalCr3);

        //SYSCALL_INSTRUCTION

        if (InstructionBuffer[0] == 0x0F &&

            InstructionBuffer[1] == 0x05)

        {

            goto EmulateSYSCALL;

        }

        //SYSRET_INSTRUCTION

        if (InstructionBuffer[0] == 0x48 &&

            InstructionBuffer[1] == 0x0F &&

            InstructionBuffer[2] == 0x07)

        {

            goto EmulateSYSRET;

        }

        return FALSE;

    }

    //----------------------------------------------------------------------------------------

    //

    // Emulate SYSRET instruction

    //

EmulateSYSRET:

    //

    // Test

    //

    // LogInfo("SYSRET instruction => 0x%llX", Rip);

    //

    //

    // Perform the dispatching and the emulation of the SYSRET event

    //

    DispatchEventEferSysret(CoreIndex, Regs, Rip);

    return TRUE;

    //

    // Emulate SYSCALL instruction

    //

EmulateSYSCALL:

    //

    // Test

    //

    // LogInfo("SYSCALL instruction => 0x%llX , Process Id : 0x%x", Rip, PsGetCurrentProcessId());

    //

    //

    // Perform the dispatching and the emulation of the SYSCAKK event

    //

    DispatchEventEferSyscall(CoreIndex, Regs, Rip);

    return TRUE;

}


文章来源: https://bbs.pediy.com/thread-274997.htm
如有侵权请联系:admin#unsafe.sh