sreenivas003 wrote:Is there any way i can prevent the console window opening or any ways to enable sandbox even if the executable and subprocess names are different.
Actually, it is possible. Not an easy or a pleasant thing to do.
Short story: the sandbox conflicts with our own AV product and cannot be used (not easily, at least).
Use the following examples and ideas on your own risk.
* * *
Inside pepper Flash it is code that spawns a console with something like "cmd /c echo NOT SANDBOXED".
The API call for this is CreateProcessA.
What I did is this:
- self patching CreateProcessA in the host executable (I didn't read the whole thread, but I saw it is suggested to hook CreateProcess)
- look at the arguments of CreateProcessA
- get the path of cmd.exe
- if command line ends up being the one we're looking for (LPSTARTUPINFOA StartupInfo is the penultimate argument of CreateProcessA), hide the console
- Code: Select all
WORD wShowWindow = StartupInfo->wShowWindow;
StartupInfo->wShowWindow = SW_HIDE;
- let CreateProcessA hook continue
- restore flags
- Code: Select all
StartupInfo->wShowWindow = wShowWindow;
I won't go in the details on how to hook the API calls.
The patching needs to go thru 2 stages:
- patch LoadLibraryW/LoadLibraryA/LoadLibraryExW/LoadLibraryExA for intercepting when pepflashplayer is loaded.
My application is Unicode so libcef!LoadLibraryW will do, but is always possible that your dll might use LoadLibraryExA for some reason etc.
- Code: Select all
#if !defined(ENABLE_CEF_SANDBOX)
// libcef!LoadLibraryW
IATPatch::PatchImport(
"libcef.dll",
"kernel32.dll", "LoadLibraryW",
(FARPROC)&Jmp_LoadLibraryW);
// libcef!LoadLibraryExW
IATPatch::PatchImport(
"libcef.dll",
"kernel32.dll", "LoadLibraryExW",
(FARPROC)&Jmp_LoadLibraryExW);
#endif // ENABLE_CEF_SANDBOX
We'll consider Jmp_LoadLibraryW to be the target here.
- the patched Jmp_LoadLibraryW needs to intercept when pepflashplayer is loaded, so it can patch also inside pepflashplayer the call to CreateProcessA:
- Code: Select all
HMODULE WINAPI patch_handler_t::Jmp_LoadLibraryW(
LPCWSTR lpFileName
) {
...
// let original function call
HMODULE result = __C__Jmp_LoadLibraryW(
pfnOriginalFunction,
lpFileName
);
...
// save last error to restore after; we can use a secondary thread and wait, but why bother
DWORD last_error = GetLastError();
#if !defined(ENABLE_CEF_SANDBOX)
if(result != NULL) {
if(lpFileName != NULL && lstrlenW(lpFileName) != 0) {
WCHAR szDllName[MAX_PATH] = L"";
if(wcsncpy_s(szDllName, _countof(szDllName),
lpFileName, _TRUNCATE) != STRUNCATE) {
PathStripPathW(szDllName);
_wcslwr_s(szDllName, _countof(szDllName));
LPWSTR lpExt = PathFindExtensionW(szDllName);
if(lpExt != NULL && _wcsicmp(lpExt, L".dll") == 0) {
const wchar_t* ptrpep_32 = wcsstr(szDllName, L"pepflashplayer32");
const wchar_t* ptrpep_64 = wcsstr(szDllName, L"pepflashplayer64");
bool fIsPepFlashPlayer32 = ptrpep_32 == szDllName;
bool fIsPepFlashPlayer64 = ptrpep_64 == szDllName;
if(fIsPepFlashPlayer32 || fIsPepFlashPlayer64) {
CHAR szDllName_A[MAX_PATH] = "";
if(WideCharToMultiByte(CP_ACP, 0,
szDllName, -1, szDllName_A, _countof(szDllName_A),
NULL, NULL) != 0) {
IATPatch::PatchImport(
szDllName_A,
"kernel32.dll", "CreateProcessA",
(FARPROC)&Jmp_CreateProcessA);
}
}
}
}
}
}
#endif // ENABLE_CEF_SANDBOX
// restore last error
if(result == NULL) {
SetLastError(last_error);
}
...
Now we patched CreateProcessA inside pepflashplayer32.dll/pepflashplayer3264.dll.
- inside the patched CreateProcessA do the processing described above to detect cmd /c echo NOT SANDBOXED
- Code: Select all
BOOL WINAPI patch_handler_t::Jmp_CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
) {
...
#if !defined(ENABLE_CEF_SANDBOX)
// is our command prompt launched from pepflashplayer?
// if so, modify it
// we don't have a context to know "CreateProcessA was launched from
// pepflashplayer and not from libcef.dll or our exe" because all functions
// are patched thru the same entry Jmp_CreateProcessA
// so we're using detection/patching in place using whatever arguments
// recognition we have locally.
bool fIsPepflashplayerCmdNotSandboxed = false;
{
CHAR szCmd_A[MAX_PATH] = "";
if(lpCommandLine != NULL &&
lstrlenA(lpCommandLine) != 0) {
LPITEMIDLIST pidl = NULL;
HRESULT hr = SHGetKnownFolderIDList(
FOLDERID_System, 0, NULL, &pidl);
if(SUCCEEDED(hr)) {
CHAR szPath_A[MAX_PATH] = "";
if(SHGetPathFromIDListA(pidl, szPath_A)) {
static const char* kCmdExe = "cmd.exe";
static const char* kArgNotSandboxed = "/c echo NOT SANDBOXED";
if(::PathAppendA(szPath_A, kCmdExe)) {
CHAR szApp_A[MAX_PATH] = "";
strncpy_s(szApp_A, _countof(szApp_A),
szPath_A, _TRUNCATE);
strncpy_s(szCmd_A, _countof(szCmd_A),
szApp_A, _TRUNCATE);
strncat_s(szCmd_A, _countof(szCmd_A),
" ", _TRUNCATE);
strncat_s(szCmd_A, _countof(szCmd_A),
kArgNotSandboxed, _TRUNCATE);
}
}
}
if(pidl != NULL) {
ILFree(pidl);
}
}
if(lstrlenA(szCmd_A) != 0) {
__trackVW(
L"[IAT-PATCH] lpCommandLine=[%hs] szCmd_A=[%hs]",
LOG_LEVEL_TRACE,
lpCommandLine, szCmd_A);
if(lstrcmpiA(szCmd_A, lpCommandLine) == 0) {
fIsPepflashplayerCmdNotSandboxed = true;
}
}
}
#endif // ENABLE_CEF_SANDBOX
do {
#if !defined(ENABLE_CEF_SANDBOX)
__trackVW(
L"[IAT-PATCH] fIsPepflashplayerCmdNotSandboxed=%s",
LOG_LEVEL_TRACE,
fIsPepflashplayerCmdNotSandboxed ? L"true" : L"false");
DWORD dwFlags = lpStartupInfo->dwFlags;
WORD wShowWindow = lpStartupInfo->wShowWindow;
if(fIsPepflashplayerCmdNotSandboxed) {
// let the process run to avoid tampering caller,
// but modify its windowing to be invisible by changing
// flags and window visibility
if(lpStartupInfo != NULL) {
if((lpStartupInfo->dwFlags & STARTF_USESHOWWINDOW) == 0) {
lpStartupInfo->dwFlags |= STARTF_USESHOWWINDOW;
}
lpStartupInfo->wShowWindow = SW_HIDE;
}
}
#endif // ENABLE_CEF_SANDBOX
result = __C__Jmp_CreateProcessA(
pfnOriginalFunction,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
#if !defined(ENABLE_CEF_SANDBOX)
// restore STARTUPINFOA if changed
// to play nice with the caller
if(lpStartupInfo->dwFlags != dwFlags)
lpStartupInfo->dwFlags = dwFlags;
if(lpStartupInfo->wShowWindow != wShowWindow)
lpStartupInfo->wShowWindow = wShowWindow;
#endif // ENABLE_CEF_SANDBOX
#pragma warning(disable: 4127)
} while(0);
#pragma warning(default: 4127)
...
Notes.
1. __C__Jmp_CreateProcessA is the "C" version of C++ called Jmp_CreateProcessA (basically the __C__XXX functions are extern "C" and uses __try/__except or __try/__finally, a custom SEH handler etc.) to avoid C++ inside calls.
2. Patching is different between 32 and 64 bit. But VirtualProtect is the call in both.
A short example:
- Code: Select all
#ifdef WIN64
namespace IATPatch64 {
struct iat_patch_t {
void* original;
char patched[256];
unsigned __int64 patchSize;
void* original_function;
};
...
};
...
namespace IATPatchMemory64 {
void _memwrite(void* dest,
const void* source,
unsigned __int64 size)
{
DWORD access = 0;
VirtualProtect(dest, size,
PAGE_EXECUTE_READWRITE,
&access);
__try {
memcpy_s(dest, size, source, size);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
}
VirtualProtect(dest, size,
access, &access);
return;
}
void _memwrite(unsigned __int64 dest,
const void* source,
unsigned __int64 size)
{
_memwrite((void*)dest, source, size);
return;
}
void memwrite(void* dest,
const void* source,
unsigned __int64 size)
{
critical_section_lock_t lock(
&IATPatch64::s__csPatches);
IATPatch64::iat_patch_t patch;
patch.original = dest;
patch.patchSize = size;
memcpy_s(patch.patched,
_countof(patch.patched),
source, size);
patch.original_function = *(FARPROC*)dest;
_memwrite(dest, source, size);
IATPatch64::getPatches()->push_back(patch);
return;
}
};
FARPROC
PatchImportModule(
const char* sourceModule,
const char* importModule,
const char* name,
void* patchFunction)
{
...
FARPROC oldFxn = (FARPROC)f_import[i];
IATPatchMemory64::memwrite(
&f_import[i],
&patchFunction,
sizeof(patchFunction));
return oldFxn;
...
The above excerpts are obviously incomplete and I won't pretend it will be easy for reader to fill the gaps.
But as a general idea for those wanting to adventure in places like these it might help.