Конференция "WinAPI" » Запуск файла в памяти
 
  • NeedHelp (26.10.11 20:47) [0]
    Всем привет!
    Есть ехе файл, который содержит в себе еще 1 ехе.
    Нужно запустить его прямо в памяти не сохраняя на диск.
    Делаю это так:

    var
     ZwUnmapViewOfSection: function(hProcess: Cardinal;
                                    BaseAddress: Pointer): Cardinal; stdcall;
     SetThreadContext: function(hThread: THandle;
                                const lpContext: TContext): BOOL; stdcall;
     CreateProcess: function (lpApplicationName: PChar; lpCommandLine: PChar;
                              lpProcessAttributes,
                              lpThreadAttributes: PSecurityAttributes;
                              bInheritHandles: BOOL; dwCreationFlags: DWORD;
                              lpEnvironment: Pointer;
                              lpCurrentDirectory: PChar;
                              const lpStartupInfo: TStartupInfo;
                              var lpProcessInformation: TProcessInformation): BOOL;
                              stdcall;
     ReadProcessMemory: function(hProcess: THandle; const lpBaseAddress: Pointer;
                                 lpBuffer: Pointer; nSize: DWORD;
                                 var lpNumberOfBytesRead: DWORD): BOOL; stdcall;
     WriteProcessMemory: function(hProcess: THandle; const lpBaseAddress: Pointer;
                                  lpBuffer: Pointer; nSize: DWORD;
                                  var lpNumberOfBytesWritten: DWORD): BOOL; stdcall;
     ResumeThread: function(hThread: THandle): DWORD; stdcall;
     VirtualProtectEx: function(hProcess: THandle; lpAddress: Pointer;
                                dwSize, flNewProtect: DWORD;
                                var OldProtect: DWORD): BOOL; stdcall;

    procedure ExecuteMemImage(MemImage: Pointer);
    type
     PImageDosHeader = ^TImageDosHeader;
     PImageNtHeaders = ^TImageNtHeaders;
     PImageSectionHeader = ^TImageSectionHeader;
    const
     Mapping: array[0..7] of DWORD = (PAGE_NOACCESS, PAGE_EXECUTE, PAGE_READONLY,
                                      PAGE_EXECUTE_READ, PAGE_READWRITE,
                                      PAGE_EXECUTE_READWRITE, PAGE_READWRITE,
                                      PAGE_EXECUTE_READWRITE);
    var
     i, rpm, wpm: Cardinal;
     pi: TProcessInformation;
     Context: TContext;
     si: TStartUpinfo;
     Addr, ImageBase: Pointer;
     inh: PImageNtHeaders;
     ish: PImageSectionHeader;
     hNtDll, hKernelDll: Dword;
    begin
     hNtDll := LoadLibrary('ntdll.dll');
     if hNtDll <> 0 then
        ZwUnmapViewOfSection := GetProcAddress(hNtDll, 'ZwUnmapViewOfSection');
     hKernelDll := LoadLibrary('kernel32.dll');
     if hKernelDll <> 0 then
     begin
       SetThreadContext := GetProcAddress(hKernelDll, 'SetThreadContext');
       CreateProcess := GetProcAddress(hKernelDll, 'CreateProcessA');
       ReadProcessMemory := GetProcAddress(hKernelDll, 'ReadProcessMemory');
       WriteProcessMemory := GetProcAddress(hKernelDll, 'WriteProcessMemory');
       ResumeThread := GetProcAddress(hKernelDll, 'ResumeThread');
       VirtualProtectEx := GetProcAddress(hKernelDll, 'VirtualProtectEx');
     end;
     inh := PImageNtHeaders(DWORD(MemImage) +
            DWORD(PImageDosHeader(MemImage)^._lfanew));
     ZeroMemory(@si, SizeOf(si));
     si.cb := SizeOf(si);
     if not CreateProcess(nil, PChar(ParamStr(0)), nil, nil,
                          False, CREATE_SUSPENDED or CREATE_NEW_CONSOLE,
                          nil, nil, si, pi) then exit;

     try
       Context.ContextFlags := CONTEXT_INTEGER;
       if not GetThreadContext(pi.hThread, Context) then exit;
       ReadProcessMemory(pi.hProcess, Pointer(Context.Ebx + 8),
                         @Addr, SizeOf(Addr), rpm);
       if Addr = nil then exit;
       if ZwUnmapViewOfSection(pi.hProcess, Addr) <> 0 then exit;
       ImageBase := VirtualAllocEx(pi.hProcess,
                                   Pointer(inh.OptionalHeader.ImageBase),
                                   inh.OptionalHeader.SizeOfImage,
                                   MEM_RESERVE or MEM_COMMIT,
                                   PAGE_EXECUTE_READWRITE);
       if ImageBase = nil then exit;
       WriteProcessMemory(pi.hProcess, ImageBase,
                          MemImage, inh.OptionalHeader.SizeOfHeaders, wpm);
       ish := PImageSectionHeader(inh);
       Inc(PImageNtHeaders(ish));
       for i := 0 to inh.FileHeader.NumberOfSections - 1 do
       begin
         if ish.SizeOfRawData > 0 then
         begin
           WriteProcessMemory(pi.hProcess, PChar(ImageBase) + ish.VirtualAddress,
                              PChar(MemImage) + ish.PointerToRawData,
                              ish.SizeOfRawData, wpm);
           VirtualProtectEx(pi.hProcess, PChar(ImageBase) +
                            ish.VirtualAddress, ish.SizeOfRawData,
                            Mapping[ish.Characteristics shr 29], wpm);
         end;
         Inc(ish);
       end;
       WriteProcessMemory(pi.hProcess, Pointer(Context.Ebx + 8),
                          @ImageBase, SizeOf(ImageBase), wpm);
       Context.Eax := DWORD(ImageBase) + inh.OptionalHeader.AddressOfEntryPoint;
       SetThreadContext(pi.hThread, Context);
       ResumeThread(pi.hThread);
     finally
       CloseHandle(pi.hThread);
       CloseHandle(pi.hProcess);
       FreeLibrary(hNtDll);
       FreeLibrary(hKernelDll);
     end;
    end;


    Не нравится то, что создается новый процесс с помощью CreateProcess.

    Подскажите, есть ли способ запуска прямо в памяти не используя CreateProcess.
    Как я понимаю у нас есть свой процесс файла-контейнера, почему бы не сделать все именно в нем, не задействовать другие процессы.
    Даже не знаю направление в котором следует копать :(
  • Rouse_ © (26.10.11 22:33) [1]
    UPX опенсорсный, посмотри как он делает...
  • Rouse_ © (27.10.11 00:05) [2]
    ЗЫ: в качестве оффтопа, а зачем вообще нужен такой алгоритм запуска в обычной прикладной программе?
  • Германн © (27.10.11 00:17) [3]

    > ЗЫ: в качестве оффтопа, а зачем вообще нужен такой алгоритм
    > запуска в обычной прикладной программе?

    Вот тоже не понимаю зачем?
    Если
    > Как я понимаю у нас есть свой процесс файла-контейнера,
    > почему бы не сделать все именно в нем, не задействовать
    > другие процессы.

    Ну разве что "выдать чужое за своё".
  • Rouse_ © (27.10.11 00:20) [4]

    > Германн ©   (27.10.11 00:17) [3]
    > Ну разве что "выдать чужое за своё".

    Не, ну это нормальный алго для пакера, просто я и подумал - неушто очередной пакер пишется :)
  • Rouse_ © (27.10.11 00:20) [5]
    Удалено модератором
    Примечание: dbl
  • Германн © (27.10.11 01:06) [6]

    > Не, ну это нормальный алго для пакера

    Только ли для пакера, Саш?
    Точнее пакер "выдаёт за своё" для обеспечения нормальной своей работы. А ведь есть ещё и "псевдоучебные" задачи.
    P.S. На мой взгляд ну очень дурные, но судя по форумам вполне "реально задаваемые".
  • Rouse_ © (27.10.11 01:09) [7]
    Ну я бы не назвал это "псевдоучебным" - понимание карты памяти процесса еще никому не мешало...
  • Rouse_ © (27.10.11 01:11) [8]
    А, я понял - ты видимо про Joiner-ы говоришь, ну это неизбежный вариант направления ПО, как и лекарства в медицине, чем одних лечят, тем другие ширяются...
  • Германн © (27.10.11 01:31) [9]

    > Rouse_ ©   (27.10.11 01:09) [7]
    >
    > Ну я бы не назвал это "псевдоучебным" - понимание карты
    > памяти процесса еще никому не мешало...
    >


    > Rouse_ ©   (27.10.11 01:11) [8]
    >
    > А, я понял - ты видимо про Joiner-ы говоришь, ну это неизбежный
    > вариант направления ПО, как и лекарства в медицине, чем
    > одних лечят, тем другие ширяются...
    >

    Что такое joiner'ы я не знаю.
    Я знаю только (по форумам), что в моде учебные задачи типа, "Документ вшивается в exe-шник, и прочитать его можно только средствами самой программы. Ну и т.д.
  • Rouse_ © (27.10.11 01:40) [10]

    > Документ вшивается в exe-шник, и прочитать его можно только
    > средствами самой программы

    Хм, тогда к задаче ТС это никоим образом не относится, ибо это ни что иное как "Защищенное Хранилище", со своими алгоритмами удачными и неудачными и большинстве случаев, даже если алгоритм удачен все сводится к републикации ключа доступа, ну а если не удачен, тут даже обсужать нечего... (Самая применимая в коммерции для данного алго задача - это SecureBook, примеры Защищенных книг и ПО, их защищающих, приводить не буду. Самая правильно реализованная, это один из известных опенсорсных проектов... )
  • han_malign (27.10.11 09:26) [11]
    Немного смущает меня, что секция импорта не обрабатывается(и первоначальная вроде как затирается)... Привязка адресов импорта(TimeDateStamp) вроде не особо распространенная опция.

    > запуска прямо в памяти

    - если из образа вырезана таблица переадресации(а обычно эта фича идет рука об руку с привязанной таблицей импорта) - то придется еще и код анализировать, чтобы базу подвинуть...

    З.Ы. Что за голимая привычка переводить "обнаженный" С-шный код - как есть, не посмотрев какие функции уже и так импортированы, а типы - описаны???
    Чего бы тогда и LoadLibrary не импортировать, на всякий случай?
    Бездумное копирование кода(не всегда(обычно не)корректного) - не лучший путь...
  • Сергей М. © (27.10.11 09:36) [12]
    А куда, спрашивается, стартованный "в самом себе" липовый "процесс" будет лазить за своими ресурсами ?
  • NeedHelp (28.10.11 16:16) [13]

    > А куда, спрашивается, стартованный "в самом себе" липовый
    > "процесс" будет лазить за своими ресурсами ?


    Т.е. это нереализуемо я правильно понимаю?

    UPX опенсорсный, посмотри как он делает...
    Спс..
    есть ли подобный, похожий код на дельфи?
  • Сергей М. © (28.10.11 16:30) [14]
    > это нереализуемо я правильно понимаю?

    Это реализуемо, но далеко так просто как тебе кажется)
  • NeedHelp (29.10.11 13:02) [15]

    > Это реализуемо, но далеко так просто как тебе кажется)


    Ясно, спасибо за ответы! =)
  • Miha (05.12.14 12:33) [16]

    var
    eu:array of byte;
    FS:TFileStream;
    CONT:TContext;
    imgbase,btsIO:DWORD;
    IDH:PImageDosHeader;
    INH:PImageNtHeaders;
    ISH:PImageSectionHeader;
    i:Integer;
    PInfo:TProcessInformation;
    SInfo:TStartupInfo;
    begin
    if OpenDialog1.Execute then
     begin
       FS:=TFileStream.Create(OpenDialog1.FileName,fmOpenRead or fmShareDenyNone);
       SetLength(eu,FS.Size);
       FS.Read(eu[0],FS.Size);
       FS.Free;
       Sinfo.cb:=Sizeof(TStartupInfo);
       CreateProcess(nil,Pchar(paramstr(0)),nil,nil,FALSE,CREATE_SUSPENDED,nil,nil,SInf o,PInfo);
       IDH:=@eu[0];
       INH:=@eu[IDH^._lfanew];
       imgbase:=DWORD(VirtualAllocEx(PInfo.hProcess,Ptr(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE));
       ShowMessage(IntToHex(imgbase,8));
       WriteProcessMemory(PInfo.hProcess,Ptr(imgbase),@eu[0],INH^.OptionalHeader.SizeOf Headers,btsIO);
       for i:=0 to INH^.FileHeader.NumberOfSections - 1 do
         begin
             ISH:=@eu[IDH^._lfanew + Sizeof(TImageNtHeaders) + i * Sizeof(TImageSectionHeader)];
             WriteProcessMemory(PInfo.hProcess,Ptr(imgbase + ISH^.VirtualAddress),@eu[ISH^.PointerToRawData],ISH^.SizeOfRawData,btsIO);
         end;
       CONT.ContextFlags:=CONTEXT_FULL;
       GetThreadContext(PInfo.hThread,CONT);
       CONT.Eax:=imgbase + INH^.OptionalHeader.AddressOfEntryPoint;
       WriteProcessMemory(PInfo.hProcess,Ptr(CONT.Ebx+8),@imgbase,4,btsIO);
       ShowMessage('Press ok on ENTER');
       SetThreadContext(PInfo.hThread,CONT);
       ResumeThread(PInfo.hThread);
       CloseHandle(Pinfo.hThread);
       CloseHandle(PInfo.hProcess);
     end;
    end;
  • имя (28.02.15 19:41) [17]
    Удалено модератором
 
Конференция "WinAPI" » Запуск файла в памяти
Есть новые Нет новых   [118691   +22][b:0.001][p:0.004]