CREATE_ SUSPENDED и XP непонятки

Тема в разделе "WASM.RESEARCH", создана пользователем PedroPorosenko, 23 апр 2017.

  1. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    Есть задача - заинжектить выполнение одного процесса в другой. Подробнее
    есть 2 exe x86:
    1) C:\autoruns.exe - этот процесс стартует в засупенденном состоянии, в него пишется образ внедряемого екзе и потом ResumeThread (это прога autoruns из пакета sysinternals) , в нем через PE-редактор убран флажок Dll Can Move чтобы файл только работал по стандартной imagebase 0x400000
    2) C:\1.exe - образ этого екзе инжекститься в autoruns.exe (простейший MessageBox ("hello world"))

    injector.exe - делает внедрение 1.exe в autoruns.exe
    Внедрение происходит стандартно,
    - собирается из rawbytes 1.exe его же виртуальный образ
    - запускается autoruns.exe в засуспенденном состоянии, для чистоты эксперимента на весь образ autoruns выставляются аттрибуты PAGE_EXECUTE_READWRITE
    - GetThreadContext замороженного потока autoruns
    - WriteProcessMemory в него записывается VirtualImage ("1.exe"), ImageBase у всех одинаковые 0x400000 , SizeOfImage 1.exe меньше autoruns.exe
    - context.eax = remoteImageBase + AddressOfEntryPoint("1.exe")
    - SetThreadContext(pi.hThread, &context )
    - ResumeThread

    Код собсно проверенный и работает отлично на >= Windows7 , а вот на XP почему отказывается работать, autoruns даже не слетает, а после ResumeThread сразу завершается.
    Есть ли какие догадки почему такое происходит ?
    Вся сложность что к засупенденному процессу нельзя присоединить отладчик или бряк поставить,
    или можно как-то ?
    Можно ли через системные механизмы все-таки как-то брякнуться напр. на LdrpInitializeProcess или посмотреть лог - на каком этапе после ResumeThread процесс autoruns завершается ?
     
  2. RET

    RET Well-Known Member

    Публикаций:
    17
    Регистрация:
    5 янв 2008
    Сообщения:
    789
    Адрес:
    Jabber: darksys@sj.ms
    WriteProcessMemory -> int 3 на EP
     
  3. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    что интересно, вот после такого оно работает - подхватывает jit отладчик, x32dbg в данном случае , далее исправляю инструкцию на EP на оригинальную и передаю управление на нее - выскакивает MessageBox. проделывал такое как раз, это еще больше запутало меня

    на всяк прикладываю файлы
    https://fex.net/382610885309
     
    Последнее редактирование: 23 апр 2017
  4. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    файлы
     

    Вложения:

    • exes.zip
      Размер файла:
      357,2 КБ
      Просмотров:
      338
  5. yashechka

    yashechka Ростовский фанат Нарвахи

    Публикаций:
    90
    Регистрация:
    2 янв 2012
    Сообщения:
    1.449
    Адрес:
    Россия
    Пэдро, там же ехе файлы только!!!
     
  6. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    [math][/math]
    расшифруйте...

    ап:
    попробовал выполнить 1.exe без импорта, просто цикл бесконечный - выполняется, значит чего-то импорт не настраивается.
     
  7. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.329
    Потому что при CREATE_SUSPENDED процесс замораживается не на OEP, а в середине процесса инициализации. В это время лоадер уже настроил импорты для kernel и ntdll, но не притрагивался к остальным. После замены образа и ResumeThread(), лоадер продолжит настройку импорта в новом образе, а импорты kernel32 в нем будут невалидны (потому что лоадер думает, что уже их настроил). Но это не точно :)
     
    PedroPorosenko нравится это.
  8. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    интересная мысль, щас проверим )
     
  9. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.329
    Или вот, что более вероятно: во внутренних структурах процесса лоадер сохраняет адрес точки входа из оригинального ехе и когда подменяем образ и размораживаем процесс, его выполнение начнется с фактически мусорного кода (старый OEP в новом образе).
     
  10. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    неа, везде на всех ОС подгружена только одна ntdll при CREATE_SUSPENDED.
    Что интересно , на win10, server 2012, srv2016 - LdrpInitializeProcess также настраивает и релоки, на Win7 такая фишка не проходит - грузить только нужно по одинаковым imagebase, точнее процесс, в который внедряют, не должен релоцироваться или отсуствовать релоки или убран флажок dllcanmove. Т.е. только настройка импорта - собсно в сорцах LdrpInitializeProcess wrk там также нет настройки релоков.
    xp,vista - не пашет.
     
  11. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    тоже думал над этим, но пока еще не пробовал - но что-то кажется маловероятным, в сорцах видно, что все пляшет от PE хидера, который находиться по адресу remoteImageBase,
    а там уже хидер нашего скопированного образа. И дальше уже заполняется Ldr исходя из нашего хидера
    Код (C++):
    1.  Peb->Ldr = RtlAllocateHeap(Peb->ProcessHeap, MAKE_TAG( LDR_TAG ), sizeof(PEB_LDR_DATA));
    2.  
    3. NTSTATUS
    4. LdrpInitializeProcess (
    5.     IN PCONTEXT Context OPTIONAL,
    6.     IN PVOID SystemDllBase,
    7.     IN PUNICODE_STRING UnicodeImageName
    8.     )
    9. {
    10.     PPEB Peb;
    11.     NTSTATUS st;
    12.     PWCH p, pp;
    13.     UNICODE_STRING CurDir;
    14.     UNICODE_STRING FullImageName;
    15.     UNICODE_STRING CommandLine;
    16.     HANDLE LinkHandle;
    17.     WCHAR SystemDllPathBuffer[DOS_MAX_PATH_LENGTH];
    18.     UNICODE_STRING SystemDllPath;
    19.     PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    20.     PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    21.     UNICODE_STRING Unicode;
    22.     OBJECT_ATTRIBUTES Obja;
    23.     BOOLEAN StaticCurDir = FALSE;
    24.     ULONG i;
    25.     PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader( NtCurrentPeb()->ImageBaseAddress ); // <=  наш образ уже скопирован и читается в нового PE хидера
    26.     PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
    27.     ULONG ProcessHeapFlags;
    28.     RTL_HEAP_PARAMETERS HeapParameters;
    29.     NLSTABLEINFO InitTableInfo;
    30.     LARGE_INTEGER LongTimeout;
    31.     UNICODE_STRING NtSystemRoot;
    32.  
    33.  
    34. ...
    35.  
    36.     Peb->Ldr = RtlAllocateHeap(Peb->ProcessHeap, MAKE_TAG( LDR_TAG ), sizeof(PEB_LDR_DATA));
    37.     if ( !Peb->Ldr ) {
    38.         RtlRaiseStatus(STATUS_NO_MEMORY);
    39.         }
    40.     Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
    41.     Peb->Ldr->Initialized = TRUE;
    42.     Peb->Ldr->SsHandle = NULL;
    43.     InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
    44.     InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
    45.     InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
    46.     //
    47.     // Allocate the first data table entry for the image. Since we
    48.     // have already mapped this one, we need to do the allocation by hand.
    49.     // Its characteristics identify it as not a Dll, but it is linked
    50.     // into the table so that pc correlation searching doesn't have to
    51.     // be special cased.
    52.     //
    53.     LdrDataTableEntry = LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
    54.     LdrDataTableEntry->LoadCount = (USHORT)0xffff;
    55.     LdrDataTableEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrDataTableEntry->DllBase);
    56.     LdrDataTableEntry->FullDllName = FullImageName;
    57.     LdrDataTableEntry->Flags = 0;
    58.     // p = strrchr(FullImageName, '\\');
    59.     pp = UNICODE_NULL;
    60.     p = FullImageName.Buffer;
    61.     while (*p) {
    62.         if (*p++ == (WCHAR)'\\') {
    63.             pp = p;
    64.         }
    65.     }
    66.     LdrDataTableEntry->FullDllName.Length = (USHORT)((ULONG)p - (ULONG)FullImageName.Buffer);
    67.     LdrDataTableEntry->FullDllName.MaximumLength = LdrDataTableEntry->FullDllName.Length + (USHORT)sizeof(UNICODE_NULL);
    68.     if (pp) {
    69.        LdrDataTableEntry->BaseDllName.Length = (USHORT)((ULONG)p - (ULONG)pp);
    70.        LdrDataTableEntry->BaseDllName.MaximumLength = LdrDataTableEntry->BaseDllName.Length + (USHORT)sizeof(UNICODE_NULL);
    71.        LdrDataTableEntry->BaseDllName.Buffer = RtlAllocateHeap(Peb->ProcessHeap, MAKE_TAG( LDR_TAG ),
    72.                                                                LdrDataTableEntry->BaseDllName.MaximumLength
    73.                                                               );
    74.        RtlMoveMemory(LdrDataTableEntry->BaseDllName.Buffer,
    75.                      pp,
    76.                      LdrDataTableEntry->BaseDllName.MaximumLength
    77.                     );
    78.     }  else {
    79.               LdrDataTableEntry->BaseDllName = LdrDataTableEntry->FullDllName;
    80.             }
    81.     LdrpInsertMemoryTableEntry(LdrDataTableEntry);
    82.     LdrDataTableEntry->Flags |= LDRP_ENTRY_PROCESSED;
    83.     if (ShowSnaps) {
    84.         DbgPrint( "LDR: NEW PROCESS\n" );
    85.         DbgPrint( "     Image Path: %wZ (%wZ)\n",
    86.                   &LdrDataTableEntry->FullDllName,
    87.                   &LdrDataTableEntry->BaseDllName
    88.                 );
    89.         DbgPrint( "     Current Directory: %wZ\n", &CurDir );
    90.         DbgPrint( "     Search Path: %wZ\n", &LdrpDefaultPath );
    91.     }
    92.     //
    93.     // The process references the system DLL, so map this one next. Since
    94.     // we have already mapped this one, we need to do the allocation by
    95.     // hand. Since every application will be statically linked to the
    96.     // system Dll, we'll keep the LoadCount initialized to 0.
    97.     //
    98.     LdrDataTableEntry = LdrpAllocateDataTableEntry(SystemDllBase);
    99.     LdrDataTableEntry->Flags = (USHORT)LDRP_IMAGE_DLL;
    100.     LdrDataTableEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrDataTableEntry->DllBase);
    101.     LdrDataTableEntry->LoadCount = (USHORT)0xffff;
    102.     LdrDataTableEntry->BaseDllName.Length = SystemDllPath.Length;
    103.     RtlAppendUnicodeToString( &SystemDllPath, L"ntdll.dll" );
    104.     LdrDataTableEntry->BaseDllName.Length = SystemDllPath.Length - LdrDataTableEntry->BaseDllName.Length;
    105.     LdrDataTableEntry->BaseDllName.MaximumLength = LdrDataTableEntry->BaseDllName.Length + sizeof( UNICODE_NULL );
    106. ....
     
  12. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    теперь для большей наглядности заинжектил вот такую прогу
    Код (C++):
    1. #include <Windows.h>
    2. int CALLBACK WinMain(
    3. _In_ HINSTANCE hInstance,
    4. _In_ HINSTANCE hPrevInstance,
    5. _In_ LPSTR     lpCmdLine,
    6. _In_ int       nCmdShow)
    7. {
    8.        int y = 0;
    9.        int z = 0;
    10.        while(TRUE)
    11.        {
    12.             y++;
    13.             z++;
    14.         }
    15.         MessageBoxA(0,"qwer",0,0);
    16. }
    она зациклилась, присоединился отладчиком, перевел управление на MessageBox - все-таки импорты нормально настраиваются и я перешел по адресу user32!MessageBoxA. Но само окошко не высвечивается, далее начал переходить в недра messagebox, особо ничего толкового не заметил из-за чего не работает он.
    И все-таки подозрение на то, что нарушается окружение какое-то , или не дозаписывается в PEB чето, или как-то оно по пути файла ориентируется.

    Интересно, что такой вариант работает
    Код (C++):
    1. WCHAR toinjpath[MAX_PATH] = L"C:\\autoruns.exe";
    2. DWORD injexesize = 0;
    3. BYTE* injexebytes = (BYTE*)_fileGetFileContents(L"C:\\12345678.exe", &injexesize);
    4. GetModuleFileNameW(0,toinjpath,256);  // в самого себя инжектим в итоге
    5. ExecuteExeByInjection(injexebytes, toinjpath);
    А уже так - не пашет:
    Код (C++):
    1. WCHAR toinjpath[MAX_PATH] = L"C:\\autoruns.exe";
    2. DWORD injexesize = 0;
    3. BYTE* injexebytes = (BYTE*)_fileGetFileContents(L"C:\\12345678.exe", &injexesize);
    4. //GetModuleFileNameW(0,toinjpath,256); //закоментил, внедряемся в C:\\autoruns.exe
    5. ExecuteExeByInjection(injexebytes, toinjpath);
    Чудеса просто, добавить нечего.
     
  13. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    rmn,

    > Потому что при CREATE_SUSPENDED процесс замораживается не на OEP, а в середине процесса инициализации.

    При любом запуске треда начинается инициализация загрузчика, она проходит однократно. ntdll, kernel32, user32 либы не релокабельны.

    PedroPorosenko,

    > Можно ли через системные механизмы все-таки как-то брякнуться напр. на LdrpInitializeProcess или посмотреть лог

    Да. Загрузчик может выводить полный лог, для этого нужно запустить соотвествующий механизм, установив параметры в реестре. Так же загрузчик может накапливать стек вызовов, выполнять точки останова, аттачить отладчик. Поиск по форуму даст много инфы.

    В целом же впрыснуть экзешник можно только при остановленном процессе, который не начал исполнение. После того, как инициализация загрузчика закончилась, загрузить корректно экзе не получится(подключение к csrss фейлит, нужно много чего почистить в загрузчике). Может вы найдёте решение, но я его не вижу, поэтому и не использовался этот механизм.

    https://yadi.sk/d/a0n1noAB3Fa3pM
     
    PedroPorosenko нравится это.
  14. PedroPorosenko

    PedroPorosenko New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2017
    Сообщения:
    9
    да, нашел уже механизмы, будем смотреть.

    будем копать, хочется докопаться до истины.

    спс, интересные сорцы.
     
  15. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Аватарку всё же смените, не годится.