options linesize=250; * Richard A. DeVenezia; * http://www.devenezia.com; * * 30AUG2003 * 02JUN2005 - fix LastWriteTime * * Examine Windows registry from SAS * Investigate the values Microsoft logs in the keys * HKEY_CURRENT_USER * \Software * \Microsoft * \Windows * \CurrentVersion * \Explorer * \UserAssist * \{5E6AB780-7743-11CF-A12B-00AA004AE837} * \Count * and * \{75048700-EF1F-11D0-9888-006097DEACF9} * \Count * * behind a simple ROT-13 encryption * * to turn off the ROT-13 or logging all together, create variables * \UserAssist * \Settings * -> NoEncrypt = 1 (DWORD) * -> NoLog = 1 (DWORD) * and reboot * * The values under Count\ can be deleted using RegEdit, or * search up UserAssist Registry in your favorite engine * * NoEncrypt and NoLog settings gleaned from * http://www.computing.net/windowsme/wwwboard/forum/32481.html *; filename SASCBTBL catalog 'WORK.WINAPI.WINAPI.SOURCE'; data _null_; file SASCBTBL; input ; put _infile_; cards4; routine RegOpenKeyExA module = advapi32 minarg = 5 maxarg = 5 stackpop = called returns = long ; arg 1 input num byvalue format = pib4.; * HKEY hKey, // handle of open key ; arg 2 input char byaddr format = $cstr200.; * LPCTSTR lpSubKey, // address of name of subkey to open; arg 3 input num byvalue format = pib4.; * DWORD ulOptions, // reserved ; arg 4 input num byvalue format = pib4.; * REGSAM samDesired, // security access mask ; arg 5 update num byaddr format = pib4.; * PHKEY phkResult // address of handle of open key ; routine RegQueryInfoKeyA module = advapi32 minarg = 12 maxarg = 12 stackpop = called returns = long ; arg 1 input num byvalue format = pib4.; * HKEY hKey, // handle of key to query; arg 2 update char byaddr format = $cstr200.; * LPTSTR lpClass, // address of buffer for class string ; arg 3 input num byaddr format = pib4.; * LPDWORD lpcbClass, // address of size of class string buffer ; arg 4 input num byvalue format = pib4.; * LPDWORD lpReserved, // reserved ; arg 5 update num byaddr format = pib4.; * LPDWORD lpcSubKeys, // address of buffer for number of subkeys ; arg 6 update num byaddr format = pib4.; * LPDWORD lpcbMaxSubKeyLen, // address of buffer for longest subkey name length ; arg 7 update num byaddr format = pib4.; * LPDWORD lpcbMaxClassLen, // address of buffer for longest class string length ; arg 8 update num byaddr format = pib4.; * LPDWORD lpcValues, // address of buffer for number of value entries ; arg 9 update num byaddr format = pib4.; * LPDWORD lpcbMaxValueNameLen, // address of buffer for longest value name length ; arg 10 update num byaddr format = pib4.; * LPDWORD lpcbMaxValueLen, // address of buffer for longest value data length ; arg 11 update num byaddr format = pib4.; * LPDWORD lpcbSecurityDescriptor, // address of buffer for security descriptor length ; arg 12 update char byaddr format = $cstr8.; * PFILETIME lpftLastWriteTime // address of buffer for last write time (64bit time value); routine RegEnumValueA module = advapi32 minarg = 8 maxarg = 8 stackpop = called returns = long ; arg 1 input num byvalue format=pib4.; * HKEY hKey, // handle of key to query ; arg 2 input num byvalue format=pib4.; * DWORD dwIndex, // index of value to query ; arg 3 update char byaddr format=$cstr200.; * LPTSTR lpValueName, // address of buffer for value string ; arg 4 update num byaddr format=pib4.; * LPDWORD lpcbValueName, // address for size of value buffer ; arg 5 input num byvalue format=pib4.; * LPDWORD lpReserved, // reserved ; arg 6 update num byaddr format=pib4.; * LPDWORD lpType, // address of buffer for type code ; arg 7 input num byvalue format=pib4.; * LPBYTE lpData, // address of buffer for value data, USE ADDR(); arg 8 update num byaddr format=pib4.; * LPDWORD lpcbData // address for size of data buffer ; routine RegCloseKey module = advapi32 minarg = 1 maxarg = 1 stackpop = called returns = long ; arg 1 input num byvalue format = pib4.; * HKEY hKey, // handle of key to close ; routine RegQueryValueExA module = advapi32 minarg = 6 maxarg = 6 stackpop = called returns = long ; arg 1 input num byvalue format = pib4.; * HKEY hKey, // handle of key to query ; arg 2 input char byaddr format = $cstr200.; * LPTSTR lpValueName, // address of name of value to query ; arg 3 input num byvalue format = pib4.; * LPDWORD lpReserved, // reserved ; arg 4 update num byaddr format = pib4.; * LPDWORD lpType, // address of buffer for value type ; arg 5 input num byvalue format = pib4.; * LPBYTE lpData, // address of data buffer *** must use addr(); arg 6 update num byaddr format = pib4.; * LPDWORD lpcbData // address of data buffer size ; ;;;; run; %let HKEY_CLASSES_ROOT = 80000000x; %let HKEY_CURRENT_USER = 80000001x; %let HKEY_LOCAL_MACHINE = 80000002x; %let HKEY_USERS = 80000003x; %let HKEY_PERFORMANCE_DATA = 80000004x; %let HKEY_CURRENT_CONFIG = 80000005x; %let HKEY_DYN_DATA = 80000006x; %let REG_SZ = 00000001x; %let REG_DWORD = 00000004x; %let KEY_QUERY_VALUE = 00000001x; %let KEY_SET_VALUE = 00000002x; %let ERROR_MORE_DATA = 234; data UserAssist; length cval $200; length valtype cvallen hkey 8; node = 'Software\Microsoft\Windows\CurrentVersion\Explorer\'; rc = ModuleN ( '*e' , 'RegOpenKeyExA' , &HKEY_CURRENT_USER , node , 0 , &KEY_QUERY_VALUE , hkey1 ); put rc= hkey1=; do examine = 'UserAssist\{5E6AB780-7743-11CF-A12B-00AA004AE837}\Count' , 'UserAssist\{75048700-EF1F-11D0-9888-006097DEACF9}\Count' ; hkey2 = 0; rc = ModuleN ( '*e' , 'RegOpenKeyExA' , hkey1 , examine , 0 , &KEY_QUERY_VALUE , hkey2 ); put rc= hkey2=; length class $50; classLen = vlength(class); length LastWriteTime $8; LastWriteTime = 'abcdefgh'; * moduleN will change this value; rc = ModuleN ( '*e' , 'RegQueryInfoKeyA' , hkey2 , class , classLen , 0 , SubKeys , MaxSubKeyLen , MaxClassLen , Values , MaxValueNameLen , MaxValueLen , SecurityDescriptor , LastWriteTime ); put examine= 'has ' values 'values'; lo = input (substr(lastwritetime,1,4),pib4.); hi = input (substr(lastwritetime,5,4),pib4.); lwt_msoft = lo + hi * 2**32; * # of 100ns intervals since 01jan1601:0:0:0; lwt_sasdt = lwt_msoft / 10e6 + '01jan1601:0:0:0'dt; * convert ns to s and adjust epoch; put 'LastWriteTime' lwt_sasdt datetime19.; do ix = 0 to Values-1; length rotn name $200 value $200; nameLen = vlength(name); valueLen = vlength (value); rc = ModuleN ( '*e' , 'RegEnumValueA' , hkey2 , ix , rotn , nameLen , 0 , type , addr(value) , valueLen ); * apply ROT-13 transformation; name = translate ( rotn , 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' , 'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM' ); * put rc= ix=z4. value=$HEX32. rotn= / +47 name=; vhex = put (value, $HEX32.); output; end; rc = ModuleN ( '*e' , 'RegCloseKey' , hkey2 ); end; rc = ModuleN ( '*e' , 'RegCloseKey' , hkey1 ); stop; keep examine ix value vhex rotn name; run;