内核级利用通用Hook函数方法检测进程

vc++6.0全局Hook(钩子) vc++6.0下的全局Hook(钩子)展示 视频教程 附源码 立即下载
AI摘要

本文深入探讨了Hook技术的基本原理,特别是在系统内核层面如何安全地Hook函数而不干扰系统稳定性。通过实例演示了如何Hook KiReadyThread函数来监控系统中的进程活动。

 

介绍通用Hook的一点思想:

在系统内核级中,MS的很多信息都没公开,包括函数的参数数目,每个参数的类型等。在系统内核中,访问了大量的寄存器,而很多寄存器的值,是上层调用者提供的。如果值改变系统就会变得不稳定。很可能出现不可想象的后果。另外有时候对需要Hook的函数的参数不了解,所以不能随便就去改变它的堆栈,如果不小心也有可能导致蓝屏。所以Hook的最佳原则是在自己的Hook函数中呼叫原函数的时候,所有的寄存器值,堆栈里面的值和Hook前的信息一样。这样就能保证在原函数中不会出错。一般我们自己的Hook的函数都是写在C文件里面的。例如Hook的目标函数KiReadyThread。

那么一般就自己实现一个:

 

MyKiReadyThread(...)
{
  ......
  call KiReadyThread
  ......
}

但是用C编译器编译出来的代码会出现一个堆栈帧:

 

Push ebp
mov ebp,esp

这就和我们的初衷不改变寄存器的数违背了,所以我们可以自己用汇编来实现MyKiReadyThread。

 

_func@0 proc
  pushad     ;保存通用寄存器
  call _cfunc@0 ;这里是在进入原来函数前进行的一些处理。
  popad       ;恢复通用寄存器
  push eax   
  mov eax,[esp+4] ;得到系统在call 目标函数时入栈的返回地址。
  mov ds:_OrgRet,eax ;保存在一个临时变量中
  pop eax
  mov [esp],retaddr ;把目标函数的返回地址改成自己的代码空间的返回地址,使其返回
后能接手继续的处理
  jmp _OrgDestFunction ;跳到原目标函数中
retaddr:
  pushad       ;原函数处理完后保存寄存器
  call _HookDestFunction@0 ;再处理
  popad     ;回复寄存器
  jmp ds:_OrgRet ;跳到系统调用目标函数的下一条指令。
_func@0 endp

当我们要拦截目标API的时候,只要修改原函数头5个字节的机器为一个JMP_func就行了。然后把原来的5字节保存,在跳入原函数时,恢复那5个字节即可。

Hook KiReadyThread检测系统中的进程:

在线程调度抢占的的时候会调用KiReadyThread,它的原型为VOID FASTCALL KiReadyThread (IN PRKTHREAD Thread),在进入KiReadyThread时,ecx指向Thread。所以完全可以Hook KiReadyThread 然后用ecx的值得到但前线程的进程信息。KiReadyThread没被ntosknrl.exe导出,所以通过硬编码来。在2000Sp4中地址为0x8043141f。

具体实现:

 

////////////////////////////////
// 1.cpp
////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif 

#include "ntddk.h"
#include "string.h"
#include "ntifs.h"
#include "stdio.h"

#define FILE_DEVICE_EVENT 0x8000

#define IOCTL_PASSBUF /
  CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)

void DriverUnload (IN PDRIVER_OBJECT pDriverObject);

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);

void cfunc ();

void HookDestFunction();
NTSTATUS DeviceIoControlDispatch(IN PDEVICE_OBJECT DeviceObject,
                      IN PIRP         pIrp);
extern void func();

void ResumeDestFunction();

const WCHAR devLink[] = L"//??//MyEvent";
const WCHAR devName[] = L"//Device//MyEvent";
UNICODE_STRING       devNameUnicd;
UNICODE_STRING       devLinkUnicd;   

ULONG OrgDestFunction = (ULONG)0x8043141f; //KiReadyThread

char JmpMyCode [] = {0xE9,0x00,0x00,0x00,0x00};
char OrgCode [5];

char OutBuf[128][16];

int Count = 0;

ULONG orgcr0;
#ifdef __cplusplus
}
#endif

VOID DisableWriteProtect( PULONG pOldAttr)
{

  ULONG uAttr;

  _asm
  {
      push eax;
      mov eax, cr0;
      mov uAttr, eax;
      and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
      mov cr0, eax;
      pop eax;
  };

  *pOldAttr = uAttr; //保存原有的 CRO 属性

}

VOID EnableWriteProtect( ULONG uOldAttr )
{

_asm
{
    push eax;
    mov eax, uOldAttr; //恢复原有 CR0 属性
    mov cr0, eax;
    pop eax;
};

}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath)
{
  NTSTATUS           Status;
  PDEVICE_OBJECT         pDevice;

  DbgPrint("DriverEntry called!/n");
  RtlInitUnicodeString (&devNameUnicd, devName );
  RtlInitUnicodeString (&devLinkUnicd, devLink );
  Status = IoCreateDevice ( pDriverObject,
  0,
      &devNameUnicd,
  FILE_DEVICE_UNKNOWN,
    0,
    TRUE,
    &pDevice );
    if( !NT_SUCCESS(Status)) 
    {
    DbgPrint(("Can not create device./n"));
    return Status;
  }
    Status = IoCreateSymbolicLink (&devLinkUnicd, &devNameUnicd);
    if( !NT_SUCCESS(Status)) 
    {
      DbgPrint(("Cannot create link./n"));
      return Status;
    }
    pDriverObject->DriverUnload = DriverUnload; 
    pDriverObject->MajorFunction[IRP_MJ_CREATE] = 
  pDriverObject->MajorFunction[IRP_MJ_CLOSE] =
  pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =   DeviceIoControlDispatch;
    
  pDriverObject->DriverUnload = DriverUnload;
  * ( (ULONG*) (JmpMyCode+1) ) = (ULONG)func - (ULONG)OrgDestFunction - 5;
  memcpy(OrgCode,(char*)OrgDestFunction,5);
  HookDestFunction();
  
  return STATUS_SUCCESS;
}

void DriverUnload (IN PDRIVER_OBJECT pDriverObject)
{
  NTSTATUS         status;
  ResumeDestFunction();
  if(pDriverObject->DeviceObject != NULL)
    {
      status=IoDeleteSymbolicLink( &devLinkUnicd );
    if ( !NT_SUCCESS( status ) )
        {
            DbgPrint(( "IoDeleteSymbolicLink() failed/n" ));
        }
        IoDeleteDevice( pDriverObject->DeviceObject );
    }
}

void DisplayName(PKTHREAD Thread)
{
  PKPROCESS Process = Thread->ApcState.Process;
  PEPROCESS pEprocess = (PEPROCESS)Process;
  DbgPrint("ImageFileName = %s /n",pEprocess->ImageFileName);
  sprintf(OutBuf[Count++],"%s",pEprocess->ImageFileName);
}

void cfunc (void)
{
  ULONG PKHeader=0;
  __asm
  {
    mov PKHeader,ecx //ecx寄存器是KiReadyThread中的PRKTHREAD参数
  }
  ResumeDestFunction();
  
  if ( PKHeader != 0 && Count < 128 )
  {
    DisplayName((PKTHREAD)PKHeader);   
  }   
}

void HookDestFunction()
{
  DisableWriteProtect(&orgcr0);
  memcpy((char*)OrgDestFunction,JmpMyCode,5);
  EnableWriteProtect(orgcr0);   
}

void ResumeDestFunction()
{
  DisableWriteProtect(&orgcr0);
  memcpy((char*)OrgDestFunction,OrgCode,5);
  EnableWriteProtect(orgcr0);
}

NTSTATUS DeviceIoControlDispatch(
                      IN PDEVICE_OBJECT DeviceObject,
                      IN PIRP         pIrp
                      )
{
  PIO_STACK_LOCATION         irpStack;
  NTSTATUS                 status;
  PVOID                   inputBuffer;
  ULONG                   inputLength;
  PVOID                   outputBuffer;
  ULONG                   outputLength;
  OBJECT_HANDLE_INFORMATION     objHandleInfo;

  status = STATUS_SUCCESS;
  // 取出IOCTL请求代码
  irpStack = IoGetCurrentIrpStackLocation(pIrp);

  switch (irpStack->MajorFunction)
  {
  case IRP_MJ_CREATE :
    DbgPrint("Call IRP_MJ_CREATE/n");
    break;
  case IRP_MJ_CLOSE:
    DbgPrint("Call IRP_MJ_CLOSE/n");
    break;
  case IRP_MJ_DEVICE_CONTROL:
    DbgPrint("IRP_MJ_DEVICE_CONTROL/n");
    inputLength=irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outputLength=irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    switch (irpStack->Parameters.DeviceIoControl.IoControlCode) 
    {
        case   IOCTL_PASSBUF:
        {
          RtlCopyMemory(pIrp->UserBuffer, OutBuf, 20*16);
          
          memset(OutBuf,0,128*16);
          Count = 0;
          break;
        }
        default:
          break;
    }

  default:
    DbgPrint("Call IRP_MJ_UNKNOWN/n");
    break;
  }
  pIrp->IoStatus.Status = status; 
  pIrp->IoStatus.Information = 0; 
  IoCompleteRequest (pIrp, IO_NO_INCREMENT);
  return status;
}

////////////////////////////////
// 1.asm
////////////////////////////////
.386
.model small

.data
_OrgRet dd 0

.code
public _func@0
extrn _cfunc@0:near
extrn _HookDestFunction@0:near
extrn _OrgDestFunction:DWORD

_func@0 proc
  pushad
  call _cfunc@0
  popad
  push eax
  mov eax,[esp+4]
  mov ds:_OrgRet,eax
  pop eax
  mov [esp],retaddr
  jmp _OrgDestFunction
retaddr:
  pushad
  call _HookDestFunction@0
  popad
  jmp ds:_OrgRet
_func@0 endp
END

//////////////////////////////////////////
// app.cpp
//////////////////////////////////////////

#include 
#include 

#define FILE_DEVICE_EVENT 0x8000
#define CTL_CODE( DeviceType, Function, Method, Access ) (           /
  ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) /
)

#define FILE_ANY_ACCESS           0
#define METHOD_BUFFERED           0
#define FILE_DEVICE_UNKNOWN         0x00000022

#define IOCTL_PASSBUF /
  CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)

int main()
{
    HANDLE     hDevice;   
    bool     status; 
    ULONG     dwReturn;
    char     outbuf[129][16];
    hDevice = NULL;
    m_hCommEvent = NULL;
    hDevice = CreateFile( "////.//MyEvent",
            GENERIC_READ|GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE, 
            NULL,
            OPEN_EXISTING, 
            FILE_ATTRIBUTE_NORMAL, 
            NULL);
    if(hDevice == INVALID_HANDLE_VALUE)
    {
      printf("createfile wrong/n");
      getchar();
      return 0;
    }
  while(1)
  {
    memset(outbuf,0,129*16);
    status =DeviceIoControl(hDevice,
            IOCTL_PASSBUF,
            NULL,
            0,
            &outbuf,
            128*16,
            &dwReturn,NULL);
    if( !status)
    {
        printf("IO wrong+%d/n", GetLastError());
        getchar();
        return 0;
    }
    int c=0;
    while( *((char*)(&outbuf)+c*16) )
    {
        //把csrss.exe和自身进程信息跳过,因为会产生有大量的信息。
        if ( strcmp((char*)(&outbuf)+c*16,"app.exe") && /
          strcmp((char*)(&outbuf)+c*16,"csrss.exe") )
          printf("%s/n",(char*)(&outbuf)+c*16);
        c++;
    }
    Sleep(1);
  }
}

试验结果:

 

......
TTPlayer.exe
System
TTPlayer.exe
vrvmon.exe
TTPlayer.exe
System
System
Explorer.EXE
Explorer.EXE
Explorer.EXE
......

测试、编译环境Windows2000 Sp4、Windows2000 DDK。没写出线程的隐藏进程代码,不过基本上实现得差不多了,只需要把返回的信息,和Ring3级查询得到的信息进行适时对比就能查出异常进程了。

快速搭建SpringBoot3+Vue3+ElementPlus管理系统 快速搭建SpringBoot3+Vue3管理系统前端项目搭建(默认开发环境:node20,Jdk17)创建项目并下载依赖--执行以下命令 前端项目搭建(默认开发环境:node20,Jdk17) 创建项目并下载依赖–执行以下命令 创建项目 yarn create vite admin-vue --template 2.下载依赖(也可按需下载) yarn add echarts --save yarn add vue-router --save yarn add element-plus --save y 阅读详情

相关推荐

MRI多序列,多中心数据集预处理--使用FSL-Flirt 配准数据

FLIRT(FMRIB 的线性图像配准工具)是用于线性(仿射)模态内和模态间脑图像配准的全自动稳健且准确的工具。 什么是配准 在这两张图片上,很容易看出它们没有对齐,左边相对右边倾斜,虽然我们人类视觉系统还是能把对应的解剖关系连系在一起,但是我们使用计算机分析时确不能够 因此,我们希望相同的解剖结构对齐,用坐标表示的话,希望他们在相同的坐标上。如下图 对齐这些解剖结构的过程就叫做配准(register) 因此,配准的目的也是使相同的解剖结构在同一个位置,便于分析。可以将CT和MRI配准,看同一结构在两个

Tina姐的博客 1万+

学习笔记-linker框架层的Hook和利用

系统框架native hook init_array原理so加载执行流程 hook_linker init_array自吐 应用以32位在64位终端运行 adb install --abi armeabi-v7a <path to apk> hook linker中的call_function函数,打印出函数的虚拟地址 ,进而把函数在so文件中的偏移打印出来,所以说我们要...

ai agent 775

主题033:燃烧反应工程

燃烧反应工程(Combustion Reaction Engineering)是研究燃料与氧化剂发生剧烈氧化反应的科学,涉及化学反应动力学、流体力学、传热传质等多个学科。燃烧是人类利用能源的主要方式,广泛应用于发电、交通运输、工业加热等领域。燃烧反应通常通过自由基链式反应进行。链引发:RH+O2⟶R⋅+HO2⋅ RH + O_2 \longrightarrow R^\cdot + HO_2^\cdot RH+O2​⟶R⋅+HO2⋅​链传递:R⋅+O2⟶RO2⋅ R^\cdot + O_2 \longrigh

kkchenjj的博客 231

linux 系统调用 hook 总结

1. 系统调用Hook简介 系统调用属于一种软中断机制(内中断陷阱),它有操作系统提供的功能入口(sys_call)以及CPU提供的硬件支持(int 3 trap)共同完成。 我们必须要明白,Hook技术是一个相对较宽的话题,因为操作系统从ring3到ring0是分层次的结构,在每一个层次上都可以进行相应的Hook,它们使用的技术方法以及取得的效果也是不尽相同的。本文的主题是"系统调用的Hoo...

whatday的专栏 5822

【施磊】C++课程笔记目录

【C++编程】施磊老师C++笔记目录

GeniusAng的博客 4126

【打卡帖】7日玩转ESP32——(第4日) 串口的输入输出

【福利帖】7日玩转ESP32——(第4日) 串口的输入输出

1377

linux系统下的各种hook方式\Linux内核hook系统调用

文章目录一、linux系统下的各种hook方式1. 函数指针hook2. 动态库劫持3. Linux系统调用劫持 hook4. 堆栈式文件系统5. LSM二、Linux内核hook系统调用 一、linux系统下的各种hook方式 在计算机中,基本所有的软件程序都可以通过hook方式进行行为拦截,hook方式就是改变原始的执行流, Linux平台上常见的拦截: 修改函数指针。 用户态动态库拦截。 内核态系统调用拦截。 堆栈式文件系统拦截。 LSM(Linux Security Modules) 1. 函数

西京刀客 1万+

YOLO26 数据标注工具:LabelImg、Label Studio实战指南:主流标注工具的安装配置与使用技巧,高效完成目标检测数据标注

本文介绍了目标检测中数据标注的核心地位与常用工具。数据标注质量直接影响模型性能,需要关注准确性、一致性等维度。文章详细讲解了边界框、类别标签等基本概念,并对比了LabelImg、Label Studio等主流标注工具的特点。重点介绍了LabelImg的轻量级、易用性等优势,以及Label Studio的协作功能,为不同规模项目提供标注工具选择建议。

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1177

Android hook检测(安全方向)

什么是hook 所谓hook技术,就是通过一段代码(反射、代理)侵入到App启动过程中,在原本执行的代码前插入其它的功能。比如:通过hook技术,上传登陆页面的账号密码等。 干货 对于主流hook框架(Xposed、Cydia Substrate),通常有以下三种方式来检测一个App是否被hook: 安装目录中是否存在hook工具 存储中是否存在hook安装文件 运行栈中是否存在ho...

weixin_41508948的博客 1万+

分享一个完整的KANO问卷(包含正反问题和选项设置)

本文介绍了KANO模型问卷的设计与应用,用于评估功能需求优先级。问卷包含基本信息、功能评估(正反问题设计)、界面评估及开放问题,选项定义明确(如"非常喜欢"到"很不喜欢")。数据清洗规则包括剔除矛盾回答和注意力检验。通过量化编码和矩阵分析,将需求分为魅力型、期望型、必备型等类别。示例数据显示健康监测为必备型(72%),电子围栏为期望型(45%),适老化改造为无差异型(38%)。该模型为产品决策提供客观量化依据。

从技术实践立足,从项目管理方法论延伸思考 1796

基于STM32的智能浇花系统毕业设计(全部资料)

摘要:本文设计了一种基于STM32单片机的智能浇花系统,集成了环境温湿度检测、土壤温湿度监测、LCD显示、Wi-Fi联网及手机APP远程控制等功能。系统通过传感器实时采集环境参数,自动控制水泵工作实现智能灌溉,同时支持用户通过手机APP远程监控和调节。论文详细阐述了硬件选型、软件设计及系统测试过程,验证了系统的稳定性和实用性。该设计为家庭园艺提供了智能化解决方案,具有节水高效、操作便捷等特点。关键词:STM32;智能灌溉;远程控制;环境监测;Wi-Fi通信。

3254968421的博客 1196

Visual Studio关于hook项目的简单使用

参考 DLL注入_拦截技术之Hook方式: 可知 如果我想要使用hook的dll注入方式来获取其他程序的数据,则关键的对象有: 操作 启动程序和给dll传递程序线程id 的一个程序 对目标程序的消息进行处理的dll 目标程序.exe dll文件编写 操作dll文件和目标程序的 代码编写 新建项目 新建项目->找到 控制台应用(在Windows终端运行代码)->填写其他项目后,看到 将解决方案和项目放在同一目录中。 根据 终于理解了解决方案和项目之间的关系了可知:项目和解决方案的关系是:

啷个哩个啷 2572

SAP OData 开发从入门到提高教程的目录

笔者 18 年的 SAP 技术开发生涯,对 SAP OData 服务的开发,测试,发布,部署,测试,及基于各种不同 SAP 技术实现的 OData 服务的幕后技术实现细节和使用场合,均有着深入的研究。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 7249

[转载]内核级利用通用Hook函数方法检测进程

内核级利用通用Hook函数方法检测进程作者:    LionD8QQ:    10415468Email: LionD8@126.comBlog:    http://blog.youkuaiyun.com/LionD8     or http://liond8.126.com介绍通用Hook的一点思想:    在系统内核级中,MS的很多信息都没公开,包括函数的参数数目,每个参数的类型等。在系统内核中,访问了

815

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

【收藏】内核级利用通用Hook函数方法检测进程

来源:http://www.xfocus.net/articles/200505/798.html创建时间:2005-05-10文章属性:原创文章提交:LionD8 (liond8_at_126.com)内核级利用通用Hook函数方法检测进程作者:    LionD8QQ:    10415468Email: LionD8@126.comBlog:    http://blog.youkuaiyun.com/

Purpleendurer@优快云 1608

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

(转载)利用内核级通用Hook检测系统中的进程

利用内核级通用Hook检测系统中的进程作者:    LionD8QQ:    10415468Email: LionD8@126.comBlog:    http://blog.youkuaiyun.com/LionD8     or http://liond8.126.com/介绍通用Hook的一点思想:    在系统内核级中,MS的很多信息都没公开,包括函数的参数数目,每个参数的类型等。在系统内核中,访问

Kendiv's Box 2466

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

上一篇: 关于Windows下ShellCode编写的一点思考
下一篇: use ASM and CPP together
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值