Невозможно отучить людей изучать самые ненужные предметы.
Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3
Надо знать обо всем понемножку, но все о немногом.
Идентификаторы
Контекстные селекторы
Соседние селекторы
Дочерние селекторы
Селекторы атрибутов
Универсальный селектор
Псевдоклассы
Псевдоэлементы
Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)
Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода
Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
Списки
Ссылки
Дизайны сайтов
Формы
Таблицы
CSS3
HTML5
Блог для вебмастеров
Новости мира Интернет
Сайтостроение
Ремонт и советы
Все новости
Справочник от А до Я
HTML, CSS, JavaScript
Афоризмы о учёбе
Статьи об афоризмах
Все Афоризмы
Помогли мы вам |
Теперь нырнем в пучины интернета и поищем кастомную реализацию GetProcAddress(
. Я выбрал самый аккуратный и милый вариант.
FARPROC myGetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hModule + dosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)hModule +
ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* addressOfFunctions = (DWORD*)((BYTE*)hModule + exportDirectory->AddressOfFunctions);
WORD* addressOfNameOrdinals = (WORD*)((BYTE*)hModule + exportDirectory->AddressOfNameOrdinals);
DWORD* addressOfNames = (DWORD*)((BYTE*)hModule + exportDirectory->AddressOfNames);
for (DWORD i = 0; i < exportDirectory->NumberOfNames; ++i) {
if (strcmp(lpProcName, (const char*)hModule + addressOfNames[i]) == 0) {
return (FARPROC)((BYTE*)hModule + addressOfFunctions[addressOfNameOrdinals[i]]);
}
}
return NULL;
}
Функция достаточно проста: принимает базовый адрес загрузки библиотеки, а также имя функции, адрес которой надо получить. Работает так, как нам и нужно, — путем парсинга EAT.
Помнишь, мы отключили CRT? Поэтому использование функции strcmp(
из этого кода невозможно. К счастью, сравнение двух строк — базовый алгоритм, который пишут еще на паскале в седьмом классе. На C++ я вынес его в отдельную функцию custom_strcmp(
.
int custom_strcmp(const char* str1, const char* str2) {
while (*str1 || *str2) {
if (*str1 < *str2) {
return -1;
}
else if (*str1 > *str2) {
return 1;
}
str1++;
str2++;
}
return 0;
}
Разобравшись, как и что делать, получаем следующий код.
#include <Windows.h>
#include <winternl.h>
typedef int (WINAPI* MessageBoxWFunc)(
HWND hWnd,
LPCWSTR lpText,
LPCWSTR lpCaption,
UINT uType
);
int custom_strcmp(const char* str1, const char* str2) {
while (*str1 || *str2) {
if (*str1 < *str2) {
return -1;
}
else if (*str1 > *str2) {
return 1;
}
str1++;
str2++;
}
return 0;
}
FARPROC myGetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hModule + dosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)hModule +
ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* addressOfFunctions = (DWORD*)((BYTE*)hModule + exportDirectory->AddressOfFunctions);
WORD* addressOfNameOrdinals = (WORD*)((BYTE*)hModule + exportDirectory->AddressOfNameOrdinals);
DWORD* addressOfNames = (DWORD*)((BYTE*)hModule + exportDirectory->AddressOfNames);
for (DWORD i = 0; i < exportDirectory->NumberOfNames; ++i) {
if (custom_strcmp(lpProcName, (const char*)hModule + addressOfNames[i]) == 0) {
return (FARPROC)((BYTE*)hModule + addressOfFunctions[addressOfNameOrdinals[i]]);
}
}
return NULL;
}
int main() {
HMODULE user32Module = LoadLibrary(L"user32.dll");
MessageBoxWFunc MessageBoxWPtr = (MessageBoxWFunc)(myGetProcAddress(user32Module, "MessageBoxW"));
MessageBoxWPtr(NULL, L"HI", L"HI", MB_OK);
return 0;
}
Компилируем, запускаем. Видим, что остался лишь один импорт.
Чем же заменить LoadLibrary(
? Если мы глянем на последовательность вызовов функций, то увидим, что LoadLibrary(
вызывает LdrLoadDll(
, она — LdrpLoadDll(
, а та — еще одну функцию... Процесс, скажу честно, достаточно сложный. Вот картинка, которая хорошо описывает последовательность вызовов при загрузке DLL.
|
|