'How to impersonate current process as SYSTEM on windows xp?

Process originaly runs as user (with admin privileges). In some point I want to rename file owned by user SYSTEM. So I need to impersonate my process as SYSTEM.

I have code that works correct on any windows later XP (and 2003):

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle);

...

var systemProcessId = Process.GetProcessesByName("wininit").First().Id;
var handle = OpenProcess(ProcessAllAccess, false, systemProcessId);
private IntPtr _token;
OpenProcessToken(handle, (uint) TokenAccessLevels.MaximumAllowed, out _token)
WindowsIdentity.Impersonate(_token);

It doesn't work on Windows XP (and 2003). How can I get same result on XP and 2003?



Solution 1:[1]

I suppose you can try to do something like this:

var handle = Kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, false,
                        **smss.exe**);
if (handle.IsInvalid)
    throw new Exception("Can't open system process for access.");

if (!AdvApi32.OpenProcessToken(handle.DangerousGetHandle(),
        WRITE_DAC, out var token))
    throw new Exception($"OpenProcessToken failed, error code: {GetLastError()}");

if (!ConvertStringSecurityDescriptorToSecurityDescriptor("O:BAG:BAD:P(A;CIOI;GA;;;BA)", 1, out var pSd, out _))
    throw new Exception(
        $"ConvertStringSecurityDescriptorToSecurityDescriptor failed, error code: [{GetLastError()}]");

if (!SetKernelObjectSecurity(token.DangerousGetHandle(),
        DACL_SECURITY_INFORMATION, pSd))
    throw new Exception($"SetKernelObjectSecurity failed, error code: {GetLastError()}");
if (!token.IsInvalid && !token.IsClosed)
    token.Close();

if (!AdvApi32.OpenProcessToken(handle.DangerousGetHandle(),
        TOKEN_DUPLICATE,
        out token))
    throw new Exception($"OpenProcessToken failed, error code: {GetLastError()}");

if (!AdvApi32.DuplicateTokenEx(token,
        TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
        null,
        SecurityImpersonation,
        TokenPrimary,
        out var newToken))
    throw new Exception($"DuplicateTokenEx failed, error code: {GetLastError()}");
if (!token.IsInvalid && !token.IsClosed)
    token.Close();

WindowsIdentity.Impersonate(newToken.DangerousGetHandle());

I really, really think it's working code on Windows XP.

Solution 2:[2]

Explicit conversion Boolean -> INT:

SELECT *, col1::INT + col2::INT + col3::INT AS num_of_true
FROM tab

Solution 3:[3]

The CASE of Samuel's answer CASE WHEN [COL 1]=1 THEN 1 ELSE 0 END can be replace with an IFF IFF("COL 1",1,0)

thus

SELECT 
    *,
    IFF("COL 1",1,0) + IFF("COL 2",1,0) + IFF("COL 3",1,0) AS "# TRUE"
FROM table

You can loop across columns in a stored procedure, or use client side scripts in python/javascript/etc to build the SQL.

Solution 4:[4]

I don't believe there's a way to automatically iterate through columns in SQL (in a sort of 'SUM columns 1-5' sort of way), so I believe you'd have to explicitly name each column.

You could create your calculated column above by doing something like

SELECT *,
(
CASE WHEN [COL 1]=1 THEN 1 ELSE 0 END +
CASE WHEN [COL 2]=1 THEN 1 ELSE 0 END +
CASE WHEN [COL 3]=1 THEN 1 ELSE 0 END
) AS "# TRUE"
FROM [...]

Solution 5:[5]

A solution that doesn't care about how many columns you have - by leveraging object_construct:

with data as (
    select $1 id, $2 c1, $3 c2, $4 c3, $5 c4
    from values(1, true, false, true, true)
    , (2, true, true, false, false)
    , (3, true, true, true, true)
), transformed as (
    select object_construct(a.*) b
    from data a
)

select seq, count_if(value='true')
from transformed, table(flatten(b))
group by 1

enter image description here

Solution 6:[6]

This might come in more handy if you have a lot of non-null columns.

select regexp_count(concat(col1,col2,col3),'true', 1, 'i') -- i is a case insensitive flag

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Lukasz Szozda
Solution 3 marc_s
Solution 4 Samuel Cochrane
Solution 5 Felipe Hoffa
Solution 6 Phil Coulson