CreateFile Hook
От: reg_edit  
Дата: 21.11.08 14:05
Оценка:
Добрый день.

У меня проблема не удаётся установить хук на функцию 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;
}
createfile hook
Re: CreateFile Hook
От: x64 Россия  
Дата: 22.11.08 12:40
Оценка:
_>в частности она вылетает при попытки записать по адрессу 328AB350 , где находиться значение 7c801a28 и заменить его надо на a1c098

Хм, что-то адрес какой-то странный, imho. Проверь адреса ещё раз.
Re[2]: CreateFile Hook
От: x64 Россия  
Дата: 22.11.08 13:17
Оценка:
Вот запостил
Автор: x64
Дата: 22.11.08
из своих старых-престарых запасов исходник — перехват в IAT по имени. Посмотри, может поможет. Кстати, на RSDN есть статьи по этому поводу — там правда не без косяков, но вполне понятно.
Re[3]: CreateFile Hook
От: reg_edit  
Дата: 22.11.08 14:11
Оценка:
Спасибо за пример, я его посмотрел.
Но как я понимаю он найдёт только одно вхождение функции в таблицу импорта и заменит его ?
так какпосле замены там стоит goto FINISHED;

В связи с чем у меня возникает вопрос нормально ли то что адресс функции в таблице импорта может встречаться несколько раз ?
к примеру у меня находиться адресс функции CreateFileA (да и остальных функций) несколько раз (5-9) в таблице импорта. Причём по разным адрессам само собой.
К примеру адресс функции CreateFileA (7c801a28), с которой у меня и возникает проблема, встречается по адресам (программка notepad.exe (WinXP) ):
77DD10F8
77C111A4
77F61198
6F88108C
77121230
200887CC
76C9108C
328AB350 — при записи сюда программка вылетает, хотя я устанавливаю PAGE_READWRITE (успешно), а было PAGE_READONLY.

Другие функции заменяются успешно и среди них тоже есть такие маленькие адреса как последний и даже меньши, например 010010C8 (для LoadLibraryW)

может можно заменять только один адресс ? или же не менять просто последний (хардкодно)
Re[4]: CreateFile Hook
От: x64 Россия  
Дата: 22.11.08 14:20
Оценка:
_>В связи с чем у меня возникает вопрос нормально ли то что адресс функции в таблице импорта может встречаться несколько раз ?

Нормально, т.к. строго говоря, одна и та же функция может экспортироваться под разными именами. Я правда, очень сомневаюсь, что такая ситуация имеет место быть в kernel32.dll. Попробуй мой код — только не забудь туда VirtualProtect() вставить где нужно.

_>к примеру у меня находиться адресс функции CreateFileA (да и остальных функций) несколько раз (5-9) в таблице импорта. Причём по разным адрессам само собой.

_>328AB350 — при записи сюда программка вылетает, хотя я устанавливаю PAGE_READWRITE (успешно), а было PAGE_READONLY.
_>может можно заменять только один адресс ? или же не менять просто последний (хардкодно)

Тут ничего не могу сказать, давно это было и сейчас я предпочитаю сплайсинг. Посмотри статьи по перехвату на RSDN в разделе "Базовые сервисы / Перехват вызовов API" — их там несколько штук и некоторые весьма интересные.
Re: CreateFile Hook
От: -prus-  
Дата: 22.11.08 20:21
Оценка:
Здравствуйте, 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.
С уважением,
Евгений
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.