65.9K
CodeProject is changing. Read more.
Home

Empty Standby List in Windows

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (3 votes)

Jan 1, 2015

CPOL

1 min read

viewsIcon

274154

downloadIcon

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.

[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:

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:

[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();