Дата: Понедельник, 27.08.2012, 02:18 | Сообщение # 1
Авторитетный
Зарегистрирован: 24.07.2011
Группа: Модераторы
Сообщений: 463
Статус: 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
Группа: Модераторы
Сообщений: 463
Статус: Offline
Quote
Так может быть тогда в приват его?
Да нет. Не стоит. Здесь нету ничего особо приватного.
Quote
для чего можно применить эту функцию?
Много для чего. Ну, например, для перехвата API или самопал функций в стороннем процессе. Так же для инжекта кода, т.к библиотеки могут быть загружены по разным адресам, соответственно у api функций будет иной адрес. Ну а GetModuleHandleInProcess уж всяко пригодится.
Дата: Понедельник, 27.08.2012, 21:18 | Сообщение # 6
Продвинутый
Зарегистрирован: 16.04.2012
Группа: Пользователи
Сообщений: 250
Статус: 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
Группа: Модераторы
Сообщений: 463
Статус: 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 функций легко находятся в Гугле.