У нас есть 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
Локальные статические переменные не инициализируются, если приложение загружается как dll. ⇐ C++
Программы на C++. Форум разработчиков
1761898235
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);
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79791868/local-static-variables-are-not-initialized-if-app-is-loaded-as-dll[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия