Локальные статические переменные не инициализируются, если приложение загружается как 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 = GetThreadId(nullptr) + 1; // non zero value
return ret;
}

Дизассемблирование неоптимизированного инициализатора:
int F() {
00007FF6F0D19640 push rbp
00007FF6F0D19642 push rdi
00007FF6F0D19643 sub rsp,0E8h
00007FF6F0D1964A lea rbp,[rsp+20h]
00007FF6F0D1964F lea rcx,[__DFB28677_dllmain@cpp (07FF6F0E4209Fh)]
00007FF6F0D19656 call __CheckForDebuggerJustMyCode (07FF6F0D130C0h)
00007FF6F0D1965B nop
static const int ret = GetThreadId(nullptr) + 1; // non zero value
00007FF6F0D1965C mov eax,108h
00007FF6F0D19661 mov eax,eax
00007FF6F0D19663 mov ecx,dword ptr [_tls_index (07FF6F0E32274h)]
00007FF6F0D19669 mov rdx,qword ptr gs:[58h]
00007FF6F0D19672 mov rcx,qword ptr [rdx+rcx*8]
00007FF6F0D19676 mov eax,dword ptr [rax+rcx]
00007FF6F0D19679 cmp dword ptr [$TSS0 (07FF6F0E32284h)],eax
00007FF6F0D1967F jle F+73h (07FF6F0D196B3h)
00007FF6F0D19681 lea rcx,[$TSS0 (07FF6F0E32284h)]
00007FF6F0D19688 call _Init_thread_header (07FF6F0D135B1h)
00007FF6F0D1968D cmp dword ptr [$TSS0 (07FF6F0E32284h)],0FFFFFFFFh
00007FF6F0D19694 jne F+73h (07FF6F0D196B3h)
00007FF6F0D19696 xor ecx,ecx
00007FF6F0D19698 call qword ptr [__imp_GetThreadId (07FF6F0E40000h)]
00007FF6F0D1969E inc eax
00007FF6F0D196A0 mov dword ptr [ret (07FF6F0E32280h)],eax
00007FF6F0D196A6 lea rcx,[$TSS0 (07FF6F0E32284h)]
00007FF6F0D196AD call _Init_thread_footer (07FF6F0D135B6h)
00007FF6F0D196B2 nop
return ret;
00007FF6F0D196B3 mov eax,dword ptr [ret (07FF6F0E32280h)]
}

По неизвестной причине 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;
// 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 должен быть связан с /FIXED:NO.
#include

thread_local const auto thread_id = GetThreadId(nullptr);

int F() {
static const int ret = GetThreadId(nullptr) + 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++»