Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.138.33.178] |
|
Сообщ.
#1
,
|
|
|
Есть код MemoryModule это старый порт отсюда MemoryModule
Есть схема запуска DLL из памяти Цитата rundll32 out64.dll,f0 в out64.dll такой код: 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. 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 вообще всё запускается и работает, ошибок нет. Он наверно адреса для этого как-то особенно выделяет. |
Сообщ.
#2
,
|
|
|
Этот перевод на Дельфи мой, но я сам не особо шарю в механике. Возможно, стоит задать вопрос автору оригинального MemoryModule
|
Сообщ.
#3
,
|
|
|
я его не много поредактировал, в MemoryLoadLibary под образ DLL выделяю память обязательно выше HInstance. Плюс
{$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. Неуверен что автор сможет помочь лучше чем здесь) |
Сообщ.
#4
,
|
|
|
Цитата kin01 @ Неуверен что автор сможет помочь лучше чем здесь) Автор хотя бы шарит К тому же у тебя такое сильное колдунство, что тут разве что титаны могут что-то подсказать - Rouse, CodeMonkey, leo |
Сообщ.
#5
,
|
|
|
В общем весь код у меня написан на Delphi и продублирован на masm в том числе MemoryModule.pas. На днях нашёл что в коде на Delphi у меня ошибка. (на масм такой ошибки нет)
Result.DDLProcs[i].Name := PAnsiChar(PByte(codebase) + nameRef^); Name - AnsiString из-за чего под строку выделялся новый адрес и он мог быть иногда ниже базы. Получались отрицательные адреса после вычитания. Сделал Name: Pointer; и всё заработало. В итоге получилась такая ситуация, что я вопрос задавал про Delphi код, но оказалось что он рабочий. И вся эта схема тоже. Но Delphi линковщик много чего докручивает дополнительно на своё усмотрение в PE заголовке, возможно из-за этого и работает. Пока в коде на масм не могу найти есть там ошибка или нет. И выложить его не могу, всё равно никто смотреть не будет т.к. его много) В общем про Delphi вопрос решён. Но в masm всё равно не работает и всё именно так как я описывал выше :-) и Стек про MessageBoxW из студии) Буду искать дальше, спасибо. Просто хотел сказать что если кто-то будет пробовать потворить ошибку то на Delphi всё работает. Чтобы не пробовали просто так) |
Сообщ.
#6
,
|
|
|
Если будут какие-то предложения в модуль - велком PR у порта на Дельфи, как и у оригинала, есть трабл, отсекающий многие DLL - это все, что использует GetModuleHandle. Поскольку хэндл при загрузке получается фейковый, все такие функции идут лесом.
|
Сообщ.
#7
,
|
|
|
всё из-за макроса alloc в masm он юзает GlobalAlloc. Не доглядел.
|
Сообщ.
#8
,
|
|
|
Знаешь что меня смущает, судя по всему библиотека у тебя 64 битная, а с адресами ты работаешь усекая их до дворда.
vf.Func := DWORD(procs.DDLProcs[i].Proc) - vImageBase; Начни хотя бы с этого |
Сообщ.
#9
,
|
|
|
а Delphi компоновщик умеет делать базовый адрес 64 ?
в масм у меня всё QWORD, но всё равно сделал /BASE:"0x400000" ) Поидеи только смещение 32 задаётся, а так действительно должно работать и в 64 _IMAGE_DATA_DIRECTORY = record VirtualAddress: DWORD; Size: DWORD; end; |
Сообщ.
#10
,
|
|
|
Rouse_ сделал в asm коде, чтобы не зависеть от базы, спасибо
пришлось добавить как в оригинале MemoryModule section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff); и регистры поменял. Если в дельфи линкере можно не ограничивать базу тоже в пару мест поправить будет работать) 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; |
Сообщ.
#11
,
|
|
|
так в итоге что, работает или нет? Если не работает, то выложи аттачем все необходимые модули, чтобы можно было легко под отладкой все запустить, попробую если время будет на выходных посмотреть.
|
Сообщ.
#12
,
|
|
|
Мне надо что-нибудь менять в модуле? Кстати, там есть более свежая dev ветка, только хуки не работали
|
Сообщ.
#13
,
|
|
|
Твой я не смотрел сильно, но на вскидку вроде ровно.
|
Сообщ.
#14
,
|
|
|
Цитата Rouse_ @ так в итоге что, работает или нет? сейчас всё работает. Fr0sT, можно добавить DoInitializeSEH иначе исключения не работают. Если PE будет загружен по 64 битному адресу, то скорее работать не будет. Я просто в Delphi не могу повторить, Image Base ставлю 0 а он всё равно по 32 битному адресу загружается. |