На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> проброс экспорта DLL загруженной из памяти , win64, MemoryModule
    Есть код MemoryModule это старый порт отсюда MemoryModule

    Есть схема запуска DLL из памяти

    Цитата
    rundll32 out64.dll,f0


    в out64.dll такой код:

    ExpandedWrap disabled
      function MakeTableExport(procs: PDLLProcs): Boolean;
      var
        pNtHeaders: PImageNtHeaders;
        ExportAddr: TImageDataDirectory;
        vImageBase: HINST;
        vexport: PImageExportDirectory;
        voldp: DWORD;
        i: DWORD;
        vNewFunctions: parrayofdword;
        vNewNames: parrayofdword;
        vNewOrdinals: parrayofword;
        vf: PDLLFunc;
        vfuncs: TArray<TNameOrd>;
        MBI: TMemoryBasicInformation;
        p: PByte;
        vLenD, vLenW: DWORD;
        e: Pointer;
      begin
        Result := False;
        pNtHeaders := nil;
      try
        vImageBase := HInstance;
        if PWord(vImageBase)^ = IMAGE_DOS_SIGNATURE then
        begin
          pNtHeaders := Pointer(vImageBase + SIZE_T(PImageDosHeader(vImageBase)
            ^._lfanew));
          ExportAddr.VirtualAddress := 0;
          ExportAddr.Size := 0;
        end;
       
        New(vexport);
        ZeroMemory(vexport, SizeOf(vexport^));
       
        vLenW := (vexport.NumberOfFunctions + procs.Count) * SizeOf(WORD);
        vLenD := (vexport.NumberOfFunctions + procs.Count) * SizeOf(DWORD);
        SetLength(vfuncs, vexport.NumberOfNames + procs.Count);
       
        for I := 0 to procs.Count - 1 do
        begin
          New(vf);
          vf.Name := SIZE_T(procs.DDLProcs[i].Name) - vImageBase;
          vf.Func := DWORD(procs.DDLProcs[i].Proc) - vImageBase;
          vfuncs[vexport.NumberOfFunctions + i].Name := string(PAnsiChar(procs.DDLProcs[i].Name));
          vfuncs[vexport.NumberOfFunctions + i].Data := vf;
        end;
       
        p := TryAllocMemAt(Pointer(vImageBase), vLenD + vLenD + vLenW, PAGE_READWRITE);
       
        if p = nil then
          Exit;
       
        vNewNames := parrayofdword(p);
        vNewOrdinals := parrayofword(p + vLenD);
        vNewFunctions := parrayofdword(p + vLenD + vLenW);
       
        for i := 0 to Length(vfuncs) - 1 do
        begin
          vNewNames[i] := vfuncs[i].Data.Name;
          vNewFunctions[i] := vfuncs[i].Data.Func;
          vNewOrdinals[i] := i;
        end;
       
        if VirtualProtect(p, vLenD + vLenD + vLenW, PAGE_READONLY, MBI.Protect) then
        begin
          vexport.AddressOfFunctions := DWORD(vNewFunctions) - vImageBase;
          vexport.AddressOfNames := DWORD(vNewNames) - vImageBase;
          vexport.AddressOfNameOrdinals := DWORD(vNewOrdinals) - vImageBase;
          vexport.NumberOfFunctions := vexport.NumberOfFunctions + procs.Count;
          vexport.NumberOfNames := vexport.NumberOfNames + procs.Count;
       
          e := TryAllocMemAt(Pointer(vImageBase), SizeOf(TImageExportDirectory), PAGE_READWRITE);
       
          if VirtualProtect(@pNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,SizeOf(DWORD), PAGE_READWRITE, voldp) then
            pNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress := dword(e) - vImageBase;
       
          ExportAddr.VirtualAddress := dword(e);
       
          if VirtualProtect(Pointer(ExportAddr.VirtualAddress),SizeOf(TImageExportDirectory), PAGE_READWRITE, voldp) then
          begin
            Move(vexport^, Pointer(ExportAddr.VirtualAddress)^,SizeOf(TImageExportDirectory));
            Result := VirtualProtect(Pointer(ExportAddr.VirtualAddress),SizeOf(TImageExportDirectory), voldp, voldp);
          end;
        end;
      except
       
      end;
      end;
       
      var
        vlib: TMemoryStream;
        h: Pointer;
        p: PDLLProcs;
      begin
        vlib := TMemoryStream.Create;
        vlib.LoadFromFile('testc.dll');
        h := MemoryLoadLibary(vlib.Memory, vlib.Size);
        p := MemoryGetProcs(h);
        MakeTableExport(p);


    суть этого кода, чтобы экспортируемые функции testc.dll пробросить до out64.dll.

    ExpandedWrap disabled
      library testc;
       
      uses
        windows;
       
      procedure f0; stdcall;
      begin
        GetCurrentThreadId;
        MessageBox(0, 'f0', '', 0);
      end;
       
      procedure f1; stdcall;
      begin
        MessageBox(0, 'f1', '', 0);
      end;
       
      procedure f2; stdcall;
      begin
        MessageBox(0, 'f2', '', 0);
      end;
       
      procedure f3; stdcall;
      begin
        MessageBox(0, 'f3', '', 0);
      end;
       
      procedure f4; stdcall;
      begin
        MessageBox(0, 'f4', '', 0);
      end;
       
      procedure f5; stdcall;
      begin
        MessageBox(0, 'f5', '', 0);
      end;
       
      procedure f6; stdcall;
      begin
        MessageBox(0, 'f6', '', 0);
      end;
       
      procedure f7; stdcall;
      begin
        MessageBox(0, 'f7', '', 0);
      end;
       
      procedure f8; stdcall;
      begin
        MessageBox(0, 'f8', '', 0);
      end;
       
      procedure f9; stdcall;
      begin
        MessageBox(0, 'f9', '', 0);
      end;
       
      exports
        f0,
        f1,
        f2,
        f3,
        f4,
        f5,
        f6,
        f7,
        f8,
        f9;
       
      begin
        MessageBox(0, 'main', '', 0);
      end.


    Начинает вылетать в тот момент когда вызываются API функции внутри testc.dll. Например MessageBoxW. Стек вызовов такой:

    Цитата
    ntdll.dll!RtlpReAllocateHeap () Нет данных Непользовательский код. Символы загружены.
    ntdll.dll!RtlReAllocateHeap () Нет данных Непользовательский код. Символы загружены.
    KernelBase.dll!LocalReAlloc () Нет данных Непользовательский код. Символы загружены.
    msctf.dll!CVoidStructArray::Insert(int,int) Нет данных Непользовательский код. Символы загружены.
    msctf.dll!CAssemblyList::LoadFromCache(void) Нет данных Непользовательский код. Символы загружены.
    msctf.dll!CAssemblyList::Load(void) Нет данных Непользовательский код. Символы загружены.
    msctf.dll!EnsureAssemblyList(struct SYSTHREAD *,int) Нет данных Непользовательский код. Символы загружены.
    msctf.dll!CThreadInputMgr::Resume(void) Нет данных Непользовательский код. Символы загружены.
    msctf.dll!CThreadInputMgr::ActivateEx_P(unsigned long *,unsigned long) Нет данных Непользовательский код. Символы загружены.
    msctf.dll!CicBridge::ActivateIMMX(class TLS *,struct ITfThreadMgr_P *,unsigned long,unsigned long) Нет данных Непользовательский код. Символы загружены.
    msctf.dll!CtfImeCreateThreadMgr () Нет данных Непользовательский код. Символы загружены.
    imm32.dll!CtfImmTIMActivate () Нет данных Непользовательский код. Символы загружены.
    imm32.dll!InternalImmLockIMC () Нет данных Непользовательский код. Символы загружены.
    imm32.dll!ImmSetActiveContext () Нет данных Непользовательский код. Символы загружены.
    user32.dll!FocusSetIMCContext () Нет данных Непользовательский код. Символы загружены.
    user32.dll!ImeSystemHandler () Нет данных Непользовательский код. Символы загружены.
    user32.dll!ImeWndProcWorker () Нет данных Непользовательский код. Символы загружены.
    user32.dll!ImeWndProcW () Нет данных Непользовательский код. Символы загружены.
    user32.dll!UserCallWinProcCheckWow () Нет данных Непользовательский код. Символы загружены.
    user32.dll!DispatchClientMessage () Нет данных Непользовательский код. Символы загружены.
    user32.dll!__fnDWORD () Нет данных Непользовательский код. Символы загружены.
    ntdll.dll!KiUserCallbackDispatcherContinue () Нет данных Непользовательский код. Символы загружены.
    user32.dll!NtUserSetFocus () Нет данных Непользовательский код. Символы загружены.
    user32.dll!MB_DlgProc () Нет данных Непользовательский код. Символы загружены.
    user32.dll!UserCallDlgProcCheckWow () Нет данных Непользовательский код. Символы загружены.
    user32.dll!DefDlgProcWorker () Нет данных Непользовательский код. Символы загружены.
    user32.dll!DefDlgProcW () Нет данных Непользовательский код. Символы загружены.
    user32.dll!UserCallWinProcCheckWow () Нет данных Непользовательский код. Символы загружены.
    user32.dll!InternalCreateDialog () Нет данных Непользовательский код. Символы загружены.
    user32.dll!InternalDialogBox () Нет данных Непользовательский код. Символы загружены.
    user32.dll!SoftModalMessageBox () Нет данных Непользовательский код. Символы загружены.
    user32.dll!MessageBoxWorker () Нет данных Непользовательский код. Символы загружены.
    user32.dll!MessageBoxTimeoutW () Нет данных Непользовательский код. Символы загружены.
    user32.dll!MessageBoxW () Нет данных Непользовательский код. Символы загружены.


    В 32 всё работает. В 64 работает только в том случае если функций экспорта в testc.dll не больше 2.
    Не понятно вообще реально в случае с 64 после проброса вызывать функции. Как будто идёт обращение из адресного пространства одной длл к другой а доступа нет.

    Цитата
    Вызвано исключение по адресу 0x0000000077262478 (ntdll.dll) в myrundll.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0x000003A434D41498.


    Добавлено
    Под отладчиком WinDbg вообще всё запускается и работает, ошибок нет. Он наверно адреса для этого как-то особенно выделяет.
      Этот перевод на Дельфи мой, но я сам не особо шарю в механике. Возможно, стоит задать вопрос автору оригинального MemoryModule
        я его не много поредактировал, в MemoryLoadLibary под образ DLL выделяю память обязательно выше HInstance. Плюс
        ExpandedWrap disabled
          {$IFDEF WIN64}
          function DoInitializeSEH(Module: PMemoryModule): Boolean;
          var
            dir: PImageDataDirectory;
            EnrtyNums: DWORD;
            RtlAddFunctionTable: function(FunctionTable: PImageRuntimeFunctionEntry;
              EntryCount: DWORD; BaseAddress: DWORD64): boolean; stdcall;
          begin
            @RtlAddFunctionTable := GetProcAddress(GetModuleHandle(kernel32),
              'RtlAddFunctionTable');
            if not Assigned(RtlAddFunctionTable) then
              Exit(False);
            dir := PImageDataDirectory(@Module.headers.OptionalHeader.DataDirectory
              [IMAGE_DIRECTORY_ENTRY_EXCEPTION]);
            if (dir.VirtualAddress = 0) or (dir.Size = 0) then
            begin
              Exit(False);
            end;
            Module.runtimeFunc := PImageRuntimeFunctionEntry(@Module.codeBase[dir.VirtualAddress]);
           
            EnrtyNums := dir.Size div SizeOf(IMAGE_RUNTIME_FUNCTION_ENTRY);
            Result := RtlAddFunctionTable(Module.runtimeFunc, EnrtyNums, DWORD64(Module.codeBase));
          end;
          {$ENDIF}


        перед BuildImportTable. Плюс при вызове DLLEntry передаю дескриптор текущей DLL Иначе длл в памяти по GetModuleFileName возвращает пустую строку.

        Наверно что-то неучитываю т.к. цепочка rundll32 - dll - dllmem. Неуверен что автор сможет помочь лучше чем здесь)
          Цитата kin01 @
          Неуверен что автор сможет помочь лучше чем здесь)

          Автор хотя бы шарит :) К тому же у тебя такое сильное колдунство, что тут разве что титаны могут что-то подсказать - Rouse, CodeMonkey, leo :-?
            В общем весь код у меня написан на Delphi и продублирован на masm в том числе MemoryModule.pas. На днях нашёл что в коде на Delphi у меня ошибка. (на масм такой ошибки нет)

            ExpandedWrap disabled
              Result.DDLProcs[i].Name := PAnsiChar(PByte(codebase) + nameRef^);


            Name - AnsiString из-за чего под строку выделялся новый адрес и он мог быть иногда ниже базы. Получались отрицательные адреса после вычитания. Сделал Name: Pointer; и всё заработало.

            В итоге получилась такая ситуация, что я вопрос задавал про Delphi код, но оказалось что он рабочий. И вся эта схема тоже. Но Delphi линковщик много чего докручивает дополнительно на своё усмотрение в PE заголовке, возможно из-за этого и работает. Пока в коде на масм не могу найти есть там ошибка или нет. И выложить его не могу, всё равно никто смотреть не будет т.к. его много) В общем про Delphi вопрос решён. Но в masm всё равно не работает и всё именно так как я описывал выше :-) и Стек про MessageBoxW из студии) Буду искать дальше, спасибо. Просто хотел сказать что если кто-то будет пробовать потворить ошибку то на Delphi всё работает. Чтобы не пробовали просто так)
              Если будут какие-то предложения в модуль - велком PR :) у порта на Дельфи, как и у оригинала, есть трабл, отсекающий многие DLL - это все, что использует GetModuleHandle. Поскольку хэндл при загрузке получается фейковый, все такие функции идут лесом.
                всё из-за макроса alloc в masm он юзает GlobalAlloc. Не доглядел.
                  Знаешь что меня смущает, судя по всему библиотека у тебя 64 битная, а с адресами ты работаешь усекая их до дворда.
                  ExpandedWrap disabled
                    vf.Func := DWORD(procs.DDLProcs[i].Proc) - vImageBase;


                  Начни хотя бы с этого :)
                    а Delphi компоновщик умеет делать базовый адрес 64 ?

                    в масм у меня всё QWORD, но всё равно сделал /BASE:"0x400000" )

                    Поидеи только смещение 32 задаётся, а так действительно должно работать и в 64
                    ExpandedWrap disabled
                        _IMAGE_DATA_DIRECTORY = record
                          VirtualAddress: DWORD;
                          Size: DWORD;
                        end;
                      Rouse_ сделал в asm коде, чтобы не зависеть от базы, спасибо

                      пришлось добавить как в оригинале MemoryModule

                      ExpandedWrap disabled
                        section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff);


                      и регистры поменял. Если в дельфи линкере можно не ограничивать базу тоже в пару мест поправить будет работать)

                      ExpandedWrap disabled
                        function MakeTableExport(procs: PDLLProcs): Boolean;
                        var
                          pNtHeaders: PImageNtHeaders;
                          vImageBase: HINST;
                          vexport: PImageExportDirectory;
                          voldp: DWORD;
                          i: DWORD;
                          vNewFunctions: parrayofdword;
                          vNewNames: parrayofdword;
                          vNewOrdinals: parrayofword;
                          vf: PDLLFunc;
                          vfuncs: TArray<TNameOrd>;
                          MBI: TMemoryBasicInformation;
                          p: PByte;
                          vLenD, vLenW: DWORD;
                          e: Pointer;
                        begin
                          Result := False;
                          pNtHeaders := nil;
                        try
                          vImageBase := HInstance;
                          if PWord(vImageBase)^ = IMAGE_DOS_SIGNATURE then
                          begin
                            pNtHeaders := Pointer(vImageBase + SIZE_T(PImageDosHeader(vImageBase)
                              ^._lfanew));
                          end;
                         
                          New(vexport);
                          ZeroMemory(vexport, SizeOf(vexport^));
                         
                          vLenW := (vexport.NumberOfFunctions + procs.Count) * SizeOf(WORD);
                          vLenD := (vexport.NumberOfFunctions + procs.Count) * SizeOf(DWORD);
                          SetLength(vfuncs, vexport.NumberOfNames + procs.Count);
                         
                          for I := 0 to procs.Count - 1 do
                          begin
                            New(vf);
                            vf.Name := SIZE_T(procs.DDLProcs[i].Name) - vImageBase;
                            vf.Func := SIZE_T(procs.DDLProcs[i].Proc) - vImageBase;
                            vfuncs[vexport.NumberOfFunctions + i].Name := string(PAnsiChar(procs.DDLProcs[i].Name));
                            vfuncs[vexport.NumberOfFunctions + i].Data := vf;
                          end;
                         
                          p := TryAllocMemAt(Pointer(vImageBase), vLenD + vLenD + vLenW, PAGE_READWRITE);
                         
                          if p = nil then
                            Exit;
                         
                          vNewNames := parrayofdword(p);
                          vNewOrdinals := parrayofword(p + vLenD);
                          vNewFunctions := parrayofdword(p + vLenD + vLenW);
                         
                          for i := 0 to Length(vfuncs) - 1 do
                          begin
                            vNewNames[i] := vfuncs[i].Data.Name;
                            vNewFunctions[i] := vfuncs[i].Data.Func;
                            vNewOrdinals[i] := i;
                          end;
                         
                          if VirtualProtect(p, vLenD + vLenD + vLenW, PAGE_READONLY, MBI.Protect) then
                          begin
                            vexport.AddressOfFunctions := SIZE_T(vNewFunctions) - vImageBase;
                            vexport.AddressOfNames := SIZE_T(vNewNames) - vImageBase;
                            vexport.AddressOfNameOrdinals := SIZE_T(vNewOrdinals) - vImageBase;
                            vexport.NumberOfFunctions := vexport.NumberOfFunctions + procs.Count;
                            vexport.NumberOfNames := vexport.NumberOfNames + procs.Count;
                         
                            e := TryAllocMemAt(Pointer(vImageBase), SizeOf(TImageExportDirectory), PAGE_READWRITE);
                         
                            if VirtualProtect(@pNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,SizeOf(DWORD), PAGE_READWRITE, voldp) then
                              pNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress := SIZE_T(e) - vImageBase;
                         
                            if VirtualProtect(e,SizeOf(TImageExportDirectory), PAGE_READWRITE, voldp) then
                            begin
                              Move(vexport^, e^,SizeOf(TImageExportDirectory));
                              Result := VirtualProtect(e,SizeOf(TImageExportDirectory), voldp, voldp);
                            end;
                          end;
                        except
                         
                        end;
                        end;
                      Сообщение отредактировано: kin01 -
                        так в итоге что, работает или нет? Если не работает, то выложи аттачем все необходимые модули, чтобы можно было легко под отладкой все запустить, попробую если время будет на выходных посмотреть.
                          Мне надо что-нибудь менять в модуле? Кстати, там есть более свежая dev ветка, только хуки не работали
                            Твой я не смотрел сильно, но на вскидку вроде ровно.
                              Цитата Rouse_ @
                              так в итоге что, работает или нет?

                              сейчас всё работает.

                              Fr0sT, можно добавить DoInitializeSEH иначе исключения не работают. Если PE будет загружен по 64 битному адресу, то скорее работать не будет. Я просто в Delphi не могу повторить, Image Base ставлю 0 а он всё равно по 32 битному адресу загружается.
                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                              0 пользователей:


                              Рейтинг@Mail.ru
                              [ Script execution time: 0,0424 ]   [ 16 queries used ]   [ Generated: 29.03.24, 11:42 GMT ]