|
|
Comments and Discussions
|
|
 |

|
I am not too familiar with C++. How do I run this example? I think I need this but in C#.
Do I start the Service manually first? If so, how?
any help appreciated.
|
|
|
|

|
I used this code to obtain the mapped drives that a user would normally be able to see. Since my application must run elevated, it normally can't see the same mapped drives that the user can. Thanks!
|
|
|
|

|
This seems like a nice way to do it, provided you don't care about situations where the Shell is not running (e.g. possibly some Terminal Services application-only setups, perhaps, though I'm not sure):
http://brandonlive.com/2008/04/27/getting-the-shell-to-run-an-application-for-you-part-2-how/
It gets an interface to Explorer.exe, which should be running in the user's normal context, and asks Explorer to execute a command in its behalf. This is done just using simple, documented COM interfaces and without having to mess around with process tokens or code/DLL injection.
|
|
|
|

|
Thanks it works!
I successfully launched IE in protected mode from High Integrity level process using this method.
|
|
|
|

|
I added this into a standard dll and tried to call it from InstallShield using DoAction upon user clicking OK-Finish at the end of install. However, it prompts an error "Unknown source 'c$'" and the log shows the following. When I launch the dll custom action in the Executionj Sequence it works, but I dont really understand why dll doesnt work when launched as a DoAction at Finish. I will try creating an exe with the same code and launch an exe custom action instead of dll one.
I would appreciate any input. Thanks.
Action ended 19:14:01: DLLWrapCleanup. Return value 1.
MSI (c) (BC:68) [19:14:01:576]: Doing action: SetupCompleteSuccess
Action start 19:14:01: SetupCompleteSuccess.
MSI (c) (BC:10) [19:14:03:451]: PROPERTY CHANGE: Adding LAUNCHPROGRAM property. Its value is '1'.
MSI (c) (BC:10) [19:14:04:357]: Doing action: LaunchwithToken2
Action start 19:14:04: LaunchwithToken2.
MSI (c) (BC:10) [19:14:04:373]: Invoking remote custom action. DLL: C:\DOCUME~1\fbaggins\LOCALS~1\Temp\MSI4FD.tmp, Entrypoint: DLL2
Action ended 19:14:13: LaunchwithToken2. Return value 3.
Info 2896.Executing action LaunchwithToken2 failed.
Action ended 19:14:13: SetupCompleteSuccess. Return value 3.
|
|
|
|

|
I actually figured out the problem. A std dll custom action cant be launched at that stage, it has to be an MSI DLL.
|
|
|
|

|
Hello
Your article is interesting.
I want to use it in an installer which runs under admin privileges and at the end of the installation it should run the installed application under the account of the currently logged in user.
______________
In your code is missing a: #include "Windows.h"
______________
The worst is: Your code does not work.
It has multiple problems.
I tried it on Vista under a User account.
I compile the EXE and run it "As Administrator".
The Vista Elevation Windows pops up and asks to enter the admin password.
What happens is VERY strange.
I narrowed down your code to the follwing test code which demonstrates what is happening:
int main(int argc, char* argv[])
{
DWORD dwExplorerIL=0;
HRESULT hr=GetProcessIL(2896, &dwExplorerIL);
printf("ExplorerIL=0x%X", dwExplorerIL);
return 0;
}
The explorer process has ID 2896 during my tests.
The STRANGE thing is that
the output shows ExplorerIL=0x2000 (MEDIUM_RID) when running the EXE as the currently logged in user, but
the output shows ExplorerIL=0x3000 (HIGH_RID) when running the EXE "As Administrator"!!!
This is complete nonsense!
The explorer does not change it's IL!!
But exactly this happens!
The reason is your crappy error handling:
Instead of returning IL=0 when an error occurres your function GetProcessIL() returns HIGH_RID.
_________________
The cause is that
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS, ..., ...);
returns ERROR_ACCESS_DENIED although the program runs "As Administrator".
I thought that ALL_ACCESS is quite exaggerated and changed it into PROCESS_QUERY_INFORMATION.
This must be replaced once in
(BUG 1) GetProcessIL() and another time in
(BUG 2) CreateProcessWithExplorerIL()
After that there is no more ERROR_ACCESS_DENIED.
________________
And the code has another error:
OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken)
also returns ERROR_ACCESS_DENIED
Again I thought that TOKEN_ALL_ACCESS is quite exaggerated and changed it into
(BUG 3) TOKEN_QUERY in the function GetProcessIL() and into
(BUG 4) TOKEN_DUPLICATE in the function CreateProcessWithExplorerIL().
________________
There is another BUG 5:
Your function ReducePrivilegesForMediumIL() will NEVER be called!
First you check
if (dwCurIL==HIGH_RID && dwExplorerIL==MEDIUM_RID)
if this is true you check some lines later
if (dwCurIL==MEDIUM_RID && dwExplorerIL==MEDIUM_RID)
which will NEVER happen!
I don't understand why you wrote this function at all?
If Explorer already runs with MEDIUM_RID why do you want to reduce the privileges to MEDIUM_RID then?
Why do you check at all if Explorer runs with MEDIUM IL ?
Did you ever see that it didn't ?
So you can completely remove the unused functions SetPrivilege() and ReducePrivilegesForMediumIL()
_______________
The BUG 6 is another time crappy error handling:
If GetSidSubAuthority() returns NULL your application will crash.
_______________
LoadLibrary("Kernel32") and then FreeLibrary() can be replaced by
GetModuleHandle("Kernel32")
_______________
Your comments dont always make sense:
_______________
Your code is NOT a cleanly written code and it does NOT have clean error handling.
Nevertheless: thanks for your code!
The interesting thing is that although the admin runs your code the new process which is created will run under the user name of the currenlty logged-in user as I can see in Taskmanager.
This is exactly what I need for my installer because the new process must access the correct "Documents and Settings" folder.
Elmü
|
|
|
|

|
I cleaned your code and fixed the bugs.
I tested it on Windows 2000,XP,Vista and Windows 7.
Now it works seamlessly.
#include "stdafx.h"
#include "windows.h"
#ifndef SECURITY_MANDATORY_HIGH_RID
#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L)
#define SECURITY_MANDATORY_LOW_RID (0x00001000L)
#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
#define SECURITY_MANDATORY_HIGH_RID (0x00003000L)
#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L)
#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L)
#endif
#ifndef TokenIntegrityLevel
#define TokenIntegrityLevel ((TOKEN_INFORMATION_CLASS)25)
#endif
#ifndef TOKEN_MANDATORY_LABEL
typedef struct
{
SID_AND_ATTRIBUTES Label;
} TOKEN_MANDATORY_LABEL;
#endif
typedef BOOL (WINAPI *defCreateProcessWithTokenW)
(HANDLE,DWORD,LPCWSTR,LPWSTR,DWORD,LPVOID,LPCWSTR,LPSTARTUPINFOW,LPPROCESS_INFORMATION);
DWORD GetProcessIL(DWORD u32_PID, DWORD* pu32_ProcessIL)
{
*pu32_ProcessIL = 0;
HANDLE h_Process = 0;
HANDLE h_Token = 0;
DWORD u32_Size = 0;
BYTE* pu8_Count = 0;
DWORD* pu32_ProcIL = 0;
TOKEN_MANDATORY_LABEL* pk_Label = 0;
h_Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, u32_PID);
if (!h_Process)
goto _CleanUp;
if (!OpenProcessToken(h_Process, TOKEN_QUERY, &h_Token))
goto _CleanUp;
if (!GetTokenInformation(h_Token, TokenIntegrityLevel, NULL, 0, &u32_Size) &&
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto _CleanUp;
pk_Label = (TOKEN_MANDATORY_LABEL*) HeapAlloc(GetProcessHeap(), 0, u32_Size);
if (!pk_Label)
goto _CleanUp;
if (!GetTokenInformation(h_Token, TokenIntegrityLevel, pk_Label, u32_Size, &u32_Size))
goto _CleanUp;
pu8_Count = GetSidSubAuthorityCount(pk_Label->Label.Sid);
if (!pu8_Count)
goto _CleanUp;
pu32_ProcIL = GetSidSubAuthority(pk_Label->Label.Sid, *pu8_Count-1);
if (!pu32_ProcIL)
goto _CleanUp;
*pu32_ProcessIL = *pu32_ProcIL;
SetLastError(ERROR_SUCCESS);
_CleanUp:
DWORD u32_Error = GetLastError();
if (pk_Label) HeapFree(GetProcessHeap(), 0, pk_Label);
if (h_Token) CloseHandle(h_Token);
if (h_Process) CloseHandle(h_Process);
return u32_Error;
}
DWORD CreateProcessMediumIL(WCHAR* u16_Path, WCHAR* u16_CmdLine)
{
HANDLE h_Process = 0;
HANDLE h_Token = 0;
HANDLE h_Token2 = 0;
PROCESS_INFORMATION k_ProcInfo = {0};
STARTUPINFOW k_StartupInfo = {0};
BOOL b_UseToken = FALSE;
if (GetProcAddress(GetModuleHandleA("Kernel32"), "GetProductInfo"))
{
DWORD u32_CurIL;
DWORD u32_Err = GetProcessIL(GetCurrentProcessId(), &u32_CurIL);
if (u32_Err)
return u32_Err;
if (u32_CurIL > SECURITY_MANDATORY_MEDIUM_RID)
b_UseToken = TRUE;
}
if (!b_UseToken)
{
if (!CreateProcessW(u16_Path, u16_CmdLine, 0, 0, FALSE, 0, 0, 0, &k_StartupInfo, &k_ProcInfo))
return GetLastError();
CloseHandle(k_ProcInfo.hThread);
CloseHandle(k_ProcInfo.hProcess);
return ERROR_SUCCESS;
}
defCreateProcessWithTokenW f_CreateProcessWithTokenW =
(defCreateProcessWithTokenW) GetProcAddress(GetModuleHandleA("Advapi32"), "CreateProcessWithTokenW");
if (!f_CreateProcessWithTokenW) return ERROR_INVALID_FUNCTION;
HWND h_Progman = ::GetShellWindow();
DWORD u32_ExplorerPID = 0;
GetWindowThreadProcessId(h_Progman, &u32_ExplorerPID);
h_Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, u32_ExplorerPID);
if (!h_Process)
goto _CleanUp;
if (!OpenProcessToken(h_Process, TOKEN_DUPLICATE, &h_Token))
goto _CleanUp;
if (!DuplicateTokenEx(h_Token, TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &h_Token2))
goto _CleanUp;
if (!f_CreateProcessWithTokenW(h_Token2, 0, u16_Path, u16_CmdLine, 0, 0, 0, &k_StartupInfo, &k_ProcInfo))
goto _CleanUp;
SetLastError(ERROR_SUCCESS);
_CleanUp:
DWORD u32_Error = GetLastError();
if (h_Token) CloseHandle(h_Token);
if (h_Token2) CloseHandle(h_Token2);
if (h_Process) CloseHandle(h_Process);
CloseHandle(k_ProcInfo.hThread);
CloseHandle(k_ProcInfo.hProcess);
return u32_Error;
}
int main(int argc, char* argv[])
{
DWORD u32_Err = CreateProcessMediumIL(L"C:\\Windows\\System32\\Calc.exe", NULL);
printf("CreateProcessMediumIL() exited with error %d\r\n", u32_Err);
Sleep(2000);
return 0;
}
|
|
|
|

|
Thanks for the code!
It is incredible that we have to write so much code because the <*!stupid!*> guys at Microsoft did not imeplement a "runas CurrentUser" !!!
|
|
|
|

|
Hey, super coder genius...
_T("Progman").
If you are going to correct code at least make sure it is compatible with the current set of compilers/OS, such as 2008 and XP.
Why you have to be the ultimate jerk is unknown, but good luck with that.
What you say?
|
|
|
|

|
Many thanks for the effort the original author put in the code and also thanks for these bug fixes!
Though the code is still not 100% bug-free because you did not close the unused handles of the newly created process. See my fix below:
if (!b_UseToken)
{
if (!CreateProcessW(u16_Path, u16_CmdLine, 0, 0, FALSE, 0, 0, 0, &k_StartupInfo, &k_ProcInfo))
return GetLastError();
::CloseHandle( k_ProcInfo.hThread );
::CloseHandle( k_ProcInfo.hProcess );
return ERROR_SUCCESS;
}
And another one:
if (!f_CreateProcessWithTokenW(h_Token2, 0, u16_Path, u16_CmdLine, 0, 0, 0, &k_StartupInfo, &k_ProcInfo))
goto _CleanUp;
::CloseHandle( k_ProcInfo.hThread );
::CloseHandle( k_ProcInfo.hProcess );
SetLastError(ERROR_SUCCESS);
Even better would be to extend the function declaration of CreateProcessMediumIL() to accept all parameters of the original CreateProcess() / CreateProcessWithTokenW() and forward them unmodified. So we would still have the flexibility to use the process handles, if we want to wait for the process, for example.
|
|
|
|

|
Hello
Thanks for the hint.
I added your changes.
> ...So we would still have the flexibility to use the process handles, if we want to wait for the process, for example.
Obviously.
But if you don't need it (like me) its just blowing up the code...
and you generate a new problem: The caller must not forget to close the handles.
In the real live I use a C++ class CHandle that stores my handles and it's destructor cares about closing them.
Elmü
|
|
|
|
|

|
Hi Friends,
Vista for Internet Explorer, doesn't allow to inject any DLL present in HKLM\SOFTWARE\MICROSOFT\Windows NT\CurrentVersion\Windows\AppInit_Dlls.
I've also set the entry LoadAppInit_Dlls to 1.
When IE start, it stop working.
Please, help me to solve the problem.
Thanks,
Sunil.
|
|
|
|

|
So far this solution is working for me, the only place I think it might not work is on a DRM'd Vista Media PC. I'll check that out later.
Can't this be done without impersonating explorer? Can't a token just be adjusted to have the same qualities as the explorer process?
It looks like the explorer process has the following attributes:
Administrator group is set as "deny only"
Mandatory Label is set to Medium (S-1-16-8192)
Most privileges are disabled.
I've tried creating a copy of my token and setting these values but there must be something else in the explorer token that is different because it still isn't working unless I just copy the explorer token. Are there any good tools to fully analyze the properties of a token?
Weee!!!
|
|
|
|

|
This will help me to survive in the move to Vista!
|
|
|
|

|
This is a tricky problem to get around, and you have provided a creative solution using token duplication. Well done and thanks.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
Article introduce to the way of creation a process with the same IL as the shell process (explorer.exe) in Vista. If the shell process is executed with Medium IL and the current process has High IL the new process will be started with Medium IL.
| Type | Article |
| Licence | CPOL |
| First Posted | 21 Jan 2008 |
| Views | 35,190 |
| Downloads | 420 |
| Bookmarked | 27 times |
|
|