GREPEXEC: Grepping Executive Objects from Pool Memory
bugcheck
chris@bugcheck.org
1) Foreword
Abstract:
As rootkits continue to evolve and become more advanced, methods that can be
used to detect hidden objects must also evolve. For example, relying on system
provided APIs to enumerate maintained lists is no longer enough to provide
effective cross-view detection. To that point, scanning virtual memory for
object signatures has been shown to provide useful, but limited, results. The
following paper outlines the theory and practice behind scanning memory for
hidden objects. This method relies upon the ability to safely reference the
Windows system virtual address space and also depends upon the building and
locating effective memory signatures. Using this method as a base, suggestions
are made as to what actions might be performed once objects are detected. The
paper also provides a simple example of how object-independent signatures can be
built and used to detect several different kernel objects on all versions of
Windows NT+. Due to time constraints, the source code associated with this
paper will be made publicly available in the near future.
Thanks:
Thanks to skape, Peter, and the rest of the uninformed hooligans;
you guys and gals rock!
Disclaimer:
The author is not responsible for how the papers contents are used
or interpreted. Some information may be inaccurate or incorrect. If
the reader feels any information is incorrect or has not been
properly credited please contact the author so corrections can be
made. All content refers to the Windows XP Service Pack 2
platform unless otherwise noted.
2) Introduction
As rootkits become increasingly popular and more sophisticated than
ever before, detection methods must also evolve. While rootkit
technologies have evolved beyond API hooking methods, detectors have
also evolved beyond the hook detection ages. At first
rootkits such as FU were detected using various methods
which exploited its weak and proof-of-concept design by applications
such as Blacklight. These specific weaknesses were
addressed in FUTo. However, some still remain excluding
the topic of this paper.
RAIDE, a rootkit detection tool, uses a memory
signature scanning method in order to find EPROCESS blocks hidden by
FUTo. This specific implementation works, however, it too has its
weaknesses. This paper attempts to outline the general concepts of
implementing a successful rootkit detection method using memory
signatures.
The following chapters will discuss how to safely enumerate system
memory, what to look for when building a memory signature, what to
do once a memory signature has been found, and potential methods of
breaking memory signatures. Finally, an accompanying tool will be used
to concretely illustrate the subject of this paper.
After reading the following paper, the reader should have an
understanding of the concepts and issues related to kernel object
detection using memory signatures. The author believes this to be an
acceptable method of rootkit detection. However, as with most things
in the security realm, no one technique is the ultimate solution and
this technique should only be considered complimentary to other known
detection methods.
3) Scanning Memory
Enumerating arbitrary system memory is nowhere near a science since
its state can change at anytime while you are attempting to access
it. While this is true, the memory that surrounds kernel executive
objects should be fairly consistent. With proper care, memory accesses
should be safe and the chance of false positives and negatives should be
fairly minimal. The following sections will outline a safe method to
enumerate the contents of both the system's PagedPool and
NonPagedPool.
3.1) Retrieving Pool Ranges
For the purpose of enumerating pool memory it is unnecessary to
enumerate the entire system address space. The system maintains a
few global variables such as nt!MmPagedPoolStart,
nt!MmPagedPoolEnd and related NonPagedPool
variables that can be used in order to speed up a search and reduce
the possibility of unnecessary false positives. Although these
global variables are not exported, there are a couple ways in that
they can be obtained.
The most reliable method on modern systems (Windows XP Service Pack 2
and up) is through the use of the KPCR->KdVersionBlock pointer located
at fs:[0x34]. This points to a KDDEBUGGER_DATA64 structure which is
defined in the Debugging Tools For Windows SDK header file wdbgexts.h.
This structure is commonly used by malicious software in order to gain
access to non-exported global variables to manipulate the system.
A second method to obtain PagedPool values is to reference the
per-session nt!_MM_SESSION_SPACE found at EPROCESS->Session. This contains
information about the session owning the process, including its ranges
and many other PagedPool related values shown here.
kd> dt nt!_MM_SESSION_SPACE
+0x01c NonPagedPoolBytes : Uint4B
+0x020 PagedPoolBytes : Uint4B
+0x024 NonPagedPoolAllocations : Uint4B
+0x028 PagedPoolAllocations : Uint4B
+0x044 PagedPoolMutex : _FAST_MUTEX
+0x064 PagedPoolStart : Ptr32 Void
+0x068 PagedPoolEnd : Ptr32 Void
+0x06c PagedPoolBasePde : Ptr32 _MMPTE
+0x070 PagedPoolInfo : _MM_PAGED_POOL_INFO
+0x244 PagedPool : _POOL_DESCRIPTOR
While enumerating the entire system address space is not preferable, it
can still be used in situations where pool information cannot be
obtained. The start of the system address space can be assumed to be
any address above nt!MmHighestUserAddress. However, it would appear
that an even safer assumption would be the address following the
LARGE_PAGE where ntoskrnl.exe and hal.dll are mapped. This can be
obtained by using any address exported by hal.dll and rounding up to the
nearest large page.
3.2) Locking Memory
When accessing arbitrary memory locations, it is important that pages be
locked in memory prior to accessing them. This is done to ensure that
accessing the page can be done safely and will not cause an exception
due to a race condition, such as if it were to be de-allocated between a
check and a reference. The system provides a routine to lock pages
named nt!MmProbeAndLockPages. This routine can be used to lock either
pagable or non-paged memory. Since physical pages maintain a reference
count in the nt!MmPfnDatabase there is no worry of an outside source
unlocking the pages and having them page out to disk or become invalid.
In order to use MmProbeAndLockPages, a caller must first build an MDL
structure using something such as nt!IoAllocateMdl or
nt!MmInitializeMdl. The MDL creation routines are passed a virtual
address and length describing the block of virtual memory to be
referenced. On a successful call to nt!MmProbeAndLockPages, the virtual
address range described by the MDL structure is safe to access. Once the
block is no longer needed to be accessed, the pages must be unlocked
using nt!MmUnlockPages.
A trick can be used to further reduce the number of pages locked when
enumerating the NonPagedPool. As documented, MmProbeAndLockPages can be
called at DISPATCH_LEVEL with the limitation of it only being allowed to
lock resident memory pages and failing otherwise, which is a desirable
side-effect in this case.
4) Detecting Executive Objects
In general, all of the executive components of the NT kernel rely on the
object manager in order to manage the objects they allocate. All objects
allocated by the object manager have a common header named OBJECT_HEADER
and additional optional headers such as OBJECT_HEADER_NAME_INFO, process
quota information, and handle trace information. Let's take a look to
see what is common to all executive objects and how we can use the pool
block header information to identify an allocated executive object.
Lastly, some object specific information will be discussed in terms of
generating a useful memory signature for an object.
4.1) Generic Object Information
Since the OBJECT_HEADER is common to all objects, let's look at it in
detail. A static field here refers to all objects of specific type, not
all executive objects in the system.
kd> dt _OBJECT_HEADER
+0x000 PointerCount : Int4B
+0x004 HandleCount : Int4B
+0x004 NextToFree : Ptr32 Void
+0x008 Type : Ptr32 _OBJECT_TYPE
+0x00c NameInfoOffset : UChar
+0x00d HandleInfoOffset : UChar
+0x00e QuotaInfoOffset : UChar
+0x00f Flags : UChar
+0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : Ptr32 Void
+0x014 SecurityDescriptor : Ptr32 Void
+0x018 Body : _QUAD
-------------------+------------+-------------------------------------
PointerCount | Variable | of references
HandleCount | Variable | of open handles
NextToFree | NotValid | Used when freed
Type | Static | Pointer to OBJECTTYPE
NameInfoOffset | Static | 0 or offset to related header
HandleInfoOffset | Static | 0 or offset to related header
QuotaInfoOffset | Static | 0 or offset to related header
Flags | NotCertain | Not certain
ObjectCreateInfo | Variable | Pointer to OBJECTCREATEINFORMATION
QuotaBlockCharged | NotCertain | Not certain
SecurityDescriptor | Variable | Pointer to SECURITYDESCRIPTOR
Body | NotValid | Union with the actual object
-------------------+------------+-------------------------------------
From this it is assumed that the most reliable and unique signature is
the Type field of the OBJECT_HEADER which could be used in order to
identify objects of a specific type such as EPROCESS, ETHREAD,
DRIVER_OBJECT, and DEVICE_OBJECT objects.
4.2) Validating Pool Block Information
Kernel pool management appears to be slightly different from usermode
heap management. However, if one assumes that the only concern is
dealing with pool memory allocations which are less then PAGE_SIZE, it is
fairly similar. Each call to ExAllocatePoolWithTag() returns a
pre-buffer header as follows:
kd> dt _POOL_HEADER
+0x000 PreviousSize : Pos 0, 9 Bits
+0x000 PoolIndex : Pos 9, 7 Bits
+0x002 BlockSize : Pos 0, 9 Bits
+0x002 PoolType : Pos 9, 7 Bits
+0x000 Ulong1 : Uint4B
+0x004 ProcessBilled : Ptr32 _EPROCESS
+0x004 PoolTag : Uint4B
+0x004 AllocatorBackTraceIndex : Uint2B
+0x006 PoolTagHash : Uint2B
For the purposes of locating objects, the following is a breakdown of
what could be useful. Again, static refers to fields common between similar
executive objects and not all allocated POOL_HEADER structures.
------------------------+------------+----------------------------------
PreviousSize | Variable | Offset to previous pool block
PoolIndex | NotCertain | Not certain
BlockSize | Static | Size of pool block
PoolType | Static | POOL_TYPE
Ulong1 | Union | Padding, not valid
ProcessBilled | Variable | Allocator EPROCESS when no Tag specified
PoolTag | Static | Pool Tag (ULONG)
AllocatorBackTraceIndex | NotCertain | Not certain
PoolTagHash | NotCertain | Not certain
------------------------+------------+----------------------------------
The POOL_HEADER contains several fields that appear to be common to similar
objects which could be used to further verify the likelihood of
locating an object of a specific type such as BlockSize, PoolType, and
PoolTag.
In addition to the mentioned static fields, two other fields,
PreviousSize and BlockSize, can be used to validate that the currently
assumed POOL_HEADER appears to be a valid, allocated pool block and is in
one of the pool managers maintained link lists. PreviousSize and
BlockSize are multiples of the minimum pool alignment which is 8 bytes
on a 32bit system and 16 bytes on a 64bit system. These two elements supply byte offsets to the
neighboring pool blocks.
If PreviousSize equals 0, the current POOL_HEADER should be the first
pool block in the pool's contiguous allocations. If it is not, it
should be the same as the previous POOL_HEADERs BlockSize. The
BlockSize should never equal 0 and should always be the same as the
proceeding POOL_HEADERs PreviousSize.
The following code validates a POOL_HEADER of an allocated pool block.
//
// Assumes BlockOffset < PAGE_SIZE
// ASSERTS Flink == Flink->Blink && Blink == Blink->Flink
//
BOOLEAN ValidatePoolBlock (
IN PPOOL_HEADER pPoolHdr,
IN VALIDATE_ADDR pValidator
) {
BOOLEAN bReturn = FALSE;
PPOOL_HEADER pPrev;
PPOOL_HEADER pNext;
pPrev = (PPOOL_HEADER)((PUCHAR)pPoolHdr
- (pPoolHdr->PreviousSize * sizeof(POOL_HEADER)));
pNext = (PPOOL_HEADER)((PUCHAR)pPoolHdr
+ (pPoolHdr->BlockSize * sizeof(POOL_HEADER)));
if
((
( pPoolHdr == pNext )
||( pValidator( pNext + sizeof(POOL_HEADER) - 1 )
&& pPoolHdr->BlockSize == pNext->PreviousSize )
)
&&
(
( pPoolHdr != pPrev )
||( pValidator( pPrev )
&& pPoolHdr->PreviousSize == pPrev->BlockSize )
))
{
bReturn = TRUE;
}
return bReturn;
}
4.3) Object Specific Signatures
So far a few useful signatures have been shown which apply to all
executive objects and could be used to identify them in memory. For some
cases these may be enough to be effective. However, in other cases, it
may be necessary to examine information within the object's body itself
in order to identify them. It should be noted that some objects of
interest may be clearly defined and documented while others may not be.
Furthermore, executive object definitions may vary between OS versions.
The following subsections briefly outline obvious memory signatures for
a few objects which generally are of interest when identifying
rootkit-like behavior. A few examples of object-specific signatures
will also be discussed, some of which have been used in previous work.
4.3.1) Process Objects
Here are just a few of the most basic EPROCESS fields which can form a
simple signature using rather predictable constant values which hold
true for all EPROCESS structures in the same system.
-----------------------------+------------------------------------------
Pcb.Header.Type | Dispatch header type number
Pcb.Header.Size | Size of dispatcher object
Pcb.Affinity | CPU affinity bit mask, typically CPU in system
Pcb.BasePriority | Typically the default of 8
Pcb.ThreadQuantum | Workstations is typically 18
ExitTime | 0 for running processes
UniqueProcessId | 0 if bitwise AND with 0xFFFF0002
SectionBaseAddress | Typically 0x00400000 for non-system executables
InheritedFromUniqueProcessId | Same as UniqueProcessId, typically a valid running pid
Session | Unique on a per-session basis
ImageFileName | Printable ASCII, typically ending in '.exe'
Peb | 0x7FF00000 if bitwise AND with 0xFFF00FFF
SubSystemVersion | XP Service Pack 2 is 0x400
-----------------------------+------------------------------------------
Note that there are several other DISPATCH_HEADERs embedded within
locks, events, timers, etc in the structure which also have a predicable
Header.Type and Header.Size.
4.3.2) Thread Objects
Here are just a few of the most basic ETHREAD fields which can form a
simple signature using rather predictable constant values which hold
true for all ETHREAD structures in the same system.
------------------+------------------------------------------------------
Tcb.Header.Type | Dispatch header type number
Tcb.Header.Size | Size of dispatcher object
Teb | 0x7FF00000 if bitwise AND with 0xFFF00FFF
BasePriority | Typically the default of 8
ServiceTable | nt!KeServiceDescriptorTable(Shadow) used by RAIDE
Affinity | CPU affinity bit mask, typically CPU in system
PreviousMode | 0 or 1, which is KernelMode or UserMode
Cid.UniqueProcess | 0 if bitwise AND with 0xFFFF0002
Cid.UniqueThread | 0 if bitwise AND with 0xFFFF0002
------------------+------------------------------------------------------
Note that there are several other DISPATCH_HEADERs embedded within
locks, events, timers, etc in the structure which also have a predicable
Header.Type and Header.Size.
4.3.3) Driver Objects
A tool written previously named MODGREPPER by Joanna Rutkowska of
invisiblethings.org used a signature based approach to detect hidden
DRIVER_OBJECTs. This signature was later 'broken' by valerino described
in a rootkit.com article titled "Please don't greap me!". Listed here
are a few fields which a signature could be built upon to detect
DRIVER_OBJECTs.
--------------+-----------------------------------------------------------
Type | I/O Subsystem structure type ID, should be 4
Size | Size of the structure, should be 0x168
DeviceObject | Pointer to a valid first created device object(can be NULL)
DriverSection | Pointer to a nt!_LDR_DATA_TABLE_ENTRY structure
DriverName | A UNICODE_STRING structure containing the driver name
--------------+-----------------------------------------------------------
The following fields of the DRIVER_OBJECT can be validated by assuring
they fall within the range of a loaded driver image such that:
DriverStart < FIELD < DriverStart + DriverSize.
--------------------+----------------------------------------------------
DriverInit | Address of DriverEntry() function
DriverUnload | Address of DriverUnload() function, can be NULL
MajorFunction[0x1c] | Dispatch handlers for IRPMJXXX, can default to ntoskrnl.exe
--------------------+----------------------------------------------------
4.3.4) Device Objects
For the DEVICE_OBJECT structure there are few static
signatures which are usable. Here are the only obvious ones.
-------------+----------------------------------------------------------
Type | I/O Subsystem structure type ID, should be 3
Size | Size of the structure, should be 0xb8
DriverObject | Pointer to a valid driver object
-------------+----------------------------------------------------------
Note that the DriverObject field must be valid in order for the device
to function.
4.3.5) Miscellaneous
So far the memory signatures discussed have been fairly straightforward
and for the most part are simply a binary comparison with a specific
value. Later in this paper, a technique called N-depth pointer
validation will be discussed as a method of developing a more effective
signature in situations where pointer based memory signatures are
attempted to be evaded.
Another way of considering an object field as a signature is to validate
it in terms of its characteristics instead of by its value. A common
example of this would be to validate an object field LIST_ENTRY.
Validating a LIST_ENTRY structure can be done as follows:
Entry == Entry->Flink->Blink == Entry->Blink->Flink.
A pointer to any object or memory allocation can also be checked using
the function shown previously, named ValidatePoolBlock. Even a
UNICODE_STRING.Buffer can be validated this way provided the allocation
is less than PAGE_SIZE.
5) Found An Object, Now What?
The question of what to do after potentially identifying an executive
object through a signature depends on what the underlying goal is. For
the purpose of a the sample utility included with this paper, the goal
may be to simply display some information about the objects as it finds
them.
In the context of a rootkit detector, however, there may be many more
steps that need to be taken. For example, consider a detector looking
for EPROCESS blocks which have been unlinked from the process linked
list or a driver module hidden from the system service API. In order to
determine this, some cross-view comparisons of the raw objects detected
and the output from an API call or a list enumeration is needed.
Detectors must also take into consideration the race condition of an
object being created or destroyed in between the memory enumeration and
the acquisition of the "known to the system" data.
Additionally, it may be desired that some additional sanity checks be
performed on these objects in addition to the signature. Do the object
fields x,y,z contain valid pointers? Is field c equal to b? Does this
object appear to be valid however has signs of tampering in order to
hide it? Does the number of detected objects match up with a global
count value such as the one maintained in an OBJECT_TYPE structure? The
following sections will briefly mention some random thoughts of what to
do with a suspected object of the four types previously mentioned in
this paper in Chapter 4.
5.1) Process Objects
Here is a brief list of things to check when scanning for EPROCESS
objects.
1. Compare against a high level API such as kernel32!CreateToolhelp32Snapshot.
2. Compare against a system call such as nt!NtQuerySystemInformation.
3. Compare against the EPROCESS->ActiveProcessLinks list.
4. Does the process have a valid list of threads?
5. Can PsLookupProcessByProcessId open its
6. UniqueProcessId?
7. Is ImageFileName a valid string? zeroed? garbage?
5.2) Thread Objects
Here is a brief list of things to check when scanning for ETHREAD
objects.
1. Compare against a high level API such as kernel32!CreateToolhelp32Snapshot.
2. Compare against a system call such as nt!NtQuerySystemInformation.
3. Does the process have a valid owning process?
4. Can PsLookupThreadByThreadId open its
5. Cid.UniqueThread?
6. What does Win32StartAddress point to? Is it a valid module address?
7. What is its ServiceTable value?
8. If it is in a wait state, for how long?
9. Where is its stack? What does its stack trace look like?
5.3) Driver Objects
Here is a brief list of things to check when scanning for DRIVER_OBJECT
objects.
1. Compare against services found in the service control manager database.
2. Compare against a system call such as nt!NtQuerySystemInformation.
3. Is the object in the global system namespace?
4. Does the driver own any valid device objects?
5. Does the drive base address point to a valid MZ header?
6. Do the object's function pointer fields look correct?
7. Does DriverSection point to a valid nt!LDRDATATABLEENTRY?
8. Does DriverName or the
9. LDR_DATA_TABLE_ENTRY have valid strings? zeroed? garbage?
5.4) Device Objects
Here is a brief list of things to check when scanning for DEVICE_OBJECT
objects.
1. Is the owning driver object valid?
2. Is the device named and is it mapped into the global namespace?
3. Does it appear to be in a valid device stack?
4. Are its Type and Size fields correct?
6) Breaking Signatures
Memory signatures can be an effective method of identifying allocated
objects and can serve as a low level baseline in order to detect objects
hidden by several different methods. Although the memory signature
detection method may be effective, it doesn't come without its own set
of problems. Many signatures can be evaded using several different
techniques and non-evadable signatures for objects, if any exist, have
yet to be explored. The following sections discuss issues and counter
measures related to defeating memory signatures.
6.1) Pointer Based Signatures
Using a memory signature which is a valid pointer to some common object
or static data is a very appealing signature to use for detection due to
its reliability, however is also an easy signature to bypass. The
following demonstrates the most simplistic method of bypassing the
OBJECT_HEADER->Type signature this paper uses as a generic object memory
signature. This is possible because the OBJECT_TYPE is just an allocated
structure of fairly stable data. Many pointer based signatures with
similar static characteristics are open to the same attack.
NTSTATUS KillObjectTypeSignature (
IN PVOID Object
)
{
NTSTATUS ntStatus = STATUS_SUCESS;
PVOID pDummyObject;
POBJECT_HEADER pHdr;
pHdr = OBJECT_TO_OBJECT_HEADER( Object );
pDummyObject = ExAllocatePool( sizeof(OBJECT_TYPE) );
RtlCopyMemory( pDummyObject, pHdr->Type, sizeof(OBJECT_TYPE) );
pHdr->Type = pDummyObject;
return STATUS_SUCCESS;
}
6.2) N-Depth Pointer Validation
As demonstrated in the previous section, pointer based signatures are
effective. However, in some cases, they may be trivial to bypass. The
following code demonstrates an example which does what this paper refers
to as N-depth pointer validation in an attempt to create a more complex,
and potentially more difficult to bypass, signature using pointers. The
following example is also evadable using the same principal of
relocation shown above.
The algorithm assumes a given address is an executive object and
attempts validation by performing the following steps:
1. Calculates an assumed OBJECT_HEADER
2. Assumes pObjectHeader->Type is an OBJECT_TYPE
3. Calculates an assumed OBJECT_HEADER for the OBJECT_TYPE
4. Assumes pObjectHeader->Type is nt!ObpTypeObjectType
5. Validates pTypeObject->TypeInfo.DeleteProcedure == nt!ObpDeleteObjectType
BOOLEAN ValidateNDepthPtrSignature (
IN PVOID Address,
IN VALIDATE_ADDR pValidate
)
{
PVOID pObject;
POBJECT_TYPE pTypeObject;
POBJECT_HEADER pHdr;
pHdr = OBJECT_TO_OBJECT_HEADER( Address );
if( ! pValidate(pHdr) || ! pValidate(&pHdr->Type) ) return FALSE;
// Assume this is the OBJECT_TYPE for this assumed object
pTypeObject = pHdr->Type;
// OBJECT_TYPE's have headers too
pHdr = OBJECT_TO_OBJECT_HEADER( pTypeObject );
if( ! pValidate(pHdr) || ! pValidate(&pHdr->Type) ) return FALSE;
// OBJECT_TYPE's have an OBJECT_TYPE of nt!ObpTypeObjectType
pTypeObject = pHdr->Type;
if( ! pValidate(&pTypeObject->TypeInfo.DeleteProcedure) ) return FALSE;
// /ObjectTypes/Type has a DeleteProcedure of nt!ObpDeleteObjectType
if( pTypeObject->TypeInfo.DeleteProcedure
!= nt!ObpDeleteObjectType ) return FALSE;
return TRUE;
}
6.3) Miscellaneous
An obvious method of preventing detection from memory scanning would be
to use what is commonly referred to as the Shadow Walker memory
subversion technique. If virtual memory is unable to be read then of
course a memory scan will skip over this area of memory. In the context
of pool memory, however, this may not be an easy attack since it may
create a situation where the pool appears corrupted which could lead to
crashes or system bugchecks. Of course, attacking a function like
nt!MmProbeAndLockPages or IoAllocateMdl globally or specifically in the
import address table of the detector itself would work.
For memory signatures based on constant or predicable values it may be
feasible to either zero out or change these fields and not disturb
system operation. For example take the author's enhancements to the FUTo
rootkit where it is seen that the EPROCESS->UniqueProcessId can be
safely cleared to 0 or previously mentioned rootkit.com article titled
"Please don't greap me!" which clears DRIVER_OBJECT->DriverName and its
associated buffer in order to defeat MODGREPPER.
For the case of some pointer signatures a simple binary comparison may
not be enough to validate it. Take the above example and using
nt!ObpDeleteObjectType. This could be defeated by overwriting
pTypeObject->TypeInfo.DeleteProcedure to point to a simple jump
trampoline which is allocated elsewhere which simple jumps back to
nt!ObpDeleteObjectType.
7) GrepExec: The Tool
Included with this paper is a proof-of-concept tool complete with source
which demonstrates scanning the pool for signatures to detect executable
objects. Objects detected are DRIVER_OBJECT, DEVICE_OBJECT, EPROCESS,
and ETHREAD. The tool does nothing to determine if an object has been
attempted to be hidden in any way. Instead, it simply displays found
objects to standard output. At this time the author has no plans to
continue work with this specific tool, however, there are plans to
integrate the memory scanning technique into another project. The source
code for the tool can be easily modified to detect other signatures
and/or other objects.
7.1) The Signature
For demonstration purposes the signature used is simple. All objects are
allocated in NonPagedPool so only non-paged memory is enumerated for the
search. The signature is detected as follows:
1. Enumeration is performed by assuming the start of a pool block.
2. The signature offset is added to this pointer.
3. The assumed signature is compared with the OBJECT_HEADER->Type
for the object type being searched for.
4. The assumed POOL_HEADER->PoolType is compared to the objects known
pool type.
5. The assumed POOL_HEADER is validated using the function
from section , ValidatePoolBlock.
The following is the function which sets up the parameters in order to
perform the pool enumeration and validation of a block by a single PVOID
signature. On a match, a callback is made using the pointer to the start
of the matching block. As an alternative to the PVOID signature, the
poolgrep.c code can easily be modified to accept either a structure to
several signatures and offsets or a validation function pointer in order
to perform a more complex signature validation.
NTSTATUS ScanPoolForExecutiveObjectByType (
IN PVOID Object,
IN FOUND_BLOCK_CB Callback,
IN PVOID CallbackContext
) {
NTSTATUS ntStatus = STATUS_SUCCESS;
POBJECT_HEADER pObjHdr;
PPOOL_HEADER pPoolHdr;
ULONG_PTR blockSigOffset;
ULONG_PTR blockSignature;
pObjHdr = OBJECT_TO_OBJECT_HEADER( Object );
pPoolHdr = OBJHDR_TO_POOL_HEADER( pObjHdr );
blockSigOffset = (ULONG_PTR)&pObjHdr->Type - (ULONG_PTR)pObjHdr
+ OBJHDR_TO_POOL_BLOCK_OFFSET(pObjHdr);
blockSignature = (ULONG_PTR)pObjHdr->Type;
(VOID)ScanPoolForBlockBySignature( pPoolHdr->PoolType - 1,
0, // pPoolHdr->PoolTag OPTIONAL,
blockSigOffset,
blockSignature,
Callback,
CallbackContext );
return ntStatus;
}
7.2) Usage
GrepExec usage is pretty straightforward. Here is the output of the
help command.
**********************************************************
GREPEXEC 0.1 * Grepping executive objects from the pool *
Author: bugcheck
Built on: May 30 2006
**********************************************************
Usage: grepexec.exe [options]
--help, -h Displays this information
--install, -i Manually install driver
--uninstall, -u Manually uninstall driver
--status, -s Display installation status
--process, -p GREP process objects
--thread, -t GREP thread objects
--driver, -d GREP driver objects
--device, -e GREP device objects
7.3) Sample Output
The standard output is also straight forward. Here is a sample of each
supported command.
C:/grepexec>grepexec.exe -p
EPROCESS=81736C88 CID=0354 NAME: svchost.exe
EPROCESS=8174E238 CID=0634 NAME: explorer.exe
EPROCESS=81792020 CID=027c NAME: winlogon.exe
...
C:/grepexec>grepexec.exe -t
EPROCESS=817993C0 ETHREAD=815D4A58 CID=0778.077c wscntfy.exe
EPROCESS=8174AA88 ETHREAD=815D6860 CID=0408.0678 svchost.exe
EPROCESS=819CA830 ETHREAD=815F3B30 CID=0004.0368 System
EPROCESS=81792020 ETHREAD=81600398 CID=027c.0460 winlogon.exe
...
C:/grepexec>grepexec.exe -d
DRIVER=81722DA0 BASE=F9B5C000 /FileSystem/NetBIOS
DRIVER=819A4B50 BASE=F983D000 /Driver/Ftdisk
DRIVER=81725DA0 BASE=00000000 /Driver/Win32k
DRIVER=81771880 BASE=F9EB4000 /Driver/Beep
...
C:/grepexec>grepexec.exe -e
DEVICE=81733860 /Driver/IpNat NAME: IPNAT
DEVICE=81738958 /Driver/Tcpip NAME: Udp
DEVICE=817394B8 /Driver/Tcpip NAME: RawIp
DEVICE=81637CE0 /FileSystem/Srv NAME: LanmanServer
...
8) Conclusion
From reading this paper the reader should have a good understanding of
the concepts and issues related to scanning memory for signatures in
order to detect objects in the system pool. The reader should be able
to enumerate system memory safely, construct their own customized memory
signatures, locate signatures in memory, and implement their own
reporting mechanism.
It is obvious that object detection using memory scanning is no exact
science. However, it does provide a method which, for the most part,
interacts with the system as little as possible. The
author believes that the outlined technique can be successfully
implemented to obtain acceptable results in detecting objects hidden by
rootkits.
Bibliography
Blackhat.com. RAIDE: Rootkit Analysis Identification Elimination.
http://www.blackhat.com/presentations/bh-europe-06/bh-eu-06-Silberman-Butler.pdf;
Accessed May. 30, 2006.
F-Secure. Blacklight.
http://www.f-secure.com/blacklight/;
Accessed May. 30, 2006.
Invisiblethings.org. MODGREPPER.
http://www.invisiblethings.org/tools.html;
Accessed May. 30, 2006.
Phrack.org. Shadow Walker.
http://www.phrack.org/phrack/63/p63-0x08_Raising_The_Bar_For_Windows_Rootkit_Detection.txt;
Accessed May. 30, 2006.
Rootkit.com. FU.
http://rootkit.com/project.php?id=12;
Accessed May. 30, 2006.
Rootkit.com. Please don't greap me!.
http://rootkit.com/newsread.php?newsid=316;
Accessed May. 30, 2006.
Uninformed.org. futo.
http://uninformed.org/?v=3&a=7&t=sumry;
Accessed May. 30, 2006.
Windows Hardware Developer Central. Debugging Tools for Windows.
http://www.microsoft.com/whdc/devtools/debugging/default.mspx;
Accessed May. 30, 2006.
相关推荐
多智能体-系统-形成-控制 附matlab代码.rar
多智能体-系统-形成-控制 附matlab代码.rar
多目标粒子群算法求解综合能源系统最优容量配置研究(Matlab代码实现)
内容概要:本文围绕多目标粒子群算法在综合能源系统最优容量配置中的应用展开研究,旨在通过Matlab代码实现,解决包含多种能源设备(如光伏、风电、储能等)的综合能源系统在经济性、环保性和能效性等多目标下的容量优化配置问题。文中详细介绍了综合能源系统的构成与运行机理,建立了考虑设备投资成本、运行维护费用、购能支出及碳排放惩罚等多目标的优化模型,并采用多目标粒子群算法(MOPSO)进行求解,实现了Pareto最优前沿的搜索。研究通过具体算例验证了所提方法的有效性与优越性,能够为综合能源系统的规划设计提供科学依据和技术支持。; 适合人群:具备一定电力系统、能源系统基础知识和Matlab编程能力的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于综合能源系统、微电网等领域的科研与教学,帮助理解多目标优化问题的建模与求解过程;②为实际工程项目中的能源设备选型与容量配置提供决策支持,实现系统经济、环保、高效的运行目标。; 阅读建议:建议读者结合Matlab代码,深入理解算法实现细节与模型构建逻辑,通过调整算例参数和优化目标,探究不同因素对优化结果的影响,以加深对多目标粒子群算法及综合能源系统优化配置问题的理解。
SQLite Expert Professional v6.2.12.746 (x86 & x64) + License Key & Keygen.7z
SQLite Expert Professional v6.2.12.746 (x86 & x64) + License Key & Keygen.7z
虚拟同步发电机(VSG)惯量阻尼自适应控制仿真模型(simulink仿真实现)
内容概要:本文详细阐述了虚拟同步发电机(VSG)惯量阻尼自适应控制的Simulink仿真模型构建与研究过程,旨在通过仿真手段深入探究VSG在电力系统中的动态响应特性及其控制性能。文章首先介绍了VSG的基本工作原理,重点剖析其如何通过模拟传统同步发电机的惯性和阻尼特性来增强电力电子接口电源的频率支撑能力。在此基础上,提出了惯量和阻尼参数的自适应控制策略,该策略能够根据系统频率变化率和偏差实时调整VSG的控制参数,从而有效提升微电网或高比例可再生能源接入系统在面对负荷突变或电源波动时的频率稳定性和抗干扰能力。文中系统地描述了Simulink仿真模型的设计与实现过程,包括主电路拓扑、VSG控制算法模块、自适应逻辑判断模块的搭建,以及关键参数的设定与优化流程。通过对不同工况(如负载投切、电源功率波动)下的仿真结果进行分析,全面验证了所提自适应控制策略相较于固定参数控制在抑制频率波动、减小频率偏差和加快恢复速度等方面的显著优越性。; 适合人群:具备一定电力系统自动化、新能源并网技术或电力电子技术基础,熟悉Simulink/Matlab仿真工具的应用,从事相关领域研究的研发人员、高校研究生及科研工作者。; 使用场景及目标:①研究虚拟同步发电机在微电网、孤岛运行系统或高比例可再生能源并网场景下的频率稳定控制机制;②探索并设计基于系统状态反馈的惯量和阻尼自适应控制算法,以优化电力系统的动态性能;③为高等院校相关专业的课程设计、毕业设计或科研项目提供一个完整的、可复现的仿真案例和技术参考。; 阅读建议:建议读者在阅读时结合Simulink软件进行实操,亲手搭建或调试文中的仿真模型,通过改变自适应控制策略的阈值、增益等参数,观察系统频率响应的变化,从而深刻理解VSG的工作机理和自适应控制的精髓。同时,鼓励读者进一步查阅关于VSG虚拟阻抗、一次调频与二次调频协同控制等方面的文献,以拓宽知识视野,为后续的创新研究奠定基础。
足球运动员精英身价预测数据集1万名球员26特征
本数据集模拟足球运动员的身价与竞技特征,包含10000名球员、26个字段、单CSV约1016KB。提供elite分类目标(身价前10%)与market_value_eur_m回归目标,结果字段独立分离,便于练习避免目标泄漏。字段覆盖国籍、年龄、场上位置、所属联赛、俱乐部层级、综合与潜力评分、速度射门传球盘带防守身体六维能力值、身高、惯用脚、非惯用脚与花式技巧等级、国家队出场数、赛季出场时间、进球数、助攻数等维度。数据完整无缺失、无需表关联,非线性效应与特征交互明显,调优后模型可显著超越朴素基线,适合足球行业分析、球员身价研究、青训潜力评估建模与机器学习教学。说明:本数据为Python生成的合成数据,仅反映生成规则,不含真实球员与个人信息。许可:CC0公有领域,可自由使用与二次分发。
chrome-headless-shell-win32-159.0.8147.0(Canary).zip
内容概要:Chrome for Testing 官方 chrome-headless-shell 159.0.8147.0 win32 平台(金丝雀版通道),原版未修改,附来源说明。 适合人群:Windows 32 位 上的自动化测试工程师、爬虫开发者、CI 环境搭建者。 使用场景及目标:①无头浏览器(Playwright/Puppeteer/Selenium 无界面自动化与爬虫的运行内核);②服务器/容器离线内置;③版本精准匹配(chromedriver 与 Chrome 需同大版本)。 其他说明:Chrome for Testing 为 Google 官方发布、允许自由分发的文件;本资源为第三方整理的下载便利服务。
单相PWM整流器基于直流电流控制+虚拟dq两种闭环控制仿真【2个仿真+参考资料】
内容概要:本文系统介绍了单相PWM整流器的两种闭环控制策略——基于直流电流控制和基于虚拟dq变换的控制方法,并提供了相应的Simulink仿真模型及参考资料。通过构建两种控制方案的仿真系统,详细阐述了各自的控制原理、系统建模流程与关键参数设计思路,重点对比分析了二者在直流电压稳定性、功率因数校正能力、谐波抑制性能及动态响应特性等方面的差异。基于虚拟dq变换的控制通过构造虚拟中性点实现单相系统的类三相化处理,提升了电流控制精度;而直流电流控制则结构简洁、易于实现。仿真结果验证了两种策略在实现高效能量转换、提升电能质量方面的有效性,为实际工程应用提供了理论依据和技术参考。; 适合人群:具备电力电子、自动控制理论基础,熟悉MATLAB/Simulink仿真环境,从事新能源发电、电力传动、电能质量治理或电力电子装置研发的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握单相PWM整流器的工作原理与数学建模方法;②深入理解直流电流控制与虚拟dq控制的实现机制、控制自由度及其在稳态与动态性能上的优劣;③通过搭建仿真平台验证控制策略,优化控制器参数,提升系统在负载扰动、输入波动等工况下的鲁棒性与稳定性,服务于实际产品开发与性能评估。; 阅读建议:建议结合所提供的仿真模型与参考资料进行同步学习与实践操作。在仿真过程中应重点关注PI控制器参数整定对系统动态响应和稳态精度的影响,尝试设置不同负载、输入电压波动等工况,观察系统的抗干扰能力与控制性能变化,从而深化对控制机理的理解,全面提升对单相PWM整流器闭环控制技术的掌握水平。
门禁监控报警等系统与消防联动规划方案(生态合作版).pptx
门禁监控报警等系统与消防联动规划方案(生态合作版).pptx
固定电容器可控晶闸管无功补偿装置 (FCTCR)(simulink仿真实现)
内容概要:本文详细介绍了固定电容器可控晶闸管无功补偿装置(FCTCR)的Simulink仿真实现方法,系统阐述了其整体结构、工作原理及核心控制策略。FCTCR通过结合固定电容器组与基于晶闸管的相控电抗器,实现对电网无功功率的连续、快速、精确调节,有效提升系统功率因数、改善电压稳定性并抑制谐波。文中深入剖析了晶闸管的触发控制逻辑、无功动态响应特性,并利用Simulink构建了完整的仿真模型,通过在不同负载工况下的仿真测试,验证了该装置在动态无功补偿方面的优异性能和良好的响应能力。; 适合人群:具备电力系统分析、电力电子技术基础知识以及Simulink仿真操作经验的电气工程专业本科生、研究生、科研人员,以及从事无功补偿设备研发与应用的工程技术人员。; 使用场景及目标:①深入理解FCTCR装置的物理结构、工作机理与数学建模方法;②应用于高校电力系统自动化、电力电子课程设计或毕业设计,完成无功补偿系统的仿真验证;③为工业界开发新型动态无功补偿方案提供理论依据和技术参考,并可用于优化现有补偿装置的控制参数。; 阅读建议:建议读者结合提供的Simulink模型文件,按照文档步骤动手搭建与调试仿真系统,重点关注晶闸管触发角与系统等效电抗、无功输出之间的非线性关系,通过改变负载和控制参数,观察系统的瞬态与稳态响应,从而深刻掌握FCTCR的控制精髓与工程应用要点。
数字工厂AI大模型赋能智能体平台及AI场景应用规划方案(决策评审版).pptx
数字工厂AI大模型赋能智能体平台及AI场景应用规划方案(决策评审版).pptx
两相交错并联BuckBoost变换器仿真模型(Simulink仿真实现)
内容概要:本文详细介绍了两相交错并联Buck-Boost变换器的Simulink仿真模型设计与实现过程,系统阐述了该拓扑结构的工作原理及其在升降压模式下的运行特性。通过引入交错并联技术,有效降低了输入输出电流纹波,提升了系统效率与功率密度。文中构建了完整的电压电流双闭环PI控制系统,确保输出电压稳定并具备良好的动态响应能力,同时深入分析了占空比分配与相位交错对系统性能的影响。仿真模型全面验证了变换器在不同负载条件及输入电压波动下的静态与动态性能,充分体现了控制策略的有效性与系统的鲁棒性。; 适合人群:具备电力电子技术基础和Simulink仿真经验,从事开关电源、新能源变换系统研发的工程技术人员或高等院校电力电子与电力传动方向的研究生。; 使用场景及目标:①掌握两相交错并联Buck-Boost变换器的建模方法与工作机理;②学习双闭环PI控制器的设计流程与参数整定技巧;③深入理解多相变换器的均流控制、纹波抑制机制与动态响应特性;④为高效率、高功率密度DC-DC变换器的实际工程设计提供理论依据与仿真验证平台。; 阅读建议:建议读者结合所提供的Simulink模型文件进行同步操作,亲手搭建与调试电路,重点关注控制器参数调整对系统稳定性、响应速度及抗扰能力的影响,后续可进一步拓展至数字控制实现、硬件在环测试及实际样机开发。
单相boost功率因数校正 PFC电路仿真(Simulink仿真实现)
内容概要:本文围绕单相boost功率因数校正(PFC)电路的Simulink仿真展开,详细介绍了基于平均电流控制和PI电压双闭环前馈控制策略的PFC电路建模与仿真方法。文中系统阐述了boost电路的基本工作原理及其在提升功率因数、降低电流谐波、提高电能质量方面的技术优势,重点剖析了如何通过控制算法实现输入电流对电网电压的精确跟随。仿真模型涵盖主电路拓扑设计、双闭环控制结构搭建以及关键参数的整定过程,充分验证了所采用控制策略在稳态和动态工况下的有效性,确保了输出电压的高度稳定性与输入电流的良好正弦化。; 适合人群:具备电力电子技术基础知识和Simulink软件操作经验的电气工程及其自动化、电力系统及其相关专业的本科生、研究生,以及从事开关电源、新能源变流器等电力电子产品研发的工程技术人员。; 使用场景及目标:①深入理解boost型PFC电路的核心拓扑结构与工作机理;②掌握基于平均电流模式的双闭环控制策略的设计思想与具体实现方法;③熟练运用Simulink仿真平台完成PFC系统的全流程建模、参数调试与性能评估;④为实际工程中高功率因数、低谐波的开关电源产品开发提供坚实的理论支撑与可靠的仿真依据。; 阅读建议:建议读者结合经典电力电子技术教材与Simulink官方操作手册进行同步学习,特别关注控制环路的构建细节与PI参数的调节技巧,可通过改变负载大小或输入电压条件来观察系统的动态响应,从而深化对PFC控制内在机制的理解。
【CEEMDAN-WOA-LSTM】完备集合经验模态分解-鲸鱼优化-长短时记忆神经网络研究(Python代码实现)
内容概要:本文详细介绍了一种结合完备集合经验模态分解(CEEMDAN)、鲸鱼优化算法(WOA)与长短时记忆神经网络(LSTM)的时间序列预测模型,并提供了完整的Python代码实现。该模型首先利用CEEMDAN对原始非平稳、高噪声的时间序列信号进行自适应分解,获得一组相对平稳的本征模态函数(IMF)分量;接着采用WOA对LSTM的关键超参数进行智能寻优,以克服传统手动调参的局限性,提升模型的泛化性能与预测精度;最后构建多通道LSTM网络对各IMF分量分别建模预测,并将结果叠加重构得到最终预测输出。通过实验验证,该混合模型在处理非线性、非平稳且含强噪声的数据时,相较单一LSTM或其他组合模型展现出更优异的预测准确性与鲁棒性。; 适合人群:具备Python编程基础和机器学习基础知识的科研人员、研究生及工程师,特别适用于从事能源预测(如风电、光伏、电力负荷)、信号处理、故障诊断、金融时序分析等相关领域的研究人员。; 使用场景及目标:①应用于电力系统中的风速、光照强度、负荷等关键变量的高精度短期与中期预测;②用于处理工业现场中受噪声干扰严重的传感器信号,提升数据分析质量;③为需要高性能预测模型的科研项目提供可复现、可扩展的算法框架与代码支持,推动智能优化算法与深度学习在实际工程问题中的深度融合与应用。; 阅读建议:建议读者结合提供的Python代码逐模块学习,重点理解CEEMDAN的信号分解机制、WOA优化LSTM超参数的实现流程以及多分量预测结果的重构策略,鼓励在真实数据集上动手复现并调整参数,以深入掌握模型的设计思想与调优技巧。
针对波动计算复杂性的吸收边界条件(PML 用于一般波动方程)(Matlab代码实现)
内容概要:本文围绕波动方程在数值模拟中因计算域无限而导致的复杂性问题,系统性地介绍了完美匹配层(PML)作为一种高效的吸收边界条件的理论基础与实现方法,并提供了基于Matlab的完整代码实现方案。文章深入阐述了PML的基本原理及其在一般波动方程中的数学建模过程,通过数值仿真验证了PML在抑制边界反射波、降低截断误差方面的显著效果,从而有效提升了地震波、声波等波动问题仿真结果的精度与计算效率。同时,文中详细分析了PML关键参数(如厚度、衰减系数分布)对吸收性能的影响,并结合典型算例进行了对比验证,展示了其在实际科研中的应用价值。; 适合人群:具备波动方程、偏微分方程数值解及Matlab编程基础,从事地球物理勘探、结构动力学、声学或电磁场仿真等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①解决有限元、有限差分等数值方法在模拟无限域波动传播时产生的虚假边界反射问题;②提高地震波成像、噪声控制、雷达散射等仿真模型的准确性与可靠性;③掌握PML吸收边界条件的Matlab编程实现技巧,并将其迁移应用于自身科研项目的数值模拟中。; 阅读建议:建议读者结合文中的理论推导与Matlab代码进行实践操作,尝试调整PML区域的参数设置以观察其对吸收效果的影响,进一步可通过扩展该方法至其他类型的偏微分方程(如Maxwell方程、Navier-Stokes方程)的求解中,深化对吸收边界条件的理解与应用能力。
继电保护小电流接地系统故障仿真-中性点不接地与经消弧线圈接地仿真模型(Simulink仿真实现)
内容概要:本文详细介绍了三电平VIENNA整流器的双闭环控制与中点电位平衡的仿真研究,重点探讨了由电压外环与电流内环构成的双闭环PI控制结构,以及基于上下电容电压差值补偿的中点电位平衡策略。通过引入SVPWM调制技术,利用冗余小矢量的时间分配自由度,实现对中点电位的主动调节,从而在不牺牲输入电流谐波性能的前提下,显著提升了电容电压的均衡度。仿真结果表明,该控制策略能够有效稳定直流母线电压并实现中点电位的精确平衡,具备良好的动态响应能力和鲁棒性。; 适合人群:具备电力电子与电力系统基础知识,从事新能源发电、电动汽车充电、工业电源等领域的科研人员及工程技术人员,尤其是熟悉MATLAB/Simulink仿真环境的研发人员。; 使用场景及目标:①用于中大功率单向整流场合如充电桩、航空电源等系统中三电平VIENNA整流器的控制设计与优化;②为解决三电平拓扑固有的中点电位波动问题提供可行的技术方案,提升系统输出品质与可靠性;③作为高校研究生在电力电子变换器先进控制策略方面的教学与研究参考案例。; 阅读建议:建议读者结合文中提供的仿真模型与参数设置进行复现实验,重点关注双闭环带宽匹配、差值补偿环的设计边界及SVPWM调制细节,同时可进一步探究在电网不平衡、轻载等极端工况下的控制性能,以深化对系统动态特性的理解。
两路半桥LLC谐振变换器软开关Simulink仿真(模拟谐振参数不同、分裂电容)
内容概要:本文围绕两路半桥LLC谐振变换器的软开关特性展开Simulink仿真研究,重点分析了不同谐振参数(如谐振电感、谐振电容)以及分裂电容结构对系统性能的影响。通过构建详细的开环与闭环控制仿真模型,深入探究变换器在变频控制下的动态响应、能量传输效率及软开关实现条件,验证了在宽负载范围内实现零电压开通(ZVS)和零电流关断(ZCS)的可行性。研究特别关注分裂电容对谐振腔参数调节的作用机制,揭示其在优化高频高效电源设计中的关键价值,为高性能DC-DC变换器的设计提供了理论依据与实践指导。; 适合人群:电力电子、电气工程及其自动化等相关专业的高校师生,以及从事高频电源、新能源变换器、电动汽车充电模块等领域的研发工程师和技术人员。; 使用场景及目标:①深入理解LLC谐振变换器的工作原理及其软开关的实现条件;②掌握基于Simulink的电力电子系统建模与仿真分析方法;③探究分裂电容等关键结构对谐振参数与系统效率的影响,进而优化高效率、高功率密度电源的拓扑设计与参数匹配。; 阅读建议:读者应具备电路理论、电力电子变流技术的基础知识,建议在学习过程中结合所提供的Simulink模型进行实际操作,重点观察谐振参数变化对电流电压波形及软开关过程的影响,并尝试调整控制器参数以分析系统的动态响应与稳定性表现。
大学生职业生涯规划.pptx
大学生职业生涯规划.pptx
具有PWM控制VSC-HVDC链路的IEEE30总线传输系统(Simulink仿真实现)
内容概要:本文详细介绍了基于Simulink的具有PWM控制VSC-HVDC链路的IEEE30总线传输系统的建模与仿真研究。系统采用电压源型换流器(VSC)结合脉宽调制(PWM)技术实现高压直流输电(HVDC),并将其集成到标准的IEEE30节点电力系统中,以验证其在潮流控制、电压稳定和功率传输方面的性能。通过构建完整的系统模型,包括交流电网、VSC换流站、PWM控制器、直流输电线路及配套控制系统,实现了对有功功率与无功功率的独立精确调控。仿真结果表明,该VSC-HVDC系统在提升电网灵活性、增强系统稳定性以及优化电能传输效率方面具有显著优势,为现代柔性交流输电系统(FACTS)和智能电网建设提供了有力的技术支撑与参考依据。; 适合人群:具备电力系统分析、电力电子技术和自动控制理论基础知识的研究生、科研人员及电气工程领域的技术人员。; 使用场景及目标:①研究VSC-HVDC技术在复杂电网(如IEEE30节点系统)中的集成与应用;②掌握PWM控制策略在高压直流输电中的具体实现方法;③分析VSC-HVDC系统对电网潮流分布、电压稳定性和传输能力的影响。; 阅读建议:此资源以Simulink仿真为核心,不仅提供了系统的实现代码,更侧重于背后的技术原理和控制策略的解析。建议读者在学习时,应结合电力电子、电力系统暂稳态分析等理论知识,动手搭建并调试模型,通过改变系统参数和运行工况,深入理解VSC-HVDC的动态响应特性与控制机理。



被折叠的 条评论
为什么被折叠?



