В целях обучения я делаю собственную реализацию функции WINAPI GetModuleHandle.
вот:
PVOID SelfGetModuleHandle(PCWSTR name) {
PEB* pPeb = RtlGetCurrentPeb();//getting Process Environement Bloc
PPEB_LDR_DATA pLdr = pPeb->Ldr; //https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
LIST_ENTRY Lentry = pLdr->InMemoryOrderModuleList;//https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data
LIST_ENTRY FirstLentry = Lentry;
do
{
LDR_DATA_TABLE_ENTRY LDataTableEntry = *(LDR_DATA_TABLE_ENTRY*)Lentry.Flink;
if (StrCmpW(LDataTableEntry.FullDllName.Buffer, name) == 0) {
printf("Base foud: %p\n", LDataTableEntry.DllBase);
return (LDataTableEntry.DllBase);
}
Lentry = *Lentry.Flink;
} while (memcmp(&Lentry, &FirstLentry, sizeof(LIST_ENTRY)));
return NULL;
}
Я думал, что моя функция довольно крутая и работает, но код примера получает segfault
typedef
double
(__stdcall* POW)( //pow from NTDLL (offset 0x151498)
double a,
double b
);
int main(){
HMODULE dllBase = (HMODULE)SelfGetModuleHandle(L"ntdll.dll");//00000000001F8000 instead of 00007FFD36FD0000
POW pow = (POW)GetProcAddress(dllBase, "pow");
printf("%f", pow(2.0,3.0));
}
Я ищу, что я сделал не так, но не могу найти.
Может быть, я не получаю правильную базу dll для этого, в неправильной таблице, или, может быть, PVOID нуждается в большем преобразовании для того, чтобы быть HMODULE, но я не думаю, что это так.
Спасибо.
@ikegami да, я говорил о разнице между DllBase из LDR_DATA_TABLE_ENTRY и ожидаемым значением для GetProcAddress, а не самим типом
SIGSEGV — это не то, с чем вы столкнетесь в Windows. Пожалуйста, объясните проблему так, чтобы это совпадало с реальностью. Используйте отладчик, чтобы получить полезную информацию.
@IInspectable Я делаю это, моя программа пытается связаться с адресом, который не существует в текущем контексте.
Это неверное приведение: LDR_DATA_TABLE_ENTRY LDataTableEntry = *(LDR_DATA_TABLE_ENTRY*)Lentry.Flink;
Вам нужно отрегулировать смещение соответствующей записи списка до заголовка структуры.
Lentry = *Lentry.Flink;
и memcmp(&Lentry, &FirstLentry, sizeof(LIST_ENTRY))
- это что-то
@IInspectable: Если предположить, что он действительно получил SIGSEGV, он не будет первым программистом, который сначала разработает программное обеспечение для Windows на Wine.
В Windows тоже нет "segfaults". Если вы наблюдаете нарушение прав доступа, нет ничего плохого в том, чтобы назвать это нарушением прав доступа.
Используйте CONTAINING_RECORD
, чтобы перейти от указателя LIST_ENTRY к заголовку структуры. И memcmp не нужен для завершения цикла.
Попробуйте что-то вроде этого:
PLIST_ENTRY current = pPeb->Ldr->InMemoryOrderModuleList.Flink;
while ((current != NULL) && (current != &pPeb->Ldr->InMemoryOrderModuleList))
{
LDR_DATA_TABLE_ENTRY* module = (LDR_DATA_TABLE_ENTRY*)CONTAINING_RECORD(current, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
wprintf(L"%p %p ", module, module->DllBase);
wprintf(L"'%wZ' ", &module->FullDllName);
wprintf(L"'%wZ' ", &module->BaseDllName);
wprintf(L"\n");
current = current->Flink;
}
Я не уверен, что это правильно; по непонятным мне причинам. Когда я запустил подобный цикл для своего собственного 64-битного процесса, я получил адрес загрузки для kernel32.dll; но передача этого GetProcAddress не сработала.
@Joshua, для меня запуск этого тестового кода приводит к ожидаемому результату в приложении x64 + Win10 (foundkernel32 назначается во время цикла сопоставления wcscmp): HMODULE kernel32 = GetModuleHandleA("kernel32"); printf("%p\n", foundkernel32); printf("%p\n", kernel32); printf("%p\n", GetProcAddress(foundkernel32, "FindFirstFileW")); printf("%p\n", GetProcAddress(kernel32, "FindFirstFileW"));
Не знаю, что тебе сказать. Наконец-то я решил свою проблему, найдя GetModuleHandle, используя адрес загрузки, и вызвав его.
(current != NULL)
не нужно, и литой (LDR_DATA_TABLE_ENTRY*)CONTAINING_RECORD
тоже не нужен. что нужно (будь хорошим) пользуйся LdrLockLoaderLock / LdrUnlockLoaderLock
Вы круты, так что моя проблема связана с задержкой на каждой итерации в LDR_DATA_TABLE_ENTRY? Я думал, что если у меня будет отставание, я не смогу получить DllName в своем первом коде, но я могу
Что касается «возможно, PVOID нуждается в большей конверсии для того, чтобы быть HMODULE»,
HMODULE
определяется какHINSTANCE
, который определяется какPVOID
. Так что нет. (PVOID
определяется какvoid *
.) Источник