Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];

Вниз

Перехват функций Dll   Найти похожие ветки 

 
DinoRay   (2005-08-10 22:11) [0]

Есть dll. Нужно перехватывать вызовы функций этой длл всеми приложениями использующими ее.
Я так думаю алгоритм такой.
1. Перехватить createprocess
2. Проверить загружена эта длл
3. Если загружена внедриться в процесс
4. Переписать вызовы функций на себя.

Отсюда вопрос есть где на Делфях пример?
Эксперементировал с MessageBox работает нормально а вот с не виндовой длл не хочет


 
NikotiN ©   (2005-08-10 23:15) [1]

если смог перехватить MessageBox, то перехвати createprocess или loadlibrary.


 
Alexander Panov ©   (2005-08-11 01:08) [2]

Подменить библиотеку своей.


 
Digitman ©   (2005-08-11 08:17) [3]

в частном случае (для приложений, обращающихся в ходе работы к оконному механизму Windows) достаточно установить глоб.хук на создание окна - как только то или иное приложение вызовет CreateWindow[Ex], в АП его процесса система автоматически внедрит образ экз-ра хук-библиотеки.

в общем случае (для любых приложений) под НТ можно воспользоваться механизмом нотификации о старт/стопе процессов, механизм доступен в режиме ядра и м.б. задействован в коде собственного инсталлируемого драйвера режима ядра (пример есть на wasm.ru) - как только драйвер известит приложение-монитор о старте очередного процесса, приложение-монитор внедряет в АП стартовавшего процесса свою "шпионскую" библиотеку

и в том и ином случае внедренная тем или иным образом библиотека в ходе иниц-ции как раз и выполняет перехват нужных элементов IAT и EAT


 
KyberTECH   (2005-08-19 15:56) [4]

Ктото подскажет мне как можно в определённой DLL узнать какая функция выполняется в данный момент.

Ответ прошу на kybertech@mail.ru


 
Digitman ©   (2005-08-19 16:09) [5]


> какая функция выполняется в данный момент


какая вызвана, та и выполняется


 
Игорь Шевченко ©   (2005-08-19 16:12) [6]


> Ответ прошу на kybertech@mail.ru


Это неуважение к отвечающим


 
alpet ©   (2005-08-19 16:39) [7]

Игорь Шевченко ©   (19.08.05 16:12) [6]
Видать спаму ему мало.


 
alpet ©   (2005-08-19 16:48) [8]

Копать нужно в строну SuspendThread, GetThreadContext, ReadProcessMemory + получить список всех функций в DLL.


 
Игорь Шевченко ©   (2005-08-19 16:56) [9]

alpet ©   (19.08.05 16:48) [8]

Зацем ? Не проще взять DLL с диска и проанализировать ?


 
alpet ©   (2005-08-19 17:02) [10]

Игорь Шевченко ©   (19.08.05 16:56) [9]

Как с диска? В текущий момент в DLL Функция может выполнятся любая, и идентифицировать ее можно разве что по EIP. Что значит придется считывать контест, стек (от esp и выше, для его послед. развертки до вызова экспортируемой функции).  Это только по сабжу [4].


 
Defunct ©   (2005-08-20 04:25) [11]

alpet ©   (19.08.05 17:02) [10]

> и идентифицировать ее можно разве что по EIP

как ты себе представляешь такую идентификацию?

проверить какие функции сейчас выполняются можно в том случае, если поставить инкремент счетчика вызовов на входе в функцию и декремент на выходе.

> Что значит придется считывать контест, стек (от esp и выше, для его послед. развертки до вызова экспортируемой функции

и что это даст?
Пример который развеивает подобного рода идеи:

function zzzz;
asm
 sub esp, 3
  ...
  ...      ; <-- в этом месте развертка стека кроме гемороя ничего больше не даст        
  ...
 add esp, 3
end;


 
n0name   (2005-08-20 08:51) [12]

>>Defunct ©   (20.08.05 04:25) [11]
Считать EIP и посмотреть в таблице экспорта к какой функции относиться этот адрес. Но возможно то, что EIP указывает на общую функцию которая вызывается не из одной экспортируемой, а их нескольких.


 
iskatel ©   (2005-08-20 11:04) [13]

Перехват API-функций в Windows NT/2000/XP

Автор: Тихомиров В.А.
Зав.кафедрой математического обеспечения и применения ЭВМ
Комсомольского-на-Амуре государственного технического университета
К.т.н., доцент, практикующий программист
kmopevm@knastu.ru
Что такое «перехват API-функций»

Метод 1. Перехват API непосредственной записью в код системной функции.
Метод 2. Перехват API через таблицу импорта.

Внедрение кода в чужой процесс в Windows NT

Внедрение 1
Внедрение 2

Как отлаживать такие выкрутасы

Отладка кода загрузчика
Отладка функций, выполняющихся при старте DLL
Отладка функций – двойников, получающих управление при вызове перехваченных API функций

Тестирование

Заключение

Системные программисты, работавшие под MS DOS, прекрасно помнят технологию перехвата системных прерываний, позволявшую брать под контроль практически все процессы, проходившие в любимой операционной системе.

С переходом на Windows использование системных ресурсов программистами в большом объеме стало осуществляться через функции API, и у многих «сиспрогов» стал возникать вопрос: «существуют ли в Windows технологии перехватов этих системных функций?» Особый интерес это вызывает применительно к высокозащищенным ОС, выполненным на ядре NT. Данная статья подробнейшим образом, с действующими примерами покажет практическую реализацию такой технологии (предполагается, что читатель знаком с принципами системного программирования в Windows и умеет применять в своей работе Visual C++).

Что такое «перехват API-функций»
Перехват системной функции API заключается в изменении некоторого адреса в памяти процесса или некоторого кода в теле функции таким образом, чтобы при вызове этой самой API-функции управление передавалось не ей, а вашей функции, подменяющей системную. Эта функция, работая вместо системной, выполняет какие-то запланированные вами действия, и затем, в зависимости от вашего желания, либо вызывает оригинальную функцию, либо не вызывает ее вообще. Перехват функций является очень полезным средством в том случае, если вы хотите отследить, изменить или заблокировать некоторые конкретные действия приложения.

Перехват функций чужого процесса удобнее всего осуществлять внедрением собственной DLL с функцией-двойником в адресное пространство того процесса, контроль над функциями API которого вы хотите установить. При написании двойников функций следует особое внимание обратить на соглашения о вызовах функций __cdecl и __stdcall. В __cdecl функциях подразумевается, что параметры кладутся в стек справа налево, и вызывающая функция очищает стек от аргументов. В __stdcall функциях подразумевается, что параметры кладутся в стек справа налево, но стек от аргументов очищает вызываемая функция. Кроме того, следует учитывать, что в Windows API многие функции встречается в 2-х экземплярах: ANSI и UNICODE. Первые обозначаются суффиксом A: например MessageBoxA, вторые – суффиксом W – например MessageBoxW.

Рассмотрим два метода перехвата API функций:

Непосредственная запись в код функции.
Подмена адреса функции в таблице импорта.
Метод 1. Перехват API непосредственной записью в код системной функции.
Прием заключается в том, чтобы в начало перехватываемой функции записать команду jmp ваша_функция_двойник или эквивалентную ей. Затираемые байты желательно где-нибудь сохранить. После вызова исправленной функции приложением управление будет передано вашей функции. Она должна корректно обработать стек, то есть извлечь переданные ей параметры и произвести необходимые вам действия. Затем, если вы собираетесь вызывать оригинальную функцию, необходимо восстановить затертые байты в начале оригинальной функции. Вызвать ее, передав ей все необходимые параметры. После возврата из оригинальной функции, необходимо снова в начало кода функции записать команду перехода на вашу функцию. Вернуть управление вызвавшей программе.

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

Недостаток: в многопоточных приложениях может возникнуть такая ситуация, когда один поток вызвал перехваченную вами функцию, управление было передано функции-двойнику, она восстановила оригинальное начало функции, но в этот момент параллельно выполняющийся поток произвел вызов той же функции. В результате управление будет передано сразу оригинальной функции, минуя вашу :(.

Разберем пример программы (в виде DLL-файла), перехватывающей функцию MessageBoxA методом 1.

Для работы нам потребуются следующие заголовочные файлы:

#include "stdafx.h"
#include "intercpt.h"



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

push xxxxxxxx
ret



где хххххххх – это адрес функции-двойника. В результате структура, которая будет хранить нужный код перехода, выглядит так:

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; //здесь будет машинный код инструкции перехода



Главная функция DLL будет выглядеть следующим образом:

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;
}



Функция, которую мы только что вызвали и которая выполняет основную хитрость, перехват API перезаписью начальных байт стандартной функции, выглядит следующим образом:

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);
}


 
iskatel ©   (2005-08-20 11:08) [14]

Теперь посмотрим, как выглядит сама функция-двойник. Она должна заменить стандартную MessageBoxA, поэтому её тип и состав параметров должны точно соответствовать оригиналу:

//данное определение аналогично __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;
}



Если откомпилировать этот код как DLL, то получим файл, который в дальнейшем (см.ниже) следует внедрить в процесс, в котором мы хотим перехватить API MessageBoxA.

Метод 2. Перехват API через таблицу импорта.
Прием заключается в замене адреса функции в таблице импорта на адрес функции-двойника. Для понимания данного метода потребуется знание формата PE исполняемых файлов Windows. Как известно, большинство приложений вызывает функции из dll через таблицу импорта, представляющую собой после загрузки exe файла в память списки адресов функций, импортируемых из различных Dll. Откомпилированный вызов функции через таблицу импорта выглядит следующим образом:

Call dword ptr[address_of_function]



или что-то наподобие. Здесь address_of_function – адрес в таблице импорта, по которому находится адрес вызываемой функции. (Тем, кто не знаком со структурой PE заголовка EXE файла, рекомендуем заглянуть в Интернет за соответствующей информацией.)

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

найти в таблице импорта элемент IMAGE_IMPORT_DESCRIPTOR, соответствующий той DLL, из которой импортирована функция;
узнать адрес перехватываемой функции при помощи GetProcAddress;
перебирая элементы массива, на который указывает поле FirstThunk, найти адрес перехватываемой функции;
запомнить этот адрес где-нибудь и записать на его место адрес функции-двойника.
Теперь при вызове подмененной функции вначале будет вызываться функция-двойник. После этого она может вызвать (или не вызывать) оригинальную функцию.

Достоинство данного метода в том, что он будет корректно работать в многопоточном приложении, когда несколько потоков одновременно вызывают подмененную функцию. Так же данный метод будет работать в ОС WINDOWS 9.x.

Недостаток – не все функции вызываются через таблицу импорта.

Ниже приведен пример программы, аналогичной приведенной выше, но использующей второй метод перехвата функции:

DWORD adr_MessageBoxA;

BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call,
                     LPVOID lpReserved)
{
 if(ul_reason_for_call == DLL_PROCESS_ATTACH)
   InterceptFunctions();
 return TRUE;
}

// Эта функция ищет в таблице импорта - .idata нужный адрес и меняет на
// адрес процедуры-двойника
void InterceptFunctions(void)
{
 // Начало отображения в памяти процесса
 BYTE *pimage = (BYTE*)GetModuleHandle(NULL);
 BYTE *pidata;
 // Стандартные структуры описания PE заголовка
 IMAGE_DOS_HEADER *idh;
 IMAGE_OPTIONAL_HEADER *ioh;
 IMAGE_SECTION_HEADER *ish;
 IMAGE_IMPORT_DESCRIPTOR *iid;
 DWORD *isd;  //image_thunk_data dword

 // Получаем указатели на стандартные структуры данных PE заголовка
 idh = (IMAGE_DOS_HEADER*)pimage;
 ioh = (IMAGE_OPTIONAL_HEADER*)(pimage + idh->e_lfanew
                                + 4 + sizeof(IMAGE_FILE_HEADER));
 ish = (IMAGE_SECTION_HEADER*)((BYTE*)ioh + sizeof(IMAGE_OPTIONAL_HEADER));
 //если не обнаружен магический код, то у этой программы нет PE заголовка
 if (idh->e_magic != 0x5A4D)
 {
   MessageBox(NULL, "Not exe hdr", "Error!", 0);
   return;
 }

 //ищем секцию .idata
 for(int i=0; i<16; i++)
   if(strcmp((char*)((ish+ i)->Name) , ".idata") == 0) break;
 if(i==16)
 {
   MessageBox(NULL, "Unable to find .idata section", "Error!", 0);
   return;
 }

 // Получаем адрес секции .idata(первого элемента IMAGE_IMPORT_DESCRIPTOR)
 iid = (IMAGE_IMPORT_DESCRIPTOR*)(pimage + (ish +i)->VirtualAddress );
 
 // Получаем абсолютный адрес функции для перехвата
 adr_MessageBoxA = (DWORD)GetProcAddress(
                       GetModuleHandle("user32.dll"), "MessageBoxA");
 if(adr_MessageBoxA == 0)
 {
   MessageBox(NULL, "Can`t get addr_MessageBoxA", "Error!", 0);
   return;
 }

 // В таблице импорта ищем соответствующий элемент для
 // библиотеки user32.dll
 while(iid->Name)  //до тех пор пока поле структуры не содержит 0
 {
   if(strcmp((char*)(pimage + iid->Name), "USER32.dll") ==0 ) break;
   iid++;
 }

 // Ищем в IMAGE_THUNK_DATA нужный адрес
 isd = (DWORD*)(pimage + iid->FirstThunk);
 while(*isd!=adr_MessageBoxA && *isd!=0)  isd++;
 if(*isd == 0)
 {
   MessageBox(NULL, "adr_MessageBoxA not found in .idata", "Error!", 0);
   return;
 }
 
 // Заменяем адрес на свою функцию
 
 DWORD buf =  (DWORD)&Intercept_MessageBoxA;
 DWORD op;
 
 // Обычно страницы в этой области недоступны для записи
 // поэтому принудительно разрешаем запись
 VirtualProtect((void*)(isd),4,PAGE_READWRITE, &op);
 
 // Пишем новый адрес
 WriteProcessMemory(GetCurrentProcess(), (void*)(isd),
                   (void*)&buf,4,&written);
 //восстанавливаем первоначальную защиту области по записи
 VirtualProtect((void*)(isd),4,op, &op);
 //если записать не удалось – увы, все пошло прахом…
 if(written!=4)
 {
   MessageBox(NULL, "Unable rewrite address", "Error!", 0);
   return;
 }
}


 
iskatel ©   (2005-08-20 11:08) [15]

А вот так выглядит подстановочная функция:

BOOL WINAPI Intercept_MessageBoxA(HWND hwnd, char *text,
                                 char *hdr, UINT utype)
{
 //здесь вы выполняете любые свои действия
 char *str = "Hi From MessageBOX!!!!";
 // вызываем оригинальную функцию через указатель
 ((BOOL (__stdcall*)(HWND, char*, char*, UINT))adr_MessageBoxA)(hwnd,
           str, hdr, utype);
 return TRUE;
}



Внедрение кода в чужой процесс в Windows NT
Теперь осталось показать, как вышеописанные DLL можно внедрить в процесс, избранный в качестве жертвы эксперимента. (Нелишне напомнить, что для нашего примера процесс-жертва должен иметь окна со стандартными сообщениями MessageBox ).

Внедрить код – значит, записать некоторую программу в чужой процесс и исполнить ее от имени этого процесса. Таким образом, внедренный код становится частью процесса и получает доступ ко всем ресурсам, которыми обладает процесс. В отличие от DOS, семейство ОС Windows (на ядре NT) – операционные системы с разделяемой памятью, т.е каждое приложение выполняется в своем адресном пространстве, не пересекающемся с другими, и не имеет непосредственного доступа к памяти чужого приложения. Таким образом, внедрение кода является нетривиальной задачей. Существует несколько способов внедрить свой код:

1. «Вручную».

2. При помощи хуков.

Внедрение 1
Рассмотрим наиболее эффективный, на наш взгляд, способ внедрения – первый. Он заключается в записи короткого участка машинного кода в память процесса, который должен присоединить DLL к этому процессу, запустить ее код, после чего Dll сможет выполнять любые действия от имени данного процесса. В принципе можно и не присоединять DLL, а реализовать нужные действия во внедряемом машинном коде, но это будет слишком трудоемкой задачей, поскольку все смещения для данных потеряют смысл, и вы не сможете корректно обратиться к ним, не настроив соответствующим образом смещения (морока :( ).

При присоединении DLL загрузчик автоматически устанавливает все смещения в соответствии с адресом, по которому загружена DLL. Следует также отметить, что для записи кода в процесс и его исполнения необходимо открыть процесс с доступом как минимум:

PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION.

ПРЕДУПРЕЖДЕНИЕ

При реализации данного метода необходимо указать компилятору выравнивать структуры ПОБАЙТОВО. Иначе структура с машинным кодом будет содержать совершенно не тот код, что был запланирован.


Общая схема внедрения:

Открыть процесс (OpenProcess).
Выделить в нем память (VirtualAllocEx – доступно только для WinNT).
Записать внедряемый код в эту память (WriteProcessMemory).
Исполнить его(CreateRemoteThread).
Внедряемый машинный код должен (по нашему сценарию) произвести такие действия:

call LoadLibrary – вызвать функцию LoadLibrary из kernel32.dll для загрузки присоединяемой библиотеки (одной из разбиравшихся выше).
Call ExitThread – вызвать функцию ExitThread из kernel32.dll для корректного завершения данного потока.
В WinNT стартовый адрес отображения системных DLL (user32, kernel32 и т. д.) один и тот же для всех приложений. Это означает, что адрес некоторой функции из системной DLL в одном приложении будет актуален и в другом приложении. То есть точки входа функций системных DLL всегда одни и те же.

Ниже приведен пример процедуры, внедряющей dll с заданным именем в процесс с заданным PID (идентификатором процесса) (их можно наблюдать в закладке «процессы» диспетчера задач или получить с помощью стандартных API-функций).

//структура описывает поля, в которых содержится код внедрения
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;

 //открыть процесс с нужным доступом
 hProess=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;
   }


 
iskatel ©   (2005-08-20 11:08) [16]

//инициализировать  машинный код
 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;
}


 
iskatel ©   (2005-08-20 11:09) [17]

Внедрение 2
Второй способ внедрения исполняемого кода (через хуки) наиболее прост в использовании. Он основан на технологии хуков, а именно: если установить хук на поток чужого процесса, то, как только поток получит сообщение, соответствующее заданному типу хука, система автоматически подключит DLL c хуком к данному процессу. Недостатком данного способа в том, что нельзя внедрить DLL в процесс, не имеющий очереди сообщений. Данная DLL будет присоединена к чужому процессу лишь до тех пор, пока запущена программа, установившая хук. Как только вы завершите эту программу, dll автоматически будет отключена. Первый способ лишен таких недостатков.

С другой стороны, первый способ будет работать лишь в WinNT, по причине использования функции VirtualAllocEx, которая резервирует память в заданном (отличном от того, в котором происходит вызов этой функции) процессе. Теоретически, данную проблему можно обойти, если писать код в некоторую часть отображения exe-файла чужого процесса, например в заголовок DOS, который после загрузки не используется. Но ОС не всегда позволяет писать в эту область памяти, даже если попытаться изменить разрешения при помощи VirtualProtextEx.

Есть еще и третий способ внедрения, но он наиболее опасен, так как может привести к краху системы. При помощи данного метода ОС сама внедряет указанную dll во все без исключения процессы операционной системы, даже защищенные. Для реализации необходимо прописать в реестре по пути Hkey_local_machine\software\microsoft\windowsnt\currentversion\windows в ключе AppInit_DLLs полный путь к своей dll.


 
iskatel ©   (2005-08-20 11:10) [18]

извини, что на сях, но это не мой пример, там в начале указан автор))
я пробовал - все работает ))
удачи!


 
alpet ©   (2005-08-20 12:15) [19]

Defunct ©   (20.08.05 04:25) [11]

EIP и ESP. Если некоторая функция из импортированного списка вызывается, и выполнение внутрии ее зацикливается - определить можно по EIP, если она вызывает какую-либо функцию, можно поискать в стеке адрес возврата в нее. Способ работать не будет - если функция передает управление с помощью jmp за свои пределы.


 
KyberTECH   (2005-08-26 03:39) [20]

Спасибо всем ! Кто хоть что-то написал !
А то, что кто-то там заикнулся за НЕУВАЖЕНИЕ, тебе тоже спасибо ! Буду знать ! Просто я не так часто задаю вопросы, восновном пытаюсь сам разбираться !

Вобщем всем спасибо !

Ребята, кто-то из вас работал с CashFiesta ???



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2005.10.30;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.109 c
3-1127198715
pasha_golub
2005-09-20 10:45
2005.10.30
TDatasetProvider s stuff


8-1117651080
dan
2005-06-01 22:38
2005.10.30
Прокрутка в DSPack


14-1128501536
DelphiN!
2005-10-05 12:38
2005.10.30
Сколько часов в день вы уделяете непосредственно программированию


4-1125305689
ANB
2005-08-29 12:54
2005.10.30
Как переключить раскладку в чужом процессе ?


8-1118066972
TORT
2005-06-06 18:09
2005.10.30
ГРУГЛАЯ ФОРМА





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский