Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Last active March 9, 2020 11:12
Show Gist options
  • Save Noitidart/ad025c76a34e84544856 to your computer and use it in GitHub Desktop.
Save Noitidart/ad025c76a34e84544856 to your computer and use it in GitHub Desktop.
_ff-addon-snippet-WinAPI_EnumHandles - Enumerate handles WinAPI. (js-ctypes) (Windows)
Cu.import("resource://gre/modules/ctypes.jsm");
var lib_ntdll = ctypes.open("ntdll.dll");
var lib_kernel32 = ctypes.open("kernel32.dll");
var STATUS_BUFFER_TOO_SMALL = 0xC0000023>>0;
var STATUS_INFO_LENGTH_MISMATCH = 0xC0000004>>0;
var SystemHandleInformation = 16;
var UNICODE_STRING = new ctypes.StructType("UNICODE_STRING", [
{'Length': ctypes.unsigned_short}, //USHORT
{'MaximumLength': ctypes.unsigned_short}, //USHORT
{'Buffer': ctypes.jschar.ptr}
]); //PWSTR
//https://github.com/tjguk/winsys/blob/5f11b308171382046ff0f67ef3129e47e9fee06c/random/file_handles.py#L100
var SYSTEM_HANDLE_TABLE_ENTRY_INFO = new ctypes.StructType('SYSTEM_HANDLE_TABLE_ENTRY_INFO', [ //typedef struct _TagHANDLEINFO
{'UniqueProcessId': ctypes.unsigned_long}, //USHORT dwPid; //UniqueProcessId
{'CreatorBackTraceIndex': ctypes.unsigned_long}, //USHORT CreatorBackTraceIndex; //CreatorBackTraceIndex
{'ObjectTypeIndex': ctypes.unsigned_long}, //BYTE ObjType; //ObjectTypeIndex UCHAR
{'HandleAttributes': ctypes.unsigned_long}, //BYTE HandleAttributes; //im not sure if byte should be unsigned_long, maybe unsigned_char //HandleAttributes UCHAR
{'HandleValue': ctypes.unsigned_long}, //USHORT HndlOffset; //HandleValue USHORT
{'Object': ctypes.unsigned_long}, //DWORD dwKeObject; //Object PVOID
{'GrantedAccess': ctypes.unsigned_long} //ULONG GrantedAccess; //GrantedAccess ULONG
]); //HANDLEINFO, PHANDLEINFO;
var SYSTEM_HANDLE_INFORMATION = new ctypes.StructType('SYSTEM_HANDLE_INFORMATION', [
{'NumberOfHandles': ctypes.unsigned_long},
{'Handles': ctypes.ArrayType(SYSTEM_HANDLE_TABLE_ENTRY_INFO, 1)}
]);
var NtQuerySystemInformation = lib_ntdll.declare("NtQuerySystemInformation", ctypes.winapi_abi, ctypes.long, // return //NTSTATUS
ctypes.int, // SystemInformationClass //SYSTEM_INFORMATION_CLASS
ctypes.void_t.ptr, // SystemInformation //PVOID
ctypes.unsigned_long, // SystemInformationLength //ULONG
ctypes.unsigned_long.ptr
); // ReturnLength //PULONG
/* http://msdn.microsoft.com/en-us/library/ms633499%28v=vs.85%29.aspx
* HWND WINAPI FindWindow(
* __in_opt LPCTSTR lpClassName,
* __in_opt LPCTSTR lpWindowName
* );
*/
// NOT SUPPORTED BY WINXP so just doing this to test and then later will figure out how to get handle to path name then look in here
var GetFinalPathNameByHandle = lib_kernel32.declare('GetFinalPathNameByHandleW', ctypes.winapi_abi, ctypes.uint32_t, //DWORD
ctypes.unsigned_short, // HANDLE
ctypes.void_t.ptr, // LPTSTR
ctypes.uint32_t, // DWORD
ctypes.uint32_t // DWORD
);
function enumHandles() {
var res = {};
/*
var _enumBufSize = new ctypes.unsigned_long(0x4000);
var buffer = ctypes.char.array(_enumBufSize.value)();
*/
var buffer = new SYSTEM_HANDLE_INFORMATION(); //ctypes.char.array(_enumBufSize.value)();
var _enumBufSize = new ctypes.unsigned_long(buffer.constructor.size); //size when 1 element == 32. when 2 element == 60, 3 == 88// this is 32 - 4 / 4 == 7 fields. 60-4/4 == 14 fields
console.log('buffer:', buffer)
//var numFields = (32 - 4) / 7 / 4;
//while (true) {
var status = NtQuerySystemInformation(SystemHandleInformation, buffer.address(), _enumBufSize, _enumBufSize.address());
//if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) {
// buffer = ctypes.char.array(_enumBufSize.value)();
//} else break;
//}
console.log('status:', status.toString(), 'STATUS_BUFFER_TOO_SMALL:', status == STATUS_BUFFER_TOO_SMALL, 'STATUS_INFO_LENGTH_MISMATCH:', status == STATUS_INFO_LENGTH_MISMATCH);
console.log('_enumBufSize:', _enumBufSize.value.toString());
console.log('NumberOfHandles:', buffer.NumberOfHandles.toString());
////////// rep it
SYSTEM_HANDLE_INFORMATION = new ctypes.StructType('SYSTEM_HANDLE_INFORMATION', [
{'NumberOfHandles': ctypes.unsigned_long},
{'Handles': ctypes.ArrayType(SYSTEM_HANDLE_TABLE_ENTRY_INFO, buffer.NumberOfHandles)}
]);
var buffer = new SYSTEM_HANDLE_INFORMATION(); //ctypes.char.array(_enumBufSize.value)();
var _enumBufSize = new ctypes.unsigned_long(buffer.constructor.size); //size when 1 element == 32. when 2 element == 60, 3 == 88// this is 32 - 4 / 4 == 7 fields. 60-4/4 == 14 fields
console.log('buffer:', buffer)
//var numFields = (32 - 4) / 7 / 4;
//while (true) {
var status = NtQuerySystemInformation(SystemHandleInformation, buffer.address(), _enumBufSize, _enumBufSize.address());
//if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) {
// buffer = ctypes.char.array(_enumBufSize.value)();
//} else break;
//}
console.log('status:', status.toString(), 'STATUS_BUFFER_TOO_SMALL:', status == STATUS_BUFFER_TOO_SMALL, 'STATUS_INFO_LENGTH_MISMATCH:', status == STATUS_INFO_LENGTH_MISMATCH);
console.log('_enumBufSize:', _enumBufSize.value.toString());
console.log('NumberOfHandles:', buffer.NumberOfHandles.toString());
///end rep
if (status != 0) {
console.error('failed getting handles, numbero of hadles must have changed between the two reps in order to fail and get here, status:', status.toString());
return {};
} else {
console.info('succesfully got handles');
console.log('Handles:', buffer.Handles);
console.log('Handles[0]:', uneval(buffer.Handles[0]));
console.log('Handles[1]:', uneval(buffer.Handles[1]));
for (var i=0; i<buffer.NumberOfHandles; i++) {
var UniqueProcessId = buffer.Handles[i].UniqueProcessId.toString();
/*
if (UniqueProcessId == 5020) {
res
}
*/
}
}
return res;
}
console.time('enumHandles');
var allHandles = enumHandles();
console.timeEnd('enumHandles');
console.log('enumHandles:', Object.keys(allHandles).length, allHandles);
lib_ntdll.close();
lib_kernel32.close();
@Noitidart
Copy link
Author

README

SEE ALSO _ff-addon-snippet-WinAPI_EnumHandlesExAndReadFilePaths.js

Based on work from GitHubGIST :: Noitidart / _ff-addon-snippet-WinAPI_NtDll.js.

Rev1

  • Issue with getting array length right on Handles
  • Figured out how to properly get handles from HERE
  • JS-Ctypes code from HERE
  • Array is capped at 5 length
  • So the SystemHandleInfo structure is being properly obtained however the Handles field is only at 5

Rev2

  • Uncapped array from 5, made it 70k
  • Now looping through handles obtained
  • CRASHES!! when looping through

Rev3

  • Trying to fix crash
  • Still CRASHING when looping through even though using slightly different approach to access fields

Rev4

  • Finally got it to work, can now access items on Handles, I was casting it when I shouldn't have, understand a loooot now
  • Dynamic resizing of the array so it fits the proper NumberOfHandles
    • Took out the NTQuery.. from while loop and made it once to get number of handles, then resize it, then run NTQuery... again to fill Handles array, sometimes do get STATUS_BUFFER_TOO_SMALL on second run but its because handles increased by +/- a one or two handles, every ms things are changing so this is expected
  • Timing
    • Takes average of 400ms to go through 40k handles on amd a10
    • Average of 500ms, max 600ms on winXp my OLD machine for 10k handles
  • Verified structure of SYTEM_HANDLE_TABLE_ENTRY_INFO from file D:\SONY VAIO\Documents and Settings\SONY VAIO\My Documents\_Downloads\EnTeHandle\myntdll.h L#60
    typedef struct _TagHANDLEINFO { USHORT dwPid; USHORT CreatorBackTraceIndex; BYTE ObjType; BYTE HandleAttributes; USHORT HndlOffset; DWORD dwKeObject; ULONG GrantedAccess; }HANDLEINFO, PHANDLEINFO;

Rev5

  • Renamed gist and file to include "WinAPI_"

Rev6

  • I havent done a Rev5 yet but this gist has some mistakes, see this gist to correct all of these mistakes: GitHubGIST :: Noitidart / ff-addon-snippet-WINAPI_EnumHandlesAndReadFilePaths.js
    • for instance in the structure it should be short instead of long, unless i use EX structure and BYTE is unsigned_char not long like i have it here
    • I have GetFinalPathNameByHandle here but it will always return blank because I need to feed GetFinalPathNameByHandle a duplicated handle if its owned by another pid (another means something other then the firefox im running this code from) as learned in the linked gists

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment