Стандартная процедура инициализации: найти GetProcAddress, в цикле найти указатели на все необходимые функции. Под ХР работает на ура, а вот под 98 и МЕ - облом. Некоторые функции их кернела находяться неправильно. Например, вместо GlobalAlloc получаю LocalAlloc, и это еще не самая страшная ошибка, большинство остальных фукнций вообще "не в тему"... Помогите!!!
psu Может быть ты сравниваешь адреса, полученные под дебагером с реальными адресами экспортов кернела?
зачем? стандартный пример, взят из этого же сайта масив имен функций, масив двордовских переменных им соответствующих цикл вызовов GetProcAddress Проганял через Олли, на вход GetProcAddress приходит "правильный" параметр, на выходе - туфта , при чем, повторяю, далеко не для всех функций!
psu Бес кода, нет подсказки! Как можно судить где у тебя не верно, если мы не видим места в коде, где у тебя ошибка?
kernel32_imp: db "GetModuleHandleA", 0 db "LoadLibraryExA", 0 db "CreateFileW", 0 ................. kernel32_imp_addr label DWORD _GetModuleHandleA dd ? _LoadLibraryExA dd ? _CreateFileW dd ? ................. GetAPIs proc dwNumber, dwSource, dwTarget, dwKernelBase, dwGetProcAddress : DWORD pushad mov ecx, dwGetProcAddress mov esi, dwKernelBase mov ebx, dwTarget mov edi, dwSource mov eax, ecx mov ecx, dwNumber NextFunc: push eax push esi push edi push ebx push ecx push edi ;имя функции push esi ;база kernel32 call eax ;вызов GetProcAddress pop ecx pop ebx pop edi pop esi .IF eax == 0 pop eax mov eax, -1 ;error popad ret .ENDIF mov dword ptr [ ebx ], eax ;помещаем адрес функции в переменную pop eax add ebx, 4 ;следующая переменная push ecx ;сохраняем счетчик MOV_REG ecx, 30 ;для цепочечной команды push eax mov al, 0 ;ищем 0 repne scasb pop eax pop ecx loop NextFunc popad xor eax, eax ;OK ret GetAPIs endp ------------------------------------- Вызов функции: ........... push [ ebp + offset _GetProcAddress ] push [ ebp + offset dwKernel32Base ] lea eax, [ ebp + kernel32_imp_addr ] push eax lea eax, [ ebp + kernel32_imp ] push eax push KERNEL32_FUNCTIONS_COUNT lea eax, [ ebp + GetAPIs ] call eax .......... Код никак не оптимизирован, так что не пинайте... ПОВТОРЯЮ. На входе GetProcAddress правильная строка, на выходе - лажа
psu В Win9x это не туфта, а ф-ции-заглушки, препятствующие трассировке дебагером расшаренного системного кода. Посмотри получаемые адреса, когда твоя прога работает не под отладчиком. (OutputDebugString/DebugView или в файл пиши).
СreateFileW -> GetNamedPipeHandleStateW CloseHandle -> FindCloseChangeNotification FindFirstFileW -> HearSetFlags FindNextFileW -> lstrcmpiW GetTempPathW -> lstrcmpiW DeleteFileW -> TryEnterCriticalSection CopyFileW -> lstrcpynW GetModuleFileNameW -> lstrcpynW SetFileAttributesW -> lstrcmpiW Process32FirstW -> 0 думал, проблема в юникоде, так ведь CloseHandle тоже лажа...
проверил на w98 -- все ок, кроме Process32FirstW (её вроде нет, есть Process32First без A/W). если интересно, прожка в аттаче.
Или из за юникода или из-за рук, что скорее всего! ты точно уверен что полученные адреса соответствуют этим функциям?
хмм.. вот что выяснилось: все лажовые функции имеют одинаковый адрес экпорта. Например, CloseHandle и FindCloseChangeNotification = 8C8B ( win98 ). Что делать? Как найти такую функцию по имени? З.Ы. Если прогу, которая слинкована с импортом CloseHandle , например, прогнать в олли под 98-й, то не получается зайти "внутрь" CloseHandle. Как же эта функция реализована ( она что, на уровне драйвера работает )?
psu Тебе же green объяснил - в 9x под отладчиком таблица импорта и GetProcAddress выдают не реальные адреса функций kernel32, а адреса заглушек (ThunkToKernel). Даже тема такая была "IsDebuggerPresent по таблице импорта", но потерялась во время чистки форума. Вот нашел у себя заметки на эту тему: Код (Text): Еще одна хитрость работы под отладчиком уровня приложения под Win9x: можно сравнить адреса одной и той же функции API, полученные через GetProcAddress и по таблице импорта Если посмотреть, что лежит по адресу импортируемой функции (@Func), то увидим: FF 25 xx xx xx XX = JMP dword ptr [$XXxxxxxx] ... [$XXxxxxxx]: yy yy yy YY = $YYyyyyyy т.е.перейти на адрес YYyyyyyy, который лежит по адресу XXxxxxxx таблицы импорта. Так вот, если процесс запущен самостоятельно, то по адресу XXхххххх лежит адрес YYyyyyyy = ZZzzzzzz - реальный адрес функции, возвращаемый GetProcAddress. Причем величина адреса должна быть большой - больше базы модуля kernel32, возвращаемой GetModuleHandleA('kernel32'), - обычно это за пределами $B0.., т.к. ядро отображается в верхние адреса памяти. Другими словами загрузчик ОС подставляет в таблицу импорта реальные адреса вызываемых функций kernel32. Если процесс запущен под отладчиком, то импорт усложняется - создаются промежуточные пересылки - санки (thunk to kernel). Загрузчик подставляет в таблицу не реальный адрес вызываемой функции, а адрес thunk FF 25 xx xx xx XX = JMP dword ptr [$XXxxxxxx] ... [$XXxxxxxx]: yy yy yy YY = адрес thunk ... [$YYyyyyyy]: 68 zz zz zz ZZ = PUSH ZZzzzzzz, где ZZzzzzzz - адрес вызываемой функции E9 rr rr rr RR = JMP +$RRrrrrrr, где $RRrrrrrr относительное смещение 00 00 //какие-то выравнивающие байты, т.к. смещение задается отн.след.команды => +12 Причем: 1) GetProcAddress возвращает не реальный адрес ZZ.., а такой же YY.. с пересылкой; 2) Разным объявлениям функции соответствуют разные адреса пересылок YY.., т.е. если мы наряду с Windows.pas объявим свою аналогичную external функцию, то и адреса XX.. у них будут разные (они всегда разные) и то, что по ним лежит YY.. тоже разное и не равно ZZ.. и не равно адресу AA.., возвращаемому GetProcAddress; 3) результирующий адрес относительного перехода, т.е. YY..+RR..+12 у всех получается одинаковый, но куда он ведет "фиг его знает" - это не важно. ВЫВОДЫ: Для определения наличия отладчика достаточно извлечь адрес YY.. какой-либо безобидной популярной функции Win API (например GetLastError) и сравнить его 1) либо с базой модуля Kernel32 = GetModuleHandle (если <, то отладчик, т.к. обычно все санки отладчиков размещаются по адресам ~$8...), 2) либо с адресом, возвращаемым GetProcAddress (если <>, то отладчик), 3) либо с аналогичным адресом другого объявления той же функции (если <>, то отладчик). ПРИМЕРЫ: =========================================================== БЕЗ ОТЛАДЧИКА: -------------- //1) вызов ф-ии GetFileInformationByHandle, объявленной в Windows.pas FF 25 D0 82 50 00 = JMP dword ptr [$005082D025] ... [$005082D025]: E2 C9 F9 BF = $BFF9C9E2 - настоящий адрес из kernel32.dll //2) дополнительно обяъвленная функция GetFileInformationByHandle FF 25 B8 87 50 00 = = JMP dword ptr [$005087B8] ... [$005087B8]: E2 C9 F9 BF = $BFF9C9E2 - настоящий адрес из kernel32.dll //3) адрес полученный через вызов GetProcAddress = $BFF9C9E2 ===> все совпадает ПОД ОТЛАДЧИКОМ --------------- //1) вызов ф-ии GetFileInformationByHandle, объявленной в Windows.pas FF 25 D0 82 50 00 = JMP dword ptr [$005082D025] //эта строка не изменяется ... [$005082D025]: 98 EE E8 82 = $82E8EE98 //но здесь уже не реальный адрес, а санки //2) дополнительно обяъвленная функция GetFileInformationByHandle FF 25 B8 87 50 00 = JMP dword ptr [$005087B8] //эта строка не изменяется ... [$005087B8]: 48 01 E9 82 = $82E90148 //тоже санки, но другое значение ! ... [$82E90148]: //переходим на санки и видим настоящий адрес 68 E2 C9 F9 BF = PUSH $BFF9C9E2 //вот настоящий адрес !!! E9 78 56 10 3D = JMP +$3D105678 => $82E90148+$3D105678 = $BFF957C0 + 12 = $BFF957CC 00 00 //выравнивающие байты, смещение задается отн.след.команды => +12 //3) адрес полученный через вызов GetProcAddress = $82E90858 => тоже не настоящий и разница с нашим вариантом +$710 [$82E90858]: //смотрим и видим аналогичную пересылку 68 E2 C9 F9 BF = PUSH $BFF9C9E2 //вот настоящий адрес !!! E9 68 4F 10 3D = JMP +$3D104F68 => $82E90858+$3D104F68 = $BFF957C0 + 12 = $BFF957CC 00 00 !!!!!!!!! => JMP на тоже место Зайти в режиме трассировки (исполнения) нельзя, а вот просто посмотреть реализацию можно по GoTo Exspression или Follow