Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Empty Standby List in Windows

4.50/5 (3 votes)
1 Jan 2015CPOL1 min read 274.2K   611  
How to create an empty standby list in Windows

Introduction

The makers of process hacker know the Windows kernel inside and out!  Fortunately for them, they are also fluent in C++: the language that the Windows kernel was designed on. For the rest of us, we struggle to make C# perform similar functions. One of those functions is the ability to release memory from the windows standby memory. That is what we will do here.

Credits

Obviously, the procedures used here are fundamentally taken from Process Hacker's source code - Thanks!

Next, the hardest part is getting the Kernel privileges. While I've significantly tweaked the code, my thanks must also go to Nick Lowe - Thanks!

Note: I have trimmed almost all code that is not related to the task itself. If you want to know more about either project, please visit their websites.

Step One: Setting Kernel Privileges

Microsoft has designed the API to take a structure that contains an array of structures. There are no good Marshaling procedures for this - they either assume the array is length=1 or require that the size of the array be predetermined at compilation. For this purpose, I designed a class that holds the exact structure that Microsoft requires in unmanaged memory via an System.IntPtr. I had to resort to one unsafe procedure at this point ... but I'm sure that can be bypassed with more work in the future.

C#
[return: MarshalAs(UnmanagedType.Bool)]
[SuppressUnmanagedCodeSecurity, DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(AccessTokenHandle accessTokenHandle,
[MarshalAs(UnmanagedType.Bool)] bool disableAllPrivileges, IntPtr NewPriviledges,
	Int32 bufferLength, ref IntPtr PriorPriviledges, out Int32 returnLength);	

Combining my class with Nick Lowe's privilege code, we can setup our kernel privileges with:

C#
AccessTokenHandle
	myProcessToken = new AccessTokenHandle(System.Diagnostics.Process.GetCurrentProcess(),
	ProcessPrivileges.TokenAccessRights.AdjustPrivileges | TokenAccessRights.Query);
myProcessToken.EnablePrivilege(Privilege.Debug, Privilege.ProfileSingleProcess);	

Step Two: Sending the Command to the Kernel

This time, Microsoft simply wants an int array. These Marshal easily, so all we need is:

C#
[DllImport("ntdll.dll")]
public static extern NtStatus NtSetSystemInformation
(SYSTEM_INFORMATION_CLASS InfoClass, int[] Info, uint Length);

NativeMethods.NtStatus
	result = 0;
int[]
	arr = new int[] { (int)Commands.MemoryPurgeStandbyList };
result = NativeMethods.NtSetSystemInformation
(NativeMethods.SYSTEM_INFORMATION_CLASS.SystemMemoryListInformation,
arr, (uint)(sizeof(int) * arr.Length));
if (result > 0)
	throw new System.ComponentModel.Win32Exception();	

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)