Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 6 281

Раздел: Delphi » Прочее
/ вопрос решён /

Здравствуйте, уважаемые эксперты!

Пытаюсь получить адрес функции в чужом приложении.
Разобрал PE заголовки, и в итоге не могу извлеч значение ImageExportDir.AddressOfNameOrdinals.
Среда пишет что там вот такой тип значения - ^PWORD.
PWORD как я понимаю указатель на WORD.
Причём один такой параметр извлёкся без проблем, место где я в цикле читаю имена фйункций и сравниваю с тем что передают в функцию

 for I := 0 to ImageExportDir.NumberOfNames - 1 do
   begin
      FuncDataAddr := BaseAddr + CARDINAL(ImageExportDir.AddressOfNames) + I * SizeOf(CARDINAL);

Вплоть до этого места всё проверено и в итоге я выводил имя функции в эдит, но адрес функции получается не тот что я извлекаю внутри длл которую внедрил.
В общем ощибка в последних строках кода, может я вообще не правильно получаю адрес?


Полный код в приложении.

Приложение:
  1. {{code}}
  2.  
  3.  
  4. function GetProcAddressInAnotherProcess(PId: CARDINAL; ModuleName: PWideChar; FuncName: PWideChar): CARDINAL;
  5. var
  6. DosHeader: TImageDOSHeader;
  7. NTHeader: TImageNTHeaders;
  8. ImageExportDir: TImageExportDirectory;
  9. ModuleEntry: ModuleEntry32;
  10. NextModule: BOOL;
  11. Name: PAnsiChar;
  12. BaseAddr, BaseNTHeader, BaseExportDir,
  13. FuncDataAddr, NameAddr, FuncIndexAddr,
  14. HProcess, SnapModule, SizeName, FuncIndex,
  15. NameIndex, NumbReadBytes, I, FuncAddr: CARDINAL;
  16. begin
  17.  
  18. HProcess := OpenProcess(PROCESS_ALL_ACCESS, TRUE, PId);
  19. SnapModule := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, PId);
  20. ModuleEntry.dwSize := SizeOf(ModuleEntry);
  21. NextModule := Module32First(SnapModule, ModuleEntry);
  22. while NextModule do
  23. begin
  24. if ModuleEntry.szModule = WideString(ModuleName) then
  25. begin
  26. BaseAddr := (ModuleEntry.hModule and $FFFF0000);
  27. Break;
  28. end;
  29. NextModule := Module32Next(SnapModule, ModuleEntry);
  30. end;
  31. CloseHandle(SnapModule);
  32. CloseHandle(HProcess);
  33.  
  34. HProcess := OpenProcess(PROCESS_VM_READ, TRUE, PId);
  35. ReadProcessMemory(HProcess, POINTER(BaseAddr), Addr(DosHeader), SizeOf(DosHeader), NumbReadBytes);
  36. BaseNTHeader := BaseAddr + CARDINAL(DosHeader._lfanew);
  37. ReadProcessMemory(HProcess, POINTER(BaseNTHeader), Addr(NTHeader), SizeOf(NTHeader), NumbReadBytes);
  38. BaseExportDir := BaseAddr + NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  39. ReadProcessMemory(HProcess, POINTER(BaseExportDir), Addr(ImageExportDir), SizeOf(ImageExportDir), NumbReadBytes);
  40. SizeName := Length(FuncName);
  41. Name := AllocMem(SizeName);
  42. for I := 0 to ImageExportDir.NumberOfNames - 1 do
  43. begin
  44. FuncDataAddr := BaseAddr + CARDINAL(ImageExportDir.AddressOfNames) + I * SizeOf(CARDINAL);
  45. ReadProcessMemory(HProcess, POINTER(FuncDataAddr), Addr(NameAddr), SizeOf(NameAddr), NumbReadBytes);
  46. NameAddr := BaseAddr + NameAddr;
  47. ReadProcessMemory(HProcess, POINTER(NameAddr), Name, SizeName, NumbReadBytes);
  48. if STRING(Name) = STRING(FuncName) then
  49. begin
  50. NameIndex := I;
  51. FuncDataAddr := 0;
  52. Break;
  53. end;
  54. end;
  55. FuncIndexAddr := BaseAddr + WORD(ImageExportDir.AddressOfNameOrdinals) + NameIndex * SizeOf(WORD);
  56. ReadProcessMemory(HProcess, POINTER(FuncIndexAddr), Addr(FuncIndex), SizeOf(FuncIndex), NumbReadBytes);
  57. FuncDataAddr := BaseAddr + DWORD(ImageExportDir.AddressOfFunctions) + FuncIndex * SizeOf(DWORD);
  58. ReadProcessMemory(HProcess, POINTER(FuncDataAddr), Addr(FuncAddr), SizeOf(FuncAddr), NumbReadBytes);
  59.  
  60.  
  61. CloseHandle(HProcess);
  62. result := BaseAddr + FuncAddr;
  63.  
  64. end;
  65. {{/code}}


QWERYTY Вопрос решён, но можно продолжить его обсуждение в мини-форуме

Вопрос задал: QWERYTY (статус: Посетитель)
Вопрос отправлен: 14 октября 2012, 23:01
Состояние вопроса: решён, ответов: 0.


Мини-форум вопроса

Всего сообщений: 6; последнее сообщение — 20 октября 2012, 19:30; участников в обсуждении: 2.
Amidamaru

Amidamaru (статус: 4-ый класс), 15 октября 2012, 00:16 [#1]:

Не знаю правильно ты получаешь адрес или нет. Но несколько ошибок я думаю нашел:
Есть AllocMem, но нету FreeMem;
на 47й строке я думаю нужно использовать Name^;
при сравнении на 48й строке, возможно, стоит использовать UpperCase или LowerCase.

ps Вместо AllocMem я бы использовал просто SetLength.
Приглашаю Вас на наш IRC-канал: #delphiintru в сети DalNet.
QWERYTY

QWERYTY (статус: Посетитель), 15 октября 2012, 02:02 [#2]:

Справедливое замечание насчёт FreeMem. Это пока сырой код, я буду его перерабатывать когда заработает.

В 47-й строке так чтоли POINTER(Name^)?(Загнался, в смысле вместо POINTER Addr)
Name: PAnsiChar; Получается разыменуем, а функция требует указатель. Я вообще в начале пробовал AnsiChar и SetLength, но пошла какая то бычка. В интернете пошарился и нашёл примеры с AllocMem, в итоге вышло так. Я надеюсь это не сильно критичные ошибки? Прога для себя, быстродействие не основная характеристика, экономия памяти тоже.
Оставил так ибо после проверки выяснилось что работает.
Но если не сильно сложно продемонстрируйте как нужно с SetLength
if STRING(Name) = STRING(FuncName)
Код писался давно, я к нему недавно вернулся и уже не помню как я пришёл к такой конструкции.

Код переделывался с си, и разумеется не всё пошло как в коде на си. Некоторые вещи я просто не мог понять, и приходилось искать обходные пути. Я лучше покажу чем трепаться:
// Читаем строку
    ReadProcessMemory(hProcess, reinterpret_cast<const BYTE*>(baseAddress) + nameRVA, candidate.get(), size, NULL);
 
    if (strcmp(name, candidate.get()) == 0)
    {

Вот тут я не смог разобраться с candidate.get(), и началась возня которую вы видели.

// Читаем индекс (они двухбайтные!!!)
    ReadProcessMemory(hProcess, baseAddress + export.AddressOfNameOrdinals + nameIndex * sizeof(WORD), &funcIndex,
sizeof(funcIndex), NULL);
 
и 
 
// Читаем адрес
  DWORD funcRVA;
  ReadProcessMemory(hProcess, baseAddress + export.AddressOfFunctions + funcIndex * sizeof(DWORD), &funcRVA,
sizeof(funcRVA), NULL);
 
  // Результат это базовый адрес + RVA
  return (baseAddress + funcRVA);

Вот участок кода который не получается перевести на делфи.
На си выглядит гладко но на паскале пока не выходит.
ВЕРИТЬ ВО ВНЕЗЕМНЫЕ ЦИВИЛИЗАЦИИ НЕ ОЗНАЧАЕТ ВЕРИТЬ В ИНОПЛАНЕТЯН.
QWERYTY

QWERYTY (статус: Посетитель), 15 октября 2012, 02:20 [#3]:

UpperCase или LowerCase может быть и нужно использовать.
Честно говоря пока тестировал только на своей DLL.
Экспортировал три функции(по именам, поиск по ординалам меня не интересует) и этим кодом получается их найти. Вводил имена точ в точ как в экспорте и получал индексы от 0 до 2. Если будут проблемы с другими библиотеками обязательно буду приводить имена к какому нибудь из регистров.
ВЕРИТЬ ВО ВНЕЗЕМНЫЕ ЦИВИЛИЗАЦИИ НЕ ОЗНАЧАЕТ ВЕРИТЬ В ИНОПЛАНЕТЯН.
Amidamaru

Amidamaru (статус: 4-ый класс), 15 октября 2012, 09:49 [#4]:

Да с Name^ я похоже ошибся, но тогда я уже не знаю что здесь может быть не так. Если ты говоришь что получал адреса функций в своей библиотеке, значит всё работает.
Приглашаю Вас на наш IRC-канал: #delphiintru в сети DalNet.
QWERYTY

QWERYTY (статус: Посетитель), 15 октября 2012, 14:22 [#5]:

Да, я получаю адрес в биьлиотеке которую внедрил вот таким образом(сделал вывод сообщения как самый простой вариант, для проверки устраивает. Кстати на второй и последующих загрузках адрес всегда одинаковый, это нормально?)
Код в длл которую внедряю, стартует сразу после загрузки удалённым потоком
 
begin
 ...
 ...
  Mwwin32Handle := GetModuleHandle('mwwin32.dll');
 ...
 ...
  InitAddr := GetProcAddress(Mwwin32Handle, 'Init');
  ShowMessage(IntToStr(DWORD(InitAddr)));
end.
Я думаю тут нет ошибки с адресом функции, всегда их так получал и всё работало.
Следовательно ошибка в GetProcAddressInAnotherProcess если параметры не совпадают.

Пытаюсь получить адрес вот так:
FunkAddress := GetProcAddressInAnotherProcess(PId, PWideChar('mwwin32.dll'), PWideChar('Init'));

PId проверен не однократно разными программами, сомнений не вызывает.
BaseAddr := (ModuleEntry.hModule and $FFFF0000); - Вот эту конструкцию не очень понял, в си коде было так:
char* baseAddress = reinterpret_cast<char*>(reinterpret_cast<DWORD>(hLib) & 0xFFFF0000);
HMODULE hLib - Как я понимаю хендл библиотеки.
Но вопреки логике просто хендл не работал, то есть я даже не попадал на досовский заголовок. Так работает, я вышел в итоге и на дос заголовок и на нт заголовок. Проверил сигнатуру и она оказалась 4550, ну и соответственно двинулся дальше в эти дебри.


_IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals: ^PWORD
Это выводит студия когда я навожу курсор на AddressOfNameOrdinals, но что это за замута не могу понять и соответственно извлеч значение.

В итоге из самой длл я получаю вот такое значение - $50A322C,
А функцией вот такое - $50F0025.
Как я понимаю до ImageExportDir я добрался без ошибок, ибо я извлекал строку с именем библиотеки ImageExportDir.Name и она совпала с именем библиотеки.
ВЕРИТЬ ВО ВНЕЗЕМНЫЕ ЦИВИЛИЗАЦИИ НЕ ОЗНАЧАЕТ ВЕРИТЬ В ИНОПЛАНЕТЯН.
QWERYTY

QWERYTY (статус: Посетитель), 20 октября 2012, 19:30 [#6]:

Ну всё, разобрался.

_IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals: ^PWORD.
Здесь мне указывают что лежат элементы размером WORD, а дрес то нужно брать DWORD.

В 55-й строке:
FuncIndexAddr := BaseAddr + WORD(ImageExportDir.AddressOfNameOrdinals) + NameIndex *
SizeOf(WORD);
а нужно:
FuncIndexAddr := BaseAddr + DWORD(ImageExportDir.AddressOfNameOrdinals) + NameIndex *
SizeOf(WORD);
И читать нам нужно два байта по этому адресу, следовательно нужно в переменные добавить вот это:
FuncIndex: WORD;
Вот теперь можно перерабатывать код.


Спасибо Амидамару, не поленился глянуть код.
FreeMem сделал, регистр символов при сравнении учту.
ВЕРИТЬ ВО ВНЕЗЕМНЫЕ ЦИВИЛИЗАЦИИ НЕ ОЗНАЧАЕТ ВЕРИТЬ В ИНОПЛАНЕТЯН.

20 октября 2012, 19:38: Статус вопроса изменён на решённый (изменил автор вопроса — QWERYTY): Решён

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 31 января 2023, 10:33
Выполнено за 0.04 сек.
Рейтинг@Mail.ru