Дата: Понедельник, 27.08.2012, 02:18 | Сообщение # 1
Авторитетный
Зарегистрирован: 24.07.2011
Группа: Модераторы
Сообщений: 469
Статус: Offline
Вот на днях я заинтересовался данной темой. И в инете по данной тематике очень мало информации. Долго и упорно я искал. И случайно наткнулся вот на эту замечательную статью: http://www.rsdn.ru/article/baseserv/runcode.xml За что автору большая благодарность. И там было почти то, что нужно. Получилось очень не плохо. Т.е код работает. Я долгое время не хотел выкладывать этот код, ибо много парился, но всё-таки решился.
Данный код теперь даже умеет обрабатывать forwarded экспорт.
Код
function NativeGetProcAddressEx(ProcessHandle, HandleLibrary: THandle; FunctionName: PAnsiChar): Pointer; var ImageDosHeader: TImageDosHeader; ImageNtHeaders: TImageNtHeaders; ExportAddress: TImageDataDirectory; FunctionIndex, FunctionOrdinal: WORD; ForwardedExport, FwdLibName: PAnsiChar; ExportDirectory: TImageExportDirectory; MemoryInformation: TMemoryBasicInformation; FunctionAddress, AddressOfNames, AddressOfNameOrdinals, FunctionNameBuffer: Pointer; BaseAddress, IndexName, NtStatus, ReturnLength, NameRVA, FunctionRVA, FunctionNameLength, FwdPos: Cardinal; begin Result:=nil; if (Integer(HandleLibrary)<=0) then Exit; BaseAddress:=(HandleLibrary and $0FFFF0000); if (NtQueryVirtualMemory(ProcessHandle, (Pointer(BaseAddress)), MemoryBasicInformation, @MemoryInformation, (SizeOf(TMemoryBasicInformation)), @ReturnLength)=STATUS_SUCCESS)and(ReturnLength=(SizeOf(MemoryInformation))) then begin if (NtReadVirtualMemory(ProcessHandle, (Pointer(BaseAddress)), @ImageDosHeader, (SizeOf(ImageDosHeader)), @ReturnLength)=STATUS_SUCCESS)and (NtReadVirtualMemory(ProcessHandle, (Pointer(BaseAddress+Cardinal(ImageDosHeader._lfanew))), @ImageNtHeaders, (SizeOf(ImageNtHeaders)), @ReturnLength)=STATUS_SUCCESS) then begin if (ImageDosHeader.e_magic=IMAGE_DOS_SIGNATURE)and (ImageNtHeaders.Signature=IMAGE_NT_SIGNATURE)and (ImageNtHeaders.FileHeader.Machine=IMAGE_FILE_MACHINE_I386) then begin ExportAddress.Size:=0; ExportAddress.VirtualAddress:=0; ExportAddress:=ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if ExportAddress.VirtualAddress<>0 then Inc(ExportAddress.VirtualAddress, BaseAddress) else ExportAddress.Size:=0; begin if (ExportAddress.Size=0)or(ExportAddress.VirtualAddress=0) then Exit else begin NtStatus:=NtReadVirtualMemory(ProcessHandle, (Pointer(ExportAddress.VirtualAddress)), @ExportDirectory, (SizeOf(ExportDirectory)), @ReturnLength); if NtStatus=STATUS_SUCCESS then begin if (Cardinal(FunctionName)>$00000FFFF) then // Если импорт по имени. begin FunctionNameLength:=(ALength(FunctionName)); if FunctionNameLength=0 then Exit else FunctionNameBuffer:=GetMemory(FunctionNameLength+1); if Assigned(FunctionNameBuffer) then begin IndexName:=0; AddressOfNames:=(Pointer(BaseAddress+Cardinal(ExportDirectory.AddressOfNames))); while (IndexName<=ExportDirectory.NumberOfNames) do begin NtStatus:=NtReadVirtualMemory(ProcessHandle, (Pointer(Cardinal(AddressOfNames)+IndexName*(SizeOf(DWORD)))), @NameRVA, (SizeOf(NameRVA)), @ReturnLength)+(NtReadVirtualMemory(ProcessHandle, (Pointer(BaseAddress+NameRVA)), FunctionNameBuffer, (FunctionNameLength+1), @ReturnLength)); if NtStatus=STATUS_SUCCESS then begin if StrCmp(FunctionName, (PAnsiChar(FunctionNameBuffer))) then Break; end else Break; Inc(IndexName); end; FreeMemory(FunctionNameBuffer); if (NtStatus<>STATUS_SUCCESS) then Exit else begin AddressOfNameOrdinals:=(Pointer(BaseAddress+Cardinal(ExportDirectory.AddressOfNameOrdinals))); if (NtReadVirtualMemory(ProcessHandle, (Pointer(Cardinal(AddressOfNameOrdinals)+IndexName*SizeOf(WORD))), @FunctionIndex, (SizeOf(FunctionIndex)), @ReturnLength)<>STATUS_SUCCESS) then Exit; end; end; end else // Если импорт по ординалу. begin FunctionOrdinal:=(Cardinal(FunctionName)); if (FunctionOrdinal<ExportDirectory.Base)or(FunctionOrdinal>=ExportDirectory.Base+ ExportDirectory.NumberOfFunctions) then Exit else FunctionIndex:=(FunctionOrdinal-ExportDirectory.Base); end; if (FunctionIndex<=0)or(FunctionIndex>=ExportDirectory.NumberOfFunctions) then Exit else begin FunctionRVA:=0; if (NtReadVirtualMemory(ProcessHandle, (Pointer(BaseAddress+Cardinal(ExportDirectory.AddressOfFunctions)+ FunctionIndex*(SizeOf(DWORD)))), @FunctionRVA, (SizeOf(FunctionRVA)), @ReturnLength)=STATUS_SUCCESS)and(FunctionRVA<>0) then FunctionAddress:=(Pointer(BaseAddress+FunctionRVA)) else Exit; if (Cardinal(FunctionAddress)>ExportAddress.VirtualAddress)and (Cardinal(FunctionAddress)<=ExportAddress.VirtualAddress+ExportAddress.Size) then // Если указатель на адрес функции не лежит в пределах таблицы экспорта. begin ForwardedExport:=(GetMemory(MAX_PATH)); if Assigned(ForwardedExport) then begin if (NtReadVirtualMemory(ProcessHandle, FunctionAddress, ForwardedExport, MAX_PATH, @ReturnLength)=STATUS_SUCCESS)and (MemoryIsString(ForwardedExport, (ALength(ForwardedExport)-1))) then begin FwdPos:=Pos(Char($2E), ForwardedExport); if FwdPos>0 then begin FwdLibName:=ForwardedExport; FwdLibName[FwdPos-1]:=#0; // Отделяем имя библиотеки от имени функции. Result:=NativeGetProcAddressEx(ProcessHandle, (GetModuleHandleInProcess(ProcessHandle, FwdLibName)), ForwardedExport+FwdPos); end; end; FreeMemory(ForwardedExport); end; end else Result:=FunctionAddress; end; end; end; end; end; end; end; end;
И в качестве приза функция для поиска адреса загрузки модулей в процессах (Реализацию подсмотрел в коде Zeus'а)
Код
function GetModuleHandleInProcess(hProcess: THandle; ModuleName: PAnsiChar): Cardinal; var pFileName: PChar; TestModule: HMODULE; Modules: array of HMODULE; I, NeededSize, ModulesCount: DWORD; begin Result:=0; if EnumProcessModules(hProcess, @TestModule, (SizeOf(TestModule)), NeededSize) then begin ModulesCount:=NeededSize div (SizeOf(HMODULE)); SetLength(Modules, ModulesCount); if EnumProcessModules(hProcess, (Pointer(Modules)), NeededSize, NeededSize) then begin pFileName:=(GetMemory(MAX_PATH)); if Assigned(pFileName) then begin ZeroMemory(pFileName, MAX_PATH); for I:=0 to ModulesCount do begin if GetModuleFileNameEx(hProcess, Modules[I], pFileName, MAX_PATH)=0 then Continue else if StrCmp(LowerCase(PChar(ExtractOnlyFileName(pFileName))), (LowerCase(PChar(ExtractOnlyFileName(ModuleName))))) then begin Result:=Modules[I]; Break; end; end; end; FreeMemory(pFileName); end; end; end;
Дата: Понедельник, 27.08.2012, 19:11 | Сообщение # 5
Авторитетный
Зарегистрирован: 24.07.2011
Группа: Модераторы
Сообщений: 469
Статус: Offline
Quote
Так может быть тогда в приват его?
Да нет. Не стоит. Здесь нету ничего особо приватного.
Quote
для чего можно применить эту функцию?
Много для чего. Ну, например, для перехвата API или самопал функций в стороннем процессе. Так же для инжекта кода, т.к библиотеки могут быть загружены по разным адресам, соответственно у api функций будет иной адрес. Ну а GetModuleHandleInProcess уж всяко пригодится.
Дата: Понедельник, 27.08.2012, 21:18 | Сообщение # 6
Продвинутый
Зарегистрирован: 16.04.2012
Группа: Пользователи
Сообщений: 253
Статус: Offline
Quote (Волк-1024)
т.к библиотеки могут быть загружены по разным адресам
Ну для этих целей я знаю такую функцию (1-й параметр - ID процесса, 2-й имя искомой библиотеки):
Code
uses TlHelp32;
function GetModuleBase(hProcID: Cardinal; lpModName: PChar):Cardinal; var hSnap: Cardinal; tm: TModuleEntry32; begin result := 0; hSnap := CreateToolHelp32Snapshot(TH32CS_SNAPMODULE, hProcID); if hSnap <> 0 then begin tm.dwSize := sizeof(TModuleEntry32); if Module32First(hSnap, tm) = true then begin while Module32Next(hSnap, tm) = true do begin if lstrcmpi(tm.szModule, lpModName) = 0 then begin result := Cardinal(tm.modBaseAddr); break; end; end; end; CloseHandle(hSnap); end; end;
Дата: Воскресенье, 02.09.2012, 22:41 | Сообщение # 7
Авторитетный
Зарегистрирован: 24.07.2011
Группа: Модераторы
Сообщений: 469
Статус: Offline
Вот нашел очень серьезный баг в функции NativeGetProcAddressEx. Баг связан с тем, что индексация имен функций в библиотеках начинается с ноля, а не с единицы, что в свою очередь приводило бы к серьёзным последствиям, таким как, например, если попытаться искать не существующую функцию, то функция вернет адрес последней функции в библиотеке, например, в Kernel32.dll это функция lstrlenW. Осталось еще одна не решенная проблема: NativeGetProcAddressEx не ищет адреса функций с ординалом 1, ищет только начиная от 2 и выше, а GetProcAddress всё находит. Есть варианты, как это исправить?
Сообщение отредактировал Волк-1024 - Вторник, 04.09.2012, 19:32
возможно глупость спрошу, но у меня делфи 7 не хочет код компилировать, ругается на MemoryBasicInformation в (NtQueryVirtualMemory(ProcessHandle, (Pointer(BaseAddress)), MemoryBasicInformation, @MemoryInformation, (SizeOf(TMemoryBasicInformation)), @ReturnLength)=STATUS_SUCCESS)and(ReturnLength=(SizeOf(MemoryInformation)))
третье значение это длинное целое должно быть, чему там равен MemoryBasicInformation?
TMemoryBasicInformation - это структура. а MemoryBasicInformation это номер класса. Все недостающие структуры и прототипы Native функций легко находятся в Гугле.