城里城外看SSDT

驱动开发笔记3—SSDT表详解 SSDT表 SSDT的全称是"System Services Descriptor Table",即系统服务描述表,在内核中的实际名称是KeServiceDescriptorTable,这个表由ntoskrnl.exe导出(在x64里不导出)。 SSDT用于处理应用层通过Kernel32.dll下发的各个API操作请求。ntdll.dll中的API是一个简单的包装函数,当Kernel32.dll中的API通过Ntdll.dll时,会先完成对参数的检查,再调用一个中断(int 2Eh 或者 SysEnter指 阅读详情
2007年7月5日作于京师海淀
 
2006年,中国互联网上的斗争硝烟弥漫。这时的战场上,先前颇为流行的窗口挂钩、API挂钩、进程注入等技术已然成为昨日黄花,大有逐渐淡出之势;取而代之的,则是更狠毒、更为赤裸裸的词汇:驱动、隐藏进程、Rootkit……
在这篇文章里,李马首度从ring3(应用层)的围城跨出,一跃而投身于ring0(内核层)这一更广阔的天地,为你展现SSDT(系统服务描述符表)的奥秘。
 

点这里下载本文的配套代码

引子

2006年,中国互联网上的斗争硝烟弥漫。这时的战场上,先前颇为流行的窗口挂钩、API挂钩、进程注入等技术已然成为昨日黄花,大有逐渐淡出之势;取而代之的,则是更狠毒、更为赤裸裸的词汇:驱动、隐藏进程、Rootkit……

前不久,我不经意翻出自己2005年9月写下的一篇文章《DLL的远程注入技术》,在下面看到了一位名叫L4bm0s的网友说这种技术已经过时了。虽然我也曾想过拟出若干辩解之词聊作应对,不过最终还是作罢了——毕竟,拿出些新的、有技术含量的东西才是王道。于是这一次,李马首度从ring3(应用层)的围城跨出,一跃而投身于ring0(内核层)这一更广阔的天地,便有了这篇《城里城外看SSDT》。——顾名思义,城里和城外的这一墙之隔,就是ring3与ring0的分界。

在这篇文章里,我会用到太多杂七杂八的东西,比如汇编,比如内核调试器,比如DDK。这诚然是一件令我瞻前顾后畏首畏尾的事情——一方面在ring0我不得不依靠这些东西,另一方面我实在担心它们会导致我这篇文章的阅读门槛过高。所以,我决定尽可能少地涉及驱动、内核与DDK,也不会对诸如如何使用内核调试器等问题作任何讲解——你只需要知道我大概在做些什么,这就足够了。

什么是SSDT?

什么是SSDT?自然,这个是我必须回答的问题。不过在此之前,请你打开命令行(cmd.exe)窗口,并输入“dir”并回车——好了,列出了当前目录下的所有文件和子目录。

那么,以程序员的视角来看,整个过程应该是这样的:

由用户输入dir命令。 
cmd.exe获取用户输入的dir命令,在内部调用对应的Win32 API函数FindFirstFile、FindNextFile和FindClose,获取当前目录下的文件和子目录。 
cmd.exe将文件名和子目录输出至控制台窗口,也就是返回给用户。 
到此为止我们可以看到,cmd.exe扮演了一个非常至关重要的角色,也就是用户与Win32 API的交互。——你大概已经可以猜到,我下面要说到的SSDT亦必将扮演这个角色,这实在是一点新意都没有。

没错,你猜对了。SSDT的全称是System Services Descriptor Table,系统服务描述符表。这个表就是一个把ring3的Win32 API和ring0的内核API联系起来的角色,下面我将以API函数OpenProcess为例说明这个联系的过程。

你可以用任何反汇编工具来打开你的kernel32.dll,然后你会发现在OpenProcess中有类似这样的汇编代码:

call ds:NtOpenProcess 


这就是说,OpenProcess调用了ntdll.dll的NtOpenProcess函数。那么继续反汇编之,你会发现ntdll.dll中的这个函数很短:

mov eax, 7Ah
mov edx, 7FFE0300h
call dword ptr [edx]
retn 10h 


另外,call的一句实质是调用了KiFastSystemCall:

mov edx, esp
sysenter 


上面是我的XP Professional sp2中ntdll.dll的反汇编结果,如果你用的是2000系统,那么可能是这个样子:

mov eax, 6Ah
lea edx, [esp+4]
int 2Eh
retn 10h 


虽然它们存在着些许不同,但都可以这么来概括:

把一个数放入eax(XP是0x7A,2000是0x6A),这个数值称作系统的服务号。 
把参数堆栈指针(esp+4)放入edx。 
sysenter或int 2Eh。 
好了,你在ring3能看到的东西就到此为止了。事实上,在ntdll.dll中的这些函数可以称作真正的NT系统服务的存根(Stub)函数。分隔ring3与ring0城里城外的这一道叹息之墙,也正是由它们打通的。接下来SSDT就要出场了,come some music。

站在城墙看城外

插一句先,貌似到现在为止我仍然没有讲出来SSDT是个什么东西,真正可以算是“犹抱琵琶半遮面”了。——书接上文,在你调用sysenter或int 2Eh之后,Windows系统将会捕获你的这个调用,然后进入ring0层,并调用内核服务函数NtOpenProcess,这个过程如下图所示。

http://www.titilima.cn/pics/ssdtdump1.gif

SSDT在这个过程中所扮演的角色是至关重要的。让我们先看一看它的结构,如下图。

http://www.titilima.cn/pics/ssdtdump2.gif

当程序的处理流程进入ring0之后,系统会根据服务号(eax)在SSDT这个系统服务描述符表中查找对应的表项,这个找到的表项就是系统服务函数NtOpenProcess的真正地址。之后,系统会根据这个地址调用相应的系统服务函数,并把结果返回给ntdll.dll中的NtOpenProcess。图中的“SSDT”所示即为系统服务描述符表的各个表项;右侧的“ntoskrnl.exe”则为Windows系统内核服务进程(ntoskrnl即为NT OS KerneL的缩写),它提供了相对应的各个系统服务函数。ntoskrnl.exe这个文件位于Windows的system32目录下,有兴趣的朋友可以反汇编一下。

附带说两点。根据你处理器的不同,系统内核服务进程可能也是不一样的。真正运行于系统上的内核服务进程可能还有ntkrnlmp.exe、ntkrnlpa.exe这样的情况——不过为了统一起见,下文仍统称这个进程为ntoskrnl.exe。另外,SSDT中的各个表项也未必会全部指向ntoskrnl.exe中的服务函数,因为你机器上的杀毒监控或其它驱动程序可能会改写SSDT中的某些表项——这也就是所谓的“挂钩SSDT”——以达到它们的“主动防御”式杀毒方式或其它的特定目的。

KeServiceDescriptorTable

事实上,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等等。ntoskrnl.exe中的一个导出项KeServiceDescriptorTable即是SSDT的真身,亦即它在内核中的数据实体。SSDT的数据结构定义如下:

typedef struct _tagSSDT {
    PVOID pvSSDTBase;
    PVOID pvServiceCounterTable;
    ULONG ulNumberOfServices;
    PVOID pvParamTableBase;
} SSDT, *PSSDT; 


其中,pvSSDTBase就是上面所说的“系统服务描述符表”的基地址。pvServiceCounterTable则指向另一个索引表,该表包含了每个服务表项被调用的次数;不过这个值只在Checkd Build的内核中有效,在Free Build的内核中,这个值总为NULL(注:Check/Free是DDK的Build模式,如果你只使用SDK,可以简单地把它们理解为Debug/Release)。ulNumberOfServices表示当前系统所支持的服务个数。pvParamTableBase指向SSPT(System Service Parameter Table,即系统服务参数表),该表格包含了每个服务所需的参数字节数。

下面,让我们开看看这个结构里边到底有什么。打开内核调试器(以kd为例),输入命令显示KeServiceDescriptorTable,如下。

lkd> dd KeServiceDescriptorTable l4
8055ab80 804e3d20 00000000 0000011c 804d9f48 


接下来,亦可根据基地址与服务总数来查看整个服务表的各项:

lkd> dd 804e3d20 l11c
804e3d20 80587691 f84317aa f84317b4 f84317be
804e3d30 f84317c8 f84317d2 f84317dc f84317e6
804e3d40 8057741c f84317fa f8431804 f843180e
804e3d50 f8431818 f8431822 f843182c f8431836
... 


你获得的结果可能和我会有不同——我指的是那堆以十六进制f开头的地址项,因为我的SSDT被System Safety Monitor接管了,没留下几个原生的ntoskrnl.exe表项。

现在是写些代码的时候了。KeServiceDescriptorTable及SSDT各个表项的读取只能在ring0层完成,于是这里我使用了内核驱动并借助DeviceIoControl来完成。其中DeviceIoControl的分发代码实现如下面的代码所示,没有什么技术含量,所以不再解释。

switch ( IoControlCode ) 
{
case IOCTL_GETSSDT:
    {
        __try
        {
            ProbeForWrite( OutputBuffer, sizeof( SSDT ), sizeof( ULONG ) );
            RtlCopyMemory( OutputBuffer, KeServiceDescriptorTable, sizeof( SSDT ) );
        }
        __except ( EXCEPTION_EXECUTE_HANDLER )
        {
            IoStatus->Status = GetExceptionCode();
        }
    }
    break;
case IOCTL_GETPROC:
    {
        ULONG uIndex = 0;
        PULONG pBase = NULL;

        __try
        {
            ProbeForRead( InputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
            ProbeForWrite( OutputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
        }
        __except( EXCEPTION_EXECUTE_HANDLER )
        {
            IoStatus->Status = GetExceptionCode();
            break;
        }

        uIndex = *(PULONG)InputBuffer;
        if ( KeServiceDescriptorTable->ulNumberOfServices <= uIndex )
        {
            IoStatus->Status = STATUS_INVALID_PARAMETER;
            break;
        }
        pBase = KeServiceDescriptorTable->pvSSDTBase;
        *((PULONG)OutputBuffer) = *( pBase + uIndex );
    }
    break;
// ...
} 


补充一下,再。DDK的头文件中有一件很遗憾的事情,那就是其中并未声明KeServiceDescriptorTable,不过我们可以自己手动添加之:

extern PSSDT KeServiceDescriptorTable; 


——当然,如果你对DDK开发实在不感兴趣的话,亦可以直接使用配套代码压缩包中的SSDTDump.sys,并使用DeviceIoControl发送IOCTL_GETSSDT和IOCTL_GETPROC控制码即可;或者,直接调用我为你准备好的两个函数:

BOOL GetSSDT( IN HANDLE hDriver, OUT PSSDT buf );
BOOL GetProc( IN HANDLE hDriver, IN ULONG ulIndex, OUT PULONG buf ); 


获取详细模块信息

虽然我们现在可以获取任意一个服务号所对应的函数地址了已经,但是你可能仍然不满意,认为只有获得了这个服务函数所在的模块才是王道。换句话说,对于一个干净的SSDT表来说,它里边的表项应该都是指向ntoskrnl.exe的;如果SSDT之中有若干个表项被改写(挂钩),那么我们应该知道是哪一个或哪一些模块替换了这些服务。

首先我们需要获得当前在ring0层加载了那些模块。如我在本文开头所说,为了尽可能地少涉及ring0层的东西,于是在这里我使用了ntdll.dll的NtQuerySystemInformation函数。关键代码如下:

typedef struct _SYSTEM_MODULE_INFORMATION { 
    ULONG Reserved[2]; 
    PVOID Base; 
    ULONG Size; 
    ULONG Flags; 
    USHORT Index; 
    USHORT Unknown; 
    USHORT LoadCount; 
    USHORT ModuleNameOffset; 
    CHAR ImageName[256]; 
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; 

typedef struct _tagSysModuleList {
    ULONG ulCount;
    SYSTEM_MODULE_INFORMATION smi[1];
} SYSMODULELIST, *PSYSMODULELIST;

s = NtQuerySystemInformation( SystemModuleInformation, pRet,
    sizeof( SYSMODULELIST ), &nRetSize );
if ( STATUS_INFO_LENGTH_MISMATCH == s )
{
    // 缓冲区太小,重新分配
    delete pRet;
    pRet = (PSYSMODULELIST)new BYTE[nRetSize];
    s = NtQuerySystemInformation( SystemModuleInformation, pRet,
        nRetSize, &nRetSize ); 
} 


需要说明的是,这个函数是利用内核的PsLoadedModuleList链表来枚举系统模块的,因此如果你遇到了能够隐藏驱动的Rootkit,那么这种方法是无法找到被隐藏的模块的。在这种情况下,枚举系统的“/Driver”目录对象可能可以更好解决这个问题,在此不再赘述了就。

接下来,是根据SSDT中的地址表项查找模块。有了SYSTEM_MODULE_INFORMATION结构中的模块基地址与模块大小,这个工作完成起来也很容易:

BOOL FindModuleByAddr( IN ULONG ulAddr, IN PSYSMODULELIST pList,
                      OUT LPSTR buf, IN DWORD dwSize )
{
    for ( ULONG i = 0; i < pList->ulCount; ++i )
    {
        ULONG ulBase = (ULONG)pList->smi[i].Base;
        ULONG ulMax  = ulBase + pList->smi[i].Size;
        if ( ulBase <= ulAddr && ulAddr < ulMax )
        {
            // 对于路径信息,截取之
            PCSTR pszModule = strrchr( pList->smi[i].ImageName, '//' );
            if ( NULL != pszModule )
            {
                lstrcpynA( buf, pszModule + 1, dwSize );
            }
            else
            {
                lstrcpynA( buf, pList->smi[i].ImageName, dwSize );
            }
            return TRUE;
        }
    }
    return FALSE;
} 


详细枚举系统服务项

到现在为止,还遗留有一个问题,就是获得服务号对应的服务函数名。比如XP下0x7A对应着NtOpenProcess,但是到2000下,NtOpenProcess就改为0x6A了。

——有一个好消息一个坏消息,你先听哪个?

——什么坏消息?

——Windows并没有给我们开放这样现成的函数,所有的工作都需要我们自己来做。

——那好消息呢?

——牛粪有的是。

坏了,串词儿了。好消息是我们可以通过枚举ntdll.dll的导出函数来间接枚举SSDT所有表项所对应的函数,因为所有的内核服务函数对应于ntdll.dll的同名函数都是这样开头的:

mov eax, <ServiceIndex> 


对应的机器码为:

B8 <ServiceIndex> 


再说一遍:非常幸运,仅就我手头上的2000 sp4、XP、XP sp1、XP sp2、2003的ntdll.dll而言,无一例外。不过Mark Russinovich的《深入解析Windows操作系统》一书中指出,IA64的调用方式与此不同——由于手头上没有相应的文件,所以在这里不进行讨论了就。

接着说。我们可以把mov的一句用如下的一个结构来表示:

#pragma pack( push, 1 )
typedef struct _tagSSDTEntry {
    BYTE  byMov;   // 0xb8
    DWORD dwIndex;
} SSDTENTRY;
#pragma pack( pop ) 


那么,我们可以对ntdll.dll的所有导出函数进行枚举,并筛选出“Nt”开头者,以SSDTENTRY的结构取出其开头5个字节进行比对——这就是整个的枚举过程。相关的PE文件格式解析我不再解释,可参考注释。整个代码如下:

#define MOV        0xb8

void EnumSSDT( IN HANDLE hDriver, IN HMODULE hNtDll )
{
    DWORD dwOffset                  = (DWORD)hNtDll;
    PIMAGE_EXPORT_DIRECTORY pExpDir = NULL;
    int nNameCnt                    = 0;
    LPDWORD pNameArray              = NULL;
    int i                           = 0;

    // 到PE头部
    dwOffset += ((PIMAGE_DOS_HEADER)hNtDll)->e_lfanew + sizeof( DWORD );
    // 到第一个数据目录
    dwOffset += sizeof( IMAGE_FILE_HEADER ) + sizeof( IMAGE_OPTIONAL_HEADER )
        - IMAGE_NUMBEROF_DIRECTORY_ENTRIES * sizeof( IMAGE_DATA_DIRECTORY );
    // 到导出表位置
    dwOffset = (DWORD)hNtDll
        + ((PIMAGE_DATA_DIRECTORY)dwOffset)->VirtualAddress;
    pExpDir = (PIMAGE_EXPORT_DIRECTORY)dwOffset;

    nNameCnt = pExpDir->NumberOfNames;
    // 到函数名RVA数组
    pNameArray = (LPDWORD)( (DWORD)hNtDll + pExpDir->AddressOfNames );

    // 初始化系统模块链表
    PSYSMODULELIST pList = CreateModuleList( hNtDll );

    // 循环查找函数名
    for ( i = 0; i < nNameCnt; ++i )
    {
        PCSTR pszName = (PCSTR)( pNameArray[i] + (DWORD)hNtDll );
        if ( 'N' == pszName[0] && 't' == pszName[1] )
        {
            // 找到了函数,则定位至查找表
            LPWORD pOrdNameArray = (LPWORD)( (DWORD)hNtDll + pExpDir->AddressOfNameOrdinals );
            // 定位至总表
            LPDWORD pFuncArray   = (LPDWORD)( (DWORD)hNtDll + pExpDir->AddressOfFunctions );
            LPCVOID pFunc        = (LPCVOID)( (DWORD)hNtDll + pFuncArray[pOrdNameArray[i]] );
            
            // 解析函数,获取服务名
            SSDTENTRY entry;
            CopyMemory( &entry, pFunc, sizeof( SSDTENTRY ) );
            if ( MOV == entry.byMov )
            {
                ULONG ulAddr = 0;
                GetProc( hDriver, entry.dwIndex, &ulAddr );

                CHAR strModule[MAX_PATH] = "[Unknown Module]";
                FindModuleByAddr( ulAddr, pList, strModule, MAX_PATH );
                printf( "0x%04X/t%s/t0x%08X/t%s/r/n", entry.dwIndex,
                    strModule, ulAddr, pszName );
            }
        }
    }

    DestroyModuleList( pList );
} 


下图是示例程序SSDTDump在XP sp2上的部分运行截图,显示了SSDT的基地址、服务个数,以及各个表项所对应的服务号、所在模块、地址和服务名。

此图已经缩小,点击察看原图。

结语

ring3与ring0,城里与城外之间为一道叹息之墙所间隔,SSDT则是越过此墙的一道必经之门。因此,很多杀毒软件也势必会围绕着它大做文章。无论是System Safety Monitor的系统监控,还是卡巴斯基的主动防御,都是挂钩了SSDT。这样,病毒尚在ring3内发作之时,便被扼杀于摇篮之内。

内核最高权限,本就是兵家必争之地,魔高一尺道高一丈的争夺于此亦已变成颇为稀松平常之事。可以说和这些争夺比起来,SSDT的相关技术简直不值一提。但最初发作的病毒体总是从ring3开始的——换句话说,任你未来会成长为何等的武林高手,我都可以在你学走路的时候杀掉你——知晓了SSDT的这点优势,所有的病毒咂吧咂吧也就都没味儿了。所以说么,杀毒莫如防毒。
 
SSDT Hook技术详解与应用 SSDT Hook技术详解与应用SSDT Hook技术详解与应用 一SSDT简介 1什么是SSDT 2SSDT结构 3应用层调用 Win32 API 的完整执行流程 二SSDT Hook原理 1SSDT Hook原理简介 2进程隐藏与保护 3文件隐藏与保护 4端口隐藏一、SSDT简介1、什么是SSDT​ SSDT 的全称是 System Services Descriptor Table,系统服 阅读详情

相关推荐

工业级以太网通信实战:用FPGA驱动YT8531 PHY芯片的完整避坑指南

本文是一份针对工业级以太网通信的实战指南,详细讲解了如何使用FPGA驱动YT8531 PHY芯片。内容涵盖从硬件设计(电源、时钟、复位)到MDIO接口驱动开发、PHY配置与链路管理的全流程,并重点剖析了十个常见的开发“陷阱”及其解决方案,旨在帮助工程师在复杂的工业环境中实现稳定可靠的以太网通信连接。

weixin_29191669的博客 147

初探SSDT

SSDT 的全称是 System Services Descriptor Table,系统服务描述符表。这个表就是一个把 Ring3 的 Win32 API 和 Ring0 的内核 API 联系起来。SSDT 并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。通过修改此表的函数地址可以对常用 Windows 函数及 API 进行 Hook,从而实现对一些关心的系统动作进行过滤、监控的目的。一些 HIPS、防毒软件、系统监控、注册表监控软件往往会采用此接.

hongduilanjun的博客 2733

Oasys安装教程

在基环境下执行然后去 C:\Users.condarc打开 .condarc这个文件 删除干净里面的东西。

weixin_44254178的博客 1297

驱动保护:挂接SSDT内核钩子(1)

SSDT 中文名称为系统服务描述符表,该表的作用是将Ring3应用层与Ring0内核层,两者的API函数连接起来,起到承上启下的作用,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基址、服务函数个数等,SSDT 通过修改此表的函数地址可以对常用 Windows 函数进行内核级的Hook,从而实现对一些核心的系统动作进行过滤、监控的目的,接下来将演...

weixin_30790841的博客 661

YOLOv11在STM32H7上的MCU部署实战:基于CMSIS-NN的高效推理实现

嵌入式AI与MCU部署技术解析 本文系统介绍了基于STM32H7微控制器的YOLOv11模型部署方案。主要内容包括: 边缘计算背景下MCU的AI部署优势与挑战,重点分析了STM32H7平台特性 YOLOv11模型的结构优化,包括E-ELAN骨干网络和Meta-ACON激活函数等改进 CMSIS-NN加速库的架构原理,在STM32H743上可实现5.4倍卷积加速 完整的开发环境搭建流程,涵盖硬件选型、工具链配置和模型转换 模型优化关键技术,包括int8量化、剪枝和内存占用优化等 实验表明,该方案在保持模型精度

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

STM32 实现 4*4 矩阵键盘扫描(HAL库、标准库 都适用)

本文实现的代码是基于STM32HAL库的基础上的,不过标准库也可以用,只是调用的库函数不同,逻辑跟配置是一样的,按我这里的逻辑来配置即可。 1、键盘原理图: 原理举例:先把 F0-F7 内部拉高,这样这个8个引脚都是高电平,然后就进行列扫描。例如:假如按下3按钮,Y3 列扫描,把F4先拉低,然后读取F0-F3的状态,就会读出为1110,这就可 以知道是F3行拉低了,同时这时候是程序控制F4拉低的,这样就可以知道是F4列导致它转态变化了的,这样就可以定位出是F4列F3行的按键按下了;其他的列也是这样子扫描

lhh_qrsly的博客 7059

【SSDT】SSDT hook技术

通过修改此表的函数地址可以对常用Windows函数及API进行Hook,从而实现对一些关心的系统动作进行过滤、监控等目的。在NT4.0 以上的Windpws 操作系统中,默认存在两个系统服务描述表,两个调度表对应两类不同的系统服务。要Hook SSDT表,首选需要这个表是可写的,但是在XP之后的系统都是只读的,有三种方式修改内存保护机制。其中第1位叫做保护属性位,控制着页的读或写属性。如果为0,则只能读/执行。SSDT,IDT(中断描述符表)的页属性在默认情况下只读,可执行,但不能写。例如进程保护(驱动)

dr0op's blog 2785

微服务架构的实施与挑战:前提判断、三种落地模式、收益兑现与风险应对

微服务是用运维复杂度换取演进自由度的一笔交易,是否划算取决于系统复杂度是否越过生产率曲线的交叉点。本文先给出实施前提:微服务溢价的六项成本、四项前置能力、康威定律与领域边界,并附就绪度自检表;再拆解三种落地模式:以绞杀者为代表的渐进剥离与数据五级迁移、以模块化单体起步的绿地建设、新旧并行的混合式集成;随后逐项审视六大技术优势与组织收益的兑现条件,系统梳理分布式谬误、分布式单体、Saga与幂等、弹性容错、可观测性、契约测试等挑战与对策,最后给出四阶段落地路线、DORA四项度量与常见反模式清单。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 172万+

[转载]城里城外看SSDT

看了这篇文章,觉得写得很好,很实用,怕以后想找的时候找不到了,所以转过来。感谢文章作者马锐老师。原文链接:http://www.titilima.cn/show-201-1.html引子2006年,中国互联网上的斗争硝烟弥漫。这时的战场上,先前颇为流行的窗口挂钩、API挂钩、进程注入等技术已然成为昨日黄花,大有逐渐淡出之势;取而代之的,则是更狠毒、更为赤裸裸的词汇:驱动

iT2afL0rd's Blog 1610

【软考高项】【计算专题】- 3 - 进度类 - 双代号网络图

共需压缩 20 天。在双代号网络图中,工作一般使用箭线表示,任意一条箭线都需要占用时间、消耗资源,工作名称写在箭线的上方,而消耗的时间则写在箭线的下方或者工作后面。反映的是前后工作的交接点,节点中的编号可以任意编写,但应保证后续工作的节点比前面节点的编号大,即上图图中的1⃣️4⃣️ 即表示 B 活动和 D 活动间有依赖关系,D 活动的开始,依赖 B 活动的结束。B活动完成了一半, 各计划的实际支出为A活动6500元, B活动1000元, C活动280元, D。

欢迎来到我的博客,一起探索代码里的世界! 4566

基于RK3568的YOLOv11模型端侧推理优化与部署实战指南

在AI边缘计算领域,瑞芯微RK3568芯片凭借其强大的NPU算力和丰富的接口资源,成为了众多开发者的首选平台。然而,瑞芯微官方文档虽然提供了YOLO11预训练模型的部署方案,但对于需要自定义数据集训练的开发者来说,从模型训练到板端部署的完整流程却缺乏详细指导。本文将带你走完从环境搭建、数据准备、模型训练到最终板端部署的完整技术路线,并分享实际开发中遇到的各种坑点和解决方案。让我们一起探索如何在RK3568平台上实现30FPS稳定推理的YOLO11目标检测应用!

m0_64661770的博客 115

城里城外看SSDT[转]

点这里下载本文的配套代码 引子 2006年,中国互联网上的斗争硝烟弥漫。这时的战场上,先前颇为流行的窗口挂钩、API挂钩、进程注入等技术已然成为昨日黄花,大有逐渐淡出之势;取而代之的,则是更狠毒、更为赤裸裸的词汇:驱动、隐藏进程、Rootkit…… 前不久,我不经意翻出自己2005...

chubaisheng8627的博客 153

使用NXP SBC插件开发FS26软件

FS26作为功能安全可达ASIL D的SBC,在配合NXP MCU的使用中非常广泛,本文介绍基于NXP官网的SBC代码包快速进行FS26软件的开发FS26使用过程中还有不少坑的地方,后面有空可以再介绍相关的功能。

赞的博客 656

057 [转载]城里城外看SSDT

[转载]城里城外看SSDT 转载自:a1pass.blog.163.com 2007-12-31 09:30:59| 分类: 网文九尾狐——随 题记:这是牛人李马的一篇SSDT入门文章,虽说是入门,但还是看得我晕晕忽忽!有一些知识自己还不具备,看来“革命尚未成功,同志仍需努力”啊! 作者:李马 来源:http://www.titilima.cn/readarticle.php?id=78 200...

hackdoors的博客 201

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

上一篇: 简要安装 FreeBSD 6.2 及配置桌面环境
下一篇: 淘来的几个SMC代码
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值