Monitoring Global Atom Table part I
The aim of this article is to give a sound understanding about Atoms, how to monitor them and check whether we have or have not any process that is potentially leaking atoms. As Microsoft very well defines:
"An atom table is a system-defined table that stores strings and corresponding identifiers. An application places a string in an atom table and receives a 16-bit integer, called an atom, that can be used to access the string. A string that has been placed in an atom table is called an atom name.
The system provides a number of atom tables. Each atom table serves a different purpose. Applications can use local atom tables to store their own item-name associations.
The system uses atom tables that are not directly accessible to applications. However, the application uses these atoms when calling a variety of functions. For example, registered clipboard formats are stored in an internal atom table used by the system. An application adds atoms to this atom table using the RegisterClipboardFormat function. Also, registered classes are stored in an internal atom table used by the system. An application adds atoms to this atom table using the RegisterClass or RegisterClassEx function."
Atoms are stored as two-byte integers (uint16) and there can be 0xFFFF-0xC000=0x4000 (16384) entries maximum. If 0xFFFF is reached ERROR 8 is returned ("System Error. Code: 8. Not enough storage is available to process this command")
Discovering Atom table:
To display atom table we need to use Debugging tools for Windows: Windbg and debug the kernel to dump al registers.
"An atom table is a system-defined table that stores strings and corresponding identifiers. An application places a string in an atom table and receives a 16-bit integer, called an atom, that can be used to access the string. A string that has been placed in an atom table is called an atom name.
The system provides a number of atom tables. Each atom table serves a different purpose. Applications can use local atom tables to store their own item-name associations.
The system uses atom tables that are not directly accessible to applications. However, the application uses these atoms when calling a variety of functions. For example, registered clipboard formats are stored in an internal atom table used by the system. An application adds atoms to this atom table using the RegisterClipboardFormat function. Also, registered classes are stored in an internal atom table used by the system. An application adds atoms to this atom table using the RegisterClass or RegisterClassEx function."
source: Microsoft.
Atoms are stored as two-byte integers (uint16) and there can be 0xFFFF-0xC000=0x4000 (16384) entries maximum. If 0xFFFF is reached ERROR 8 is returned ("System Error. Code: 8. Not enough storage is available to process this command")
Discovering Atom table:
To display atom table we need to use Debugging tools for Windows: Windbg and debug the kernel to dump al registers.
First of all:
Install all necessary tools and then run Windbg and configure all symbol parameters to correctly use kernel debug mode(for windows 7/Server 2008 debug mode needs to be enforced using bcdedit /debug on ). The most important module here is win32k.sys.
Set Symbol file path (Menu File -> Symbol file path):
"symsrv*symsrv.dll*C:\Symbols*http://msdl.microsoft.com/download/symbols"
As we need win32k.sys, we need to generate the pdb files with symbols information using symchk tool from debugging directory:
C:\Program Files\Debugging Tools for Windows (x86)>symchk C:\temp\bb\win32k.sys /v [SYMCHK] Searching for symbols to C:\temp\bb\win32k.sys in path symsrv*symsrv.dll*C:\Symbols*http://msdl.microsoft.com/download/symbols DBGHELP: Symbol Search Path: symsrv*symsrv.dll*C:\Symbols*http://msdl.microsoft.com/download/symbols [SYMCHK] Using search path "symsrv*symsrv.dll*C:\Symbols*http://msdl.microsoft.com/download/symbols" DBGHELP: No header for C:\temp\bb\win32k.sys. Searching for image on disk DBGHELP: C:\temp\bb\win32k.sys - OK SYMSRV: win32k.pdb from http://msdl.microsoft.com/download/symbols: 1170455 bytes - copied DBGHELP: win32k - public symbols C:\Symbols\win32k.pdb\D8788E4736B34ED5B8516DBB9D45E9942\win32k.pdb [SYMCHK] MODULE64 Info ---------------------- [SYMCHK] Struct size: 1680 bytes [SYMCHK] Base: 0xBF800000 [SYMCHK] Image size: 1839616 bytes [SYMCHK] Date: 0x43446a58 [SYMCHK] Checksum: 0x001ca511 [SYMCHK] NumSyms: 0 [SYMCHK] SymType: SymPDB [SYMCHK] ModName: win32k [SYMCHK] ImageName: C:\temp\bb\win32k.sys [SYMCHK] LoadedImage: C:\temp\bb\win32k.sys [SYMCHK] PDB: "C:\Symbols\win32k.pdb\D8788E4736B34ED5B8516DBB9D45E9942\win32k.pdb" [SYMCHK] CV: RSDS [SYMCHK] CV DWORD: 0x53445352 [SYMCHK] CV Data: win32k.pdb [SYMCHK] PDB Sig: 0 [SYMCHK] PDB7 Sig: {D8788E47-36B3-4ED5-B851-6DBB9D45E994} [SYMCHK] Age: 2 [SYMCHK] PDB Matched: TRUE [SYMCHK] DBG Matched: TRUE [SYMCHK] Line nubmers: FALSE [SYMCHK] Global syms: FALSE [SYMCHK] Type Info: TRUE [SYMCHK] ------------------------------------ SymbolCheckVersion 0x00000002 Result 0x00130001 DbgFilename DbgTimeDateStamp 0x43446a58 DbgSizeOfImage 0x001c1200 DbgChecksum 0x001ca511 PdbFilename C:\Symbols\win32k.pdb\D8788E4736B34ED5B8516DBB9D45E9942\win32k.pdb PdbSignature {D8788E47-36B3-4ED5-B851-6DBB9D45E994} PdbDbiAge 0x00000002 [SYMCHK] [ 0x00000000 - 0x00130001 ] Checked "C:\temp\bb\win32k.sys" SYMCHK: FAILED files = 0 SYMCHK: PASSED + IGNORED files = 1
Once done, you will see the pdb file generated in C:\Symbols folder and you would be able to load it from Windbg command line using the WinDbg commands http://windbg.info/doc/1-common-cmds.html.
kd> !sym noisy noisy mode - symbol prompts on kd> .reload win32k.sys kd> lm start end module name 804d7000 806cdc00 nt (export symbols) ntkrnlpa.exe bf800000 bf9c1200 win32k (deferred)
Now we know that win32k.sys it's loaded in address bf800000 and the referenced memory can be displayed by using dq command (using a 64-bit pointer) and only the first dword (L1):
kd> dq win32k!UserAtomTableHandle L1 DBGHELP: win32k - public symbols c:\symbols\win32k.pdb\D8788E4736B34ED5B8516DBB9D45E9942\win32k.pdb bf9a7c18 81b4a270`e1c47230 kd> dq 81b4a270`e1c47230+10 e1c47240 e1a841c0`e1ba3008 e15fb8f8`e19fae00 e1c47250 e1ba3080`e1700738 e1546428`e1708f88 e1c47260 e15f4e28`e15f4c78 e19e9058`e1a04278 e1c47270 e15f9d20`e15fb878 e170eda8`e1704d90 e1c47280 e1a0bea8`e1f71658 e1a841f0`e1a61550 e1c47290 e15464a0`e1091388 e1b16bc8`e1542440 e1c472a0 e1001d00`e1a014c0 e181efe0`e1c42118 e1c472b0 e1bb9178`e16f33e0 e15fa858`e19e9078 kd> dq e170076a 04080000`000081cc 04016d53`6d4d0001 e170077a 00006156`4d430c07 00260012`6b76002c e170078a 0001007c`fec80000 7250ffff`00010000 e170079a 6f724773`7365636f 7963696c`6f507075 e17007aa 0407ffff`ffffffff d4987346`744e0c05 e17007ba 00000000`0000e16e 4fcf0000`00000000 e17007ca 29880003`00000000 04050000`0000e170 e17007da 0401e24e`4d430001 f6886944`624f0c02
Showing the content of the memory:
Now that we now where Global Atom table is allocated, we can start inspecting its elements by displaying Unicode characters from memory by using du command:
kd> du e1ba3080`e1700738+C e1700744 "DDEMLUnicodeClient" kd> du e1546428`e1708f88+C e1708f94 "ACTIVATESHELLWINDOW"
We can dump the memory using 32-bit pointers (dd command) and get the same results:
kd> dd e1c47240 e1c47240 e1ba3008 e1a841c0 e19fae00 e15fb8f8 e1c47250 e1700738 e1ba3080 e1708f88 e1546428 e1c47260 e15f4c78 e15f4e28 e1a04278 e19e9058 e1c47270 e15fb878 e15f9d20 e1704d90 e170eda8 e1c47280 e1f71658 e1a0bea8 e1a61550 e1a841f0 e1c47290 e1091388 e15464a0 e1542440 e1b16bc8 e1c472a0 e1a014c0 e1001d00 e1c42118 e181efe0 e1c472b0 e16f33e0 e1bb9178 e19e9078 e15fa858 kd> dd e1c472b0 e1c472b0 e16f33e0 e1bb9178 e19e9078 e15fa858 e1c472c0 e1a84198 e1a61500 e195d558 e15ff980 e1c472d0 e15424a0 00000000 00000000 00000000 e1c472e0 00000000 00000000 00000000 00000000 e1c472f0 00000000 00000000 00000000 00000000 e1c47300 00000000 00000000 00000000 00000000 e1c47310 00000000 00000000 00000000 00000000 e1c47320 00000000 00000000 00000000 00000000 kd> du e1ba3008+c e1ba3014 "Native" kd> du e15fa858+c e15fa864 "OleClipboardPersistOnFlush"
To display the whole content we can use the following function to loop through all buckets, listing all atoms created:
kd> r $t0=poi(poi(win32k!UserAtomTableHandle)+C) kd> .for(r $t1=0; @$t1<@$t0; r $t1=@$t1+1) {du poi(poi(win32k!UserAtomTableHandle)+10+(@$t1*4))+C} e1ba3014 "Native" e1a841cc "ObjectLink" e19fae0c "6.0.2600.2180!tooltips_class32" e15fb904 "Static" e1700744 "DDEMLUnicodeClient" e1ba308c "DataObject" e1708f94 "ACTIVATESHELLWINDOW" e1546434 "FlashWState" e15f4c84 "SysCH" e15f4e34 "PBrush" e1a04284 "6.0.2600.2180!msctls_progress32" e19e9064 "SysIC" e15fb884 "DDEMLEvent" e15f9d2c "SHELLHOOK" e1704d9c "Custom Link Source" e170edb4 "ControlOfsM*EVJK" e1f71664 "DesktopSFTBarHost" e1a0beb4 "SysDT" e1a6155c "Link Source" e1a841fc "FileName" e1091394 "ReBarWindow32" e15464ac "SysWNDO" e154244c "DDEMLAnsiServer" e1b16bd4 "SysLink" e1a014cc "NetworkName" e1001d0c "USER32" e1c42124 "OleDraw" e181efec "FileNameW" e16f33ec "MoreOlePrivateData" e1bb9184 "Edit" e19e9084 "Binary" e15fa864 "OleClipboardPersistOnFlush" e1a841a4 "OwnerLink" e1a6150c "ListBox" e195d564 "Embed Source" e15ff98c "SysIMEL" e15424ac "ComboLBox"
Another way of displaying the content of Global Atom Table is by using !gatom command from user session on Windbg. (http://msdn.microsoft.com/en-us/library/ff563166(v=vs.85).aspx)
0:001> !gatom Global atom table c00c( 1) = Protocols (18) pinned c00d( 1) = Topics (12) pinned c00e( 1) = Formats (14) pinned c01f(36) = OleEndPointID (26) c026( 1) = AppProperties (26) c024( 1) = Delphi00000DB8 (28) c01e(94) = UxSubclassInfo (28) c010( 1) = EditEnvItems (24) pinned c022( 3) = CAddressComboEx_This (40) c01d( 6) = OleDropTargetMarshalHwnd (48) c028( 1) = Delphi000009C0 (28) c008( 1) = StdDoVerbItem (26) pinned c01c( 6) = OleDropTargetInterface (44) c02c( 1) = WndProcPtr0040000000000DC4 (52) c02b( 1) = ControlOfs0040000000000DC4 (52) c014( 1) = Save (8) pinned c016( 1) = MSDraw (12) pinned c02a( 1) = WndProcPtr0040000000000940 (52) c024( 1) = Delphi00000DB8 (28) c01e(94) = UxSubclassInfo (28) c023( 3) = CAutoComplete_This (36) c007( 1) = StdShowItem (22) pinned c011( 1) = True (8) pinned c010( 1) = EditEnvItems (24) pinned c019( 1) = PROGMAN (14) c012( 1) = False (10) pinned c015( 1) = Close (10) pinned c022( 3) = CAddressComboEx_This (40) c004( 1) = StdEditDocument (30) pinned c01d( 6) = OleDropTargetMarshalHwnd (48) c028( 1) = Delphi000009C0 (28) c008( 1) = StdDoVerbItem (26) pinned c01c( 6) = OleDropTargetInterface (44) c02c( 1) = WndProcPtr0040000000000DC4 (52) c005( 1) = StdNewfromTemplate (36) pinned c02b( 1) = ControlOfs0040000000000DC4 (52) c014( 1) = Save (8) pinned c016( 1) = MSDraw (12) pinned c02a( 1) = WndProcPtr0040000000000940 (52) c002( 1) = StdNewDocument (28) pinned c027( 1) = ddeconv (14) c029( 1) = ControlOfs0040000000000940 (52) c00f( 1) = Status (12) pinned c017(27) = ThemePropScrollBarCtl (42) c009( 1) = System (12) pinned c01b( 3) = AnimationID (22) c025( 1) = Folders (14) c00b( 1) = StdDocumentName (30) pinned c013( 1) = Change (12) pinned c001( 1) = StdExit (14) pinned c006( 1) = StdCloseDocument (32) pinned c01a( 6) = CAddressBand_This (34) c00a( 1) = OLEsystem (18) pinned c018( 3) = CC32SubclassInfo (32)
But As we can see, we are not displaying all table completely as it is quite difficult to find the correct entry as the table contains atoms, registered clipboard formats, classes, etc. If we follow the steps from Microsoft debug team, the job is far way easy:
kd> dq win32k!UserAtomTableHandle l1 bf9a7c18 81c58ce0`e1aa1da8 lkd> dq 81c58ce0`e1aa1da8+10 l1 e1aa1db8 e1929b00`e1423c58 kd> dt nt!_HANDLE_TABLE e1929b00`e1423c58 +0x000 TableCode : 0xe19012b8 +0x004 QuotaProcess : 0xc0040004 _EPROCESS +0x008 UniqueProcessId : 0x06010001 Void +0x00c HandleTableLock : [4] _EX_PUSH_LOCK +0x01c HandleTableList : _LIST_ENTRY [ 0x4d4d49 - 0xc060405 ] +0x024 HandleContentionEvent : _EX_PUSH_LOCK +0x028 DebugInfo : (null) +0x02c ExtraInfoPages : 0n4390977 +0x030 FirstFree : 0x490050 +0x034 LastFree : 0x50005c +0x038 NextHandleNeedingPool : 0x50004e +0x03c HandleCount : 0n3473456 +0x040 Flags : 0x310030 +0x040 StrictFIFO : 0y0 kd> !list "-t nt!_RTL_ATOM_TABLE_ENTRY.HashLink -e -x \"du @$extret+C\" e1929b00`e1423c58" du @$extret+C e1423c64 "Native" du @$extret+C e19012c4 "Object Descriptor" du @$extret+C e1905f14 "Link Source Descriptor" du @$extret+C e17e3fec "Button" du @$extret+C e108d014 "msctls_updown32" du @$extret+C e108e224 "6.0.2600.2180!Static" du @$extret+C e1c016f4 "MSIMEMouseOperation" du @$extret+C e112b32c "WorkerW" du @$extret+C e167218c "MSUIM.Msg.StubCleanUp" du @$extret+C e1e6f12c "Desktop More Programs Pane" du @$extret+C e1e949fc "FileContents" du @$extret+C e1be4c1c "CMBExecute" du @$extret+C e2218d8c "C:\WINDOWS\system32\xpsp2res.dll" e2218dcc "" du @$extret+C e222a80c "C:\WINDOWS\WinSxS\x86_Microsoft." e222a84c "Windows.Common-Controls_6595b641" e222a88c "44ccf1df_6.0.2600.2180_x-ww_a84f" e222a8cc "1ff9\comctl32.dll" du @$extret+C e16524dc "ControlOfs0040000000000DC4" du @$extret+C e1971964 "ControlOfs0040000000000940" du @$extret+C e214b4c4 "ControlOfs0040000000000EC4" du @$extret+C e162340c "ControlOfs0040000000000274" du @$extret+C e1e7b7fc "application/x-compressed"
Using Atom table monitor v1.0:
I have developed a small tool to visually monitor all atoms and look for different patterns on it using regular expressions and display the match with a different colour.
This small app will use GlobalGetAtomName (to get all atoms that have been added using GlobalAddAtom) and GetClipboardFormatName (to get all atoms that have been added using RegisterWindowMessage) functions to get all atoms and display them into a 128x128 memory grid using Delphi XE. It also keeps track of the amount of atoms through time plotting the results in a chart.
procedure ScanAtoms; var index: WORD; arrAtom, arrClipboard: array [0 .. 1024] of char; AtomName, RWMName: string; lenAtom, lenClipboard: integer; begin for index := $C000 to $FFFF do begin lenAtom := GlobalGetAtomName(index, arrAtom, 1024); lenClipboard := GetClipboardFormatName(index, arrClipboard, 1024); if lenAtom > 0 then FATomTable[index - $C000].atom := StrPas(arrAtom) else if lenClipboard > 0 then FATomTable[index - $C000].atom := StrPas(arrClipboard); end; end;
Features:
- Display global atom table from 0xC000 to 0xFFFF.
- Display atom string from table.
- Look for patterns and match them with a specific colour
- Counters detailing the matches.
- Plotting amount of atoms.
Tool can be tested by using GlobalAddAtom or RegisterWindowMessages functions and check out the monitor.
Download:
Jordi Corbilla
Related links:
I would like to say BIG thanks to you, very useful article and your Atom table monitor is amazing!
ReplyDeleteFilo
Thanks!
DeleteHi Jordi,
ReplyDeleteCan we get the name of applications which are adding to Global Atom table and Register Window Messages?
Thanks,
Prabhu
Hi Prabhu,
DeleteYes, from the same tool you can get a report of the applications that are writing to that area.
Regards,
Jordi
This blog is truly useful to convey overhauled instructive undertakings over web which is truly examination. I discovered one fruitful case of this truth through this blog. I will utilize such data now.ร้านขายโต๊ะหมู่บูชา
ReplyDeletehi Jordi, how do I use this tool? I installed the Service but not sure how to open the application screens I see in the screenshots...
ReplyDelete