Windows NT System-Call Hooking (Dr. Dobb‘s Journal)

免杀对抗—DLL劫持&白加黑&隐写分离&EDR&Syscall-hook 对于白加黑呢免杀效果是比较强的,关键是DLL后门的免杀,分离或者混淆都可以实现。至于这个Syscall,我是不会编写,只能玩一下别人的项目,而且这玩意挺难的我说实话,更加偏向于二进制那边的了。最后,以上仅为个人的拙见,如何有不对的地方,欢迎各位师傅指正与补充,有兴趣的师傅可以一起交流学习。 阅读详情
Notes from "Windows NT System-Call Hooking" (Dr. Dobb's Journal, '97)
---------------------------------------------------------------------
Intro : kernel hooks (from "Rootkits : Subverting the Windows kernel")

- kernel mem : high virtual address memory region

- x86 : kernel mem resides in region of mem 0x8000000 and above

   -- if use /3GB boot config, kernel mem starts at 0xC0000000

- processes can't access kernel mem

   -- exception : when a process has debug privileges or
  when a call gate has been installed

- rootkit : can access krenel memory IF implements a device driver

   -- then rootkit operating in ring 0

Core components of NT : ntoskrnl (ntoskrnl.exe), win32k (win32k.sys)

- NTOSKRNL and WIN32K : are part of the kernel

- win32k : added to kernel in NT 4.0

   -- implements graphical system services

   -- much of win32 API's graphics engine moved to kernel to boost perf

   -- that fxnality was previously implemented in user mode by gdi32.dll
      and user32.dll

- NTDLL.DLL : also exists at user level, sits on top of NTOSKRNL

- win32 (API) : consists of kernel32.dll, gdi32.dll, user32.dll
- win32 (API) : sits on top of NTDLL.DLL, exists at user level

   -- win32 subsystem
   -- when an app makes a call to a win32 (api) function, usually the
      called DLL will in the end call upon native NT services provided by
      NTOSKRNL or WIN32K

      - invoke NTOSKRNL via calling to NTDLL.DLL

      - for example CreateFile(...) is a function exported by kernel32.dll

      - but this function calls several kernel functions depending upon
        the values of the flags passed to CreateFile(...)

- call to kernel to see whether desired file already exists

- call to kernel to create or open the file

- call to kernel to get the new/opened file's attributes

User-level subsystems : win32 (by which we mean the win32 api), POSIX, OS/2

NTDLL.DLL : exports NTOSKRNL to user-level subsystems

- populates EAX register with system call number of kernel function

- then executes system call trap (int 2Eh for x86 NT)

- provides a very thin wrapper on kernel services

- for example the ntdll.dll function ZwCreateFile(...) is invoked by CreateFile(...)

   -- ZwCreateFile(...) disassembled

      mov eax, 17h         // system call # is 0x17 for NT (0x20 for 2k, 0x25 for XP)
      lea edx, [esp+4]    // make edx point to function params (user-mode stack)
   // lea : loads edx with address of user args
      int 2Eh    // execute sys call trap for NT, 2k on x86
   // (SYSENTER is used for XP,2003 on x86)
      ret 2Ch

- ZwCreateFile(...) has alias NtCreateFile(...) - either can be used

   -- this is true for all Zw* calls :

      - for user-mode programs, either of these two can be used interchangeably

-- each refers to the same entry point in ntdll.dll

      - for kernel-mode programs, these are linked against ntoskrnl.exe,
not against ntdll.dll; so the different forms (NtXxx and ZwXxx)
refer to different entry points

ZwXxx : contains copy of the code from ntdll.dll

  - reenters the kernel, uses the system service dispatcher

  - system service dispatcher sets previous mode to be kernel mode

  - then when the actual code of the system service is exec'd,
    much of the preamble is skipped

  - b/c preamble code includes privilege checks etc which will
    succeed regardless of ACLs on any object since previous mode
    == kernel mode
       
        NtXxx : results depend on the previous mode

  - kernel mode code has little control over what previous mode is here
 
  - if service has any params that are pointers and these pointers
            point to automatic or static vars in the kernel mode program
    then if previous mode is user mode then call will fail

- some fraction of native API calls are defined in <ntddk.h>

   - and in general user code can access ntdll functions directly (though
     the official documentation on these is sparse)

- Trapping to kernel-mode ( x86 ):

   - there is no mode of x86 cpu called "kernel-mode"

     - contrast : Motorola 68000 which has a flag in a status regiter that tells
       the cpu if it is currently exec'ing in user-mode or supervisor-mode

     - for x86 : the privilege level of the code segment that is currently
       executing determinies the privilege level of the executing program

- the kernel finds the addy of the service (function) to handle the call
   by looking at the executing thread's Thread Environment Block (TEB)

   - this contains a thread's registers, priority level, a pointer to its
     process, and a pointer to the thread's Service Table List

- The Service Table List contains a pointer to a table that contains the
   addresses of all kernel services

   -- so Service Table List is a data structure, contains :

      - a pointer to the NTOSKRNL call table
      - the # of NTOSKRNL syscalls
      - a pointer to the NTOSKRNL arg table
      - a pointer to the win32k call table
      - the # of win32k syscalls
      - a pointer to the win32k arg table

- the appropriate address is determined via returning the entry in that
   table at the location specified by eax * 4 (each entry is 4 bytes long)

   -- kernel's system call trap handler does this (& makes sure sys call #
      is a valid one -- i.e. is within the range covered by this table)

- there is a parallel table which contains the size of each function's
   arguments in bytes

- win32 (api) "system calls" have "system call numbers" that start at
   0x1000 whereas kernel system call numbers start at 0

- kernel's system call trap handler then gets the address of the service
   it must call

- then kernel's system call trap handler reads how many bytes are
   required by this function's arguments -- this will be what that handler
   pushes onto its stack from the caller's stack as it calls the service

- Some weirdness clarification : each thread could potentially point to a
   unique Service Table List ... however all such lists actually point to
   global (shared) service and argument-length tables

   ==> so if can change an entry in either the ntoskrnl or win32k
       service tables (to make such point to a hook routine) : will cause
       all threads to use these new <altered> addresses & thus our routines

++++++++++++++++++++++++++++
Actually hooking the calls :
++++++++++++++++++++++++++++
Unlike for the Win '9x kernel, NT doesn't provide a service-hooking function

So must write NT-version-dependent code to achieve this functionality

NT versions vary in two relevant parameters :

(1) the offset in the TEB where the Service Table List pointer lives

(2) the system call numbers that identify services

UPDATED knowledge : re (1)

- KeServiceDescriptorTable is a symbol exported by ntoskrnl.exe

- so can load ntoskrnl.exe into memory

- then search its export table for that symbol to get the table's offset address (RVA)

- to get the physical addy from the offset addy, get the kernel's base address

- then from that eventually get the System Service Dispatch Table (SSDT)
   which is equivalent to what we call the NTOSKRNL Service Table above
   and the System Service Parameter Table (SSPT) is equivalent to what we
   call the NTOSKRNL Argument Table above (contains lengths of args to fxns).

+ anyway, code can be written to accomplish this regardless of the NT version

   - which was not the case for original implementation which required
     using a fixed offset to manually index into the TEB

     - where that offset varied (and still does) by version

     - as does the location of the KeServiceDescriptorTable

===================================
More in-depth & current description
===================================
"Windows NT Native API" : set of system services provided by the kernel to
  both the user and the kernel

- the address for each function which is part of this native API can be
   found in the SSDT; the length of the args for each such function can be
   found in the SSPT

   -- both tables are indexed by system call # times a constant, which for
      the SSDT is 4 and for the SSPT is 1

- KeServiceDescriptorTable : exported by ntoskrnl.exe

   -- contains a pointer to each of: SSDT, SSPT

   -- is equivalent to the "Service Table List" from above

- to call a specific function, the system service dispatcher (previously
   referred to as the "kernel's system call trap handler") -- which is
   called KiSystemService -- takes value in EAX and multiplies it by four
   to get the index into the SSDT and takes the value in EAX and uses that
   to index into the SSPT

- KiSystemService *acts* when int 2eh or SYSENTER is executed

- an application can call KiSystemService directly

- once you get your code loaded as a (kernel) device driver (described elsewhere),
   your code can change the SSDT to point to a function it provides
   instead of into NTOSKRNL.exe or WIN32K.SYS

- when non-kernel code calls into the kernel, the request is processed by
   KiSystemService which uses the altered SSDT

+++++++++++++++++++++++++++++++
Obtaining a pointer to the SSDT
+++++++++++++++++++++++++++++++

typedef struct ServiceDescriptorTable {
    SDE ServiceDescriptor[4];
} SDT;

typedef struct ServiceDescriptorEntry {
    PDWORD KiServiceTable;
    PDWORD CounterBaseTable;
    DWORD ServiceLimit;
    PBYTE ArgumentTable;
} SDE;

ServiceDescriptor[0].KiServiceTable : contains pointer to SSDT of system
       services implemented by ntoskrnl.exe

Now if the syscall # for NtWriteFile is 0xed (as it is for win 2k; it's
0xc8 for NT and 0x0112 for XP and 0x011c for win 2003 server), then the
DWORD value at KiServiceTable[0xed] is a function pointer to NtWriteFile

---------------------------------------------------
Determining the physical memory address of the SSDT
---------------------------------------------------
Recall that the KeServiceDescriptorTable has a KiServiceTable member,
which contains the address of the SSDT.

So first we'll look for the KeServiceDescriptorTable

But its address in mem varies across versions of the OS

But the KeServiceDescriptorTable is a symbol exported by ntoskrnl.exe

So strategy is to load ntoskrnl.exe into memory then search for that
symbol in ntoskrnl.exe's export table : this will give us the offset
address (RVA) of that symbol.

So to convert that to a physical memory address, we must first know the
kernel's (ntoskrnl.exe's) base address "in protected-mode virtual memory"

- call ZwQuerySystemInformation with SystemModuleInformation as 1st param

PhysMemAddyKeSvcDescrTbl = KernelVirtualBaseAddress + Offset (from above)
   - 0x8000000

  -- where that 0x80000000 comes from above

  [x86 : kernel mem resides in region of mem 0x8000000 and above]

So then we map the physical memory page containing the
KeServiceDescriptorTable into the userland process's virtual memory
[see below]

- then we get the address of the SSDT via

   KeServiceDescriptorTable[0].KiServiceTable

- then we have to convert that address to a physical memory address

PhysMemAddySSDT = VirtualMemAddyServiceTable - 0x80000000

==============================
Modifying SSDT from user space [Chew Keong Tan, SIG^2]
==============================
- write directly to kernel memory using /device/physicalmemory

- assumes program running with administrator privilege

   (1) use NtOpenSection (exported by ntdll.dll) with access flags
       SECTION_MAP_READ | SECTION_MAP_WRITE to get a handle to /device/physicalmemory

       - will usually fail since administrator doesn't have
         SECTION_MAP_WRITE privileges on /device/physicalmemory

   (2) use NtOpenSection with access flags READ_CONTROL | WRITE_DAC to get
       a handle to /device/physicalmemory

       - allows a new DACL to be added to the /device/physicalmemory
         object

   (3) add a DACL to /device/physicalmemory granting SECTION_MAP_WRITE
       access to the administrator account

   (4) repeat step (1)

  - so now user-space prog should have a handle to /device/physicalmemory

  - to write to physical memory, must map the physical memory page into
    its virtual address space

    -- use NtMapViewOfSection

    ntStatus = NtMapViewOfSection(
        hPhysMem,        // handle to /device/physicalmemory
(HANDLE)-1, //
virtualAddr, // OUT : virt mem where phys mem mapped to
0, //
*length, //
&viewBase, // IN/OUT : phys mem addy to map in
length, // IN/OUT : size of mapped phys mem
ViewShare, //
0, //
PAGE_READWRITE   // map for read/write access
       );

  - after mapping the physical memory pages into its virtual memory space,
    the user-space program can read and write to those pages like any other
    allocated memory

--------------------
Overwriting the SSDT
--------------------
Recall that the SSDT lives in kernel memory

- this is why our hooker must be a kernel device driver

- then we're running in kernel mode and thus can modify the SSDT, theoretically

However, the SSDT may be read-only which decreases the effect of our
kernel-mode existence on ability to write to the SSDT; in this case we
have to do some funny stuff in order to be able to write to the SSDT

[NB: if attempt to write to read-only mem, get blue screen of death]

(1) modify CR0 register to bypass memory protections (pgs. 66-7,
     "Rootkits: Subverting...")

  - control register zero (cr0)

    -- contains bits which control how the processor behaves

    -- modify cr0 to disable memory-access protection in the kernel

  - has write-protect bit : controls whether processor will allow writes
    to memory pages marked as read-only

    -- set to zero disables memory protection (hey, is this what we do
       when we create a REG_DWORD value in

       HKLM/System/CurrentControlSet/Control/SessionManager/Memory Management

       called "EnforceWriteProtection" which has value 0?

  - assembly code to achieve this

(2) using an MDL

  - you can describe a region of memory with a Memory Descriptor List (MDL)

  - MDL : contains start addy, owning process, # of bytes, and flags for
  that memory region

  // <ntddk.h>, <wdm.h>       
  typedef struct _MDL {
  
      struct _MDL *Next;
      CSHORT Size;
      CSHORT MdlFlags;
      struct _EPROCESS *Process;  // owning process
      PVOID MappedSystemVa;
      PVOID StartVa;
      ULONG ByteCount;
      ULONG ByteOffset;

   } MDL, *PMDL;

  - so we'll want to change the flags in order to be able to write to the SSDT

  ***********************************************************************************
  #pragma pack(1)
  typedef struct ServiceDescriptorEntry {
     unsigned int *ServiceTableBase;
     unsigned int *ServiceCounterTableBase;
     unsigned int NumberOfServices;
     unsigned char *ParamTableBase;
  } SSDT_Entry;
  #pragma pack()

  __declspec( dllimport ) SSDT_Entry KeServiceDescriptorTable;

  PMDL g_pmdlSystemCall;

  PVOID *MappedSystemCallTable;

  // obtain value for KeServiceDescriptorTable.ServiceTableBase and
  // obtain value for KeServiceDescriptorTable.NumberOfServices

  // save old sys call locations

  // map the SSDT into userland
  g_pmdlSystemCall = MmCreateMdl( NULL,
  KeServiceDescriptorTable.ServiceTableBase,
  KeServiceDescriptorTable.NumberOfServices );

    // 1st arg : IN memory descriptor list
    // 2nd arg : IN base (PVOID) --> think this becomes PVOID StartVa
    // 3rd arg : IN length (SIZE_T) --> think this becomes CSHORT Size

    // See also : IoAllocateMdl(...)

  if ( !g_pmdlSystemCall )
     return STATUS_UNSUCCESSFUL;

  // updates g_pmdlSystemCall MDL;
  // given the starting virtual address (ServiceTableBase) and its size,
  // figure out the corresponding physical pages' address, ByteCount, etc.
  MmBuildMdlForNonPagedPool( g_pmdlSystemCall );

  // change permissions on the MDL : will allow you to write to this mem region
  g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

  // locks desired pages (the MDL pages)
  // maps the physical pages described by g_pmdlSystemCall
  // using access mode == KernelMode
  // returns : starting address of the mapped pages
  MappedSystemCallTable = MmMapLockedPages( g_pmdlSystemCall, KernelMode );

  // now change addresses in KeServiceDescriptorTable to what you want...

  // MappedSystemCallTable : same address as original SSDT but now writable.
  ***********************************************************************************

  Taking a step back : what did we just do?

   (1) imposed a description onto a region of memory

    - where that region contains our SSDT

   (2) change a property of that description so that we could write to
       that region

----------------
Actually hooking
----------------
Both of the following two #defines work because all Zw* functions
exported by NTOSKRNL.exe start with :

   mov eax, ULONG // where ULONG is the index # of the syscall in th SSDT

   --> so look at the second byte of any Zw* function in order to get its
       syscall # (clever! see Hoglund/Butler)

// takes addy of a Zw* function and returns the index # of its Nt* in the SSDT
#define SYSTEMSERVICE( _func ) /
    KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR) _func + 1) ]

// takes addy of a Zw* function and returns its index in the SSDT
#define SYSCALL_INDEX( _Function ) *(PULONG)((PUCHAR) _Function + 1)

// take the address of a Zw* function, get its index, exchange the addy
// at that index in the SSDT with the addy of _Hook
// write the original Zw* function address to _Orig (used for restoration later)
#define HOOK_SYSCALL( _Function, _Hook, _Orig ) /
     _Orig = (PVOID) InterlockedExchange( /
               (PLONG) &MappedSystemCallTable[ SYSCALL_INDEX( _Function )], /
       (LONG)  _Hook )

//
// not sure why this takes _Hook as an argument?
//
#define UNHOOK_SYSCALL( _Func, _Hook, _Orig ) /
     InterlockedExchange( (PLONG) &MappedSystemCallTable[ SYSCALL_INDEX( _Func ) ], /
  (LONG)  _Orig )

============
References :
============

(1) Windows NT System Call Hooking

http://www.ddj.com/documents/s=945/ddj9701e/

(2) Windows System Call Table (NT/2k/XP/2003)

http://www.metasploit.com/users/opcode/syscalls.html

(3) Windows NT/2000 Native API Reference (Gary Nebbett)

(4) How Do Windows NT System Calls REALLY Work? (John Gulbrandsen)

http://www.codeguru.com/Cpp/W-P/system/devicedriverdevelopment/article.php/c8035/

(5) Defeating Kernel Native-API hookers via SSDT Restoration

http://www.security.org.sg/code/SIG2_DefeatingNativeAPIHookers.pdf

(6) Rootkits: Subverting the Windows Kernel (Hoglund/Butler)
Windows下OpenMBEE项目MMS部署失败经历及改正 在Github里找到了上面的第一份文档,下载了MMS源代码(不知道为什么这个代码跟上面操作克隆得到的MMS代码不一样?好像是因为Gradle的版本问题,我本地之前已经安装过7.6.4的Gradle了,于是我找到gradle-wrapper.properties文件。后面在VScode中运行了一下依然是报这个错误,我在VScode终端直接执行。不知道为什么依然没什么用。打开“Windows PowerShell”。(如果是第一次运行它,将看到更长的输出)导航到要克隆存储库的文件夹,例如, 阅读详情

相关推荐

从Cartographer3D到LIO-SAM:主流3D激光SLAM算法怎么选?一份给机器人工程师的实战避坑指南

本文深入探讨了从Cartographer3D到LIO-SAM等主流3D激光SLAM算法的选型策略,为机器人工程师提供实战避坑指南。通过对比不同算法在传感器配置、环境特性和计算资源等方面的表现,帮助开发者根据项目需求选择最优方案,并分享传感器标定、资源优化等实用技巧。

weixin_27310985的博客 155

Nt vs. Zw - Clearing Confusion On The Native API

The NT native API is nothing new. It’s been discussed ad nauseum, it’s been exploited by umpteen different utilities, and portions of it have even migrated into the realm of the fully documented and s

yebikangfu的专栏 1191

Qwen3.5在昇腾910B上的vLLM Ascend高性能部署实战

大语言模型推理优化是AI工程落地的核心环节,其本质是计算、内存与通信三者的协同调度。vLLM作为主流推理框架,通过PagedAttention和Continuous Batching显著提升GPU利用率;而昇腾NPU凭借高带宽HBM与专用AI算子,在国产化算力平台中展现出独特优势。当vLLM深度适配昇腾(即vLLM Ascend),不仅保留动态批处理、流式输出等关键能力,更实现KV Cache的HBM感知管理与HCCL直通优化,使中小尺寸模型(如Qwen3.5-35B)在单台Atlas A3服务器上达成百并

weixin_30558697的博客 439

NT kernel structures(xp_sp3) xp sp3未文档化结构体

The following source code can be very useful when you are debuging kernel & user objects under either ring0 or ring3 within Windows XP sp3. (note: you'd better verify it using dt -b !ntXXX within win

lixiangminghate的专栏 1771

由Sensor光谱响应曲线联想到的白平衡增益计算

由Sensor光谱响应曲线联想到的白平衡增益计算 由于传感器硬件的限制,传感器在某个预定波长范围内的响应不可能是100% 响应。现实中都是类似于正态分布的单峰函数。如果仅做粗略计算,由一个中心波长和半高宽(也成半波宽)完全可以由数学公式计算出一个高斯分布曲线。这个分布曲线就叫波谱响应函数。 波谱响应函数反映了传感器通道获取能量的情况。实际上每个传感器厂商都提供了具体的光谱响应函数,一般由两列数据组成,一列数据是波长,另一列数据是相对响应强度。下图某sensor光谱的响应的波谱响应函数。 ...

大熊 7492

PowerPMAC配置EtherCAT设备

本文详细介绍了在PowerPMAC IDE环境下配置EtherCAT伺服电机的完整流程。主要内容包括:准备工作(连接硬件和获取ESI文件)、通过ESI管理器加载配置文件、网络扫描识别从站设备、变量映射(定义输入输出位置参数)、激活EtherCAT通讯(验证状态字和实际位置)以及相关参数说明。文章还概述了主站配置的8个方面和从站配置的7个选项,重点说明了PDO映射和变量分配机制,为伺服电机的EtherCAT通信配置提供了系统指导。

mahuliang321的博客 980

【Windows笔记】-----任务管理器发现 NT Kernel & System 进程占用CPU很高

两个月前win10更新之后就发现系统用起来没以前流畅了,后来也没怎么去优化。 电脑也没装游戏之类的软件件,但这两天突然发现电脑管家老显示CPU占用95%以上,内存占用86%以上(总内存12G),情况不对呀。 问题所在: 系统更新后会出现一些软件执行出现问题,造成占用较高的内存导致电脑变慢 本次问题是因为我打开的Microsoft.Photos.exe占用特别高的内存,将其kill之后,电脑管...

weixin_42611900的博客 3万+

2025年华为杯中国研究生数学建模竞赛E题 高速列车轴承智能故障诊断问题 思路+代码

all_data, file_info = preprocessor.load_mat_files(file_list[:50]) # 加载前50个文件作为示例。[y_source, y_source, domain_labels], # 注意:这里使用伪标签。X_target = np.random.randn(100, X_source.shape[1], 1) # 示例数据。"""构建CNN-Transformer混合模型""""""构建Transformer模型"""

YOLO 1047

windows下的内联hook实现

HOOK技术正如其名,就像是代码中放下的一个“钩子”,它在静静地等待捕获系统中的某个消息或动作。在编程技术中,钩子技术在DOS时代就已经存在了。在windows下,钩子按照实现技术的不同和挂钩位置的不同,其种类也是越来越多,但是设置钩子的本质却是始终不变的。 那么钩子究竟有什么用?它能干的事非常多,例如输入监控、API拦截、消息捕获、改变程序执行流程等。杀毒软件会用HOOK技术钩住一些API函数

其疾如风 其徐如林 侵略如火 不动如山 6704

在WIN10系统中安装TIA博途V18,重启后提示安装介质不可用,请插入DVD 或检查网络连接的解决办法

在WIN10系统中安装TIA博途V18,重启后提示安装介质不可用,请插入DVD 或检查网络连接的解决办法

Robot_PLC_HMI_Automation 1万+

AWR1843+DCA1000通过mmwave studio采集数据遇到的问题及解决方法

确保DCA1000的拨钮拨在了RADAR_5V_IN一边,这代表DCA1000通过与其相连的雷达板子供电,如果拨到了DC_JACK5V_IN一边,表示DCA1000用单独的电源供电。

qq_50974341的博客 4165

windows 7 x64 下的 System Call

很自然地 windows 7 x64 版本会使用 processor 提供的 syscall/sysret 指令来构造一个快速的调用系统服务例程机制。 ntdll!NtCreateDebugObject: 00000000`76d70680 4c8bd1          mov     r10,rcx 00000000`76d70683 b890000000      mov 

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 5718

YOLOv13改进策略【YOLO和Mamba】| 替换骨干 Mamba-YOLOv13-T !!! 最新的发文热点

模块是模型中的一个重要组成部分,其主要作用是在模型的初始阶段对输入图像进行处理,方便后续的特征提取和目标检测。以下是对。

Limiiiing的博客 356

syscall指令_[原创]简析syscall,sysret和sysenter,sysexit的具体过程

这里我以windows系统为例子,在其他系统实现方式是一样的.我们都知道xp系统是通过int 2E中断从用户态进入内核态的.,但xp系统之后windows都是通过系统快速调用从用户态进入内核态的.系统快速调用有两种:sysenter/sysexitsyscall/sysret前置知识MSRMSR(Model-Specific Register) 是一类寄存器,这类寄存器数量庞大,并且和处理器的mo...

weixin_39627408的博客 2656

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Windows NT System-Call Hooking (Dr. Dobb's Journal)

---------------------------------------------------------------------Notes from "Windows NT System-Call Hooking" (Dr. Dobbs Journal, 97)----------------------------------------------------------

2073

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Python+Agent入门笔记(六):记忆和状态,从“一次性问答”到“能用助手”

滑动窗口的缺点很明显:被扔掉的信息就真没了。如果用户第一轮说“我不吃辣”,隔了二十轮让他推荐餐厅,模型已经忘了。定期把旧的对话压缩成一段总结,作为一条特殊的消息插进去。"""把除 system 和最近 keep_recent 条以外的消息,压缩成一条摘要。返回新的 messages 列表。"""# 把旧消息拼成纯文本,让模型总结content = f"[工具结果]把除 system 和最近 keep_recent 条以外的消息,压缩成一条摘要。返回新的 messages 列表。

qq_41241612的博客 113

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

循环嵌套(多层 for 循环)

表:order(订单表,order_id, user_id)、user(用户表,user_id, user_name)✅ 优化:先查所有订单,拿到所有 user_id 批量 in 查询,内存 join。✅ 优化:先把优惠券转 HashMap,单层循环查找(hash 查找 O (1))SQL 只有 2 次,O (1) 数据库查询,内存遍历 O (n)。需求:查询所有订单列表,同时带出每个订单对应的用户名称。需求:订单列表、优惠券列表,把订单匹配对应的优惠券名称。复杂度:O (M+N),非常快。

weixin_43732943的博客 222

【数据结构-5】单链表的实现

单链表,具体来说是单向的、不带头的、不循环的链表。链表由一个一个节点组成,每个节点分为数据域和指针域,数据域存放数据,指针域存放下一节点的地址。这样,就可以根据指针域中的地址找到下一个节点,节点就串起来了构成了单链表。

a bit 217

C++ 入门笔记(十七):list 入门 —— 为什么 list 不能 sort?

第17课:用大白话讲清 list 的双向链表结构、哨兵头、push_back 四步、迭代器封装、merge 与 splice 的区别,以及 vector 排序为什么常比 list 快。

wo_jack的博客 259

C# 数据结构和特殊类型

.NET Core(现称.NET)提供丰富数据结构,优化性能与开发效率。日常开发首选List<T>和Dictionary<TKey,TValue>;高性能场景推荐Span<T>与Memory<T>减少内存分配;并发环境使用ConcurrentDictionary等线程安全集合;避免非泛型集合如ArrayList。

cccloveforever的博客 751

list

的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。迭代到该位置,在这段位置上迭代需要线性的时间开销;最大的缺陷是不支持任意位置的随机访问,比如:要访问。还需要一些额外的空间,以保存每个节点的相关联信息。个元素,必须从已知的位置。

xie0510_的博客 295

软件商店常见问题标准处理流程

从底层软件源来看,/etc/apt/sources.list配置错误、源地址失效、公网与内网离线源混用、ARM64与x86_64架构源串用,以及DNS解析异常、系统代理配置错误,都会导致商店无法获取应用数据;打开该应用,确认可正常运行;软件商店作为系统内置的图形化软件分发与安装入口(UKUI桌面配套组件,底层依赖APT软件源),承担着应用软件的浏览、搜索、下载、安装、升级与卸载等核心功能,是终端软件部署与管理的关键通道。覆盖软件商店启动、页面加载、应用下载、安装、卸载、搜索、自身更新等全部业务场景。

qq_39496637的博客 308

【AI 开发从入门到进阶 · 10】收官篇:LoRA 微调、模型评估、推理加速与生产部署全链路

本文系统梳理了大模型微调与生产落地的全流程,从决策是否微调、优选LoRA技术方案,到代码实现、效果评估、推理加速与FastAPI服务封装,最终构建可迭代的生产级AI系统。强调“逐级升级”原则,倡导以数据闭环驱动优化,避免技术冲动。全系列贯穿工程化思维,提供可复用模板与实战建议,助力开发者从模型训练迈向稳定可用的AI服务部署。

信息安全领域优质创作者|操作系统领域专家 132
上一篇: 如何优雅地关闭一个socket
下一篇: 怎样在内存缓冲中画图
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值