[原创]枚举系统全局原子表
之前写着玩的一个小DEMO, 能枚举或者监控系统全局原子信息
对于系统资源的枚举常规方式一般是设法得到该资源的链表头或者数组首地址等等
这可以通过在代码中搜索或者将自身加入到资源列表中而进一步定位到它
这次枚举原子表的实验中我是通过HOOK方式来进行的, 因为内核的导出函数RtlAddAtomToAtomTable中直接引用了原子表的首地址
NTSYSAPI
NTSTATUS
NTAPI
RtlAddAtomToAtomTable(
__in PVOID AtomTableHandle,
__in PWSTR AtomName,
__inout_opt PRTL_ATOM Atom
);
这样只要勾住这个函数, 等该函数被调用时就能得到原子表地址了进而将它的元素表都枚举出来
实际操作中我目前只发现了两个系统级原子表, 一个是常规的原子表, 由GlobalAddAtom可以触发RtlAddAtomToAtomTable的调用,
另一个是与窗口有关的原子表, 由RegisterWindowMessage可以触发RtlAddAtomToAtomTable的调用
在进行枚举操作时, 我就是先勾住RtlAddAtomToAtomTable, 再在应用层调用这两个函数来进行的
很幸运的是在内核中记录原子表及其原子表项的内部结构在XP和WIN7下是一样的
typedef struct _RTL_ATOM_TABLE_ENTRY{
struct _RTL_ATOM_TABLE_ENTRY *HashLink;
USHORT HandleIndex;
USHORT Atom;
USHORT ReferenceCount;
UCHAR Flags;
UCHAR NameLength;
WCHAR Name[1];
}RTL_ATOM_TABLE_ENTRY, *PRTL_ATOM_TABLE_ENTRY;
typedef struct _RTL_ATOM_TABLE{
DWORD Signature;
//DWORD FillA[6]; // +0x04 // CriticalSection
//DWORD FillB[8]; // +0x1C // RtlHandleTable
DWORD FillA;
DWORD FillB;
DWORD NumberOfBuckets;// +0x3C
PRTL_ATOM_TABLE_ENTRY Buckets[1];
}RTL_ATOM_TABLE, *PRTL_ATOM_TABLE;
NumberOfBuckets描述了有多少个Buckets入口点, 每个Buckets链的最后一项为NULL, 这样就很方便遍历了
BOOLEAN IsAtomTableExist(__in DWORD TableAddress)
{
if ( TableAddress == 0 ) return TRUE;
for ( DWORD i = 0; i < 100; i++ )
{
DWORD ThisTable = g_AtomTables[i];
if ( ThisTable == TableAddress )
{
return TRUE;
}
if ( ThisTable == 0 )
{
g_AtomTables[i] = TableAddress;
return FALSE;
}
}
return TRUE;
}
VOID EnumAtomTableEntrys(__in DWORD TableAddress)
{
PRTL_ATOM_TABLE TableInfo = (PRTL_ATOM_TABLE)TableAddress;
DWORD dw = TableInfo->NumberOfBuckets;
for ( DWORD i = 0; i < dw; i++ )
{
PRTL_ATOM_TABLE_ENTRY Entry = (PRTL_ATOM_TABLE_ENTRY)TableInfo->Buckets[i];
while ( Entry )
{
// 回传数据
PATOMDATAINFO DataEntry = (PATOMDATAINFO)ExAllocatePoolWithTag(PagedPool, sizeof(AtomDataInfo), 'fff');
RtlZeroMemory(DataEntry, sizeof(AtomDataInfo));
DataEntry->AtomValue = (DWORD)Entry->Atom;
DataEntry->ReferenceCount = (DWORD)Entry->ReferenceCount;
DataEntry->TableAddress = TableAddress;
DataEntry->TotalBuckets = TableInfo->NumberOfBuckets;
DWORD len = (DWORD)Entry->NameLength * sizeof(WCHAR);
if ( len > sizeof(DataEntry->AtomName) - sizeof(WCHAR) ) len = sizeof(DataEntry->AtomName) - sizeof(WCHAR);
RtlMoveMemory(DataEntry->AtomName, Entry->Name, len);
ExAcquireFastMutex(&g_EnumDataListFM);
InsertTailList(&g_EnumDataList, &DataEntry->DataList);
ExReleaseFastMutex(&g_EnumDataListFM);
if ( Entry->HashLink == NULL ) break;
Entry = Entry->HashLink;
}
}
}
BOOLEAN __stdcall AddAtomFilter(__in PVOID AtomTableHandle, __in PWCHAR AtomName, __inout_opt PUSHORT Atom)
{
// 监控
if ( g_DriverState.ControlMask & CONTROL_MASK_MONITOR )
{
// 回传数据
PATOMDATAINFO Entry = (PATOMDATAINFO)ExAllocatePoolWithTag(PagedPool, sizeof(AtomDataInfo), 'ddd');
if ( Entry )
{
RtlZeroMemory(Entry, sizeof(AtomDataInfo));
Entry->ProcId = (DWORD)PsGetCurrentProcessId();
PEPROCESS eprocess = PsGetCurrentProcess();
PUCHAR pc = PsGetProcessImageFileName(eprocess);
RtlMoveMemory(Entry->ProcName, pc, 16);
DWORD len = 0;
RtlStringCbLengthW(AtomName, sizeof(Entry->AtomName) * sizeof(WCHAR), (size_t *)&len);
RtlMoveMemory(Entry->AtomName, AtomName, len);
Entry->TableAddress = (DWORD)AtomTableHandle;
ExAcquireFastMutex(&g_MonDataListFM);
InsertTailList(&g_MonDataList, &Entry->DataList);
ExReleaseFastMutex(&g_MonDataListFM);
if ( g_DriverState.EventForMon )
KeSetEvent(g_DriverState.EventForMon, 0, FALSE);
}
}
// 枚举
if ( g_DriverState.ControlMask & CONTROL_MASK_ENUM )
{
if ( !IsAtomTableExist((DWORD)AtomTableHandle) )
{
EnumAtomTableEntrys((DWORD)AtomTableHandle);
if ( g_DriverState.EventForEnum )
KeSetEvent(g_DriverState.EventForEnum, 0, FALSE);
}
}
return TRUE;
}
程序只在XP WIN7下运行过, 其他系统请慎用
WIN7下运行请使用管理员权限运行
loadatomenum.rar
