Здравствуйте. Не могу разобраться почему не запускается следующий файл из памяти, что еще не хватает? В примере http://www.wasm.ru/print.php?article=memfile загрузчик (proc alloced_area_start) копируется в виртуальную память или просто выполняется процедура, если копируется в память то как это сделать в с++ и для чего это нужно? На сколько я понял весь код процедуры копируется в виртуальную память, а для чего? Разве нельзя просто вызвать эту процедуру? Код (Text): #include "stdafx.h" #include <Windows.h> DWORD GetSectionProtection(DWORD sc) { DWORD dwResult=0; if (sc & IMAGE_SCN_MEM_NOT_CACHED) dwResult |= PAGE_NOCACHE; if (sc & IMAGE_SCN_MEM_EXECUTE) { if (sc & IMAGE_SCN_MEM_READ) { if (sc & IMAGE_SCN_MEM_WRITE) dwResult |= PAGE_EXECUTE_READWRITE; else dwResult |= PAGE_EXECUTE_READ; } else { if (sc & IMAGE_SCN_MEM_WRITE) dwResult |= PAGE_EXECUTE_WRITECOPY; else dwResult |= PAGE_EXECUTE; } } else { if (sc & IMAGE_SCN_MEM_READ) { if (sc & IMAGE_SCN_MEM_WRITE) dwResult|=PAGE_READWRITE; else dwResult|=PAGE_READONLY; } else { if (sc & IMAGE_SCN_MEM_WRITE) dwResult|=PAGE_WRITECOPY; else dwResult|=PAGE_NOACCESS; } } return dwResult; } inline BOOL IsImportByOrdinal(DWORD ImportDescriptor) { return (ImportDescriptor & IMAGE_ORDINAL_FLAG32)!=0; } #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif //typedef BOOL (WINAPI *pointMAIN)(int , char*); typedef BOOL (WINAPI *pointWINMAIN)(HINSTANCE, HINSTANCE, LPSTR, int); HMODULE MemLoadExe(PBYTE data) { IMAGE_FILE_HEADER *pFileHeader = NULL; IMAGE_OPTIONAL_HEADER *pOptionalHeader = NULL; IMAGE_SECTION_HEADER *pSectionHeader = NULL; IMAGE_IMPORT_DESCRIPTOR *pImportDscrtr = NULL; USHORT e_lfanew = *((USHORT*)(data+0x3c)); PCHAR ImageBase = NULL; PCHAR SectionBase = NULL; DWORD dwSize, dwOldProt, ImageBaseDelta; int i; pFileHeader = (IMAGE_FILE_HEADER *)(data+e_lfanew+4); pOptionalHeader = (IMAGE_OPTIONAL_HEADER *)(data+e_lfanew+4+sizeof(IMAGE_FILE_HEADER)); if (pOptionalHeader->Magic!=IMAGE_NT_OPTIONAL_HDR32_MAGIC) return NULL; // Let's try to reserv memory ImageBase = (PCHAR)VirtualAlloc( (PVOID)pOptionalHeader->ImageBase, pOptionalHeader->SizeOfImage, MEM_RESERVE,PAGE_NOACCESS); if(ImageBase==NULL) { ImageBase=(PCHAR)VirtualAlloc(NULL, pOptionalHeader->SizeOfImage, MEM_RESERVE,PAGE_NOACCESS); if(ImageBase==NULL) return NULL; } // copy the header SectionBase=(PCHAR)VirtualAlloc(ImageBase, pOptionalHeader->SizeOfHeaders, MEM_COMMIT,PAGE_READWRITE); memcpy(SectionBase,data,pOptionalHeader->SizeOfHeaders); // Do headers read-only (to be on the safe side) VirtualProtect(SectionBase,pOptionalHeader->SizeOfHeaders,PAGE_READONLY,&dwOldProt); // find sections ... pSectionHeader = (IMAGE_SECTION_HEADER *)(pOptionalHeader+1); for (i=0; i<pFileHeader->NumberOfSections; i++) { SectionBase = (PCHAR)VirtualAlloc( ImageBase+pSectionHeader[i].VirtualAddress, pSectionHeader[i].Misc.VirtualSize, MEM_COMMIT,PAGE_READWRITE); if (SectionBase==NULL) { VirtualFree(ImageBase, 0, MEM_RELEASE); return NULL; } // ... and copy initialization data SectionBase = ImageBase+pSectionHeader[i].VirtualAddress; dwSize = MIN(pSectionHeader[i].SizeOfRawData,pSectionHeader[i].Misc.VirtualSize); memcpy(SectionBase, data+pSectionHeader[i].PointerToRawData,dwSize); } pImportDscrtr = (IMAGE_IMPORT_DESCRIPTOR *)(ImageBase+ pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); for (;pImportDscrtr->Name!=0; pImportDscrtr++) { PCHAR pLibName = (PCHAR)(ImageBase+pImportDscrtr->Name); PCHAR pImortName = NULL; HMODULE hLibModule = LoadLibraryA(pLibName); DWORD *pImport = NULL, *pAddress = NULL; DWORD ProcAddress; pAddress=(DWORD *)(ImageBase+pImportDscrtr->/*Original*/FirstThunk); if (pImportDscrtr->TimeDateStamp==0) pImport=(DWORD *)(ImageBase+pImportDscrtr->FirstThunk); else pImport=(DWORD *)(ImageBase+pImportDscrtr->OriginalFirstThunk); for (i=0; pImport[i]!=0; i++) { if (IsImportByOrdinal(pImport[i])) ProcAddress=(DWORD)GetProcAddress(hLibModule, (PCHAR)(pImport[i]&0xFFFF)); else // import by name { pImortName=(PCHAR)(ImageBase+(pImport[i])+2); ProcAddress=(DWORD)GetProcAddress(hLibModule, pImortName); } pAddress[i]=ProcAddress; } } // set section protection for (i=0; i<pFileHeader->NumberOfSections; i++) VirtualProtect((PVOID)(ImageBase+pSectionHeader[i].VirtualAddress), pSectionHeader[i].Misc.VirtualSize, GetSectionProtection(pSectionHeader[i].Characteristics), &dwOldProt); // call MainFunc if (pOptionalHeader->AddressOfEntryPoint!=0) { //pointMAIN pWinMain=(pointMAIN)(ImageBase+pOptionalHeader->AddressOfEntryPoint); pointWINMAIN pWinMain=(pointWINMAIN)(ImageBase+pOptionalHeader->AddressOfEntryPoint); if (!pWinMain((HINSTANCE)ImageBase, NULL, 0, SW_SHOWNORMAL)) { VirtualFree(ImageBase, 0, MEM_RELEASE); return NULL; } } return (HMODULE)ImageBase; } int _tmain(int argc, _TCHAR* argv[]) { FILE *fp = fopen("c:\\WINDOWS\\system32\\calc.exe", "rb"); fseek(fp, 0, SEEK_END); long fileSize = ftell(fp); fseek(fp, 0, SEEK_SET); char *data = new char[fileSize]; fread(data, fileSize, 1, fp); //Load PE and run the File MemLoadExe((PBYTE)data); delete[] data; fclose(fp); return 0; }
Если адреса (41000..) свободны то достаточно просто спроецировать туда exe, а если заняты придется выделять память в другом месте, и соответственно править релоки. Вывод - используй загрузчик с ImageBase отличным от 41000, если это возможно - не придется ковыряться с релоками.
Не факт, не факт. Во-первых, не 41 000, а 400 000, а во вторых - память может быть элементарно занята какими-то системными ... эм... мусором. Вобщем, наличие релоков крайне необходимо за исключением редких случаев.
MSoft то есть если секции релоков вообще нет в exe (я никогда ее не создаю) то файл вообще не запустится? что то на практике такого не наблюдал..
assorted А я наблюдал. Я не говорю, что файл не будет работать, но скорее всего он не будет работать. Я проверял это на многих файлах. Хочешь сказать, что адреса 400 000 никогда не бывают заняты??? Загрузись по любой базе и посмотри сам. А что касается принципиальной работы из памяти, так тут будет туева хуча камней. В частности, работа с ресурсами - база образа в данном случае берется из PEB, в котором прописана база загрузчика, а не твоего файла. Вобщем, запуск без релоков - это конечно зря. Оно и с релокам и не всегда будет работать, а без релоков тем более. Использовать такое в мальваре крайне не рекомендую.
MSoft Я вот о чем берем notepad.exe смотрим секции .text, .data, .rsrc Берем calc.exe смотрим секции .text, .data, .rsrc (для достоверности глянул в оле она показывает не только имя но и тип секции) Секцией релоков не пахнет. Это зачит что данные приложения просто бы не запускались. Можно пример - когда при запуске процесса адреса будут заняты?
assorted прав в большинстве случаев релоков нет - это оч. легко проверить (не нужно спорить) - открываем PEview.exe где то сдесь я ее скачивал -> заходим в раздел IMAGE_NT_HEDARES -> IMAGE_OPTIONAL_HEADERS -> находим каталог "base relocation table" - вот и все доказательства, тем более что больше интересует вариант без релоков! Возвращаясь к моему вопросу: Этот код без осложнений запускает freecell.exe - правда без картинок.. т.е. кажется что программа не может достучаться до ресурсов. Как быть? Ну так вопрос пока отрыт!
Блин, тебе ShellExecute вызвать или правильно настроить и выполнить файл в памяти??? У меня ощущение, что ты хочешь одно, но говоришь о другом.
Тогда ты и не запустишь файл из памяти. Если твой загрузчик имеет базу X, а файл надо загрузить по базе Y, то скорее всего (ну по крайней мере вероятно), что база Y будет занята чем-то системным. А релоки... Если нет релоков, то по другой базе просто нет смысла запускать файл - маловероятно, что он не исполььзует абсолютную адресацию.
MSoft что база Y будет занята чем-то системным Не в первый раз спрашиваю, чем будет занято 400000 к тому моменту как загрузчик будет работать? Сейчас не поленился собрал файл с базой format PE GUI at 70000000h все чудесно работает, адреса 400000 свободны, проецируй чего хочешь. Ну и ради эксперемента format PE GUI at 7C800000h (тут у меня располагается кернел) Все - файл не запускается.
PEB - помог частично! т.е. делаю следующее: 1) Компилю загрузчик стандартными настройками VC7 (Загрузчик должен быть обязательно GUI, т.к. запускаемый файл Б - гуишный, когда загрузчик был консольный у меня запускался файл Б и сразу имирал.) 2) Базовый адрес запускаемого файла Б должен быть выше 0х01000000 (как стоит у calc. exe и mspaint.exe и т.д.) 3) Правим PEB в код выше добавилось следующее Код (Text): typedef struct _PEB { UCHAR InheritedAddressSpace; /* 00h */ UCHAR ReadImageFileExecOptions; /* 01h */ UCHAR BeingDebugged; /* 02h */ BOOLEAN SpareBool; /* 03h */ HANDLE Mutant; /* 04h */ PVOID ImageBaseAddress; /* 08h */ //PPEB_LDR_DATA Ldr; /* 0Ch */ }PEB, *PPEB; typedef struct _TEB { NT_TIB Tib; /* 00h */ PVOID EnvironmentPointer; /* 1Ch */ DWORD Cid[2]; /* 20h */ PVOID ActiveRpcInfo; /* 28h */ PVOID ThreadLocalStoragePointer; /* 2Ch */ PPEB Peb; /* 30h */ ULONG LastErrorValue; /* 34h */ }TEB, *PTEB; _TEB * GetTEB() { __asm mov eax, fs:[18h]; #pragma warning(disable:4035) } Запуск файла в функции MemLoadExe теперь выглядит так: Код (Text): if (pOptionalHeader->AddressOfEntryPoint!=0) { // Get TEB TEB* teb = GetTEB(); // Get PEB PEB* peb = teb->Peb; peb->ImageBaseAddress = ImageBase; //pOptionalHeader->ImageBase = (DWORD)ImageBase; LPVOID entry = (LPVOID)( (DWORD)ImageBase + pOptionalHeader->AddressOfEntryPoint ); __asm call [entry]; } Результат: 1) Почти все запускается из каталога c:\windows\system32\*.exe 2) Приложения скомпиленые мною не запускаются в дебаг режиме если мой файл Б весит от 2 до 8 метров (приблизительно). Проблема решилась так: в файл Б поменял базовый адрес на 0x10000000 - проблема решилась для мелких файлах около 2-3 метров. Или проблему можно было решить так - в режиме релиза! Видимо памяти не хватало! 3) Я уже не говорю о Viste Какие будут мнения на этот счет?