Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.94/18: Рейтинг темы: голосов - 18, средняя оценка - 4.94
0 / 0 / 0
Регистрация: 14.10.2012
Сообщений: 4
1

Перехват API вызовов через таблицу импорта

09.12.2012, 19:03. Показов 3177. Ответов 4
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Доброго времени суток. Есть следующая задача. Нужно перехватить вызов некоторых определённых функций из определённого приложения и заменить их на свои. Пытаюсь провернуть всё это созданием удалённого потока с помощью функции CreateRemoteThread и внедрения в этот поток Dll файла. Функция которая должна подменять адреса в таблице импорта вызывается в теле DllMain. В нашем случае будем подменять вызов функции CreateFileW. Сама функция выполняющая замену называется ReplaceIATEntryInOneMod. Проблема состоит в том, что при срабатывании ReplaceIATEntryInOneMod адрес в таблице импорта подменяется и следующий вызов CreateFileW следующий сразу за ReplaceIATEntryInOneMod успешно отлавливается, однако все вызовы CreateFileW которые находятся в главном потоке приложения продолжают вызывать функцию из первоначальной библиотеки.

Сама DllMain:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    PROC proc = GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "CreateFileW"); 
    PROC proc2 = GetProcAddress(hModule, "MyCreateFileW"); 
    HANDLE h;
    HANDLE hSnapshot;
    THREADENTRY32 entry;
        entry.dwSize = sizeof(THREADENTRY32);
    DWORD dwPID = GetCurrentProcessId();
        DWORD dwCurrentTID = GetCurrentThreadId();
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
        if(Thread32First(hSnapshot, &entry))
            while(Thread32Next(hSnapshot, &entry))
                if(entry.th32OwnerProcessID==dwPID)
                {
                    if(entry.th32ThreadID!=dwCurrentTID)
                    {
                        HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, entry.th32ThreadID);
                        if(hThread)
                        {
                            std::cout << entry.th32ThreadID << std::endl;                   
                            if(SuspendThread(hThread) == -1)
                                std::cout << GetLastError();
                                                        CloseHandle(hThread);
                        }
                    }
                }
        ReplaceIATEntryInOneMod("Kernel32.dll",proc,proc2,hModule);
        CreateFileW(L"c://14.txt",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
        if(Thread32First(hSnapshot, &entry))
            while(Thread32Next(hSnapshot, &entry))
                if(entry.th32OwnerProcessID==dwPID)
                {
                    if(entry.th32ThreadID!=dwCurrentTID)
                    {
                        HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, entry.th32ThreadID);
                        if(hThread)
                        {
                            ResumeThread(hThread);
                            CloseHandle(hThread);
                        }
                    }
                }
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    std::cout << "EXIT " << GetLastError() << std::endl;
    return TRUE;
}
Код самой Dll:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
typedef int (WINAPI *Proc)(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile);
 
HANDLE WINAPI MyCreateFileW(
   LPCWSTR lpFileName,
   DWORD dwDesiredAccess,
   DWORD dwShareMode,
   LPSECURITY_ATTRIBUTES lpSecurityAttributes,
   DWORD dwCreationDisposition,
   DWORD dwFlagsAndAttributes,
   HANDLE hTemplateFile
){
    cout << "MyCreateFileW" << endl;
    
    Proc proc = (Proc)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "CreateFileW");
    cout << proc << " " << GetLastError() << endl;
    HANDLE h = (Proc)proc(lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile);
    if(h != INVALID_HANDLE_VALUE)
        cout << h;
    return h;
}
 
void ReplaceIATEntryInOneMod(PCSTR pszCalleeModName, PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
{ 
    cout << "ReplaceIATEntryInOneMod" << endl;
    ULONG ulSize = 0;
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hmodCaller,TRUE,1,&ulSize); 
    if (pImportDesc == NULL) 
        return; // в этом модуле нет раздела импорта 
    
    // находим дескриптор раздела импорт со ссылками 
    // на функции DLL (вызываемого модуля) 
    for (; pImportDesc->Name; pImportDesc++) 
    { 
        PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name); 
        if (lstrcmpiA(pszModName, pszCalleeModName) == 0) 
            break; 
    } 
    if (pImportDesc->Name == 0)         
        return;  // этот модуль не импортирует никаких функций из данной DLL
 
        // получаем таблицу адресов импорта (IAT) для функций 
        PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) ((PBYTE) hmodCaller + pImportDesc->FirstThunk); 
    
        // заменяем адреса исходных функций адресами своих функций 
        for (; pThunk->u1.Function; pThunk++) 
        {
            // получаем адрес адреса функции 
            PROC* ppfn = (PROC*) &pThunk->u1.Function;
        
            BOOL fFound = (*ppfn == pfnCurrent);
            
            if (fFound) 
            { 
                // адреса сходятся, изменяем адрес в разделе импорта 
                WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), NULL ); 
                cout << "Replace" << endl;
                return; // получилось, выходим 
            } 
        } 
        std::cout << "Error" << std::endl;
        // нет ссылки на нужную функцию 
}
Приложение в которое внедряется Dll:

C++
1
2
3
4
5
6
7
8
9
int _tmain(int argc, _TCHAR* argv[])
{
    getchar();
    HANDLE h = CreateFileW(L"c:\\12.txt",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if(h != INVALID_HANDLE_VALUE)
        std::cout << h;
    getchar();
    return 0;
}
Приложение которое внедряет Dll:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int _tmain(int argc, _TCHAR* argv[])
{
    STARTUPINFOA si = {sizeof(si)};
        PROCESS_INFORMATION pi;     
    CreateProcessA("Приложение в которое внедряется Dll",NULL,NULL,NULL,false,NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi);
    PROCESSENTRY32 entry;
        entry.dwSize = sizeof(PROCESSENTRY32);
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
        if (Process32First(snapshot, &entry) == TRUE)
       {
            while (Process32Next(snapshot, &entry) == TRUE)
            {
                 if (wcsicmp(entry.szExeFile, L"Имя процесса в которое ведется внедрение") == 0)
                {  
                HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
                PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"Kernel32"), "LoadLibraryW"); 
                if(pfnThreadRtn == NULL)
                    cout << "Error: GetProcAddress" << endl;
                wstring str = L"Путь к Dll которая будет внедрятся";
                SIZE_T N;
                LPVOID Virtual = VirtualAllocEx(hProcess,NULL,str.length()*2, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                if(Virtual == NULL)
                    cout << "Error: VirtualAllocEx " << GetLastError() << endl;
                bool f = WriteProcessMemory(hProcess,Virtual,str.c_str(),str.length()*2,&N);
                if(f == false)
                    cout << "Error: WriteProcessMemory " << GetLastError() << endl;
                HANDLE thread = CreateRemoteThread(hProcess,NULL,0,pfnThreadRtn,Virtual,0,NULL);
 
                WaitForSingleObject(thread, INFINITE);
                CloseHandle(hProcess);
            }
        }
    }
    CloseHandle(snapshot);
    Sleep(10000);
    return 0;
}
Прошу помощи!!!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
09.12.2012, 19:03
Ответы с готовыми решениями:

Перехват API вызовов
Здравствуйте! Пытаюсь перехватить вызов функции CreateFileW и заменить на свою MyCreateFileW. Для...

Перехват API функций. Таблица импорта
Необходимо лoггиpoвaть вызовы некоторых API-шных функций (для примера CloseHandle) в заданном...

Перехват API
Сразу код ) DWORD dwProtect = PAGE_READWRITE; BYTE old; BYTE * fPtr; #pragma...

Перехват API функции
Доброго времени суток всем! Уважаемые форумчене помогите решить задачу, я взял функцию MessageBox и...

4
2835 / 1644 / 254
Регистрация: 03.12.2007
Сообщений: 4,222
09.12.2012, 20:33 2
То есть VirtualAllocEx с одним MEM_COMMIT работает? Вообще, как я понимаю, тут надо бы MEM_COMMIT | MEM_RESERVE.
Видимо, адреса импортируемых функций где-то сохраняются... Процесс, в котором надо перехватывать, всегда создаётся твоей прогой или это только для примера?
0
0 / 0 / 0
Регистрация: 14.10.2012
Сообщений: 4
09.12.2012, 20:50  [ТС] 3
Поставил MEM_COMMIT | MEM_RESERVE никаких изменений не произошло.
Создание процесса только для примера, его можно и в ручную запустить.
0
2835 / 1644 / 254
Регистрация: 03.12.2007
Сообщений: 4,222
09.12.2012, 20:59 4
Если самому процесс запускать, можно его запустить с CREATE_SUSPENDED, потом поправить импорт, потом ResumeThread для главного потока. Тогда если адреса импортов сохраняются не в DllMain'е какой-то из dll'ок, всё должно быть нормально.
Если заранее известная прога может запускаться вручную, можно попробовать написать запускалку для неё, которую юзер будет запускать вместо самой проги. Тогда получится то же, что и в предыдущем случае.
В общем случае, если процесс заранее неизвестен, то, думаю, менять таблицу импорта уже может быть бесполезно - тогда надо ставить jmp в начало самой перехватываемой функции.
1
0 / 0 / 0
Регистрация: 14.10.2012
Сообщений: 4
10.12.2012, 02:22  [ТС] 5
Спасибо, буду думать

Добавлено через 51 минуту
Пробовал создавать процесс с флагом CREATE_SUSPENDED и использовать ResumeThread после того как удалённый процесс завершится, но тогда функция GetLastError в теле DllMain возвращает значение 87 : Параметр задан неверно. Из-за чего может возникнуть эта ошибка в данном случае?

Добавлено через 4 часа 25 минут
Решение было найдено. Ошибка была в том что я меня таблицу импорта самой Dll библиотеки, а не процесса в целом. Для исправления этой ошибки нужно передавать в вызове ReplaceIATEntryInOneMod в DllMain четвёртым параметром дескриптор файла, используемого для создания процесса. Получить его можно вызовом GetModuleHandle(NULL).
0
10.12.2012, 02:22
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.12.2012, 02:22
Помогаю со студенческими работами здесь

Перехват API, Рихтер
Всем доброго времени суток! Собственно такой вопросик... я вот читаю сейчас Рихтера и мне интересен...

Перехват API функций
Разработать программу, которая запускает приложение, переданное программе на вход. После запуска...

Перехват API с возвратом значения
Я тут решил разобраться в перехвате API с помощью инжектированной dll. Спустя 2 дня написал...

Перехват API через таблицу импорта
Всем привет. Давно задумал совершить сабжевое действие, но в интернете всегда попадается либо...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru