Добрый день.
У меня проблема не удаётся установить хук на функцию CreateFile A(W).
Метод который я использую — подменить адрес в таблице импорта. Видел много где про него написано в интернете, включая сами исходники.
Я пытаюсь заменить эту CreateFile на MyCreateFile у процесса notepad.exe (или другого не суть).
Программа находит несколько записей в таблице импорта о вызове CreateFile и заменяет на адресс MyCreateFile, но почему то на 7-ой записи вылетает в момент замены адресса. Функция:
//Сменим адрес на свой
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), NULL);
в частности она вылетает при попытки записать по адрессу 328AB350 , где находиться значение 7c801a28 и заменить его надо на a1c098
хотя я проверял результат VirtualProtect выполняется нормально и ошибок там не происходит.
Проблема именно с заменой функции CreateFile.
Функции LoadLibraryA(W), LoadLibraryExA(W), GetFileSize, ExitProcess заменились на мои функции нормально, а вот CreateFile не хочет
У меня вопросы:
1. кто то сталкивался с подобной проблемой ? или может у него есть работующий код для подмены CreateFile ?
2. Это нормально что в таблице импорта данные о вызове CreateFile встречаются 7 раз и более ? для других функций данные встречаются тоже более 1-го раза, но там они успешно переписывались и работали как надо.
Вот функция которая это делает (взята с инета):
BOOL CHookedFunction::ReplaceInOneModule(
PCSTR pszCalleeModName,
PROC pfnCurrent,
PROC pfnNew,
HMODULE hmodCaller
)
{
BOOL bResult = FALSE;
__try
{
ULONG ulSize;
// Get the address of the module's import section
PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
hmodCaller,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&ulSize
);
// Does this module has import section ?
if (pImportDesc == NULL)
//__leave;
return bResult;
// Loop through all descriptors and
// find the import descriptor containing references to callee's functions
while (pImportDesc->Name)
{
PSTR pszModName = (PSTR)((PBYTE) hmodCaller + pImportDesc->Name);
if (stricmp(pszModName, pszCalleeModName) == 0)
break; // Found
pImportDesc++;
} // while
// Does this module import any functions from this callee ?
if (pImportDesc->Name == 0)
//__leave;
return bResult;
// Get caller's IAT
PIMAGE_THUNK_DATA pThunk =
(PIMAGE_THUNK_DATA)( (PBYTE) hmodCaller + pImportDesc->FirstThunk );
// Replace current function address with new one
while (pThunk->u1.Function)
{
// Get the address of the function address
PROC* ppfn = (PROC*) &pThunk->u1.Function;
// Is this the function we're looking for?
BOOL bFound = (*ppfn == pfnCurrent);
// Is this Windows 9x
if (!bFound && (*ppfn > sm_pvMaxAppAddr))
{
PBYTE pbInFunc = (PBYTE) *ppfn;
// Is this a wrapper (debug thunk) represented by PUSH instruction?
if (pbInFunc[0] == cPushOpCode)
{
ppfn = (PROC*) &pbInFunc[1];
// Is this the function we're looking for?
bFound = (*ppfn == pfnCurrent);
} // if
} // if
if (bFound)
{
BOOL vr;
//Нашли!!!
DWORD dwDummy;
//Разрешим запись в эту страницу
VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy);
//Сменим адрес на свой
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,
sizeof(pfnNew), NULL);
//Восстановим атрибуты
VirtualProtect(ppfn, sizeof(ppfn), dwDummy , &dwDummy);
//Готово!!!
bResult = TRUE;
} // if
pThunk++;
} // while
}
__finally
{
// do nothing
}
// This function is not in the caller's import section
return bResult;
}
Вот
запостилАвтор: x64
Дата: 22.11.08
из своих старых-престарых запасов исходник — перехват в IAT по имени. Посмотри, может поможет. Кстати, на RSDN есть статьи по этому поводу — там правда не без косяков, но вполне понятно.
Спасибо за пример, я его посмотрел.
Но как я понимаю он найдёт только одно вхождение функции в таблицу импорта и заменит его ?
так какпосле замены там стоит goto FINISHED;
В связи с чем у меня возникает вопрос нормально ли то что адресс функции в таблице импорта может встречаться несколько раз ?
к примеру у меня находиться адресс функции CreateFileA (да и остальных функций) несколько раз (5-9) в таблице импорта. Причём по разным адрессам само собой.
К примеру адресс функции CreateFileA (7c801a28), с которой у меня и возникает проблема, встречается по адресам (программка notepad.exe (WinXP) ):
77DD10F8
77C111A4
77F61198
6F88108C
77121230
200887CC
76C9108C
328AB350 — при записи сюда программка вылетает, хотя я устанавливаю PAGE_READWRITE (успешно), а было PAGE_READONLY.
Другие функции заменяются успешно и среди них тоже есть такие маленькие адреса как последний и даже меньши, например 010010C8 (для LoadLibraryW)
может можно заменять только один адресс ? или же не менять просто последний (хардкодно)
Здравствуйте, reg_edit, Вы писали:
...
Мне как-то нужно было подменить функцию в своем собственном приложении. Делал это так:
#define MakePtr(cast, base, offset) (cast)((DWORD_PTR)(base) + (DWORD_PTR)(offset))
HRESULT WriteProtectedMemory(LPVOID lpvDest, LPVOID lpvSrc, DWORD dwSize) {
DWORD dwOldProtect = 0;
__try {
if( VirtualProtect(lpvDest, dwSize, PAGE_READWRITE, &dwOldProtect) ) {
InterlockedExchange((LONG*)lpvDest, (LONG)lpvSrc);
VirtualProtect(lpvDest, dwSize, dwOldProtect, &dwOldProtect);
return S_OK;
} // if( VirtualProtect(pDest, dwSize, PAGE_READWRITE, &dwOldProtect) )
}
__except( EXCEPTION_EXECUTE_HANDLER ) {
}
return HRESULT_FROM_WIN32(GetLastError());
}
BOOL HookImportsOfImage(HMODULE hModule, PCHAR pchDllTarget, PCHAR pchFuncTarget, LPVOID lpvMineFunc) {
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNTHeaders;
PIMAGE_IMPORT_DESCRIPTOR pImpDesc;
PIMAGE_IMPORT_BY_NAME pImageImpByName;
DWORD dwImportsStartRVA;
PDWORD pdwIAT, pdwINTO;
int iCount, iIndex;
PCHAR pchDllName = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)hModule;
pNTHeaders = MakePtr(PIMAGE_NT_HEADERS, hModule, pDosHeader->e_lfanew);
if( pNTHeaders->Signature != IMAGE_NT_SIGNATURE || pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
return FALSE;
dwImportsStartRVA = pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if( !dwImportsStartRVA )
return FALSE;
pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(dwImportsStartRVA+(DWORD)pDosHeader);
for( iCount = 0; pImpDesc[iCount].Characteristics != 0; iCount++ ) {
pchDllName = (PCHAR)(pImpDesc[iCount].Name + (DWORD)pDosHeader);
pdwIAT = (PDWORD)(((DWORD)pDosHeader) + (DWORD)pImpDesc[iCount].FirstThunk);
pdwINTO = (PDWORD)(((DWORD)pDosHeader) + (DWORD)pImpDesc[iCount].OriginalFirstThunk);
for( iIndex = 0; pdwIAT[iIndex] != 0; iIndex++ ) {
if( (pdwIAT[iIndex] & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG ) {
pImageImpByName = (PIMAGE_IMPORT_BY_NAME)(pdwINTO[iIndex] + ((DWORD)pDosHeader));
if( (stricmp(pchDllName, pchDllTarget) == 0 ) && (strcmp((PCHAR)(pImageImpByName->Name), pchFuncTarget) == 0) ) {
WriteProtectedMemory((LPVOID)&pdwIAT[iIndex], (LPVOID)lpvMineFunc, sizeof(LPVOID));
} // if( (_stricmp(pchDllName, pchDllTarget) == 0 ) && (strcmp(pImageImpByName->Name, pchFuncTarget) == 0) )
} // if( (pdwIAT[iIndex] & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG )
} // for( iIndex = 0; pdwIAT[iIndex] != 0; iIndex++ )
} // for( iCount = 0; pImpDesc[iCount].Characteristics != 0; iCount++ )
return TRUE;
}
В Вашем случае можно создать длл с данным кодом и потом внедрить ее в нужный процесс.
В
DLL_PROCESS_ATTACH данной длл вызовите
HookImportsOfImage с нужными параметрами.
В вашем случае это может выглядеть так:
...
CREATEPROCESSA g_RealCreateProcessA;
CREATEPROCESSW g_RealCreateProcessW;
...
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
if (dwReason == DLL_PROCESS_ATTACH) {
g_RealCreateProcessA = (CREATEPROCESSA)GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateProcessA");
g_RealCreateProcessW = (CREATEPROCESSW)GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateProcessW");
HookImportsOfImage(GetModuleHandle(NULL), "kernel32.dll", "CreateProcessA", (LPVOID)Mine_CreateProcessA);
HookImportsOfImage(GetModuleHandle(NULL), "kernel32.dll", "CreateProcessW", (LPVOID)Mine_CreateProcessW);
}
else if (dwReason == DLL_PROCESS_DETACH) {
HookImportsOfImage(GetModuleHandle(NULL), "kernel32.dll", "CreateProcessA", (LPVOID)g_RealCreateProcessA);
HookImportsOfImage(GetModuleHandle(NULL), "kernel32.dll", "CreateProcessW", (LPVOID)g_RealCreateProcessW);
}
return TRUE;
}
Т.е. во внедряемой длл предварительно при
DLL_PROCESS_ATTACH сохраняете реальные указатели на перехватываемые функции, а потом подменяете их.
В момент выгрузки Вашей длл из целевого процесса необходимо вернуть все на прежние места, что и происходит при
DLL_PROCESS_DETACH.