На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania 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
Codero ergo sum
// Программирую — значит, существую
я его не много поредактировал, в 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 :-?
Codero ergo sum
// Программирую — значит, существую
В общем весь код у меня написан на 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. Поскольку хэндл при загрузке получается фейковый, все такие функции идут лесом.
Codero ergo sum
// Программирую — значит, существую
всё из-за макроса alloc в masm он юзает GlobalAlloc. Не доглядел.
Знаешь что меня смущает, судя по всему библиотека у тебя 64 битная, а с адресами ты работаешь усекая их до дворда.
ExpandedWrap disabled
    vf.Func := DWORD(procs.DDLProcs[i].Proc) - vImageBase;


Начни хотя бы с этого :)
user posted image
В русском языке есть слова, их там много.
Когда их составляешь вместе, получается предложение, где есть сказуемое, подлежащее и прочая светотень.
В нём переставь местоимение, сказуемое и подлежащее, и появится интонация!
а 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 -
так в итоге что, работает или нет? Если не работает, то выложи аттачем все необходимые модули, чтобы можно было легко под отладкой все запустить, попробую если время будет на выходных посмотреть.
user posted image
В русском языке есть слова, их там много.
Когда их составляешь вместе, получается предложение, где есть сказуемое, подлежащее и прочая светотень.
В нём переставь местоимение, сказуемое и подлежащее, и появится интонация!
Мне надо что-нибудь менять в модуле? Кстати, там есть более свежая dev ветка, только хуки не работали
Codero ergo sum
// Программирую — значит, существую
Твой я не смотрел сильно, но на вскидку вроде ровно.
user posted image
В русском языке есть слова, их там много.
Когда их составляешь вместе, получается предложение, где есть сказуемое, подлежащее и прочая светотень.
В нём переставь местоимение, сказуемое и подлежащее, и появится интонация!
Цитата Rouse_ @
так в итоге что, работает или нет?

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

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


Рейтинг@Mail.ru
[ Script Execution time: 0,1591 ]   [ 20 queries used ]   [ Generated: 22.02.19, 02:12 GMT ]