Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Перехват API функций. Пример работает неправильно. 
:(
    Опции темы
Игорь1024
Дата 31.10.2010, 10:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 151
Регистрация: 11.5.2009
Где: Дальний Восток

Репутация: нет
Всего: нет



Разбирал пример с  rsdn.ru/article/baseserv/IntercetionAPI.xml.
Разобрал исходники, представленные там, не мудрствовая лукаво скопипастил. Всё компилируется и билдится, но при попытке внедрения в любом приложении возникает исключение.
Код, я думаю, приводить не надо, т.к его и по ссылке можно глянуть.

--------------------
The God is real,unless he is declared as integer.
PM MAIL   Вверх
BorisVorontsov
Дата 31.10.2010, 15:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Thinker
**


Профиль
Группа: Комодератор
Сообщений: 714
Регистрация: 3.11.2005
Где: Молдавия, г. Киши нёв

Репутация: 4
Всего: 10



Для отлова места исключения используется отладчик. Если найдешь место, и не поймешь при этом, в чем причина исключения, тогда возвращайся в тему с кодом, приводящим к исключению



--------------------
[code=cpp]
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;
[/code]
PM MAIL ICQ GTalk   Вверх
Игорь1024
Дата 31.10.2010, 17:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 151
Регистрация: 11.5.2009
Где: Дальний Восток

Репутация: нет
Всего: нет



Мда, ничего у меня с отладчиком не получилось, понял только что к памяти как-то неправильно обращается.
Вот код.

DLL'ка:
Код

#include "stdafx.h"
#include "windows.h"
struct jmp_far
{
  BYTE instr_push;  //здесь будет код инструкции push
  DWORD arg;         //аргумент push
  BYTE  instr_ret;    //здесь будет код инструкции ret
};
BYTE old[6]; //область для хранения 6-ти затираемых байт начала функции
DWORD adr_MessageBoxA; //будущий адрес оригинальной функции
DWORD written; //вспомогательная переменная
jmp_far jump; //здесь будет машинный код инструкции перехода

//данное определение аналогично __srtdcall
BOOL WINAPI Intercept_MessageBoxA(HWND hwnd, char *text, char *hdr, UINT utype)
{
  //Сначала восстанавливаем 6 первых байт функции. Это не обязательное 
  // действие, просто мы решили подшутить над пользователем, и все 
  // сообщения функции MessageBoxA переделать на свои, поэтому нам придется
  // вызвать оригинальную функцию, а для этого следует восстановить ее адрес:
  WriteProcessMemory(GetCurrentProcess(), (void*)adr_MessageBoxA, 
                     (void*)&old, 6, &written);

  //Здесь вы можете порезвиться от души и выполнить любые, пришедшие вам 
  // в голову действия. Мы просто заменили сообщение функции на свое:
  char *str = "Hi From MessageBOX!!!!";

  //Вызываем оригинальную функцию через указатель
  ((BOOL (__stdcall*)(HWND, char*, char*, UINT))adr_MessageBoxA)(hwnd, 
             str, hdr, utype);

  //Снова заменяем  6 байт функции на команду перехода на нашу функцию
  WriteProcessMemory(GetCurrentProcess(), (void*)adr_MessageBoxA, 
                     (void*)&jump, 6,&written);
  return TRUE;
}
void InterceptFunctions(void)
{
  DWORD op;
  //сначала получим абсолютный адрес функции для перехвата
  adr_MessageBoxA = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"),
                    "MessageBoxA");
  if(adr_MessageBoxA == 0)
  {
    MessageBox(NULL, "Can`t get adr_MessageBoxA", "Error!", 0);
    return;
  }

  // Зададим машинный код инструкции перехода, который затем впишем 
  // в начало полученного адреса:
  jump.instr_push = 0x68;//Вот здесь я не понял.
  jump.arg = (DWORD)&Intercept_MessageBoxA;
  jump.instr_ret = 0xC3;//И здесь.

  //Прочитаем и сохраним первые оригинальные 6 байт стандартной API функции
  ReadProcessMemory(GetCurrentProcess(),(void*) adr_MessageBoxA, 
                    (void*)&old, 6, &written);

//Запишем команду перехода на нашу функцию поверх этих 6-ти байт
WriteProcessMemory(GetCurrentProcess(), (void*)adr_MessageBoxA, 
     (void*)&jump, sizeof(jmp_far), &written);
}
BOOL APIENTRY DllMain( HANDLE hModule,  DWORD  ul_reason_for_call,
                       LPVOID lpReserved )
{
// Если система подключает DLL к какому-либо процессу, 
// она сначала вызовет главную функцию DLL с параметром 
// DLL_PROCESS_ATTACH, на что мы сразу вызовем нашу функцию 
// InterceptFunctions, которая произведет подмену стандартной API функции
// MessageBoxA нашей функцией Intercept_MessageBoxA (см. ниже)

  if(ul_reason_for_call == DLL_PROCESS_ATTACH )
  {
    InterceptFunctions();
  }
  return TRUE;
}


Вот внедрение:

Код

#include "windows.h"
#include <stdio.h>
#include "conio.h"
#include <stddef.h>
#include <iostream>
using namespace std;
//структура описывает поля, в которых содержится код внедрения
struct INJECTORCODE
{
  BYTE  instr_push_loadlibrary_arg; //инструкция push
  DWORD loadlibrary_arg;            //аргумент push  

  WORD  instr_call_loadlibrary;     //инструкция call []  
  DWORD adr_from_call_loadlibrary;

  BYTE  instr_push_exitthread_arg;
  DWORD exitthread_arg;

  WORD  instr_call_exitthread;
  DWORD adr_from_call_exitthread;

  DWORD addr_loadlibrary;
  DWORD addr_exitthread;     //адрес функции ExitTHread
  BYTE  libraryname[100];    //имя и путь к загружаемой библиотеке  
};

BOOL InjectDll(DWORD pid, char *lpszDllName)
{
  HANDLE hProcess;
  BYTE *p_code;
  INJECTORCODE cmds;
  DWORD wr, id;

  //открыть процесс с нужным доступом
  hProcess=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|
  PROCESS_VM_OPERATION, FALSE, pid);
  if(hProcess == NULL)
  {
    MessageBoxA(NULL, "You have not enough rights to attach dlls", 
               "Error!", 0);
    return FALSE;
  }
  
  //зарезервировать память в процессе
    p_code = (BYTE*)VirtualAllocEx(hProcess, 0, sizeof(INJECTORCODE),
                                   MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if(p_code==NULL)
    {
      MessageBox(NULL, "Unable to alloc memory in remote process",
                       "Error!", 0);
      return FALSE;
    }

  //инициализировать  машинный код
  cmds.instr_push_loadlibrary_arg = 0x68; //машинный код инструкции push
  cmds.loadlibrary_arg = (DWORD)((BYTE*)p_code 
           + offsetof(INJECTORCODE, libraryname));
  
  cmds.instr_call_loadlibrary = 0x15ff; //машинный код инструкции call
  cmds.adr_from_call_loadlibrary = 
  (DWORD)(p_code + offsetof(INJECTORCODE, addr_loadlibrary));
  
  cmds.instr_push_exitthread_arg  = 0x68;
  cmds.exitthread_arg = 0;
  
  cmds.instr_call_exitthread = 0x15ff; 
  cmds.adr_from_call_exitthread = 
  (DWORD)(p_code + offsetof(INJECTORCODE, addr_exitthread));
  
  cmds.addr_loadlibrary = 
  (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
  
  cmds.addr_exitthread  = 
  (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"ExitThread");
  
  if(strlen(lpszDllName)>99)
  {
     MessageBox(NULL, "Dll Name too long", "Error!", 0);
     return FALSE;
  }
  strcpy((char*)cmds.libraryname, lpszDllName );
  
  /*После инициализации cmds в мнемонике ассемблера выглядит следующим
    образом:
      push  adr_library_name               ;аргумент ф-ции loadlibrary
      call dword ptr [loadlibrary_adr]     ; вызвать LoadLibrary 
      push exit_thread_arg                 ;аргумент для ExitThread
      call dword ptr [exit_thread_adr]     ;вызвать ExitThread     
  */
  
  //записать машинный код по зарезервированному адресу
  WriteProcessMemory(hProcess, p_code, &cmds, sizeof(cmds), &wr);
  
  //выполнить машинный код
  HANDLE z = CreateRemoteThread(hProcess, NULL, 0, 
               (unsigned long (__stdcall *)(void *))p_code, 0, 0, &id);

  //ожидать завершения удаленного потока
  WaitForSingleObject(z, INFINITE);
  //освободить память
  VirtualFreeEx(hProcess, (void*)p_code, sizeof(cmds), MEM_RELEASE);

  return TRUE;
}
int main(int argc, char* argv[])//пока оставил так, т.к пробовал запускать и 
//через командную строку (понятное дело с другим кодом в main'е) 
{
  
    DWORD PID;
    printf("Parameters: PID\n"); 
    cin>>PID;
  InjectDll(PID,"APIhook.dll");//Так проще
  return 0;
}


P.S Проблема явно в DLL, т.к я её прописывал в AppItitDllls-всё равно лагало

--------------------
The God is real,unless he is declared as integer.
PM MAIL   Вверх
DarthTon
Дата 3.11.2010, 14:44 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 106
Регистрация: 7.2.2009

Репутация: 5
Всего: 6



Код

struct jmp_far
{
  BYTE instr_push;  //здесь будет код инструкции push
  DWORD arg;         //аргумент push
  BYTE  instr_ret;    //здесь будет код инструкции ret
};


замени на 

Код

#pragma pack(1)
struct jmp_far
{
  BYTE instr_push;  //здесь будет код инструкции push
  DWORD arg;         //аргумент push
  BYTE  instr_ret;    //здесь будет код инструкции ret
};
#pragma pack()


Это выравняет все поля структуры по 1 байту, и структура будет занимать корректных 6 байт в памяти вместо 12-ми.


Это сообщение отредактировал(а) DarthTon - 3.11.2010, 14:44
PM MAIL   Вверх
Addidas
Дата 5.11.2010, 00:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 20.8.2007

Репутация: нет
Всего: нет



Мммм... это вообще называется защита от дурака... в примерах перехвата МС Рема тоже было пару уловок от лупней...
PM MAIL   Вверх
Игорь1024
Дата 6.11.2010, 14:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 151
Регистрация: 11.5.2009
Где: Дальний Восток

Репутация: нет
Всего: нет



не помогло, спасибо за советы ( в том числе и про лупня   smile   );
хма, про защиту от дурака что верно,то верно (просто стало интересно и вот решил попробовать разобрать).
всё равно спасибо.
--------------------
The God is real,unless he is declared as integer.
PM MAIL   Вверх
bass
Дата 6.11.2010, 18:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 315
Регистрация: 5.8.2007

Репутация: 2
Всего: 2



Ребят насколько помню надо разрешить запись , потому что в коде стоит только чтение VirtualProtect((void*)(SENDMessageUser32),20,PAGE_READWRITE, &op)).......

Добавлено через 2 минуты и 21 секунду
Еще поставь компилятор длл в одно байтовое выравнивание....
PM MAIL   Вверх
Игорь1024
Дата 7.11.2010, 09:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 151
Регистрация: 11.5.2009
Где: Дальний Восток

Репутация: нет
Всего: нет



bass, я говорил про первые способы.
по-моему флаг PAGE_READWRITE разрешает запись и чтение. При чём здесь "надо разрешить запись"?
--------------------
The God is real,unless he is declared as integer.
PM MAIL   Вверх
bass
Дата 8.11.2010, 19:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 315
Регистрация: 5.8.2007

Репутация: 2
Всего: 2



Блин пример рабочий ставь компилятор длл в однобайтовое выравнивание........

  jump.instr_push = 0x68;//Вот здесь я не понял.
  jump.arg = (DWORD)&Intercept_MessageBoxA; // если не будет стоять однобайтовое выравнивание адрес здесь будет неверен и вследствии крах приложения.....
  jump.instr_ret = 0xC3;//И здесь.

получаеться 

PUSH 405678// адрес возврата
RET

если это не поможет то ......

перед вот этим поставь.....
//Запишем команду перехода на нашу функцию поверх этих 6-ти байт
WriteProcessMemory(GetCurrentProcess(), (void*)adr_MessageBoxA, 
     (void*)&jump, sizeof(jmp_far), &written);

Вот это VirtualProtect((void*)adr_MessageBoxA,6,PAGE_READWRITE, &op)).. разрешить запись.........

Можеш скинуть скрин ошибки которая выдает программа.....
Хоть пойму что у тебя происходит , где ошибка.....
А вообще отладчик в помощь....

PM MAIL   Вверх
GremlinProg
Дата 8.11.2010, 21:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(bass @  6.11.2010,  20:29 Найти цитируемый пост)
Еще поставь компилятор длл в одно байтовое выравнивание....

Цитата(bass @  8.11.2010,  21:53 Найти цитируемый пост)
Блин пример рабочий ставь компилятор длл в однобайтовое выравнивание........

именно это #pragma pack(1) и делает


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Игорь1024
Дата 9.11.2010, 07:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 151
Регистрация: 11.5.2009
Где: Дальний Восток

Репутация: нет
Всего: нет



ошибка 0xC0000005.
смотрел дамп убитого приложения. Там описание исключения-мол не подходящие права для записи и чтения.
но ведь вообще же это неправильное обращение к памяти. или я неправ?

знаете, я видать ещё "зелёный". Постараюсь позже разобрать этот пример.
Во всяком случае у Рихтера есть несколько примеров перехвата API разными способами.

всем спасибо за участие, но даже с предложенным DarthTon  и bass выравниванием ничено не получается. наверное тему можно закрыть.
--------------------
The God is real,unless he is declared as integer.
PM MAIL   Вверх
bass
Дата 9.11.2010, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 315
Регистрация: 5.8.2007

Репутация: 2
Всего: 2



Если синий экран и такая ошибка то ты убил Winlogon.... Лан не буду интересоваться за чем тебе это надо.....
Потренеруйся на блокноте........ А потом лезь в системный процесс... Я писал прогу она работает в процессе winlogon  но отлаживал я ее на калькуляторе...... Если на билдоре работаешь то могу помоч .....
PM MAIL   Вверх
xvr
Дата 9.11.2010, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Цитата(bass @  8.11.2010,  19:53 Найти цитируемый пост)
Вот это VirtualProtect((void*)adr_MessageBoxA,6,PAGE_READWRITE, &op)).. разрешить запись.........
Разрешит, если Windows даст разрешить  smile Судя по убиенному winlogon'у - не дала  smile 

PM MAIL   Вверх
bass
Дата 9.11.2010, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 315
Регистрация: 5.8.2007

Репутация: 2
Всего: 2



Цитата(xvr @ 9.11.2010,  14:24)
Цитата(bass @  8.11.2010,  19:53 Найти цитируемый пост)
Вот это VirtualProtect((void*)adr_MessageBoxA,6,PAGE_READWRITE, &op)).. разрешить запись.........
Разрешит, если Windows даст разрешить  smile Судя по убиенному winlogon'у - не дала  smile

Если ХР и от админа то даст 100% тестировал......... Правда наткнулся на такую хрень один раз, я пользовался не writeproccesMemory
А на асме комадой mov и черт ее дери первый байт в функции хоть застрелись не меняет. smile  smile  подменил адрес вызова nt.dll на свою функцию...... Ну а потом вызов nt.dll.... заработало  smile  smile ну как всегда все через жжжжжжж........ У мене задача стояла перехватывать во всех gdi процессах ..... Поэтому нужно было аккуратно все сделать..... пользовался асмом из за этого.....
А вообще такие вещи без отладчика не делаються(без представления что в процессе происходит...).
PM MAIL   Вверх
xvr
Дата 9.11.2010, 16:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Цитата(bass @  9.11.2010,  14:54 Найти цитируемый пост)
Если ХР и от админа то даст 100% тестировал
А на Viste и 7 скорее всего не даст (хотя не тестировал  smile )

Добавлено через 26 секунд
И антивирусы будут ругаться (причем хором)

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0980 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.