Piszę IDE i właśnie wpadłem na zwariowany pomysł - możliwość uruchamiania kompilatora jako inny użytkownik (w razie braku zaufania do danego exe). Ale pojawił się mały problem - funkcja CreateProcessWithLogonW nie ma parametru InheritHandles tak jak jest w CreateProcess.
Pierwszy problem jaki mnie spotkał, to błąd InvalidHandle - process nie uruchamiał się wcale - musiałem usunąć STARTF_USESTDHANDLES ze struktury STARTUPINFO.
Drugi problem - jak podmienić stdout takiego procesu - proste, DuplicateHandle i kilka operacji read/write memory symulujących zdalne wywołanie SetStdHandle. Zrobiłem tak i faktycznie mój uchwyt pojawił się w stdout i stderror procesu.
Ale tuż po ResumeThread proces kończy z exitcode=1. Pomyślałem że to brak uprawnień, więc ręcznie dodałem usera do 'folderu' z pełnymi uprawnieniami (XP). Pomyślałem też, że w jakiś sposób dany process nie jest w stanie zapisać do pliku który jest w moim profilu, w /temp - kopia jego uchwytu jest wpisana jako stdout tego procesu z identycznym ACCESS_MASK (DuplicateHandle). Zmieniłem ścieżkę tego pliku żeby był w bardziej dostępnym miejscu, ale to nie pomogło, nic nie wychodzi na stdout (plik jest pusty). Gdy używam CreateProcess to wszystko działa jak trzeba.
To jest kawałeczek mojego kodu - jeżeli UserName i Password zostaną odczytane, to odpalam proces przez CreateProcessWithLogonW, else przez CreateProcess
DWORD dwCreationFlags = 0;
// dwCreationFlags = CREATE_SUSPENDED; - w razie potrzeby wepchania plugina
// cd : struct COMPILERDATA
// cd.data: strukturka dla kazdego MDI
// szTemp : working dir
// si : zainicjowane STARTUPINFO; .hStdOutput zawiera uchwyt pliku
// odczytaj username i hasło z XML kompilatora
BSTR bstrUserName = NULL;
BSTR bstrPasword = NULL;
BOOL withLogon = FALSE;
if (cd.compiler->FindChild(L"Logon", TRUE, Logon))
{
Logon.GetAttributeHere(L"UserName", &bstrUserName, 0);
Logon.GetAttributeHere(L"Password", &bstrPasword, 0);
}
// uruchomienie kompilatora
if (bstrUserName && bstrPasword)
{
withLogon = TRUE;
dwCreationFlags |= CREATE_SUSPENDED;
si.dwFlags = STARTF_USESHOWWINDOW; // usuń STARTF_USESTDHANDLES
ProcessCreated = CreateProcessWithLogonW(bstrUserName, L".", bstrPasword, LOGON_WITH_PROFILE, NULL, cd.bstrCommandLine, dwCreationFlags, 0, szTemp, &si, &pi);
}
else
{
ProcessCreated = CreateProcess(0, cd.bstrCommandLine, 0, 0, TRUE, dwCreationFlags, NULL, szTemp, &si, &pi);
}
DWORD LastError = GetLastError();
MySysFreeString(&bstrUserName);
MySysFreeString(&bstrPasword);
if (!ProcessCreated)
{
FormatMessage(0x000010FF, 0, LastError, 0, szTemp, MAX_PATH, 0);
BuildAddStringEx(cd.data, TEXT("Failed to execute %s : error %d (%s)"), cd.bstrCompilerPath, LastError, szTemp);
}
else
{
if (dwCreationFlags & CREATE_SUSPENDED)
{
if (withLogon)
{
// zapisz si.hStdOutput w PEB->ProcessParameters->StdOutputHandle i StdErrorHandle
HANDLE hTargetHandle;
if (DuplicateHandle(GetCurrentProcess(), si.hStdOutput, pi.hProcess, &hTargetHandle, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
CONTEXT ctx;
LDT_ENTRY sel;
ctx.ContextFlags = CONTEXT_SEGMENTS;
if (GetThreadContext(pi.hThread, &ctx))
{
if (GetThreadSelectorEntry(pi.hThread, ctx.SegFs, &sel))
{
DWORD fsbase = (sel.HighWord.Bytes.BaseHi << 8 | sel.HighWord.Bytes.BaseMid) << 16 | sel.BaseLow;
PEB *pPeb;
RTL_USER_PROCESS_PARAMETERS *ProcessParameters;
if (ReadProcessMemory(pi.hProcess, fsbase + 0x30, &pPeb, 4, NULL))
{
if (ReadProcessMemory(pi.hProcess, &pPeb->ProcessParameters, &ProcessParameters, 4, NULL))
{
if (WriteProcessMemory(pi.hProcess, &ProcessParameters->StdOutputHandle, &hTargetHandle, 4, NULL))
WriteProcessMemory(pi.hProcess, &ProcessParameters->StdErrorHandle, &hTargetHandle, 4, NULL);
}
}
}
}
}
}
// wepchanie plugina na siłę - zmiana EP na kod z LoadLibrary...
if (nRedirCount | nPluginCount)
InjectRedirectorDllToProcess(pi.hProcess, pi.hThread, nRedirCount, nPluginCount);
ResumeThread(pi.hThread);
}
// standardowe czekanie z MsgWaitForMultipleObjectsEx
compilerWaitForProcess(pi.hProcess);
GetExitCodeProcess(pi.hProcess, &pcd->dwExitCode);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
compilerReadLogFromFile(cd.data, si.hStdOutput); // ładuje stdout do listboxa
CloseHandle(si.hStdOutput);
}
Wszystkie kroki po "if (withLogon)" wykonują się poprawnie, w każdym IF/else mam print'a z informacją, tylko nie wiem czego mi brakuje?
Jedno jest pewne - proces (nasm 2.07) odczytuje podany mu plik .asm, tworzy plik .lst, ale nic więcej mi nie wiadomo.
screen: http://i46.tinypic.com/xaur6s.png