Quantcast
Channel: Windows SDK Support Team Blog
Viewing all 27 articles
Browse latest View live

Hotfix for January 2016


Hotfix List for February 2016

$
0
0

Hi guys,

Jeff here from the Windows SDK team. Here are the Windows hotfixes for February 2016.

KB3007507   “HTTP Error 500.19″ error when you browse an IIS 8.5 website in Windows

KB3090343   Cluster service stops during the VSS backup in a Windows Server 2012 R2 or Windows Server 2012-based Hyper-V cluster

KB3123593   A multi-site failover cluster goes into a split brain situation in Windows Server 2012 R2

KB3133689   UBPM doesn’t set environmental variables correctly when you run scheduled tasks in Windows Server 2012 R2

Happy patching!

/Jeff

Follow us on Twitter, www.twitter.com/WindowsSDK.

Why does SqlDataReader behave differently with Set-PSDebug enabled?

$
0
0

We recently had someone ask why their PowerShell script stopped working correctly when they enabled tracing with the command Set-PSDebug -Trace 2.  The part of the code in question that didn’t work basically boiled down to something like this:

function Execute-Query($connectionString)
{
$connection = New-Object System.Data.SqlClient.SQLConnection;
$connection.ConnectionString = $connectionString;
$connection.Open();
$cmd = $connection.CreateCommand();
$cmd.CommandText = "SELECT * FROM [dbo].[Table]";
$cmd.Connection = $connection;
$result = $cmd.ExecuteReader();
$result
}
$result = Execute-Query $connString
foreach($Record in $result)
{
$Record[1]
}

When this was ran with Set-PSDebug -Trace 2 turned on, the foreach loop’s body would not execute no matter how many records where returned by the query.  If Set-PSDebug -Off is then set and the code ran again, it would execute the body of the loop for each record that the query returned.

This happens because the output from Set-PSDebug -Trace 2 results in the object being generically enumerated before it gets to the foreach loop and the object only supports being enumerated through once.  It’s also an issue to some degree because said object is assigned to a variable before that variable is then written to the pipeline which results in the need for more trace output.  Assigning the collection result to a variable, outputting that variable from the function, assigning to a second variable, and operating the foreach loop against that variable while having the tracing enumerate through the collection each time in order to output its contents is what ultimately causes this to result in different behavior with the tracing enabled versus disabled.  That is not supported to behave differently in that scenario and thus will not be changed to accommodate that scenario.  Most collections can be enumerated through multiple times so this won’t come up with them, but if you do want to use Set-PSDebug and use classes which are enumerable but only once for a given object, you do have some options besides just turning Set-PSDebug off.

If you don’t need to do the multiple variable assignments or have the function return the collection directly, you can output the $cmd object and only call ExecuteReader() when your code actually needs the result of the query.

If you’re using PowerShell 4 or 5, this can be worked around by changing the lines “$result =$cmd.ExecuteReader(); $result” to “$result = $cmd.ExecuteReader().GetEnumerator(); $result” unless you need to use members of SqlDataReader that aren’t present in its IEnumerator.  That isn’t the only way to resolve it but it is the smallest code change that comes to mind while keeping the multiple variable assignments in tact.  You can see how the output differs in the trace output from Set-PSDebug -Trace 2 when calling ExecuteReader().GetEnumerator() versus ExecuteReader().  When just ExecuteReader() is assigned to the variable, the collection is enumerated through in the output and the type of the variable is SqlDataReader.  When ExecuteReader().GetEnumerator() is assigned to the variable,  just IEnumerator is seen in the trace output when the variable is set instead of the collections being enumerated through and the variable is of the type DbEnumerator.  If one doesn’t need the assignment to $result in the function, simply outputting “$cmd.ExecuteReader()” to the pipeline also works in this situation.  If you do need to assign the SqlDataReader type to a variable to use its members but only from within the function itself and don’t mind doing the query twice, you can assign $result to $cmd.ExecuteReader(), do what you need to do with $result, call $result.Close(), and then  call $cmd.ExecuteReader() again to output its result.

If the multiple variable assignments of the collection and working with Set-PSDebug -Trace 2 are necessary for one’s scenario, one thing that you can do that works at least as far back as Powershell 2 is to wrap the enumerable results into another collection object which supports multiple enumerations.  For instance, instead of assigning the result of $cmd.ExecuteReader() directly to result, you could make $result = New-Object System.Collections.ArrayList and then pipe the ExecuteReader function’s results to ForEach-Object { [void]$reader.Add($_) }.  That would result in an ArrayList containing the data record objects which could be enumerated through multiple times.  If you want to assign that collection to a variable to work with within a function before putting it to the pipeline from that function and using that variable in a foreach loop, you’ll want to wrap that in another collection as well if Write-Output with the NoEnumerate option isn’t available (e.g. your PowerShell version is older than 4).

 

Visual Studio Team Services and Personal Microsoft Accounts

$
0
0

Visual Studio Team Services and Personal Microsoft Accounts

10/5/2016 UpdateDue to the unexpectedly high impact to many corporate VSTS accounts backed by Personal Microsoft accounts, VSTS accounts are temporarily exempted from the scenario described below. Personal Microsoft accounts created from VSTS invite links or on VisualStudio.com can now be created even if they have the same sign-in name as a Work or School account. This is temporary! Some time in 2017, Personal Microsoft accounts will be permanently blocked if the sign-in name is already in use by a Work or School account.

Please use this extra time to plan your move to one of the 3 options below, and if you are setting up a new VSTS account, please use one of the 3 options below from the start.

/Jeff


Jeff here from the Windows SDK team. I am on temporary assignment to the VSTS group, so this blog post is something a little different.

Microsoft operates two cloud-scale identity systems: Personal Microsoft accounts and Azure Active Directory (AAD).
1. Personal Microsoft accounts (formerly called Live ID). These accounts are meant to be created, managed and used by individuals and are bound to Microsoft’s consumer Terms and Privacy policy.
2. Work or school accounts in Azure AD. These are typically created by IT departments for their users (employees or students). They’re meant to be used to access corporate owned resources such as Office 365 services. They are governable by IT (meaning that IT gets to control and audit the use of these accounts).

When you create a Personal Microsoft account, you either get a new email address from Microsoft (@Outlook.com, @Hotmail.com, etc.) or you can use your own email address or phone number as a sign-in name. Some users have created a Personal Microsoft account with their Work or School email address as a sign-in name. If their organization uses Office 365 or any other business service from Microsoft that relies on Azure AD for authentication, these users will end up with two Microsoft identities with the same sign-in name. When logging on with one of these “Dopplegangers” you may see this dialog:
MSAWSA

Starting on 9/15/2016, Microsoft blocked being able to create new Personal Microsoft accounts using a Work or School email address of a domain that’s configured in an Azure AD or Office 365. There are several problems that can arise when you have duplicate Personal/Work or School accounts with the same sign-in name. It is always confusing which account you need or are using, and in some situations it is not possible to choose the correct account. To address these problems, Microsoft no longer lets you create accounts that overlap. This is explained in this blog. Previously created Personal Microsoft accounts will continue to work, though.

Trying to create a duplicate account throws the error: “You can’t sign up here with a work or school email address.”Error

Impact to Visual Studio Team Services

VSTS has been greatly impacted by this change. Many VSTS accounts are “Personal Microsoft account backed,” this means that you can only logon to VSTS using a Personal Microsoft account. Many businesses have been adding users to Personal Microsoft account backed VSTS accounts by inviting User@company.com. VSTS allows you to invite any user, whether or not the account already exists. In this scenario, the VSTS admin invites a new corporate user, User@company.com, and they receive the email in their corporate inbox. After receiving the email invite, they are prompted to create a Personal Microsoft account when they try to access VSTS, if needed. Many VSTS administrators assume users will be able to create the new Personal Microsoft account, but since 9/15/2016 this has been blocked. Previously invitees to VSTS successfully created Personal Microsoft accounts with their @company.com address, however new invitees may not create a Personal Microsoft account that duplicated the sign-in name of their Work School account.

One of the VSTS program managers shared this with me, as to why using a Personal Microsoft account version of User@company.com (Work or School account) isn’t secure.

“Using a corporate email address to create a personal Microsoft account does not make [it] more or less governable than using a personal email address, but it creates a expectation/perception of governability that has hurt enough customers that we’ve decided to stop that practice. 

Unlike user accounts in Azure AD,  IT pros have no administrative control of personal Microsoft accounts, regardless of the email address those accounts were created with. They can’t prevent users from changing the account username and they can’t prevent users from continuing to use those accounts after they leave the organization. They can’t apply policies to them. They can’t delete them. They can’t exert any control over what applications are accessed by these accounts. They can’t audit usage and can’t validate to authorities any particular use of those accounts. They can’t ask Microsoft to release control of these accounts or of account data.”

Now that new duplicate Personal Microsoft accounts are blocked, the only ways for new users to access VSTS are:

1)      Invite users using a real Personal Microsoft account email account (@Hotmail, @Outlook).

2)      Invite users using an email account NOT associated with Azure/O365 (@Gmail, @Yahoo). These users will still need to create a Personal Microsoft account, if they haven’t already.

3)      Create a link between your Azure/O365 AAD and VSTS.

To use options 1 and 2 you need to be OK with @Hotmail, @Gmail, etc. accounts in your VSTS account list. Options 1 and 2 are the easiest, no planning needed.

If you need your VSTS users to only use their corporate email accounts, then you need to use option 3. Option 3 is the more difficult, and requires some thought and planning. Information on linking an AAD and VSTS can be found here.

Some things to watch out for if you link your AAD and VSTS.

1)      External accounts. When you link VSTS and an AAD, only users in the AAD can access VSTS. Corporate users will be fine, but if your VSTS account had any @Hotmail, etc. accounts you will need to add them to your AAD. (When adding a user, choose ‘User with an existing Microsoft Account’.)

2)      Guest accounts. When a VSTS account is backed by Personal Microsoft accounts, there is no concept of guest users, only when you link an AAD to your VSTS account does this show up. Corporate users in the AAD will be members so they are OK, but there are several gotchas with using external Personal Microsoft accounts (guests) with a VSTS account. You can see the user type in the new Azure portal (www.azure.com.)

Guest

  1. Guests can’t search the AAD to add new users VSTS. See this blog for more information and how to use PowerShell to change Guests to Members. Please note: the error message has changed recently, instead of one about AAD guests searching the directory, you will receive the error, “No identities found.”
  2. A guest can’t be assigned ownership of a VSTS account. A guest can still own it, if they owned it before the AAD was linked and you then added their account to the AAD. You could also use PowerShell to switch them to a guest in the AAD (but shouldn’t.)
  3. Guests can be denied all access. There is an option on the settings tab for a VSTS account, External Guest Access. It is set to allow by default, if you set it to deny then no guests can access VSTS. It is possible to have an AAD with only guests in it and in this case no one will be able to access VSTS. You would need to use PowerShell to flip the VSTS owner to be a member, then logon to VSTS and set guest access back to Allow.
    External

/Jeff
 

Why can’t I restore files even when I have backup/restore privileges enabled?

$
0
0

Backup and restore privileges allow some, but not all, types of access checks to be bypassed.  Typically those are sufficient to allow a backup utility to restore data to even sensitive folders.  However, there are some exceptions to that.  For example, at the time of this writing, much of the contents under %programfiles%\WindowsApps out of the box won’t grant sufficient privileges for restore operations that need to modify data on the disk.  If I enable auditing on my Windows 10 1607 system, I may see entries such as this when trying to restore data even when running from a service as local system:

Access Reasons:  READ_CONTROL: Unknown or unchecked
WRITE_DAC: Unknown or unchecked
WRITE_OWNER: Unknown or unchecked
SYNCHRONIZE: Unknown or unchecked
ACCESS_SYS_SEC: Unknown or unchecked
ReadData (or ListDirectory): Unknown or unchecked
WriteData (or AddFile): Denied by Process Trust Label ACE
AppendData (or AddSubdirectory or CreatePipeInstance): Denied by Process Trust Label ACE
WriteEA: Denied by Process Trust Label ACE
ReadAttributes: Unknown or unchecked
WriteAttributes: Unknown or unchecked

Access Mask:  0x11E0197
Privileges Used for Access Check: SeBackupPrivilege
SeRestorePrivilege

This is probably because of the SYSTEM_PROCESS_TRUST_LABEL_ACE present in an object’s SACL; while its meaning isn’t documented, you can reason that the SYSTEM_PROCESS_TRUST_LABEL_ACE, which you can see on the object through the use of common security APIs, corresponds to the message “Denied by Process Trust Label ACE.”  You can see that by running code such as (which could easily be modified to check for said ACE if one wanted to do so):

#include <Windows.h>
#include <sddl.h>
#include <AclAPI.h>
#include <winternl.h>
#include <sstream>
typedef  NTSTATUS(__stdcall *PZwQueryDirectoryFile)(HANDLE FileHandle,
   
HANDLE Event,
   
void* ApcRoutine,
   
void* ApcContext,
   
PIO_STATUS_BLOCK IoStatusBlock,
   
void* FileInformation,
   
ULONG Length,
   
ULONG FileInformationClass,
   
BOOLEAN ReturnSingleEntry,
   
PUNICODE_STRING FileName,
   
BOOLEAN RestartScan
   
); typedef struct _FILE_DIRECTORY_INFORMATION {
   
ULONG NextEntryOffset;
   
ULONG FileIndex;
   
LARGE_INTEGER CreationTime;
   
LARGE_INTEGER LastAccessTime;
   
LARGE_INTEGER LastWriteTime;
   
LARGE_INTEGER ChangeTime;
   
LARGE_INTEGER EndOfFile;
   
LARGE_INTEGER AllocationSize;
   
ULONG FileAttributes;
   
ULONG FileNameLength;
   
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
PZwQueryDirectoryFile NtQueryDirectoryFile;
enum FileInfoClass : ULONG
{
   
FileDirInformation = 1
};
void EnablePrivileges() {
   
HANDLE myToken = NULL;
   
LUID_AND_ATTRIBUTES attr[3] = {};
   
for (int i = 0; i < _countof(attr); i++)    attr[i].Attributes = SE_PRIVILEGE_ENABLED;
   
LookupPrivilegeValueW(NULL, SE_BACKUP_NAME, &attr[0].Luid);
   
LookupPrivilegeValueW(NULL, SE_RESTORE_NAME, &attr[1].Luid);
   
LookupPrivilegeValueW(NULL, SE_SECURITY_NAME, &attr[2].Luid);
   
DWORD bufferSize = sizeof(LUID_AND_ATTRIBUTES) * _countof(attr) + sizeof(DWORD);
   
PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)malloc(bufferSize);
   
if (!tp) DebugBreak();
   
tp->PrivilegeCount = _countof(attr);
   
memcpy(tp->Privileges, attr, sizeof(attr));
   
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &myToken)) DebugBreak();
   
if (!AdjustTokenPrivileges(myToken, FALSE, tp, NULL, NULL, NULL))DebugBreak();
   
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) wprintf(L”Not all privileges were assigned…\n”);
   
if (tp) {
       
free(tp);
       
tp = NULL;
   
}
   
if (myToken) CloseHandle(myToken);
}

void OutputSYSTEM_PROCESS_TRUST_LABEL_ACE_TYPESACLEntries(LPCWSTR fileName) {
   
PSECURITY_DESCRIPTOR psd = NULL;
   
PACL dacl = NULL;
   
PACL sacl = NULL;
   
HANDLE hFile = CreateFile(fileName, ACCESS_SYSTEM_SECURITY | READ_CONTROL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
   
if (hFile == INVALID_HANDLE_VALUE) DebugBreak();
   
int err = GetSecurityInfo(hFile, SE_OBJECT_TYPE::SE_FILE_OBJECT, SACL_SECURITY_INFORMATION | PROCESS_TRUST_LABEL_SECURITY_INFORMATION, NULL, NULL, &dacl, &sacl, &psd);
   
if (err != 0) {
       
wprintf(L”Failed to get security info:\t%d\n”, err);
       
CloseHandle(hFile);
       
return;
   
}
   
else
   
{
       
ACL_SIZE_INFORMATION sizeInfo = {};
       
if (sacl) {
           
if (GetAclInformation(sacl, &sizeInfo, sizeof(sizeInfo), AclSizeInformation)) {
               
for (ULONG i = 0; i < sizeInfo.AceCount; i++) {
                   
PACE_HEADER ah = NULL;
                   
if (GetAce(sacl, i, (void**)&ah) && ah) {
                       
DWORD type = ah->AceType;
                       
DWORD flags = ah->AceFlags;
                       
wprintf(L”System ACE %d is of type %d with flags %x\n”, i, type, flags);
                       
if (type == SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE) {
                           
SYSTEM_PROCESS_TRUST_LABEL_ACE* ace = (SYSTEM_PROCESS_TRUST_LABEL_ACE*)ah;
                           
PSID aceSid = (PSID)(&ace->SidStart);
                           
LPWSTR ssid = NULL;
                           
wprintf(L”%s:\tProcess Trust Level Ace with access mask %x for SID “, fileName, ace->Mask);
                           
if (aceSid == NULL) {
                               
wprintf(L”(NULL)\n”);
                           
}
                           
else if (ConvertSidToStringSidW(aceSid, &ssid)) {
                               
wprintf(L”%s\n”, ssid);
                               
LocalFree(ssid);
                           
}
                           
else {
                               
wprintf(L”(could not convert)\n”);
                           
}
                           
ace->Mask = 0;
                       
}
                   
}
               
}
           
}
       
}
       
else wprintf(L”Null SACL\n”);
   
}
   
CloseHandle(hFile);
}
void ProcessDirectory(LPCWSTR directoryName, int currentRecurseLevel, int maxRecurseLevel);
void ProcessFdi(LPCWSTR directoryName, PFILE_DIRECTORY_INFORMATION p, int currentRecurseLevel, int maxRecurseLevel) {
   
//Skip . and ..
    DWORD one = CompareStringOrdinal(L”.”, 1, p->FileName, p->FileNameLength / 2, TRUE);
   
if (one == CSTR_EQUAL || CompareStringOrdinal(L”..”, 1, p->FileName, p->FileNameLength / 2, TRUE) == CSTR_EQUAL) return;
   
std::wstringstream wss;
   
wss << directoryName;
   
if (*(–(wss.str().end()))._Ptr != ‘\\’) wss << L”\\”;
   
wss.write(p->FileName, p->FileNameLength / 2);
   
if (p->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
       
OutputSYSTEM_PROCESS_TRUST_LABEL_ACE_TYPESACLEntries(wss.str().data());
       
ProcessDirectory(wss.str().data(), currentRecurseLevel + 1, maxRecurseLevel);
   
}
   
else {
       
OutputSYSTEM_PROCESS_TRUST_LABEL_ACE_TYPESACLEntries(wss.str().data());
   
}
}
void ProcessDirectory(LPCWSTR directoryName, int currentRecurseLevel, int maxRecurseLevel) {
   
if (currentRecurseLevel > maxRecurseLevel) return;
   
HANDLE hf = CreateFile(directoryName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
   
if (hf == INVALID_HANDLE_VALUE) {
       
wprintf(L”Failed to process %s:\t%d\n”, directoryName, GetLastError());
       
return;
   
}
   
DWORD fniSize = 200000; //arbitrarily large for laziness and since we’re not going to check status values
    void* FileNamesInfo = malloc(fniSize);
   
if (!FileNamesInfo) {
       
CloseHandle(hf);
       
DebugBreak();
   
}
   
IO_STATUS_BLOCK iosb = {};
   
HRESULT status = HRESULT_FROM_NT(NtQueryDirectoryFile(hf, NULL, NULL, NULL, &iosb, FileNamesInfo, fniSize, FileDirInformation, FALSE, NULL, FALSE));
   
if (FAILED(status)) {
       
wprintf(L”Failed to query %s:\t%x\n”, directoryName, status);
       
CloseHandle(hf);
       
free(FileNamesInfo);
       
return;
   
}
   
PFILE_DIRECTORY_INFORMATION fdi = (PFILE_DIRECTORY_INFORMATION)FileNamesInfo;
   
ProcessFdi(directoryName, fdi, currentRecurseLevel, maxRecurseLevel);
   
while (fdi->NextEntryOffset != 0) {
       
DWORD offset = fdi->NextEntryOffset;
       
fdi = (PFILE_DIRECTORY_INFORMATION)((__int3264)fdi + offset);
       
ProcessFdi(directoryName, fdi, currentRecurseLevel, maxRecurseLevel);
   
}
   
free(FileNamesInfo);
   
CloseHandle(hf);
}
int main() {
   
EnablePrivileges();
   
NtQueryDirectoryFile = (PZwQueryDirectoryFile)GetProcAddress(GetModuleHandle(L”ntdll.dll”), “NtQueryDirectoryFile”);
   
if (!NtQueryDirectoryFile) DebugBreak();
   
ProcessDirectory(L”C:\\Program Files\\WindowsApps\\”, 0, 3);
   
return 0;
}

Leveraging Exploit Guard in Windows Insider Build to Easily Audit Your Code

$
0
0

If you are a software developer and are looking to improve upon the security compliance of your software, there is a feature in the current Windows 10 Enterprise Insider Preview (as of 10.0.16253 - I can't guarantee this will make it or make it unchanged into future builds) that could be very useful to you.  In Settings->Windows Defender->Windows Defender Security Center->App and Browser Control->Exploit Protection Settings, you can enable custom exploit settings for either the entire system or specific programs.  There's a lot of different protections that can be turned on there and many of them can be turned on in Audit Mode.  In Audit Mode, instead of terminating a process when the situation occurs, it will write an event to the event log instead.  For admins, that means allowing the software to continue to run while being made aware of when the situation occurs.  For someone looking to improve upon their product by stopping these situations from happening in their software, it provides the added benefits of enabling security features without having to recompile (in some cases) and telling you exactly where in the code in your processes the issue occurs when it is encountered at runtime.  In build 10.0.16253, the protections that can be audited are:

  • Arbitrary Code Guard - Prevents non-image backed execute code and code page modifications (e.g. VirtualAlloc/VirtualProtect created/modified code)
  • Block Low Integrity Images
  • Block Remote Images
  • Block Untrusted Fonts
  • Code Integrity Guard
  • Disable Win32k system calls
  • Do Not Allow Child Processes
  • Export Address Filtering- One step in one common methodology to patch a function to another function
  • Import Address Filtering - One step in one common methodology to patch a function to another function
  • Simulate Execution
  • Validate API Invocation (CallerCheck)
  • Validate Image Dependency Integrity
  • Validate Stack Integrity

To take full advantage of this, install the Windows Performance Toolkit.  It's one of the installation options with the Windows SDK installer.  After enabling the settings that you are interested in for your application, open up an admin command prompt and browse to the Windows Performance Toolkit directory (typically Program Files (x86)\Windows Kits\{Version}\Windows Performance Toolkit).  You can enable and start collecting tracing for the aforementioned exploit protection settings with the data that you'll need to resolve stack traces by running the following two commands (after substituting whatever paths you want for the filenames):

xperf -on "PROC_THREAD+LOADER" -f "wdeg_klogger.etl"

xperf -start "WDEG" -on "Microsoft-Windows-Security-Mitigations:0xFFFFFFFFFFFFFFFF:0xFF:'stack'"  -f "wdeg_unmerged.etl"

After you run through whatever scenario you want to collect, you can stop the tracing and merge the data together with the following (after again substituting whatever paths you want for the filenames):

xperf -stop -stop "WDEG" -d "wdeg_merged.etl"

You can then delete the first two files that were created since you'll have all the data that you need in the third at this point.  You can open up the resultant etl file in Windows Performance Analyzer (WPA) and have a look at the data.  If you're not familiar with doing this, here's a sample preset file for looking at just this sort of data:

<?xml version="1.0" encoding="utf-8"?>
<WpaProfileContainer xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="2" xmlns="http://tempuri.org/SerializableElement.xsd">
  <Content xsi:type="WpaProfile2">
    <Sessions />
    <Views />
    <ModifiedGraphs>
      <GraphSchema Guid="04f69f98-176e-4d1c-b44e-97f734996ab8">
        <ModifiedPresets>
          <Preset Name="EG Stacks" BarGraphIntervalCount="50" IsThreadActivityTable="false" LeftFrozenColumnCount="5" RightFrozenColumnCount="9" KeyColumnCount="4" GraphColumnCount="10" InitialFilterQuery="[Event Name]:~=&quot;Microsoft-Windows-Security-Miti&quot;" InitialFilterShouldKeep="true" GraphFilterTopValue="0" GraphFilterThresholdValue="0" HelpText="{}{\rtf1\ansi\ansicpg1252\uc1\htmautsp\deff2{\fonttbl{\f0\fcharset0 Times New Roman;}{\f2\fcharset0 Segoe UI;}}{\colortbl\red0\green0\blue0;\red255\green255\blue255;}\loch\hich\dbch\pard\plain\ltrpar\itap0{\lang1033\fs18\f2\cf0 \cf0\ql{\f2 {\ltrch Groups all the events by provider, task, and opcode.}\li0\ri0\sa0\sb0\fi0\ql\par}
}
}">
            <Columns>
              <Column Name="Provider Name" Guid="8b4c40f8-0d99-437d-86ab-56ec200137dc" Width="200" IsVisible="true" SortPriority="18" />
              <Column Name="Task Name" Guid="511777f7-30ef-4e86-bd0b-0facaf23a0d3" Width="80" IsVisible="true" SortPriority="19" />
              <Column Name="Event Name" Guid="90fe0b49-e3bb-440f-b829-5813c42108a1" Width="100" IsVisible="false" SortPriority="0" />
              <Column Name="Stack" Guid="26eed6bf-f07d-4bb0-a36f-43a7d3a68828" Width="247" IsVisible="true" SortPriority="0">
                <StackOptionsParameter />
              </Column>
              <Column Name="Message" Guid="0734f1a4-fbd9-4ff6-aec0-cf43875c8253" Width="100" IsVisible="true" SortPriority="0" />
              <Column Name="Process" Guid="7ee6a5ff-1faf-428a-a7c2-7d2cb2b5cf26" Width="150" IsVisible="true" SortPriority="28" />
              <Column Name="ThreadId" Guid="edf01e5d-3644-4dbc-ab9d-f8954e6db6ea" Width="50" IsVisible="true" SortPriority="27" />
              <Column Name="Time" Guid="bbfc990a-b6c9-4dcd-858b-f040ab4a1efe" Width="80" IsVisible="true" SortPriority="29" />
            </Columns>
            <MetadataEntries>
              <MetadataEntry Guid="edf01e5d-3644-4dbc-ab9d-f8954e6db6ea" Name="ThreadId" ColumnMetadata="EndThreadId" />
              <MetadataEntry Guid="bbfc990a-b6c9-4dcd-858b-f040ab4a1efe" Name="Time" ColumnMetadata="StartTime" />
              <MetadataEntry Guid="bbfc990a-b6c9-4dcd-858b-f040ab4a1efe" Name="Time" ColumnMetadata="EndTime" />
            </MetadataEntries>
            <HighlightEntries />
          </Preset>
        </ModifiedPresets>
        <PersistedPresets />
      </GraphSchema>
    </ModifiedGraphs>
  </Content>
</WpaProfileContainer>

You can save it with a wpaPreset file extension, load your data in WPA, go to My Presets (File->Window->My Presents in the newer versions of WPA), select Import, browse to wherever you saved the preset, choose it, and double-click it to bring up the view.  You'll want to load symbols in order to make the most of this.  You set up symbols in WPA under File->Configure Symbols; you'll want to point it to the Microsoft symbol server at msdl.microsoft.com/download/symbols as well as your symbol server (or location where you have your symbols files if you don't have a symbol server setup).  You can configure WPA to load symbols automatically whenever you load a trace, but you can also always manually load symbols by going to File->Load Symbols.  Once that's done, you'll be able to look at your stack traces pretty easily.  It'll look something like this:

Here's the sample code that I used compiled as an x64 console application when creating the above:

#include <Windows.h>
#include <iostream>
using namespace std;
void* CreateCodeInVirtualMemory(BOOL writable)
{
	BYTE code[3] = { 0x33, 0xc0, 0xc3 };
	LPVOID result = VirtualAlloc(NULLsizeof(code), MEM_COMMIT | MEM_RESERVEwritable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
	if (result)
	{
		memcpy(result, code, sizeof(code));
	}
	else cout << "VirtualAllocEx failed with error " << GetLastError() << endl;
	return result;
}
void CreateCodeInVirtualMemoryAndExecute(BOOL useWritableMemory)
{
	LPTHREAD_START_ROUTINE addr = (LPTHREAD_START_ROUTINE)CreateCodeInVirtualMemory(useWritableMemory);
	if (addr)
	{
		DWORD result = addr(NULL);
		cout << "Code at 0x" << hex << (void*)addr << " returned " << result << endl;
	}
	else cout << "NULL address was not executed" << endl;
}
void ExecuteIllegalMemory()
{
	CreateCodeInVirtualMemoryAndExecute(FALSE);
}

void PrintOptions()
{
	cout << "Enter one of the following options:" << endl;
	cout << "1 - Execute Memory Not Marked As Executable" << endl;
	cout << "2 - Create Code in Virtual Memory" << endl;
	cout << "3 - Create Code in Virtual Memory and Execute" << endl;
	cout << "0 - Exit" << endl;

}
void DecisionLoop()
{
	while (true)
	{
		int selection;
		PrintOptions();
		cin >> selection;
		switch (selection)
		{
			case 0:
				return;
			case 1:
				ExecuteIllegalMemory();
				break;
			case 2:
				CreateCodeInVirtualMemory(TRUE);
				break;
			case 3:
				CreateCodeInVirtualMemoryAndExecute(TRUE);
				break;
			default:
				cout << "Invalid input" << endl;
		}
	}
}
int main()
{
	DecisionLoop();
	return 0;
}

There are certainly more use cases for this that aren't covered here; this just scratches the surface of the possibilities 🙂

This kind of thing can also be done in much the same way for most anything that you find under Applications and Services logs in Event Viewer; click on the properties for a specific log and it will have the name in the form of Provider-Name-Parts/LogName.  You just want to use the "Provider-Name-Parts" portion in the xperf command.

OpenService() fails on a service marked for deletion on Windows 10, Version 1703 (OS build 15063)

$
0
0

OpenService() fails with error code 1060 or ERROR_SERVICE_DOES_NOT_EXIST when a service is marked for deletion (DeleteService).

This is a known bug.

It should be fixed on the next version of Windows.

Viewing all 27 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>