rbx1中的follow

github地址:https://github.com/robotBing/openrobot_follower.git 

视频展示地址:http://blog.jiutucao.com:9000/upload/2018/07/color_follow.mp4

1.  基本功能

1)跟随人行走

2)语音控制开始或停止

3)颜色标定

2. 跟随实现

1)代码:

#!/usr/bin/env python

import rospy

from roslib import message

from std_msgs.msg import String

from sensor_msgs import point_cloud2

from sensor_msgs.msg import PointCloud2

from geometry_msgs.msg import Twist

from math import copysign 

class Follower():

int status = 0

    def __init__(self):

        rospy.init_node("follower")

 

        rospy.on_shutdown(self.shutdown)

 

        self.goal_z = rospy.get_param("~goal_z", 0.6)

 

        self.z_threshold = rospy.get_param("~z_threshold", 0.05)

 

        self.x_threshold = rospy.get_param("~x_threshold", 0.05)

        self.z_scale = rospy.get_param("~z_scale", 1.0)     

        self.x_scale = rospy.get_param("~x_scale", 2.5)

   

        self.max_angular_speed = rospy.get_param("~max_angular_speed", 2.0)

        self.min_angular_speed = rospy.get_param("~min_angular_speed", 0.0)

        self.max_linear_speed = rospy.get_param("~max_linear_speed", 0.3)

        self.min_linear_speed = rospy.get_param("~min_linear_speed", 0.1

        self.low_down_factor = rospy.get_param("~slow_down_factor", 0.8)

        self.move_cmd = Twist()

        self.cmd_vel_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=5)

        self.depth_subscriber = rospy.Subscriber('point_cloud', PointCloud2, self.set_cmd_vel, queue_size=1)

        rospy.Subscriber('/recognizer/output', String, self.speechcb)

        rospy.loginfo("Subscribing to point cloud...")

        rospy.wait_for_message('point_cloud', PointCloud2)

        rospy.loginfo("Ready to follow!"

def speechcb(self,msg):

        command = msg.data

        if command == 'stop':

               self.status = 0

        else if command == 'move' :

               self.status = 1

    def set_cmd_vel(self, msg):

        x = y = z = n = 0

        for point in point_cloud2.read_points(msg, skip_nans=True):

            pt_x = point[0]

            pt_y = point[1]

            pt_z = point[2]

            x += pt_x

            y += pt_y

            z += pt_z

            n += 1

        if n:

            x /= n

            y /= n

            z /= n

            if (abs(z - self.goal_z) > self.z_threshold):

                linear_speed = (z - self.goal_z) * self.z_scale

                self.move_cmd.linear.x = copysign(max(self.min_line

 

ar_speed,

                                        min(self.max_linear_speed, abs(linear_speed))), linear_speed)

            else:

                self.move_cmd.linear.x *= self.slow_down_factor

               

            if (abs(x) > self.x_threshold):    

                angular_speed = -x * self.x_scale

                self.move_cmd.angular.z = copysign(max(self.min_angular_speed,

                                        min(self.max_angular_speed, abs(angular_speed))), angular_speed)

            else:

                self.move_cmd.angular.z *= self.slow_down_factor

        else:

            self.move_cmd.linear.x *= self.slow_down_factor

            self.move_cmd.angular.z *= self.slow_down_factor

       if self.status == 0:

            self.cmd_vel_pub.publish(twist())

        else:

               self.cmd_vel_pub.publish(self.move_cmd)

    def shutdown(self):

        rospy.loginfo("Stopping the robot...")

        self.depth_subscriber.unregister()

        rospy.sleep(1)

        self.cmd_vel_pub.publish(Twist())

        rospy.sleep(1)     

if __name__ == '__main__':

    try:

        Follower()

        rospy.spin()

    except rospy.ROSInterruptException:

        rospy.loginfo("Follower node terminated.")

 

2)基本思路

订阅点云(pointcloud2)话题,点云数据包括图像的宽度,高度和一个个点的信息。

根据点云数据找出人的质心点,然后将质心点和图像的中间点和设定的距离点比较,

左右偏移则往/cmd_vel话题上发布左右消息,前后则发布前后消息

  3) launch文件

  <launch>

  <node pkg="nodelet" type="nodelet" name="pcl_manager" args="manager" output="screen" />

  <node pkg="nodelet" type="nodelet" name="voxel_grid_z" args="load pcl/VoxelGrid pcl_manager" output="screen">

    <remap from="~input" to="/camera/depth_registered/points" />

    <remap from="~output" to="/z_filtered" />

    <rosparam>

      filter_field_name: z

      filter_limit_min: 0.3

      filter_limit_max: 1.6

      filter_limit_negative: False

      leaf_size: 0.02

    </rosparam>

  </node>

  <node pkg="nodelet" type="nodelet" name="passthrough_x" args="load pcl/PassThrough pcl_manager" output="screen">

    <remap from="~input" to="/z_filtered" />

    <remap from="~output" to="/x_filtered" />

    <rosparam>

      filter_field_name: x

      filter_limit_min: -0.3

      filter_limit_max: 0.3

      filter_limit_negative: False

    </rosparam>

  </node>

  <node pkg="nodelet" type="nodelet" name="passthrough_y" args="load pcl/PassThrough pcl_manager" output="screen">

    <remap from="~input" to="/x_filtered" />

    <remap from="~output" to="/search_cloud" />

    <rosparam>

      filter_field_name: y

      filter_limit_min: -0.5

      filter_limit_max: -0.1

      filter_limit_negative: False

    </rosparam>

  </node>

 

  <node pkg="openrobot_follow" name="follower" type="follower2.py" output="screen">

    <remap from="point_cloud" to="search_cloud" />

    <rosparam>

       goal_z: 0.8

       z_threshold: 0.025

       x_threshold: 0.025

       z_scale: 1.0

       x_scale: 3.0

       max_angular_speed: 5.0

       min_angular_speed: 0.1

       max_linear_speed: 0.4

       min_linear_speed: 0.05

    </rosparam>

  </node>

</launch>

 

 

4)launch详解

nodelet是ros自带的节点管理系统,类似于java里的多线程

 

利用VoxelGrid算法,对pointcloud的深度信息过滤

 

然后利用passthrough算法,对x  ,y坐标过滤

 

过滤可以降低计算量,又不会影响follow结果

 

最后启动follow节点

 

remap表示话题的映射,相当于给话题改名

 

5)参数详解

filter_field_name:     选择过滤的坐标系(x,y,z)

filter_limit_min:      最短的过滤信息,即最短的检测距离

      filter_limit_max:      最大的过滤信息,即最大的检测距离

leaf_size:             算法切块的大小

goal_z:               距离目标的距离

      z_threshold:          深度偏差量

      x_threshold:          x方向偏差量,即允许人在图像的哪个范围

      z_scale:             距离权重,控制线速度

      x_scale:             x方向的权重,控制角速度

      max_angular_speed:   最大角速度

      min_angular_speed:    最小角速度

      max_linear_speed:     最大线速度

      min_linear_speed:     最小线速度

 

3.  语音实现

1)概述

利用ros自带的语音识别包pocketsphinx,订阅/input/recognizer话题,获得识别结果,然后给follow函数设置一个使能变量,在语音的回调函数里对使能变量做操作

 

2)环境配置

sudo apt-get install ros-indigo-turtlebot-bringup \

ros-indigo-turtlebot-create-desktop ros-indigo-openni-* \

ros-indigo-openni2-* ros-indigo-freenect-* ros-indigo-usb-cam \

ros-indigo-laser-* ros-indigo-hokuyo-node \

ros-indigo-audio-common gstreamer0.10-pocketsphinx \

ros-indigo-pocketsphinx ros-indigo-slam-gmapping \

ros-indigo-joystick-drivers python-rosinstall \

ros-indigo-orocos-kdl ros-indigo-python-orocos-kdl \

python-setuptools ros-indigo-dynamixel-motor-* \

libopencv-dev python-opencv ros-indigo-vision-opencv \

ros-indigo-depthimage-to-laserscan ros-indigo-arbotix-* \

ros-indigo-turtlebot-teleop ros-indigo-move-base \

ros-indigo-map-server ros-indigo-fake-localization \

ros-indigo-amcl git subversion mercurial

 

 

3)代码重写

 

#!/usr/bin/env python

import rospy

from roslib import message

from sensor_msgs import point_cloud2

from sensor_msgs.msg import PointCloud2

from geometry_msgs.msg import Twist

from std_msgs.msg import String

from math import copysig

class Follower():

    def __init__(self):

        rospy.init_node("follower")

        rospy.on_shutdown(self.shutdown)

        self.goal_z = rospy.get_param("~goal_z", 1.5)

        self.z_threshold = rospy.get_param("~z_threshold", 0.05)

        self.x_threshold = rospy.get_param("~x_threshold", 0.05)

        self.z_scale = rospy.get_param("~z_scale", 0.7) 

        self.x_scale = rospy.get_param("~x_scale", 2.2)

        self.max_angular_speed = rospy.get_param("~max_angular_speed", 2.0)

        self.min_angular_speed = rospy.get_param("~min_angular_speed", 0.0)        self.max_linear_speed = rospy.get_param("~max_linear_speed", 0.3)       

        self.min_linear_speed = rospy.get_param("~min_linear_speed", 0.1)

        self.slow_down_factor = rospy.get_param("~slow_down_factor", 0.8)

        self.move_cmd = Twist()

        self.cmd_vel_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=10)

  self.sta = 1

  self.speech_sub = rospy.Subscriber('recognizer/output',String,self.speechcb,queue_size=1)

 

        # Subscribe to the point cloud

        self.depth_subscriber = rospy.Subscriber('point_cloud', PointCloud2, self.set_cmd_vel, queue_size=10)

 

        rospy.loginfo("Subscribing to point cloud...")

       

        # Wait for the pointcloud topic to become available

        rospy.wait_for_message('point_cloud', PointCloud2)

 

        rospy.loginfo("Ready to follow!")

 

    def speechcb(self,msg):

  if msg.data == 'stop':

         self.sta=0

  elif msg.data == 'move':

         self.sta=1

       

    def set_cmd_vel(self, msg):

        # Initialize the centroid coordinates point count

        x = y = z = n = 0

       

        # Read in the x, y, z coordinates of all points in the cloud

        for point in point_cloud2.read_points(msg, skip_nans=True):

            pt_x = point[0]

            pt_y = point[1]

            pt_z = point[2]

           

            x += pt_x

            y += pt_y

            z += pt_z

            n += 1

        if n:

            x /= n

            y /= n

            z /= n

 

            if (abs(z - self.goal_z) > self.z_threshold):

   

                linear_speed = (z - self.goal_z) * self.z_scale

                self.move_cmd.linear.x = copysign(max(self.min_linear_speed,

                                        min(self.max_linear_speed, abs(linear_speed))), linear_speed)

            else:

                self.move_cmd.linear.x *= self.slow_down_factor

               

            if (abs(x) > self.x_threshold):    

                angular_speed = -x * self.x_scale

                

                self.move_cmd.angular.z = copysign(max(self.min_angular_speed,

                                        min(self.max_angular_speed, abs(angular_speed))), angular_speed)

            else:

                self.move_cmd.angular.z *= self.slow_down_factor

               

        else:

            self.move_cmd.linear.x *= self.slow_down_factor

            self.move_cmd.angular.z *= self.slow_down_factor

           

     

  if self.sta == 0:

         self.cmd_vel_pub.publish(Twist())

  else:

         self.cmd_vel_pub.publish(self.move_cmd)

       

    def shutdown(self):

        rospy.loginfo("Stopping the robot...")

       

        self.depth_subscriber.unregister()

        rospy.sleep(1)

       

        self.cmd_vel_pub.publish(Twist())

        rospy.sleep(1)     

                  

if __name__ == '__main__':

    try:

        Follower()

        rospy.spin()

    except rospy.ROSInterruptException:

        rospy.loginfo("Follower node terminated.")

 

4)Launch重写

<launch>

 

<node name="recognizer" pkg="pocketsphinx" type="recognizer.py" output="screen">

    <param name="lm" value="$(find rbx1_speech)/config/nav_commands.lm"/>

    <param name="dict" value="$(find rbx1_speech)/config/nav_commands.dic"/>

  </node>

 

  <node pkg="nodelet" type="nodelet" name="pcl_manager" args="manager" output="screen" />

 

  <!-- Run a VoxelGrid filter on the z axis -->

  <node pkg="nodelet" type="nodelet" name="voxel_grid_z" args="load pcl/VoxelGrid pcl_manager" output="screen">

    <remap from="~input" to="/kinect2/qhd/points" />

    <remap from="~output" to="/z_filtered" />

    <rosparam>

      filter_field_name: z

      filter_limit_min: 0.3

      filter_limit_max: 1.6

      filter_limit_negative: False

      leaf_size: 0.02

    </rosparam>

  </node>

 

  <!-- Run a passthrough filter on the x axis -->

  <node pkg="nodelet" type="nodelet" name="passthrough_x" args="load pcl/PassThrough pcl_manager" output="screen">

    <remap from="~input" to="/z_filtered" />

    <remap from="~output" to="/x_filtered" />

    <rosparam>

      filter_field_name: x

      filter_limit_min: -0.3

      filter_limit_max: 0.3

      filter_limit_negative: False

    </rosparam>

  </node>

 

  <!-- Run a passthrough filter on the y axis -->

  <node pkg="nodelet" type="nodelet" name="passthrough_y" args="load pcl/PassThrough pcl_manager" output="screen">

    <remap from="~input" to="/x_filtered" />

    <remap from="~output" to="/search_cloud" />

    <rosparam>

      filter_field_name: y

      filter_limit_min: -0.5

      filter_limit_max: -0.1

      filter_limit_negative: False

    </rosparam>

  </node>

 

  <node pkg="openrobot_follow" name="follower" type="follower2.py" output="screen">

    <remap from="point_cloud" to="search_cloud" />

   

    <rosparam>

       goal_z: 1.2

       z_threshold: 0.025

       x_threshold: 0.025

       z_scale: 0.6

       x_scale: 2.1

       max_angular_speed: 3.0

       min_angular_speed: 0.1

       max_linear_speed: 0.4

       min_linear_speed: 0.05

    </rosparam>

   

  </node>

</launch>

 

 

4. 颜色标定实现

1 ) 概述

 利用opencv提供的python接口,处理图像信息,利用cv_bridge将ros话题上发布的摄像头消息数据转化成为opencv可以处理的图像数据。

 

2 )代码见github项目

 

 

 

 3 ) launch

    <launch> 

  <node name="recognizer" pkg="pocketsphinx" type="recognizer.py" output="screen">

    <param name="lm" value="/home/tt/my_ws/src/openrobot_follow/speech_conf/command.lm"/>

    <param name="dict" value="/home/tt/my_ws/src/openrobot_follow/speech_conf/command.dic"/>

  </node>

  <node pkg="openrobot_follow" name="color_follower" type="color_follower.py" output="screen">

<remap from="camera_info" to="/camera/rgb/camera_info" />

  <remap from="depth_image" to="/camera/depth_registered/image_raw" />

    <rosparam>

       rate: 20

       max_z: 2.0  # How far out do we want to detect

       min_z: 0.1

       goal_z: 0.7

       z_threshold: 0.1

       x_threshold: 0.3

       z_scale: 1.0 # forward/back scale

       x_scale: 1.3 # left/right scale

       max_rotation_speed: 1.0

       min_rotation_speed: 0.1

       max_linear_speed: 0.2

       min_linear_speed: 0.02

       scale_roi: 0.9

    </rosparam>

  </node>

</launch>

4 )launch详解

rate:   消息回调速度,一般不用动,如果出现卡顿再改动

       max_z:   检测的最大距离

       min_z:   检测的最小距离

       goal_z:   保持机器和目标的距离

       z_threshold: 距离的可控区域

       x_threshold: 图像的可控区域,即在屏幕上画个矩形,让目标保持在矩形内

       z_scale:    线速度的权值

       x_scale:    角速度的权值

       max_rotation_speed: 最大角速度

       min_rotation_speed: 最小角速度

       max_linear_speed:   最大线速度

       min_linear_speed:    最小线速度

       scale_roi:    对roi话题上发布的信息的缩小范围

1.     运行底盘驱动

rosrun openrobot Node_p_chassis

 

 2 .打开摄像头驱动(实验室用的奥比中光深度摄像头)

  roslaunch astra_launch astra.launch

 3.启动camshift 发布/roi

  roslaunch openrobot_follow camshift.launch

这时候屏幕上会出现3个窗口,在有图像的窗口选择需要跟随的物体。这时候程序会计算物体的颜色,另外两个窗口其中一个会出现颜色的柱状图,另一个窗口出现颜色柱状图。物体移动绿色的框会跟着移动。尽量选中颜色鲜艳的物体。4.启动跟随

  roslaunch openrobot_follow color_follow.launch

kd> ed nt!Kd_DEFAULT_Mask 0xFFFFFFFF kd> ed nt!Kd_IHVDRIVER_Mask 0xFFFFFFFF kd> g [+] [DriverEntry] 驱动加载开始 [+] [DriverEntry] 驱动加载成功 [+] [ProcessNotifyCallback] 目标进程 oxygen.exe 创建 (PID: 8052) [+] [ProcessNotifyCallback] 工作线程已创建 [+] Worker thread started for hook installation on PID: 8052 Break instruction exception - code 80000003 (first chance) obpcallback!InstallHook+0x50: fffff803`0e2a12f0 cc int 3 kd> g [+] [InstallHook] 找到目标函数地址: FFFFF803062EFB60 [PTE_HOOK] 开始隔离页面: PID=8052, 地址=0xFFFFF803062EFB60 [PTE_HOOK] 正在拆分大页: 输入PDE=0xa00000002a001a1, 输出PDE=0xFFFFBB878EFA3F80 [PTE_HOOK] 大页拆分完成: 新PTE表物理地址=0x239dab000 [PTE_HOOK] G-Bit Info: Align Address: 0xFFFFF803062EF000 IsLargePage: 1 PDE: 0xa00000002a000a1 (Address: 0xFFFFFE7F3E00C188) [PTE_HOOK] 清除大页G位: PDE=0xa00000002a000a1 [PTE_HOOK] 开始隔离页表: CR3=0x12e16c000, 地址=0xFFFFF803062EF000 KDTARGET: Refreshing KD connection *** Fatal System Error: 0x0000007e (0xFFFFFFFFC0000005,0xFFFFF8030E2A2265,0xFFFF80031C95B638,0xFFFF80031C95AE70) Break instruction exception - code 80000003 (first chance) A fatal system error has occurred. Debugger entered on first try; Bugcheck callbacks have not been invoked. A fatal system error has occurred. For analysis of this file, run !analyze -v nt!DbgBreakPointWithStatus: fffff803`05ffd0b0 cc int 3 kd> !analyze -v Connected to Windows 10 19041 x64 target at (Wed Jul 9 20:20:01.053 2025 (UTC + 8:00)), ptr64 TRUE Loading Kernel Symbols ................................... Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long. Run !sym noisy before .reload to track down problems loading symbols. ............................ ................................................................ ..................................................... Loading User Symbols PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details Loading unloaded module list ...... ERROR: FindPlugIns 8007007b ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e) This is a very common BugCheck. Usually the exception address pinpoints the driver/function that caused the problem. Always note this address as well as the link date of the driver/image that contains this address. Arguments: Arg1: ffffffffc0000005, The exception code that was not handled Arg2: fffff8030e2a2265, The address that the exception occurred at Arg3: ffff80031c95b638, Exception Record Address Arg4: ffff80031c95ae70, Context Record Address Debugging Details: ------------------ Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long. Run !sym noisy before .reload to track down problems loading symbols. PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 00000000`00259018). Type ".hh dbgerr001" for details KEY_VALUES_STRING: 1 Key : AV.Type Value: Read Key : Analysis.CPU.mSec Value: 4234 Key : Analysis.Elapsed.mSec Value: 39170 Key : Analysis.IO.Other.Mb Value: 0 Key : Analysis.IO.Read.Mb Value: 2 Key : Analysis.IO.Write.Mb Value: 0 Key : Analysis.Init.CPU.mSec Value: 3250 Key : Analysis.Init.Elapsed.mSec Value: 59417 Key : Analysis.Memory.CommitPeak.Mb Value: 72 Key : Analysis.Version.DbgEng Value: 10.0.27829.1001 Key : Analysis.Version.Description Value: 10.2503.24.01 amd64fre Key : Analysis.Version.Ext Value: 1.2503.24.1 Key : Bugcheck.Code.KiBugCheckData Value: 0x7e Key : Bugcheck.Code.LegacyAPI Value: 0x7e Key : Bugcheck.Code.TargetModel Value: 0x7e Key : Failure.Bucket Value: AV_obpcallback!PteHookManager::fn_isolation_pagetable Key : Failure.Exception.Code Value: 0xc0000005 Key : Failure.Exception.IP.Address Value: 0xfffff8030e2a2265 Key : Failure.Exception.IP.Module Value: obpcallback Key : Failure.Exception.IP.Offset Value: 0x2265 Key : Failure.Exception.Record Value: 0xffff80031c95b638 Key : Failure.Hash Value: {03bbd39e-299b-91b8-212d-d002a6bff650} Key : Hypervisor.Enlightenments.Value Value: 12576 Key : Hypervisor.Enlightenments.ValueHex Value: 0x3120 Key : Hypervisor.Flags.AnyHypervisorPresent Value: 1 Key : Hypervisor.Flags.ApicEnlightened Value: 0 Key : Hypervisor.Flags.ApicVirtualizationAvailable Value: 0 Key : Hypervisor.Flags.AsyncMemoryHint Value: 0 Key : Hypervisor.Flags.CoreSchedulerRequested Value: 0 Key : Hypervisor.Flags.CpuManager Value: 0 Key : Hypervisor.Flags.DeprecateAutoEoi Value: 1 Key : Hypervisor.Flags.DynamicCpuDisabled Value: 0 Key : Hypervisor.Flags.Epf Value: 0 Key : Hypervisor.Flags.ExtendedProcessorMasks Value: 0 Key : Hypervisor.Flags.HardwareMbecAvailable Value: 0 Key : Hypervisor.Flags.MaxBankNumber Value: 0 Key : Hypervisor.Flags.MemoryZeroingControl Value: 0 Key : Hypervisor.Flags.NoExtendedRangeFlush Value: 1 Key : Hypervisor.Flags.NoNonArchCoreSharing Value: 0 Key : Hypervisor.Flags.Phase0InitDone Value: 1 Key : Hypervisor.Flags.PowerSchedulerQos Value: 0 Key : Hypervisor.Flags.RootScheduler Value: 0 Key : Hypervisor.Flags.SynicAvailable Value: 1 Key : Hypervisor.Flags.UseQpcBias Value: 0 Key : Hypervisor.Flags.Value Value: 536632 Key : Hypervisor.Flags.ValueHex Value: 0x83038 Key : Hypervisor.Flags.VpAssistPage Value: 1 Key : Hypervisor.Flags.VsmAvailable Value: 0 Key : Hypervisor.RootFlags.AccessStats Value: 0 Key : Hypervisor.RootFlags.CrashdumpEnlightened Value: 0 Key : Hypervisor.RootFlags.CreateVirtualProcessor Value: 0 Key : Hypervisor.RootFlags.DisableHyperthreading Value: 0 Key : Hypervisor.RootFlags.HostTimelineSync Value: 0 Key : Hypervisor.RootFlags.HypervisorDebuggingEnabled Value: 0 Key : Hypervisor.RootFlags.IsHyperV Value: 0 Key : Hypervisor.RootFlags.LivedumpEnlightened Value: 0 Key : Hypervisor.RootFlags.MapDeviceInterrupt Value: 0 Key : Hypervisor.RootFlags.MceEnlightened Value: 0 Key : Hypervisor.RootFlags.Nested Value: 0 Key : Hypervisor.RootFlags.StartLogicalProcessor Value: 0 Key : Hypervisor.RootFlags.Value Value: 0 Key : Hypervisor.RootFlags.ValueHex Value: 0x0 Key : SecureKernel.HalpHvciEnabled Value: 0 Key : WER.OS.Branch Value: vb_release Key : WER.OS.Version Value: 10.0.19041.1 BUGCHECK_CODE: 7e BUGCHECK_P1: ffffffffc0000005 BUGCHECK_P2: fffff8030e2a2265 BUGCHECK_P3: ffff80031c95b638 BUGCHECK_P4: ffff80031c95ae70 FAULTING_THREAD: ffffbb8793f90080 EXCEPTION_RECORD: ffff80031c95b638 -- (.exr 0xffff80031c95b638) ExceptionAddress: fffff8030e2a2265 (obpcallback!PteHookManager::fn_isolation_pagetable+0x0000000000000315) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 0000000239dab000 Attempt to read from address 0000000239dab000 CONTEXT: ffff80031c95ae70 -- (.cxr 0xffff80031c95ae70) rax=0000000239dab000 rbx=ffffbb8793f90080 rcx=0000000000001000 rdx=0000000000000000 rsi=0000000239dab000 rdi=ffff9181d99a7000 rip=fffff8030e2a2265 rsp=ffff80031c95b870 rbp=0000000000000080 r8=ffff80031c95b940 r9=8000000000000200 r10=0000000000000000 r11=ffffbb8790910000 r12=0000000000000280 r13=0000000000000000 r14=ffffbb878f4af040 r15=fffff8030c094000 iopl=0 nv up ei pl nz ac po nc cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00050216 obpcallback!PteHookManager::fn_isolation_pagetable+0x315: fffff803`0e2a2265 f3a4 rep movs byte ptr [rdi],byte ptr [rsi] Resetting default scope PROCESS_NAME: oxygen.exe READ_ADDRESS: unable to get nt!PspSessionIdBitmap 0000000239dab000 ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p 0x%p %s EXCEPTION_CODE_STR: c0000005 EXCEPTION_PARAMETER1: 0000000000000000 EXCEPTION_PARAMETER2: 0000000239dab000 EXCEPTION_STR: 0xc0000005 STACK_TEXT: ffff8003`1c95b870 fffff803`0e2a1da1 : ffffbb87`8efa7000 00000001`2e16c000 fffff803`062ef000 ffffbb87`8efa3f80 : obpcallback!PteHookManager::fn_isolation_pagetable+0x315 [C:\Users\17116\source\repos\obpcallback\obpcallback\Ô´.cpp @ 526] ffff8003`1c95b9c0 fffff803`0e2a25df : ffffbb87`8efa7000 00000000`00001f74 fffff803`062efb60 00000000`00000035 : obpcallback!PteHookManager::fn_isolation_pages+0x261 [C:\Users\17116\source\repos\obpcallback\obpcallback\Ô´.cpp @ 602] ffff8003`1c95bad0 fffff803`0e2a1344 : ffffbb87`8efa7000 00000000`00001f74 ffff8003`1c95bbb0 fffff803`0e2a1500 : obpcallback!PteHookManager::fn_pte_inline_hook_bp_pg+0x4f [C:\Users\17116\source\repos\obpcallback\obpcallback\Ô´.cpp @ 723] ffff8003`1c95bb90 fffff803`0e2a13d4 : fffff803`0e2a44a0 00000000`00001f74 00000000`00000000 fffff803`040ef180 : obpcallback!InstallHook+0xa4 [C:\Users\17116\source\repos\obpcallback\obpcallback\Ô´.cpp @ 982] ffff8003`1c95bbe0 fffff803`05ea29a5 : 00000000`00001f74 fffff803`0e2a13a0 00000000`00001f74 fffff803`00000001 : obpcallback!InstallHookWorker+0x34 [C:\Users\17116\source\repos\obpcallback\obpcallback\Ô´.cpp @ 1010] ffff8003`1c95bc10 fffff803`05ffc868 : fffff803`040ef180 ffffbb87`93f90080 fffff803`05ea2950 ffff8003`1c95bc80 : nt!PspSystemThreadStartup+0x55 ffff8003`1c95bc60 00000000`00000000 : ffff8003`1c95c000 ffff8003`1c956000 00000000`00000000 00000000`00000000 : nt!KiStartSystemThread+0x28 FAULTING_SOURCE_LINE: C:\Users\17116\source\repos\obpcallback\obpcallback\Ô´.cpp FAULTING_SOURCE_FILE: C:\Users\17116\source\repos\obpcallback\obpcallback\Ô´.cpp FAULTING_SOURCE_LINE_NUMBER: 526 FAULTING_SOURCE_CODE: 522: memcpy(Va4kb, replace_align_addr, PAGE_SIZE); 523: 524: if (Table.IsLargePage && split_pde_ptr) { 525: auto split_pde = (decltype(PAGE_TABLE::PdeAddress))split_pde_ptr; > 526: memcpy(VaPt, (void*)(split_pde->flags.page_frame_number << 12), PAGE_SIZE); 527: } 528: else { 529: memcpy(VaPt, (void*)(Table.PdeAddress->flags.page_frame_number << 12), PAGE_SIZE); 530: } 531: SYMBOL_NAME: obpcallback!PteHookManager::fn_isolation_pagetable+315 MODULE_NAME: obpcallback IMAGE_NAME: obpcallback.sys STACK_COMMAND: .cxr 0xffff80031c95ae70 ; kb BUCKET_ID_FUNC_OFFSET: 315 FAILURE_BUCKET_ID: AV_obpcallback!PteHookManager::fn_isolation_pagetable OS_VERSION: 10.0.19041.1 BUILDLAB_STR: vb_release OSPLATFORM_TYPE: x64 OSNAME: Windows 10 FAILURE_ID_HASH: {03bbd39e-299b-91b8-212d-d002a6bff650} Followup: MachineOwner ---------按照你改的结果出错了。代码如下:#include <ntifs.h> #include <ntddk.h> #include <intrin.h> #include "ptehook.h" #define CR0_WP (1 << 16) HANDLE targetProcessId = NULL; typedef INT(*LDE_DISASM)(PVOID address, INT bits); typedef unsigned long DWORD; typedef unsigned __int64 ULONG64; // 使用WDK标准类型 typedef unsigned char BYTE; typedef LONG NTSTATUS; // 修正后的跳转指令结构 #pragma pack(push, 1) typedef struct _JMP_ABS { BYTE opcode[6]; // FF 25 00 00 00 00 ULONG64 address; // 8字节绝对地址 } JMP_ABS, * PJMP_ABS; #pragma pack(pop) LDE_DISASM lde_disasm; // 初始化引擎 VOID lde_init() { lde_disasm = (LDE_DISASM)ExAllocatePool(NonPagedPool, 12800); memcpy(lde_disasm, szShellCode, 12800); } // 得到完整指令长度,避免截断 ULONG GetFullPatchSize(PUCHAR Address) { ULONG LenCount = 0, Len = 0; // 至少需要14字节 while (LenCount <= 14) { Len = lde_disasm(Address, 64); Address = Address + Len; LenCount = LenCount + Len; } return LenCount; } #define PROCESS_NAME_LENGTH 16 #define DRIVER_TAG 'HKOB' EXTERN_C char* PsGetProcessImageFileName(PEPROCESS process); char target_process_name[] = "oxygen.exe"; typedef NTSTATUS(*fn_ObReferenceObjectByHandleWithTag)( HANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, ULONG Tag, PVOID* Object, POBJECT_HANDLE_INFORMATION HandleInformation ); fn_ObReferenceObjectByHandleWithTag g_OriginalObReferenceObjectByHandleWithTag = NULL; // PTE Hook Framework #define MAX_G_BIT_RECORDS 128 #define MAX_HOOK_COUNT 64 #define PAGE_ALIGN(va) ((PVOID)((ULONG_PTR)(va) & ~0xFFF)) #define PDPTE_PS_BIT (1 << 7) #define PDE_PS_BIT (1 << 7) #define PTE_NX_BIT (1ULL << 63) #define CACHE_WB (6ULL << 3) // 页表结构定义 typedef struct _PAGE_TABLE { UINT64 LineAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 pat : 1; UINT64 global : 1; UINT64 ignored_1 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_2 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PteAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 large_page : 1; UINT64 global : 1; UINT64 ignored_2 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdeAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 ignored_1 : 1; UINT64 page_size : 1; UINT64 ignored_2 : 4; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdpteAddress; UINT64* Pml4Address; BOOLEAN IsLargePage; BOOLEAN Is1GBPage; UINT64 OriginalPte; UINT64 OriginalPde; UINT64 OriginalPdpte; UINT64 OriginalPml4e; HANDLE ProcessId; } PAGE_TABLE, * PPAGE_TABLE; // G位信息记录结构体 typedef struct _G_BIT_INFO { void* AlignAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 large_page : 1; UINT64 global : 1; UINT64 ignored_2 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdeAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 pat : 1; UINT64 global : 1; UINT64 ignored_1 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_2 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PteAddress; BOOLEAN IsLargePage; } G_BIT_INFO, * PG_BIT_INFO; typedef struct _HOOK_INFO { void* OriginalAddress; void* HookAddress; UINT8 OriginalBytes[20]; UINT8 HookBytes[20]; UINT32 HookLength; BOOLEAN IsHooked; HANDLE ProcessId; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 pat : 1; UINT64 global : 1; UINT64 ignored_1 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_2 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*HookedPte; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 large_page : 1; UINT64 global : 1; UINT64 ignored_2 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*HookedPde; } HOOK_INFO; class PteHookManager { public: bool fn_pte_inline_hook_bp_pg(HANDLE process_id, _Inout_ void** ori_addr, void* hk_addr); bool fn_remove_hook(HANDLE process_id, void* hook_addr); static PteHookManager* GetInstance(); HOOK_INFO* GetHookInfo() { return m_HookInfo; } char* GetTrampLinePool() { return m_TrampLinePool; } UINT32 GetHookCount() { return m_HookCount; } bool fn_resume_global_bits(void* align_addr); ~PteHookManager(); // 添加析构函数声明 private: bool WriteTrampolineInstruction(void* trampoline, const JMP_ABS& jmpCmd); void fn_add_g_bit_info(void* align_addr, void* pde_address, void* pte_address); bool fn_isolation_pagetable(UINT64 cr3_val, void* replace_align_addr, void* split_pde); bool fn_isolation_pages(HANDLE process_id, void* ori_addr); bool fn_split_large_pages(void* in_pde, void* out_pde); NTSTATUS get_page_table(UINT64 cr3, PAGE_TABLE& table); void* fn_pa_to_va(UINT64 pa); UINT64 fn_va_to_pa(void* va); __forceinline KIRQL DisableWriteProtection(); __forceinline void EnableWriteProtection(KIRQL oldIrql); void logger(const char* info, bool is_err, LONG err_code = 0); void PrintPageTableInfo(const PAGE_TABLE& table); void PrintHookInfo(const HOOK_INFO& hookInfo); void PrintGBitInfo(const G_BIT_INFO& gbitInfo); static constexpr SIZE_T MAX_HOOKS = 256; // 根据需求调整 G_BIT_INFO m_GbitRecords[MAX_G_BIT_RECORDS]; UINT32 m_GbitCount = 0; void* m_PteBase = 0; HOOK_INFO m_HookInfo[MAX_HOOK_COUNT] = { 0 }; DWORD m_HookCount = 0; char* m_TrampLinePool = nullptr; // 合并为一个声明 UINT32 m_PoolUsed = 0; static PteHookManager* m_Instance; }; PteHookManager* PteHookManager::m_Instance = nullptr; // 实现部分 __forceinline KIRQL PteHookManager::DisableWriteProtection() { KIRQL oldIrql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); __writecr0(cr0 & ~0x10000); // 清除CR0.WP位 _mm_mfence(); return oldIrql; } __forceinline void PteHookManager::EnableWriteProtection(KIRQL oldIrql) { _mm_mfence(); UINT64 cr0 = __readcr0(); __writecr0(cr0 | 0x10000); // 设置CR0.WP位 KeLowerIrql(oldIrql); } void PteHookManager::logger(const char* info, bool is_err, LONG err_code) { if (is_err) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] ERROR: %s (0x%X)\n", info, err_code); } else { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] INFO: %s\n", info); } } void PteHookManager::PrintPageTableInfo(const PAGE_TABLE& table) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] Page Table Info for VA: 0x%p\n", (void*)table.LineAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PML4E: 0x%llx (Address: 0x%p)\n", table.OriginalPml4e, table.Pml4Address); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PDPTE: 0x%llx (Address: 0x%p), Is1GBPage: %d\n", table.OriginalPdpte, table.PdpteAddress, table.Is1GBPage); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PDE: 0x%llx (Address: 0x%p), IsLargePage: %d\n", table.OriginalPde, table.PdeAddress, table.IsLargePage); if (!table.IsLargePage && !table.Is1GBPage) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PTE: 0x%llx (Address: 0x%p)\n", table.OriginalPte, table.PteAddress); } } void PteHookManager::PrintHookInfo(const HOOK_INFO& hookInfo) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] Hook Info:\n"); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Original Address: 0x%p\n", hookInfo.OriginalAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Hook Address: 0x%p\n", hookInfo.HookAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Hook Length: %d\n", hookInfo.HookLength); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Is Hooked: %d\n", hookInfo.IsHooked); // 打印原始字节 DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Original Bytes: "); for (UINT32 i = 0; i < sizeof(hookInfo.OriginalBytes); i++) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "%02X ", hookInfo.OriginalBytes[i]); } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "\n"); // 打印Hook字节 DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Hook Bytes: "); for (UINT32 i = 0; i < sizeof(hookInfo.HookBytes); i++) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "%02X ", hookInfo.HookBytes[i]); } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "\n"); } void PteHookManager::PrintGBitInfo(const G_BIT_INFO& gbitInfo) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] G-Bit Info:\n"); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Align Address: 0x%p\n", gbitInfo.AlignAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " IsLargePage: %d\n", gbitInfo.IsLargePage); if (gbitInfo.PdeAddress) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PDE: 0x%llx (Address: 0x%p)\n", gbitInfo.PdeAddress->value, gbitInfo.PdeAddress); } if (gbitInfo.PteAddress) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PTE: 0x%llx (Address: 0x%p)\n", gbitInfo.PteAddress->value, gbitInfo.PteAddress); } } void* PteHookManager::fn_pa_to_va(UINT64 pa) { PHYSICAL_ADDRESS physAddr; physAddr.QuadPart = pa; return MmGetVirtualForPhysical(physAddr); } UINT64 PteHookManager::fn_va_to_pa(void* va) { PHYSICAL_ADDRESS physAddr = MmGetPhysicalAddress(va); return physAddr.QuadPart; } NTSTATUS PteHookManager::get_page_table(UINT64 cr3_val, PAGE_TABLE& table) { UINT64 va = table.LineAddress; UINT64 pml4e_index = (va >> 39) & 0x1FF; UINT64 pdpte_index = (va >> 30) & 0x1FF; UINT64 pde_index = (va >> 21) & 0x1FF; UINT64 pte_index = (va >> 12) & 0x1FF; // PML4 UINT64 pml4_pa = cr3_val & ~0xFFF; UINT64* pml4_va = (UINT64*)fn_pa_to_va(pml4_pa); if (!pml4_va) return STATUS_INVALID_ADDRESS; table.Pml4Address = &pml4_va[pml4e_index]; table.OriginalPml4e = *table.Pml4Address; if (!(table.OriginalPml4e & 1)) return STATUS_ACCESS_VIOLATION; // PDPTE UINT64 pdpte_pa = table.OriginalPml4e & ~0xFFF; UINT64* pdpte_va = (UINT64*)fn_pa_to_va(pdpte_pa); if (!pdpte_va) return STATUS_INVALID_ADDRESS; table.PdpteAddress = (decltype(table.PdpteAddress))&pdpte_va[pdpte_index]; table.OriginalPdpte = table.PdpteAddress->value; table.Is1GBPage = (table.PdpteAddress->flags.page_size) ? TRUE : FALSE; if (!(table.OriginalPdpte & 1)) return STATUS_ACCESS_VIOLATION; if (table.Is1GBPage) return STATUS_SUCCESS; // PDE UINT64 pde_pa = table.OriginalPdpte & ~0xFFF; UINT64* pde_va = (UINT64*)fn_pa_to_va(pde_pa); if (!pde_va) return STATUS_INVALID_ADDRESS; table.PdeAddress = (decltype(table.PdeAddress))&pde_va[pde_index]; table.OriginalPde = table.PdeAddress->value; table.IsLargePage = (table.PdeAddress->flags.large_page) ? TRUE : FALSE; if (!(table.OriginalPde & 1)) return STATUS_ACCESS_VIOLATION; if (table.IsLargePage) return STATUS_SUCCESS; // PTE UINT64 pte_pa = table.OriginalPde & ~0xFFF; UINT64* pte_va = (UINT64*)fn_pa_to_va(pte_pa); if (!pte_va) return STATUS_INVALID_ADDRESS; table.PteAddress = (decltype(table.PteAddress))&pte_va[pte_index]; table.OriginalPte = table.PteAddress->value; if (!(table.OriginalPte & 1)) return STATUS_ACCESS_VIOLATION; // 打印页表信息 PrintPageTableInfo(table); return STATUS_SUCCESS; } bool PteHookManager::fn_split_large_pages(void* in_pde_ptr, void* out_pde_ptr) { auto in_pde = (decltype(PAGE_TABLE::PdeAddress))in_pde_ptr; auto out_pde = (decltype(PAGE_TABLE::PdeAddress))out_pde_ptr; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 正在拆分大页: 输入PDE=0x%llx, 输出PDE=0x%p\n", in_pde->value, out_pde); PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { 0 }; HighAddr.QuadPart = MAXULONG64; auto pt = (decltype(PAGE_TABLE::PteAddress))MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); if (!pt) { logger("分配连续内存失败 (用于拆分大页)", true); return false; } UINT64 start_pfn = in_pde->flags.page_frame_number; for (int i = 0; i < 512; i++) { pt[i].value = 0; pt[i].flags.present = 1; pt[i].flags.write = in_pde->flags.write; pt[i].flags.user = in_pde->flags.user; pt[i].flags.write_through = in_pde->flags.write_through; pt[i].flags.cache_disable = in_pde->flags.cache_disable; pt[i].flags.accessed = in_pde->flags.accessed; pt[i].flags.dirty = in_pde->flags.dirty; pt[i].flags.global = 0; pt[i].flags.page_frame_number = start_pfn + i; } out_pde->value = in_pde->value; out_pde->flags.large_page = 0; out_pde->flags.page_frame_number = fn_va_to_pa(pt) >> 12; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 大页拆分完成: 新PTE表物理地址=0x%llx\n", fn_va_to_pa(pt)); return true; } bool PteHookManager::fn_isolation_pagetable(UINT64 cr3_val, void* replace_align_addr, void* split_pde_ptr) { PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { 0 }; HighAddr.QuadPart = MAXULONG64; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 开始隔离页表: CR3=0x%llx, 地址=0x%p\n", cr3_val, replace_align_addr); auto Va4kb = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); auto VaPt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); auto VaPdt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); auto VaPdpt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); if (!VaPt || !Va4kb || !VaPdt || !VaPdpt) { if (VaPt) MmFreeContiguousMemory(VaPt); if (Va4kb) MmFreeContiguousMemory(Va4kb); if (VaPdt) MmFreeContiguousMemory(VaPdt); if (VaPdpt) MmFreeContiguousMemory(VaPdpt); logger("分配连续内存失败 (用于隔离页表)", true); return false; } PAGE_TABLE Table = { 0 }; Table.LineAddress = (UINT64)replace_align_addr; NTSTATUS status = get_page_table(cr3_val, Table); if (!NT_SUCCESS(status)) { MmFreeContiguousMemory(VaPt); MmFreeContiguousMemory(Va4kb); MmFreeContiguousMemory(VaPdt); MmFreeContiguousMemory(VaPdpt); logger("获取页表信息失败", true, status); return false; } UINT64 pte_index = (Table.LineAddress >> 12) & 0x1FF; UINT64 pde_index = (Table.LineAddress >> 21) & 0x1FF; UINT64 pdpte_index = (Table.LineAddress >> 30) & 0x1FF; UINT64 pml4e_index = (Table.LineAddress >> 39) & 0x1FF; memcpy(Va4kb, replace_align_addr, PAGE_SIZE); if (Table.IsLargePage && split_pde_ptr) { auto split_pde = (decltype(PAGE_TABLE::PdeAddress))split_pde_ptr; memcpy(VaPt, (void*)(split_pde->flags.page_frame_number << 12), PAGE_SIZE); } else { memcpy(VaPt, (void*)(Table.PdeAddress->flags.page_frame_number << 12), PAGE_SIZE); } memcpy(VaPdt, (void*)(Table.PdpteAddress->flags.page_frame_number << 12), PAGE_SIZE); memcpy(VaPdpt, (void*)(Table.Pml4Address[pml4e_index] & ~0xFFF), PAGE_SIZE); auto new_pte = (decltype(PAGE_TABLE::PteAddress))VaPt; new_pte[pte_index].flags.page_frame_number = fn_va_to_pa(Va4kb) >> 12; auto new_pde = (decltype(PAGE_TABLE::PdeAddress))VaPdt; new_pde[pde_index].value = Table.OriginalPde; new_pde[pde_index].flags.large_page = 0; new_pde[pde_index].flags.page_frame_number = fn_va_to_pa(VaPt) >> 12; auto new_pdpte = (decltype(PAGE_TABLE::PdpteAddress))VaPdpt; new_pdpte[pdpte_index].flags.page_frame_number = fn_va_to_pa(VaPdt) >> 12; auto new_pml4 = (UINT64*)fn_pa_to_va(cr3_val & ~0xFFF); new_pml4[pml4e_index] = (new_pml4[pml4e_index] & 0xFFF) | (fn_va_to_pa(VaPdpt) & ~0xFFF); __invlpg(replace_align_addr); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 页表隔离完成: 新PFN=0x%llx\n", fn_va_to_pa(Va4kb) >> 12); return true; } bool PteHookManager::fn_isolation_pages(HANDLE process_id, void* ori_addr) { PEPROCESS Process; if (!NT_SUCCESS(PsLookupProcessByProcessId(process_id, &Process))) { logger("查找进程失败", true); return false; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 开始隔离页面: PID=%d, 地址=0x%p\n", (ULONG)(ULONG_PTR)process_id, ori_addr); KAPC_STATE ApcState; KeStackAttachProcess(Process, &ApcState); void* AlignAddr = PAGE_ALIGN(ori_addr); PAGE_TABLE Table = { 0 }; Table.LineAddress = (UINT64)AlignAddr; UINT64 target_cr3 = *(UINT64*)((UCHAR*)Process + 0x28); if (!NT_SUCCESS(get_page_table(target_cr3, Table))) { KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); logger("获取目标进程页表失败", true); return false; } bool success = false; decltype(PAGE_TABLE::PdeAddress) split_pde = nullptr; if (Table.IsLargePage) { split_pde = (decltype(PAGE_TABLE::PdeAddress))ExAllocatePoolWithTag(NonPagedPool, sizeof(*split_pde), 'pdeS'); if (!split_pde || !fn_split_large_pages(Table.PdeAddress, split_pde)) { if (split_pde) ExFreePoolWithTag(split_pde, 'pdeS'); KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); logger("拆分大页失败", true); return false; } if (Table.PdeAddress->flags.global) { Table.PdeAddress->flags.global = 0; fn_add_g_bit_info(AlignAddr, Table.PdeAddress, nullptr); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 清除大页G位: PDE=0x%llx\n", Table.PdeAddress->value); } success = fn_isolation_pagetable(target_cr3, AlignAddr, split_pde); } else if (Table.PteAddress && Table.PteAddress->flags.global) { Table.PteAddress->flags.global = 0; fn_add_g_bit_info(AlignAddr, nullptr, Table.PteAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 清除PTE G位: PTE=0x%llx\n", Table.PteAddress->value); success = fn_isolation_pagetable(target_cr3, AlignAddr, split_pde); if (split_pde) ExFreePoolWithTag(split_pde, 'pdeS'); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 页表状态: IsLargePage=%d, Is1GBPage=%d\n", Table.IsLargePage, Table.Is1GBPage); if (Table.PteAddress) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] PTE 值: 0x%llx (G位=%d)\n", Table.PteAddress->value, Table.PteAddress->flags.global); } KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); if (success) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 页面隔离成功\n"); } else { logger("页面隔离失败", true); } return success; } KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); return true; } bool PteHookManager::WriteTrampolineInstruction(void* trampoline, const JMP_ABS& jmpCmd) { if (!MmIsAddressValid(trampoline)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 错误: 内存地址无效 (VA=%p)\n", trampoline); return false; } PHYSICAL_ADDRESS physAddr = MmGetPhysicalAddress(trampoline); if (physAddr.QuadPart == 0) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 错误: 无法获取物理地址 (VA=%p)\n", trampoline); return false; } KIRQL oldIrql = KeRaiseIrqlToDpcLevel(); BOOLEAN wpEnabled = (__readcr0() & CR0_WP); if (wpEnabled) { __writecr0(__readcr0() & ~CR0_WP); _mm_mfence(); } PMDL pMdl = IoAllocateMdl(trampoline, sizeof(JMP_ABS), FALSE, FALSE, NULL); if (!pMdl) { if (wpEnabled) __writecr0(__readcr0() | CR0_WP); KeLowerIrql(oldIrql); return false; } NTSTATUS status = STATUS_SUCCESS; __try { MmBuildMdlForNonPagedPool(pMdl); MmProtectMdlSystemAddress(pMdl, PAGE_READWRITE); // 正确写入 FF25 00000000 和 8字节地址 memcpy(trampoline, jmpCmd.opcode, 6); // FF25 00000000 *(ULONG64*)((BYTE*)trampoline + 6) = jmpCmd.address; // 地址写入 RIP+0 的位置 _mm_sfence(); _mm_clflush(trampoline); _mm_clflush((BYTE*)trampoline + 8); __invlpg(trampoline); _mm_mfence(); } __except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 异常: 写入跳板失败 (代码: 0x%X)\n", status); } IoFreeMdl(pMdl); if (wpEnabled) { __writecr0(__readcr0() | CR0_WP); _mm_mfence(); } KeLowerIrql(oldIrql); if (!NT_SUCCESS(status)) return false; // 验证写入结果 if (*(USHORT*)trampoline != 0x25FF || *(ULONG64*)((BYTE*)trampoline + 6) != jmpCmd.address) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 验证失败: 跳板内容不匹配\n" " 预期: FF25 [%p]\n" " 实际: %02X%02X %02X%02X%02X%02X [%p]\n", jmpCmd.address, ((BYTE*)trampoline)[0], ((BYTE*)trampoline)[1], ((BYTE*)trampoline)[2], ((BYTE*)trampoline)[3], ((BYTE*)trampoline)[4], ((BYTE*)trampoline)[5], *(ULONG64*)((BYTE*)trampoline + 6)); return false; } return true; } bool PteHookManager::fn_pte_inline_hook_bp_pg(HANDLE process_id, _Inout_ void** ori_addr, void* hk_addr) { // [1] 页表隔离 if (!fn_isolation_pages(process_id, *ori_addr)) { return false; } // [2] 获取目标进程上下文 PEPROCESS targetProcess; if (!NT_SUCCESS(PsLookupProcessByProcessId(process_id, &targetProcess))) { return false; } KAPC_STATE apcState; KeStackAttachProcess(targetProcess, &apcState); // [3] 构造跳转指令 JMP_ABS jmpCmd = {}; memcpy(jmpCmd.opcode, "\xFF\x25\x00\x00\x00\x00", 6); // FF25 00000000 jmpCmd.address = reinterpret_cast<ULONG64>(hk_addr); // [4] 直接写入被隔离页 void* targetFunc = *ori_addr; bool success = false; // 禁用写保护 KIRQL oldIrql = DisableWriteProtection(); __try { // 保存原始指令 (用于卸载) RtlCopyMemory(m_HookInfo[m_HookCount].OriginalBytes, targetFunc, sizeof(jmpCmd)); // 写入跳转指令到隔离页 memcpy(targetFunc, &jmpCmd, 6); *(ULONG64*)((BYTE*)targetFunc + 6) = jmpCmd.address; // 刷新缓存 _mm_sfence(); _mm_clflush(targetFunc); __invlpg(targetFunc); _mm_mfence(); success = true; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 直接写入隔离页成功: VA=%p -> Hook=%p\n", targetFunc, hk_addr); } __except (EXCEPTION_EXECUTE_HANDLER) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 写入隔离页异常: 0x%X\n", GetExceptionCode()); } // 恢复写保护 EnableWriteProtection(oldIrql); // [5] 记录Hook信息 if (success) { m_HookInfo[m_HookCount].OriginalAddress = targetFunc; m_HookInfo[m_HookCount].HookAddress = hk_addr; m_HookInfo[m_HookCount].ProcessId = process_id; m_HookInfo[m_HookCount].IsHooked = TRUE; m_HookCount++; } // [6] 清理 KeUnstackDetachProcess(&apcState); ObDereferenceObject(targetProcess); return success; } // 析构函数清理资源 PteHookManager::~PteHookManager() { if (m_TrampLinePool) { MmFreeContiguousMemory(m_TrampLinePool); m_TrampLinePool = nullptr; } } bool PteHookManager::fn_remove_hook(HANDLE process_id, void* hook_addr) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 尝试移除Hook: Hook地址=0x%p\n", hook_addr); for (UINT32 i = 0; i < m_HookCount; i++) { if (m_HookInfo[i].HookAddress == hook_addr && m_HookInfo[i].IsHooked) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 找到匹配的Hook: 原始地址=0x%p\n", m_HookInfo[i].OriginalAddress); KIRQL oldIrql = DisableWriteProtection(); memcpy(m_HookInfo[i].OriginalAddress, m_HookInfo[i].OriginalBytes, sizeof(m_HookInfo[i].OriginalBytes)); EnableWriteProtection(oldIrql); m_HookInfo[i].IsHooked = FALSE; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] Hook已成功移除\n"); return true; } } logger("未找到匹配的Hook", true); return false; } void PteHookManager::fn_add_g_bit_info(void* align_addr, void* pde_address, void* pte_address) { if (m_GbitCount >= MAX_G_BIT_RECORDS) { logger("达到最大G位记录数量限制", true); return; } PG_BIT_INFO record = &m_GbitRecords[m_GbitCount++]; record->AlignAddress = align_addr; record->PdeAddress = (decltype(G_BIT_INFO::PdeAddress))pde_address; record->PteAddress = (decltype(G_BIT_INFO::PteAddress))pte_address; record->IsLargePage = (pde_address && ((decltype(PAGE_TABLE::PdeAddress))pde_address)->flags.large_page); // 打印G位信息 PrintGBitInfo(*record); } bool PteHookManager::fn_resume_global_bits(void* align_addr) { KIRQL oldIrql = DisableWriteProtection(); bool found = false; DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 开始恢复G位: 对齐地址=0x%p\n", align_addr); for (UINT32 i = 0; i < m_GbitCount; i++) { PG_BIT_INFO record = &m_GbitRecords[i]; if (align_addr && record->AlignAddress != align_addr) continue; if (record->PteAddress) { record->PteAddress->flags.global = 1; __invlpg(record->AlignAddress); DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, " 恢复PTE G位: PTE=0x%llx, 地址=0x%p\n", record->PteAddress->value, record->AlignAddress); } if (record->PdeAddress) { record->PdeAddress->flags.global = 1; if (record->IsLargePage) { __invlpg(record->AlignAddress); } DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, " 恢复PDE G位: PDE=0x%llx, 地址=0x%p, 大页=%d\n", record->PdeAddress->value, record->AlignAddress, record->IsLargePage); } found = true; if (align_addr) break; } EnableWriteProtection(oldIrql); if (found) { DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, "[PTE_HOOK] G位恢复完成\n"); } else { logger("未找到匹配的G位记录", true); } return found; } PteHookManager* PteHookManager::GetInstance() { if (!m_Instance) { m_Instance = static_cast<PteHookManager*>( ExAllocatePoolWithTag(NonPagedPool, sizeof(PteHookManager), 'tpHk')); if (m_Instance) { RtlZeroMemory(m_Instance, sizeof(PteHookManager)); DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, "[PTE_HOOK] PTE Hook管理器实例已创建: 地址=0x%p\n", m_Instance); } else { DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 创建PTE Hook管理器实例失败\n"); } } return m_Instance; } // 全局PTE Hook管理器实例 PteHookManager* g_PteHookManager = nullptr; // 辅助函数:检查是否为目标进程 BOOLEAN IsTargetProcess(CHAR* imageName) { CHAR currentName[16]; // 复制到本地缓冲区并确保 NULL 终止 RtlCopyMemory(currentName, imageName, 16); currentName[15] = '\0'; // 确保终止 // 修剪尾部空格 for (int i = 15; i >= 0; i--) { if (currentName[i] == ' ') currentName[i] = '\0'; else if (currentName[i] != '\0') break; } return (strcmp(currentName, target_process_name) == 0); } // Hook 函数 NTSTATUS MyObReferenceObjectByHandleWithTag( HANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, ULONG Tag, PVOID* Object, POBJECT_HANDLE_INFORMATION HandleInformation ) { PEPROCESS currentProcess = PsGetCurrentProcess(); CHAR* imageName = PsGetProcessImageFileName(currentProcess); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[!] [HookFunction] 进入 Hook 函数! 当前进程: %s\n", imageName); __debugbreak(); // 强制中断,确认是否执行到这里 if (IsTargetProcess(imageName)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[!] [HookFunction] 拒绝访问目标进程 PID=%d\n", HandleToULong(PsGetCurrentProcessId())); return STATUS_ACCESS_DENIED; } return g_OriginalObReferenceObjectByHandleWithTag( Handle, DesiredAccess, ObjectType, AccessMode, Tag, Object, HandleInformation ); } NTSTATUS InstallHook() { UNICODE_STRING funcName; RtlInitUnicodeString(&funcName, L"ObReferenceObjectByHandleWithTag"); g_OriginalObReferenceObjectByHandleWithTag = (fn_ObReferenceObjectByHandleWithTag)MmGetSystemRoutineAddress(&funcName); if (!g_OriginalObReferenceObjectByHandleWithTag) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [InstallHook] 找不到 ObReferenceObjectByHandleWithTag\n"); return STATUS_NOT_FOUND; } __debugbreak(); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [InstallHook] 找到目标函数地址: %p\n", g_OriginalObReferenceObjectByHandleWithTag); void* targetFunc = (void*)g_OriginalObReferenceObjectByHandleWithTag; void* hookFunc = (void*)MyObReferenceObjectByHandleWithTag; if (!g_PteHookManager->fn_pte_inline_hook_bp_pg(targetProcessId, &targetFunc, hookFunc)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [InstallHook] PTE Hook 安装失败\n"); return STATUS_UNSUCCESSFUL; } g_OriginalObReferenceObjectByHandleWithTag = (fn_ObReferenceObjectByHandleWithTag)targetFunc; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [InstallHook] Hook 成功安装. 跳板地址: %p\n", targetFunc); __debugbreak(); // 强制中断,验证是否执行到这里 return STATUS_SUCCESS; } // 移除 Hook VOID RemoveHook() { if (g_OriginalObReferenceObjectByHandleWithTag && g_PteHookManager) { g_PteHookManager->fn_remove_hook(PsGetCurrentProcessId(), (void*)MyObReferenceObjectByHandleWithTag); } } // 工作线程函数 VOID InstallHookWorker(PVOID Context) { targetProcessId = (HANDLE)Context; DbgPrint("[+] Worker thread started for hook installation on PID: %d\n", HandleToULong(targetProcessId)); InstallHook(); PsTerminateSystemThread(STATUS_SUCCESS); } // 进程创建回调 VOID ProcessNotifyCallback( _In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create ) { UNREFERENCED_PARAMETER(ParentId); if (Create) { PEPROCESS process = NULL; if (NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &process))) { CHAR* imageName = PsGetProcessImageFileName(process); CHAR currentName[16]; RtlCopyMemory(currentName, imageName, 16); currentName[15] = '\0'; for (int i = 15; i >= 0; i--) { if (currentName[i] == ' ') currentName[i] = '\0'; else if (currentName[i] != '\0') break; } if (strcmp(currentName, target_process_name) == 0) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [ProcessNotifyCallback] 目标进程 %s 创建 (PID: %d)\n", currentName, HandleToULong(ProcessId)); HANDLE threadHandle; NTSTATUS status = PsCreateSystemThread( &threadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, InstallHookWorker, (PVOID)ProcessId // 关键:传递目标进程ID ); if (NT_SUCCESS(status)) { ZwClose(threadHandle); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [ProcessNotifyCallback] 工作线程已创建\n"); } else { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [ProcessNotifyCallback] 创建线程失败: 0x%X\n", status); } } ObDereferenceObject(process); } } } // 驱动卸载函数 VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNREFERENCED_PARAMETER(DriverObject); DbgPrint("[+] Driver unloading...\n"); // 移除进程通知回调 PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyCallback, TRUE); // 移除Hook RemoveHook(); // 清理PTE Hook资源 if (g_PteHookManager) { DbgPrint("[PTE_HOOK] Cleaning up PTE...\n"); // 恢复所有被修改的G位 g_PteHookManager->fn_resume_global_bits(nullptr); // 移除所有活动的Hook HOOK_INFO* hookInfo = g_PteHookManager->GetHookInfo(); UINT32 hookCount = g_PteHookManager->GetHookCount(); for (UINT32 i = 0; i < hookCount; i++) { if (hookInfo[i].IsHooked) { g_PteHookManager->fn_remove_hook(PsGetCurrentProcessId(), hookInfo[i].HookAddress); } } // 释放跳板池内存 char* trampLinePool = g_PteHookManager->GetTrampLinePool(); if (trampLinePool) { ExFreePoolWithTag(trampLinePool, 'JmpP'); } // 释放管理器实例 ExFreePoolWithTag(g_PteHookManager, 'tpHk'); g_PteHookManager = nullptr; } DbgPrint("[+] Driver unloaded successfully\n"); } extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(RegistryPath); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [DriverEntry] 驱动加载开始\n"); DriverObject->DriverUnload = DriverUnload; g_PteHookManager = PteHookManager::GetInstance(); if (!g_PteHookManager) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [DriverEntry] 初始化 PteHookManager 失败\n"); return STATUS_INSUFFICIENT_RESOURCES; } NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyCallback, FALSE); if (!NT_SUCCESS(status)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [DriverEntry] 注册进程通知失败 (0x%X)\n", status); return status; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [DriverEntry] 驱动加载成功\n"); return STATUS_SUCCESS; }
07-10
kd> ed nt!Kd_DEFAULT_Mask 0xFFFFFFFF kd> ed nt!Kd_IHVDRIVER_Mask 0xFFFFFFFF kd> g KDTARGET: Refreshing KD connection *** Fatal System Error: 0x0000007e (0xFFFFFFFFC0000005,0xFFFFF805802B1699,0xFFFFFC89CAC5A458,0xFFFFFC89CAC59C90) Break instruction exception - code 80000003 (first chance) A fatal system error has occurred. Debugger entered on first try; Bugcheck callbacks have not been invoked. A fatal system error has occurred. For analysis of this file, run !analyze -v nt!DbgBreakPointWithStatus: fffff805`7affd0b0 cc int 3 kd> !analyze -v Connected to Windows 10 19041 x64 target at (Tue Jul 15 22:09:55.446 2025 (UTC + 8:00)), ptr64 TRUE Loading Kernel Symbols ................................... Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long. Run !sym noisy before .reload to track down problems loading symbols. ............................ ................................................................ ..................................................... Loading User Symbols Loading unloaded module list ...... ERROR: FindPlugIns 8007007b ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e) This is a very common BugCheck. Usually the exception address pinpoints the driver/function that caused the problem. Always note this address as well as the link date of the driver/image that contains this address. Arguments: Arg1: ffffffffc0000005, The exception code that was not handled Arg2: fffff805802b1699, The address that the exception occurred at Arg3: fffffc89cac5a458, Exception Record Address Arg4: fffffc89cac59c90, Context Record Address Debugging Details: ------------------ Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long. Run !sym noisy before .reload to track down problems loading symbols. KEY_VALUES_STRING: 1 Key : AV.Type Value: Read Key : Analysis.CPU.mSec Value: 3609 Key : Analysis.Elapsed.mSec Value: 47643 Key : Analysis.IO.Other.Mb Value: 0 Key : Analysis.IO.Read.Mb Value: 3 Key : Analysis.IO.Write.Mb Value: 0 Key : Analysis.Init.CPU.mSec Value: 3734 Key : Analysis.Init.Elapsed.mSec Value: 52586 Key : Analysis.Memory.CommitPeak.Mb Value: 74 Key : Analysis.Version.DbgEng Value: 10.0.27829.1001 Key : Analysis.Version.Description Value: 10.2503.24.01 amd64fre Key : Analysis.Version.Ext Value: 1.2503.24.1 Key : Bugcheck.Code.KiBugCheckData Value: 0x7e Key : Bugcheck.Code.LegacyAPI Value: 0x7e Key : Bugcheck.Code.TargetModel Value: 0x7e Key : Failure.Bucket Value: AV_pte1!InitHookWin10 Key : Failure.Exception.Code Value: 0xc0000005 Key : Failure.Exception.IP.Address Value: 0xfffff805802b1699 Key : Failure.Exception.IP.Module Value: pte1 Key : Failure.Exception.IP.Offset Value: 0x1699 Key : Failure.Exception.Record Value: 0xfffffc89cac5a458 Key : Failure.Hash Value: {14fb13e5-207c-6ef8-f4d3-d7bd4cc8e1a3} Key : Hypervisor.Enlightenments.Value Value: 12576 Key : Hypervisor.Enlightenments.ValueHex Value: 0x3120 Key : Hypervisor.Flags.AnyHypervisorPresent Value: 1 Key : Hypervisor.Flags.ApicEnlightened Value: 0 Key : Hypervisor.Flags.ApicVirtualizationAvailable Value: 0 Key : Hypervisor.Flags.AsyncMemoryHint Value: 0 Key : Hypervisor.Flags.CoreSchedulerRequested Value: 0 Key : Hypervisor.Flags.CpuManager Value: 0 Key : Hypervisor.Flags.DeprecateAutoEoi Value: 1 Key : Hypervisor.Flags.DynamicCpuDisabled Value: 0 Key : Hypervisor.Flags.Epf Value: 0 Key : Hypervisor.Flags.ExtendedProcessorMasks Value: 0 Key : Hypervisor.Flags.HardwareMbecAvailable Value: 0 Key : Hypervisor.Flags.MaxBankNumber Value: 0 Key : Hypervisor.Flags.MemoryZeroingControl Value: 0 Key : Hypervisor.Flags.NoExtendedRangeFlush Value: 1 Key : Hypervisor.Flags.NoNonArchCoreSharing Value: 0 Key : Hypervisor.Flags.Phase0InitDone Value: 1 Key : Hypervisor.Flags.PowerSchedulerQos Value: 0 Key : Hypervisor.Flags.RootScheduler Value: 0 Key : Hypervisor.Flags.SynicAvailable Value: 1 Key : Hypervisor.Flags.UseQpcBias Value: 0 Key : Hypervisor.Flags.Value Value: 536632 Key : Hypervisor.Flags.ValueHex Value: 0x83038 Key : Hypervisor.Flags.VpAssistPage Value: 1 Key : Hypervisor.Flags.VsmAvailable Value: 0 Key : Hypervisor.RootFlags.AccessStats Value: 0 Key : Hypervisor.RootFlags.CrashdumpEnlightened Value: 0 Key : Hypervisor.RootFlags.CreateVirtualProcessor Value: 0 Key : Hypervisor.RootFlags.DisableHyperthreading Value: 0 Key : Hypervisor.RootFlags.HostTimelineSync Value: 0 Key : Hypervisor.RootFlags.HypervisorDebuggingEnabled Value: 0 Key : Hypervisor.RootFlags.IsHyperV Value: 0 Key : Hypervisor.RootFlags.LivedumpEnlightened Value: 0 Key : Hypervisor.RootFlags.MapDeviceInterrupt Value: 0 Key : Hypervisor.RootFlags.MceEnlightened Value: 0 Key : Hypervisor.RootFlags.Nested Value: 0 Key : Hypervisor.RootFlags.StartLogicalProcessor Value: 0 Key : Hypervisor.RootFlags.Value Value: 0 Key : Hypervisor.RootFlags.ValueHex Value: 0x0 Key : SecureKernel.HalpHvciEnabled Value: 0 Key : WER.OS.Branch Value: vb_release Key : WER.OS.Version Value: 10.0.19041.1 BUGCHECK_CODE: 7e BUGCHECK_P1: ffffffffc0000005 BUGCHECK_P2: fffff805802b1699 BUGCHECK_P3: fffffc89cac5a458 BUGCHECK_P4: fffffc89cac59c90 FAULTING_THREAD: ffffbd0465f0f040 EXCEPTION_RECORD: fffffc89cac5a458 -- (.exr 0xfffffc89cac5a458) ExceptionAddress: fffff805802b1699 (pte1!InitHookWin10+0x0000000000000639) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 00000245cb781000 Attempt to read from address 00000245cb781000 CONTEXT: fffffc89cac59c90 -- (.cxr 0xfffffc89cac59c90) rax=0000000000000000 rbx=0000000000000000 rcx=00000000001ff000 rdx=0000000000000000 rsi=00000245cb781000 rdi=ffffdf7d0da01000 rip=fffff805802b1699 rsp=fffffc89cac5a690 rbp=0000000000000000 r8=fffffc89cac5a068 r9=7fffbd046545f688 r10=7ffffffffffffffc r11=ffffbd0465f0f040 r12=ffff8d005e2fa950 r13=ffffffff800020c4 r14=fffff805802b42a8 r15=ffffbd046b39fe30 iopl=0 nv up ei pl zr na po nc cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00050246 pte1!InitHookWin10+0x639: fffff805`802b1699 f3a4 rep movs byte ptr [rdi],byte ptr [rsi] Resetting default scope PROCESS_NAME: System READ_ADDRESS: unable to get nt!PspSessionIdBitmap 00000245cb781000 ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p 0x%p %s EXCEPTION_CODE_STR: c0000005 EXCEPTION_PARAMETER1: 0000000000000000 EXCEPTION_PARAMETER2: 00000245cb781000 EXCEPTION_STR: 0xc0000005 STACK_TEXT: fffffc89`cac5a690 fffff805`802b1f7d : fffff805`7b266000 00000000`00001ec8 00000000`00000ca0 fffff805`7ae1cb26 : pte1!InitHookWin10+0x639 [C:\Users\17116\source\repos\pte1\pte1\Ô´.cpp @ 204] fffffc89`cac5a830 fffff805`802b20fb : ffffbd04`6b39fe30 ffffbd04`6575f000 ffffbd04`6575f000 ffffbd04`6cc53de0 : pte1!DriverEntry+0x9d [C:\Users\17116\source\repos\pte1\pte1\Ô´.cpp @ 349] fffffc89`cac5a890 fffff805`802b2030 : ffffbd04`6575f000 fffffc89`cac5aa60 ffffbd04`6c6aedd0 ffffbd04`6b39fe30 : pte1!FxDriverEntryWorker+0xbf [minkernel\wdf\framework\kmdf\src\dynamic\stub\stub.cpp @ 360] fffffc89`cac5a8d0 fffff805`7b3538f4 : ffffbd04`6575f000 00000000`00000000 ffffbd04`6b39fe30 00000000`00000000 : pte1!FxDriverEntry+0x20 [minkernel\wdf\framework\kmdf\src\dynamic\stub\stub.cpp @ 249] fffffc89`cac5a900 fffff805`7b31e3cd : 00000000`0000000a 00000000`00000000 00000000`00000000 00000000`00001000 : nt!PnpCallDriverEntry+0x4c fffffc89`cac5a960 fffff805`7b364207 : 00000000`00000000 00000000`00000000 fffff805`7b925440 00000000`00000000 : nt!IopLoadDriver+0x4e5 fffffc89`cac5ab30 fffff805`7af034b5 : ffffbd04`00000000 ffffffff`800020c4 ffffbd04`65f0f040 ffffbd04`0000000c : nt!IopLoadUnloadDriver+0x57 fffffc89`cac5ab70 fffff805`7aea29a5 : ffffbd04`65f0f040 00000000`00000080 ffffbd04`6545f1c0 000fa067`b8bbbdff : nt!ExpWorkerThread+0x105 fffffc89`cac5ac10 fffff805`7affc868 : fffff805`75eaf180 ffffbd04`65f0f040 fffff805`7aea2950 00000000`00000000 : nt!PspSystemThreadStartup+0x55 fffffc89`cac5ac60 00000000`00000000 : fffffc89`cac5b000 fffffc89`cac55000 00000000`00000000 00000000`00000000 : nt!KiStartSystemThread+0x28 FAULTING_SOURCE_LINE: C:\Users\17116\source\repos\pte1\pte1\Ô´.cpp FAULTING_SOURCE_FILE: C:\Users\17116\source\repos\pte1\pte1\Ô´.cpp FAULTING_SOURCE_LINE_NUMBER: 204 FAULTING_SOURCE_CODE: 200: UnmapPhysicalMemory(Cr3Va); 201: return status; 202: } 203: > 204: RtlCopyMemory(LargePageBuf, OrigDataVa, 0x200000); 205: UnmapPhysicalMemory(OrigDataVa); 206: 207: // ?????????????? 208: PUCHAR HookLoc = (PUCHAR)LargePageBuf + (TargetVa & 0x1FFFFF) + Offset; 209: HookLoc[0] = 0x90; // NOP SYMBOL_NAME: pte1!InitHookWin10+639 MODULE_NAME: pte1 IMAGE_NAME: pte1.sys STACK_COMMAND: .cxr 0xfffffc89cac59c90 ; kb BUCKET_ID_FUNC_OFFSET: 639 FAILURE_BUCKET_ID: AV_pte1!InitHookWin10 OS_VERSION: 10.0.19041.1 BUILDLAB_STR: vb_release OSPLATFORM_TYPE: x64 OSNAME: Windows 10 FAILURE_ID_HASH: {14fb13e5-207c-6ef8-f4d3-d7bd4cc8e1a3} Followup: MachineOwner --------- #include <ntifs.h> #include <wdm.h> // 完整的页表项结构 typedef union _HARDWARE_PTE { struct { ULONG64 Valid : 1; ULONG64 Write : 1; ULONG64 Owner : 1; ULONG64 WriteThrough : 1; ULONG64 CacheDisable : 1; ULONG64 Accessed : 1; ULONG64 Dirty : 1; ULONG64 LargePage : 1; // 修复:添加缺失的LargePage ULONG64 Global : 1; ULONG64 CopyOnWrite : 1; ULONG64 Prototype : 1; ULONG64 reserved0 : 1; ULONG64 PageFrameNumber : 36; ULONG64 reserved1 : 4; ULONG64 SoftwareWsIndex : 11; ULONG64 NoExecute : 1; }; ULONG64 AsUINT64; // 添加联合体支持 } HARDWARE_PTE, * PHARDWARE_PTE; // 全局资源记录 typedef struct _HOOK_CONTEXT { PVOID NewPages[4]; // [0]PPE [1]PDE [2]PTE [3]Data ULONG_PTR OriginalPTE; BOOLEAN IsLargePage; } HOOK_CONTEXT, * PHOOK_CONTEXT; static HANDLE g_hSection = NULL; // 全局节对象句柄 NTSTATUS MapPhysicalMemory(IN PHYSICAL_ADDRESS PhysicalAddress, OUT PVOID* MappedVa) { SIZE_T size = PAGE_SIZE; NTSTATUS status = STATUS_SUCCESS; // 第一次调用时打开节对象 if (g_hSection == NULL) { UNICODE_STRING physName; RtlInitUnicodeString(&physName, L"\\Device\\PhysicalMemory"); OBJECT_ATTRIBUTES oa; InitializeObjectAttributes(&oa, &physName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwOpenSection(&g_hSection, SECTION_ALL_ACCESS, &oa); if (!NT_SUCCESS(status)) { DbgPrint("ZwOpenSection failed: 0x%X\n", status); return status; } } // 映射物理内存 PHYSICAL_ADDRESS baseAddress = PhysicalAddress; status = ZwMapViewOfSection( g_hSection, NtCurrentProcess(), MappedVa, 0L, size, &baseAddress, &size, ViewUnmap, 0, PAGE_READWRITE ); if (!NT_SUCCESS(status)) { DbgPrint("ZwMapViewOfSection failed: 0x%X\n", status); } return status; } VOID UnmapPhysicalMemory(PVOID MappedVa) { if (MappedVa) { ZwUnmapViewOfSection(NtCurrentProcess(), MappedVa); } } NTSTATUS InitHookWin10(IN ULONG_PTR TargetVa, IN HANDLE Pid, IN ULONG_PTR Offset) { PEPROCESS Process = NULL; PHYSICAL_ADDRESS Cr3Pa = { 0 }; PVOID Cr3Va = NULL; HOOK_CONTEXT ctx = { 0 }; NTSTATUS status; // 1. 获取目标进程CR3 status = PsLookupProcessByProcessId(Pid, &Process); if (!NT_SUCCESS(status)) { DbgPrint("PsLookupProcessByProcessId failed: 0x%X\n", status); return status; } // 获取进程CR3 (Win10 10240偏移为0x28) Cr3Pa.QuadPart = *(ULONG_PTR*)((PUCHAR)Process + 0x28) & ~0xF; ObDereferenceObject(Process); // 2. 映射CR3 status = MapPhysicalMemory(Cr3Pa, &Cr3Va); if (!NT_SUCCESS(status)) { DbgPrint("MapPhysicalMemory for CR3 failed: 0x%X\n", status); return status; } // 3. 计算页表索引 (x64四级页表) ULONG Pml4Index = (TargetVa >> 39) & 0x1FF; ULONG PdptIndex = (TargetVa >> 30) & 0x1FF; ULONG PdIndex = (TargetVa >> 21) & 0x1FF; ULONG PtIndex = (TargetVa >> 12) & 0x1FF; // 4. 复制并修改PML4E (实际为PDPT) PHYSICAL_ADDRESS LowAddr = { 0 }; PHYSICAL_ADDRESS HighAddr = { 0 }; HighAddr.QuadPart = ~0ULL; // 修复:正确的初始化 ctx.NewPages[0] = MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmCached); if (ctx.NewPages[0] == NULL) { DbgPrint("MmAllocateContiguousMemorySpecifyCache for PPE failed\n"); UnmapPhysicalMemory(Cr3Va); return STATUS_INSUFFICIENT_RESOURCES; } PHARDWARE_PTE OrigPml4e = (PHARDWARE_PTE)((PUCHAR)Cr3Va + Pml4Index * sizeof(ULONG64)); PHYSICAL_ADDRESS PdptPa = { 0 }; PdptPa.QuadPart = OrigPml4e->PageFrameNumber << 12; PVOID PdptVa = NULL; status = MapPhysicalMemory(PdptPa, &PdptVa); if (!NT_SUCCESS(status)) { DbgPrint("MapPhysicalMemory for PDPT failed: 0x%X\n", status); MmFreeContiguousMemory(ctx.NewPages[0]); UnmapPhysicalMemory(Cr3Va); return status; } RtlCopyMemory(ctx.NewPages[0], PdptVa, PAGE_SIZE); // 复制原始PDPT UnmapPhysicalMemory(PdptVa); // 5. 处理PDPTE (实际为PD) ctx.NewPages[1] = MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmCached); if (ctx.NewPages[1] == NULL) { DbgPrint("MmAllocateContiguousMemorySpecifyCache for PDE failed\n"); MmFreeContiguousMemory(ctx.NewPages[0]); UnmapPhysicalMemory(Cr3Va); return STATUS_INSUFFICIENT_RESOURCES; } PHARDWARE_PTE OrigPdpte = (PHARDWARE_PTE)((PUCHAR)ctx.NewPages[0] + PdptIndex * sizeof(ULONG64)); PHYSICAL_ADDRESS PdPa = { 0 }; PdPa.QuadPart = OrigPdpte->PageFrameNumber << 12; PVOID PdVa = NULL; status = MapPhysicalMemory(PdPa, &PdVa); if (!NT_SUCCESS(status)) { DbgPrint("MapPhysicalMemory for PD failed: 0x%X\n", status); MmFreeContiguousMemory(ctx.NewPages[0]); MmFreeContiguousMemory(ctx.NewPages[1]); UnmapPhysicalMemory(Cr3Va); return status; } RtlCopyMemory(ctx.NewPages[1], PdVa, PAGE_SIZE); // 复制原始PD UnmapPhysicalMemory(PdVa); // 6. 检查大页 PHARDWARE_PTE OrigPde = (PHARDWARE_PTE)((PUCHAR)ctx.NewPages[1] + PdIndex * sizeof(ULONG64)); ctx.IsLargePage = OrigPde->LargePage; if (ctx.IsLargePage) { // 处理2MB大页 ULONG_PTR LargePageBase = TargetVa & ~0x1FFFFF; PHYSICAL_ADDRESS DataPa = { 0 }; DataPa.QuadPart = OrigPde->PageFrameNumber << 12; // 分配2MB对齐内存 PVOID LargePageBuf = MmAllocateContiguousMemorySpecifyCache( 0x200000, LowAddr, HighAddr, LowAddr, MmCached); if (LargePageBuf == NULL) { DbgPrint("Failed to allocate 2MB contiguous memory\n"); MmFreeContiguousMemory(ctx.NewPages[0]); MmFreeContiguousMemory(ctx.NewPages[1]); UnmapPhysicalMemory(Cr3Va); return STATUS_INSUFFICIENT_RESOURCES; } PHYSICAL_ADDRESS NewDataPa = MmGetPhysicalAddress(LargePageBuf); // 复制原始数据 PVOID OrigDataVa = NULL; status = MapPhysicalMemory(DataPa, &OrigDataVa); if (!NT_SUCCESS(status)) { DbgPrint("MapPhysicalMemory for large page data failed: 0x%X\n", status); MmFreeContiguousMemory(LargePageBuf); MmFreeContiguousMemory(ctx.NewPages[0]); MmFreeContiguousMemory(ctx.NewPages[1]); UnmapPhysicalMemory(Cr3Va); return status; } RtlCopyMemory(LargePageBuf, OrigDataVa, 0x200000); UnmapPhysicalMemory(OrigDataVa); // 修改新页面指令 PUCHAR HookLoc = (PUCHAR)LargePageBuf + (TargetVa & 0x1FFFFF) + Offset; HookLoc[0] = 0x90; // NOP HookLoc[1] = 0x90; // NOP HookLoc[2] = 0xC3; // RET // 更新PDE OrigPde = (PHARDWARE_PTE)((PUCHAR)ctx.NewPages[1] + PdIndex * sizeof(ULONG64)); OrigPde->PageFrameNumber = NewDataPa.QuadPart >> 12; ctx.NewPages[3] = LargePageBuf; } else { // 处理4KB页 ctx.NewPages[2] = MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmCached); if (ctx.NewPages[2] == NULL) { DbgPrint("MmAllocateContiguousMemorySpecifyCache for PTE failed\n"); MmFreeContiguousMemory(ctx.NewPages[0]); MmFreeContiguousMemory(ctx.NewPages[1]); UnmapPhysicalMemory(Cr3Va); return STATUS_INSUFFICIENT_RESOURCES; } PHYSICAL_ADDRESS PtPa = { 0 }; PtPa.QuadPart = OrigPde->PageFrameNumber << 12; PVOID PtVa = NULL; status = MapPhysicalMemory(PtPa, &PtVa); if (!NT_SUCCESS(status)) { DbgPrint("MapPhysicalMemory for PT failed: 0x%X\n", status); MmFreeContiguousMemory(ctx.NewPages[0]); MmFreeContiguousMemory(ctx.NewPages[1]); MmFreeContiguousMemory(ctx.NewPages[2]); UnmapPhysicalMemory(Cr3Va); return status; } RtlCopyMemory(ctx.NewPages[2], PtVa, PAGE_SIZE); // 复制原始PT UnmapPhysicalMemory(PtVa); // 处理PTE PHARDWARE_PTE OrigPte = (PHARDWARE_PTE)((PUCHAR)ctx.NewPages[2] + PtIndex * sizeof(ULONG64)); ctx.OriginalPTE = OrigPte->AsUINT64; // 使用联合体访问 PHYSICAL_ADDRESS DataPa = { 0 }; DataPa.QuadPart = OrigPte->PageFrameNumber << 12; // 分配新数据页 PVOID NewData = MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmCached); if (NewData == NULL) { DbgPrint("Failed to allocate data page\n"); MmFreeContiguousMemory(ctx.NewPages[0]); MmFreeContiguousMemory(ctx.NewPages[1]); MmFreeContiguousMemory(ctx.NewPages[2]); UnmapPhysicalMemory(Cr3Va); return STATUS_INSUFFICIENT_RESOURCES; } PHYSICAL_ADDRESS NewDataPa = MmGetPhysicalAddress(NewData); // 复制原始数据 PVOID OrigDataVa = NULL; status = MapPhysicalMemory(DataPa, &OrigDataVa); if (!NT_SUCCESS(status)) { DbgPrint("MapPhysicalMemory for data page failed: 0x%X\n", status); MmFreeContiguousMemory(NewData); MmFreeContiguousMemory(ctx.NewPages[0]); MmFreeContiguousMemory(ctx.NewPages[1]); MmFreeContiguousMemory(ctx.NewPages[2]); UnmapPhysicalMemory(Cr3Va); return status; } RtlCopyMemory(NewData, OrigDataVa, PAGE_SIZE); UnmapPhysicalMemory(OrigDataVa); // 修改新页面指令 PUCHAR HookLoc = (PUCHAR)NewData + (TargetVa & 0xFFF) + Offset; HookLoc[0] = 0x90; // NOP HookLoc[1] = 0x90; // NOP HookLoc[2] = 0xC3; // RET // 更新PTE OrigPte = (PHARDWARE_PTE)((PUCHAR)ctx.NewPages[2] + PtIndex * sizeof(ULONG64)); OrigPte->PageFrameNumber = NewDataPa.QuadPart >> 12; ctx.NewPages[3] = NewData; } // 7. 更新页表链 PHARDWARE_PTE NewPdpte = (PHARDWARE_PTE)((PUCHAR)ctx.NewPages[0] + PdptIndex * sizeof(ULONG64)); NewPdpte->PageFrameNumber = MmGetPhysicalAddress(ctx.NewPages[1]).QuadPart >> 12; PHARDWARE_PTE NewPml4e = (PHARDWARE_PTE)((PUCHAR)Cr3Va + Pml4Index * sizeof(ULONG64)); NewPml4e->PageFrameNumber = MmGetPhysicalAddress(ctx.NewPages[0]).QuadPart >> 12; // 8. 清理映射 UnmapPhysicalMemory(Cr3Va); // 保存上下文以便卸载(实际应保存到全局变量) // g_HookContext = ctx; return STATUS_SUCCESS; } // 驱动卸载时释放资源 VOID UninstallHook(PHOOK_CONTEXT ctx) { for (int i = 0; i < 4; i++) { if (ctx->NewPages[i] != NULL) { MmFreeContiguousMemory(ctx->NewPages[i]); ctx->NewPages[i] = NULL; } } } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { HOOK_CONTEXT ctx = { 0 }; // 实际应从全局获取 UninstallHook(&ctx); if (g_hSection) { ZwClose(g_hSection); g_hSection = NULL; } DbgPrint("Driver unloaded\n"); } extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { DriverObject->DriverUnload = DriverUnload; // 获取NtOpenProcess地址 UNICODE_STRING funcName = RTL_CONSTANT_STRING(L"NtOpenProcess"); ULONG_PTR funcAddr = (ULONG_PTR)MmGetSystemRoutineAddress(&funcName); if (funcAddr == 0) { DbgPrint("Failed to get NtOpenProcess address\n"); return STATUS_NOT_FOUND; } ULONG_PTR pageBase = funcAddr & ~0xFFF; ULONG_PTR offset = funcAddr & 0xFFF; // 假设目标进程PID为1234 return InitHookWin10(pageBase, (HANDLE)7880, offset); } 这个是什么错误导致的
最新发布
07-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值