Локальные статические переменные не инициализируются, если приложение загружается как dll.C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Локальные статические переменные не инициализируются, если приложение загружается как dll.

Сообщение Anonymous »

У нас есть sandbox.exe, app.exe и app.dll. Если пользователи хотят запустить приложение, не изолированное в песочнице, они запускают app.exe. Если пользователи хотят запустить приложение в «песочнице», они запускают sandbox.exe, который загружает app.dll. См., например, загрузочное приложение chrome.exe, которое загружает chrome.dll.
Теперь мы хотим уменьшить количество распространяемых файлов, удалить app.dll и LoadLibraryA("app.exe").
Известно, что

Если указанный модуль является исполняемым модулем, статический импорт не загружается; вместо этого модуль загружается, как если бы это был LoadLibraryEx, с флагом DONT_RESOLVE_DLL_REFERENCES.

Итак, мы загружаем исполняемый модуль, загружаем ссылки на его dll, инициализируем IAT (таблицу адресов импорта) и вызываем WinMainCRTStartup(nullptr) в экспортированной функции dll, которая вызывается sandbox.exe. Загруженное приложение работает нормально до тех пор, пока не потребуется инициализировать локальную статическую переменную.
int F() {
static const int ret = GetLastError() + 1; // non zero value
return ret;
}

Дизассемблирование неоптимизированного инициализатора:
int F() {
00007FF7C27EA680 push rdi
00007FF7C27EA682 sub rsp,60h
00007FF7C27EA686 lea rdi,[rsp+40h]
00007FF7C27EA68B mov ecx,8
00007FF7C27EA690 mov eax,0CCCCCCCCh
00007FF7C27EA695 rep stos dword ptr [rdi]
00007FF7C27EA697 lea rcx,[__8398B9A9_core-win@cc (07FF7C3033B4Dh)]
00007FF7C27EA69E call __CheckForDebuggerJustMyCode (07FF7C239D00Ch)
static const int ret = GetLastError() + 1; // non zero value
00007FF7C27EA6A3 mov eax,18Ch
00007FF7C27EA6A8 mov eax,eax
00007FF7C27EA6AA mov ecx,dword ptr [_tls_index (07FF7C2FA4C7Ch)]
00007FF7C27EA6B0 mov rdx,qword ptr gs:[58h]
00007FF7C27EA6B9 mov rcx,qword ptr [rdx+rcx*8]
00007FF7C27EA6BD mov eax,dword ptr [rax+rcx]
00007FF7C27EA6C0 cmp dword ptr [$TSS0 (07FF7C2FA2500h)],eax
00007FF7C27EA6C6 jle F+77h (07FF7C27EA6F7h)
00007FF7C27EA6C8 lea rcx,[$TSS0 (07FF7C2FA2500h)]
00007FF7C27EA6CF call _Init_thread_header (07FF7C2399D80h)
00007FF7C27EA6D4 cmp dword ptr [$TSS0 (07FF7C2FA2500h)],0FFFFFFFFh
00007FF7C27EA6DB jne F+77h (07FF7C27EA6F7h)
00007FF7C27EA6DD call qword ptr [__imp_GetLastError (07FF7C301D110h)]
00007FF7C27EA6E2 inc eax
00007FF7C27EA6E4 mov dword ptr [ret (07FF7C2FA24FCh)],eax
00007FF7C27EA6EA lea rcx,[$TSS0 (07FF7C2FA2500h)]
00007FF7C27EA6F1 call _Init_thread_footer (07FF7C239AA87h)
00007FF7C27EA6F6 nop

По неизвестной причине eax получает 0, а $TSS0 — правильный 0 при первом cmp. Таким образом, 0 Name);
if (!pszModName)
break;

IATRESULTS::MODULEINFO m;

m.name = pszModName;

HINSTANCE hImportDLL = LoadLibraryA(pszModName);
if (!hImportDLL) {
m.f = IATRESULTS::FAILUREREASON::NOTFOUND;
res.modules.push_back(m);
continue;
}
m.handle = hImportDLL;
m.f = IATRESULTS::FAILUREREASON::SUCCESS;

// Get caller's import address table (IAT) for the callee's functions
PIMAGE_THUNK_DATA pThunk =
(PIMAGE_THUNK_DATA)((PBYTE)h + pImportDesc->FirstThunk);

// Replace current function address with new function address
for (; pThunk->u1.Function; pThunk++) {
IATRESULTS::FUNCTIONINFO fu;

FARPROC pfnNew = 0;
size_t rva = 0;
#ifdef _WIN64
if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
#else
if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
#endif
{
// Ordinal
#ifdef _WIN64
size_t ord = IMAGE_ORDINAL64(pThunk->u1.Ordinal);
#else
size_t ord = IMAGE_ORDINAL32(pThunk->u1.Ordinal);
#endif

fu.ord = ord;
m.functions.push_back(fu);
PROC* ppfn = (PROC*)&pThunk->u1.Function;
if (!ppfn) {
fu.f = IATRESULTS::FAILUREREASON::NOTFOUND;
m.functions.push_back(fu);
continue;
}
rva = (size_t)pThunk;

pfnNew = GetProcAddress(hImportDLL, (LPCSTR)ord);
if (!pfnNew) {
fu.f = IATRESULTS::FAILUREREASON::NOTFOUND;
m.functions.push_back(fu);
continue;
}
} else {
// Get the address of the function address
PROC* ppfn = (PROC*)&pThunk->u1.Function;
if (!ppfn) {
fu.f = IATRESULTS::FAILUREREASON::NOTFOUND;
m.functions.push_back(fu);
continue;
}
rva = (size_t)pThunk;
PSTR fName = (PSTR)h;
fName += pThunk->u1.Function;
fName += 2;
if (!fName)
break;
fu.name = fName;
pfnNew = GetProcAddress(hImportDLL, fName);
if (!pfnNew) {
fu.f = IATRESULTS::FAILUREREASON::NOTFOUND;
m.functions.push_back(fu);
continue;
}
}

// Patch it now...
auto hp = GetCurrentProcess();

if (!WriteProcessMemory(hp, (LPVOID*)rva, &pfnNew, sizeof(pfnNew),
NULL) &&
(ERROR_NOACCESS == GetLastError())) {
DWORD dwOldProtect;
if (VirtualProtect((LPVOID)rva, sizeof(pfnNew), PAGE_WRITECOPY,
&dwOldProtect)) {
if (!WriteProcessMemory(GetCurrentProcess(), (LPVOID*)rva, &pfnNew,
sizeof(pfnNew), NULL)) {
fu.f = IATRESULTS::FAILUREREASON::CANNOTPATCH;
continue;
}
if (!VirtualProtect((LPVOID)rva, sizeof(pfnNew), dwOldProtect,
&dwOldProtect)) {
fu.f = IATRESULTS::FAILUREREASON::CANNOTPATCH;
continue;
}
}
}
m.functions.push_back(fu);
}
res.modules.push_back(m);
}
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
CoInitializeEx(0, 0);

HINSTANCE hL = LoadLibrary(L"app.exe");
if (!hL)
return 0;
IATRESULTS res;
ParseIAT(hL, res);

auto* run_win_main = (void(WINAPI*)())GetProcAddress(hL, "RunWinMain");
if (!run_win_main)
return 0;
run_win_main();
return 0;
}

#pragma comment(lib, "dbghelp.lib")

app.cc
#include

int F() {
static const int ret = GetLastError() + 1; // non zero value
return ret;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
return F();
}

extern "C" void WinMainCRTStartup(LPVOID);

extern "C" __declspec(dllexport) void RunWinMain() {
WinMainCRTStartup(nullptr);
}


Подробнее здесь: https://stackoverflow.com/questions/797 ... ded-as-dll
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»