Задержка загрузки экспортируемых функций - PullRequest
1 голос
/ 17 февраля 2020

Я пытаюсь понять, как работает отложенная загрузка экспортируемых функций (с c ++ на windows).

Насколько я понимаю, вы можете либо импортировать какой-то '* .h' и вызвать функцию. Компилятор и даже больше компоновщик позаботится обо всем, а также загрузчик windows (который затем исправит точные адреса в соответствии с разметкой памяти во время выполнения). Другой вариант - загрузить адрес экспортируемой функции во время выполнения, преобразовать его в указатель функции и просто запустить его. Поэтому я использовал простой пример для выделения массива символов и распечатки содержимого:

void writeChar(char* char_space, SSIZE_T len)
{
  memset(char_space, 0x41, len);
}

int main()
{
  // Allocate a buffer
  SSIZE_T len = 10;
  char* char_space = (char*) VirtualAlloc(NULL, len, MEM_COMMIT, PAGE_READWRITE);

  // write to it
  writeChar(char_space, len);

  // print chars omitted for readability...
  return 0;
}

Это работает так, как я ожидаю. Я просто бросил его в консольное приложение windows в VS, и оно скомпилировалось и прекрасно работало.

Поэтому я попытался просто загрузить его во время выполнения. Я скопировал точный заголовок функции из memoryapi.h и попытался найти его в экспортируемой DLL (kernel32.dll).

typedef LPVOID (*loadedAlloc) (LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 

void writeChar(char* char_space, SSIZE_T len)
{
  memset(char_space, 0x41, len);
}

int main()
{
  // Load the functions address (assume kernel32.dll is loaded)
  loadedAlloc Alloc = (loadedlAlloc)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "VirtualAlloc");

  // Allocate a buffer
  SSIZE_T len = 10;
  char* char_space = (char*) loadedAlloc(NULL, len, MEM_COMMIT, PAGE_READWRITE);

  // write to it
  writeChar(char_space, len);

  // print chars omitted for readability...
  return 0;
}

Это ведет себя совершенно иначе. Адрес эффективно загружается, и вызов также извлекает адрес памяти (тот, который выглядит хорошо). Но после его передачи в функцию «writeChar» адрес памяти (по крайней мере, в отладчике) изменяется. Это приведет к некоторому AccessViolation при следующей записи (memset -call), и программа завершится.

Так чем отличаются эти вызовы?

...