Tak jak w:
http://4programmers.net/Forum/viewtopic.php?id=108632
//EDIT
Uwaga - Opisane tu zjawiska Mogą Zabić Twój System na Śmierć :-D
Odwiedz Link powyżej.
Zastanów się... i to nie jest żart..
Dlatego chyba tylko sapero podszedł konstruktywnie do tematu.
.... myli się tylko raz :-D
Ewentualnie Proszę Moderatorów o usunięcie Tematu , odpowiedz już uzyskałem
a nie chcę mieć kogoś na sumieniu .
//EDIT
Sposób wydał mi się kuszący ze względu na prostotę
wykonania jednak natrafiłem na pewne problemy.
Przykład 1.
Tworzę katalog na dysku w celu odizolowania 'test.dll'
od ładowania przez wszystkie aplikacje.
W katalogu umieszczam plik 'test.dll' i 'Notepad.exe'.
Kluczowi rejestru:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs
(przy pomocy regedit) nadaję wartość test.dll.
Uruchamiam Notepad.exe.
Biblioteka zostaje załadowana do pamięci procesu Notepad
i pozostaje w niej aż do zakończenia programu Notepad.
Biblioteka zawiera funkcję FunTest wyświetlającą okno
MessageBox jest ona wywoływana podczas ładowania
test.dll i usunięcia test.dll.
Obecność biblioteki sprawdzaiłem 'procdumpem' siedzi
cały czas.Zresztą widać to przy kończeniu Notepad.exe,
z test.dll jest wywołana FunTest wyświetlająca MessageBox.
Problem 1 (mało istotny) :
Okno pojawia się tylko podczas usuwania biblioteki przy
kończeniu programu Notepad.exe.
Nie pojawia się podczas ładowania biblioteki przez program.
FunTest jest wywoływana i inne funkcję mogą w niej działać
poprawinie (np.WriteFile itp ..) natomiast MessageBox
się nie wyświetla.Dlaczego ?
Kod biblioteki test.dll:
//-------------------------- PLIK test.cpp --------------------------------
//----------------- Kompilator Borland C++ 3 --------
//----------------- biblioteka test.dll --------------------------
#include <windows.h>
//-------------------------------------------------------------------------
#ifdef __cplusplus
extern "C"{
#endif
int __declspec(dllexport) FunTest(void);
#ifdef __cplusplus
}
#endif
//---------------------------------------------------------------------------
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
FunTest(); // wywołanie podczas ładowania
// biblioteki 'test.dll'
break ;
case DLL_THREAD_ATTACH:
break ;
case DLL_THREAD_DETACH:
break ;
case DLL_PROCESS_DETACH:
FunTest(); // wywołanie podczas zwolnienia
// biblioteki 'test.dll'
break;
}
return true;
}
//--------------------------------------------------------------------------
int FunTest(void)
{
return MessageBox(NULL,"Test.DLL","Test Biblioteki",MB_OK);
}
=================================================
Przykład 2 :
Hook na MessageBoxW
Analogicznie jak w przykładzie 1 .
Ale tym razem biblioteka ma za zadanie po załadowaniu
a)utworzyć plik tekstowy 'log.txt'
b)odnaleźć punkt wejścia w IAT Notepada do funkcji 'MessageBoxW'
( Notepad z Win XP używa funkcji MessageBoxW )
c)przekierować Wywołanie MessageBoxW na funkcję Hook_MessageBox
z biblioteki 'test.dll'.
d)Funkcja Hook_MessageBox ma wywołać poprawnie MessageBoxW
i zdarzenie to zapisać do pliku 'log.txt'.
Przy ładowaniu biblioteki uruchamiane są w niej funkcja
tworząca plik 'log.txt' i funkcja zakładająca Hook na MessageBoxW.
Do odszukania tablicy IAT używam funkcji z biblioteki imagehlp.dll
o nazwie 'ImageDirectoryEntryToData'
Problem 2 (istotny) :
Wszystko pięknie działa do pewnego momentu .
Okazało się że użycie funkcji 'ImageDirectoryEntryToData' z imagehlp.dll
w funkcji zakładającej hook powoduje usunięcie mojej biblioteki
z procesu Notepad .
Najdziwniejsze jest to że funkcja 'ImageDirectoryEntryToData' wykonuje
się chyba poprawnie , ponieważ zwraca wartość za pomocą której
jest poprawnie lokalizowane przekierowanie na MessageBoxW,zakładany
hook , zapis do 'log.txt' .
Dopiero po dojściu do końca funkcji 'InitHookProc' z test.dll
bez jakich kolwiek oznak
że coś idzie nie tak biblioteka zostaje usunięta ('test.dll') .
Powoduje to przekierowanie wywołania MessageBoxW do funkcji
Hook_MessageBox w bibliotece której już nie ma w pamięci czyli
Notepad się wywala jeśli wywoła MessageBox ( np.monit o zapisaniu
zmienionego pliku).
Po zamknięciu Notepad.exe usuwam 'test.dll' lub ( wpis w rejestrze)
aby załadowanie biblioteki nie zniszczyło pliku 'log.txt',
zostałby nadpisany przy ogladaniu go w Notepad .
Czytam log.txt ----- i tak 3 dni .
Dlaczego biblioteka jest usuwana .
wszystko jest ok jeśli nie użyję funkcji ImageDirectoryEntryToData ,
pozostaje w pamięci .
Jeśli zaistniał by jakiś wyjątek wykonanie funkcji z mojej
biblioteki zostalo by przerwane po użyciu ImageDirectoryEntryToData.
Tak nie jest , funkcja z 'test.dll' śledzona pod Debugerem przechodzi
poprawnie przez wywołanie ImageDirectoryEntryToData dalej zapisuje
do pliku i wykonuje się do ostatniej instrukcji return funkcji InitHookProc .
Niestety nie ma gdzie już powrócić bo biblioteka zostaje wyładowana.
Dopiero tutaj następuje Access Violator.
Kompilator Borland C++ 3 .
Nie ma nagłowka "imagehlp.h" dlatego ładuję imagehlp.dll dynamicznie.
(Nie chce mi się kombinować z implibami)
Ale nie ma to znaczenia bo podobna biblioteka utworzona w Builder 4
z łaczeniem statycznym imagehlp działa podobnie , lub gorzej
,są problemy z ładowaniem przez notepad.I nie mogę się pozbyć
z niej odniesień do VCL , dziadostwo cholerne .
Przypuszczam że to powinno działać tak jak założyłem , pewności jednak
nie mam .
Fakt -> Nie działa .
???
Kod (roboczy :-)) biblioteki test.dll:
//-------------------------- Plik test.cpp ----------------------------------
//-------------------------- Biblioteka test.dll
#include <windows.h>
#include <string.h>
#include <stdlib.h>
//---------------------------------------------------------------------------
#define MESSAGEBOXW // <-- wykomentować jeśli ma być poszukiwana
// MessageBoxA
#ifdef __cplusplus
extern "C"{
#endif
int InitLog(void) ;
int InitHookProc(void);
#ifdef MESSAGEBOXW
int __declspec(dllexport) Hook_MessageBox(HWND hWnd,PCWSTR lpText,
LPCWSTR lpCaption,UINT uType);
#else
int __declspec(dllexport) Hook_MessageBox(HWND hWnd,PCSTR lpText,
LPCSTR lpCaption,UINT uType);
#endif
#ifdef __cplusplus
}
#endif
//---------------------------------------------------------------------------
//-------------------- komunikaty do log.txt
char info[] = "Ladowanie Biblioteki przez: " ;
char info_Hook[] = "\r\nUżyto Funkcji MessageBox ." ;
char info_Mod[] = "\r\nZnaleziono User32.dll" ;
char info_Error_Proc[]= "\r\nNie znaleziono MessageBox" ;
char info_Error_Mod[] = "\r\nNie znaleziono User32.dll" ;
char info_Error_Img[] = "\r\nNie znaleziono imagehlp.dll" ;
char info_Error_ImgProc[] = "\r\nNie znaleziono ImageDirectoryEntryToData" ;
char info_Error_Import[] = "\r\nNie znaleziono sekcji importów" ;
char info_Error_NoProc[] = "\r\nModul nie importuje takiej Funkcji. " ;
char info_Proc[] = "\r\nZnaleziono MessageBox w IAT ." ;
char info_Error_Base[] = "\r\nNie znaleziono test.dll" ;
char info_Return[] = "\r\nKoniec Funkcji InitHookProc(void)\r\n" ;
char AddrProc[25] ;
PCSTR pszModName = "user32.dll" ;
PSTR temp ;
HANDLE hLog ;
DWORD buf ;
HMODULE hModule ;
HMODULE hModule_user32 ;
HMODULE hTest_dll ;
HINSTANCE h_imagehlp ;
char buf_name[MAX_PATH] ;
bool status_log ;
bool status_hook ;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc ;
PIMAGE_THUNK_DATA pThunk ;
ULONG ulSize ;
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
typedef PIMAGE_IMPORT_DESCRIPTOR (*pImageDirectoryEntryToData)(HMODULE h,
DWORD a ,DWORD b,DWORD * c ) ;
pImageDirectoryEntryToData pImpDirToData ;
#ifdef MESSAGEBOXW
typedef int __declspec(dllexport)(*pMsgProc)(HWND hWnd,PCWSTR lpText,
LPCWSTR lpCaption,UINT uType);
#else
typedef int __declspec(dllexport)(*pMsgProc)(HWND hWnd,PCSTR lpText,
LPCSTR lpCaption,UINT uType);
#endif
PROC pOrgProc ;
pMsgProc pNewProc ;
PROC * ppOrgProc ; // adres do adresu funkcji
//---------------------------------------------------------------------------
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
status_log = InitLog();
if(status_log)
{
status_hook = InitHookProc();
}
break ;
case DLL_THREAD_ATTACH:
break ;
case DLL_THREAD_DETACH:
break ;
case DLL_PROCESS_DETACH:
MessageBox(NULL,"Zwolniono bibliotekę.","test.dll",MB_OK);
if(status_log)
{
CloseHandle(hLog);
// FreeLibrary(h_imagehlp);
}
break;
}
return true;
}
//--------------------------------------------------------------------------
// Funkcja otwiera plik do zapisu zdarzeń :
// 1)Załadowanie biblioteki
// 2)Użycie przechwyconej Funkcji
int InitLog(void)
{
hModule = GetModuleHandleA(NULL);
if(hModule)
{
GetModuleFileNameA(hModule,buf_name,255);
hLog = CreateFile("log.txt",GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS
,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE != hLog)
{
WriteFile(hLog,info,strlen(info),&buf,NULL);
WriteFile(hLog,buf_name,strlen(buf_name),&buf,NULL);
return true ;
}
}
return false ;
}
//--------------------------------------------------------------------------
#ifdef MESSAGEBOXW
int Hook_MessageBox(HWND hWnd,PCWSTR lpText,
LPCWSTR lpCaption,UINT uType)
{
int nresult = ((pMsgProc)pOrgProc)(hWnd ,lpText ,lpCaption,uType );
// zapisz użycie MessageBoxW do pliku
WriteFile(hLog,info_Hook,strlen(info_Hook),&buf,NULL);
return nresult ;
}
#else
int Hook_MessageBox(HWND hWnd,PCSTR lpText,
LPCSTR lpCaption,UINT uType)
{
int nresult = ((pMsgProc)pOrgProc)(hWnd ,lpText ,lpCaption,uType );
// zapisz użycie MessageBoxA do pliku
WriteFile(hLog,info_Hook,strlen(info_Hook),&buf,NULL);
return nresult ;
}
#endif
//-------------------------------------------------------------------------
int InitHookProc(void)
{
h_imagehlp = LoadLibraryA("imagehlp.dll");
if(NULL == h_imagehlp)
{
WriteFile(hLog,info_Error_Img,strlen(info_Error_Img),&buf,NULL);
return false;
}
pImpDirToData =(pImageDirectoryEntryToData)GetProcAddress(h_imagehlp,
"ImageDirectoryEntryToData");
if(NULL == pImpDirToData)
{
WriteFile(hLog,info_Error_ImgProc,strlen(info_Error_ImgProc),&buf,NULL);
return false;
}
// Poniżej wywołanie ImageDirectoryEntryToData
// wywołanie powoduje problemy , biblioteka zostaje zwolniona
// PO ZAKONCZENIU InitHookProc(void)
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)pImpDirToData(hModule,true,
IMAGE_DIRECTORY_ENTRY_IMPORT,&ulSize);
if(NULL == pImportDesc)
{
WriteFile(hLog,info_Error_Import,strlen(info_Error_Import),&buf,NULL);
return false;
}
hModule_user32 = GetModuleHandle(pszModName); // user32.dll
if(NULL == hModule_user32 )
{
WriteFile(hLog,info_Error_Mod,strlen(info_Error_Mod),&buf,NULL);
return false ;
}
#ifdef MESSAGEBOXW
pOrgProc =GetProcAddress(hModule_user32,"MessageBoxW");
#else
pOrgProc =GetProcAddress(hModule_user32,"MessageBoxA");
#endif
if(NULL == pOrgProc)
{
WriteFile(hLog,info_Error_Proc,strlen(info_Error_Proc),&buf,NULL);
return false ;
}
// jedziemy po imporcie
for( ; pImportDesc->Name ; pImportDesc++)
{
temp =(PSTR)((PBYTE) hModule + pImportDesc->Name);
if(lstrcmpiA(temp,pszModName) == 0)
break;
}
if(pImportDesc->Name == 0 )
{
WriteFile(hLog,info_Error_NoProc,strlen(info_Error_NoProc),&buf,NULL);
return false ;
}
pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + ((DWORD)(pImportDesc->FirstThunk)));
for( ; pThunk ->u1.Function; pThunk++)
{
ppOrgProc = (PROC*) &pThunk ->u1.Function ;
if(*ppOrgProc == pOrgProc)
{
ultoa((DWORD)*pOrgProc,AddrProc,16); //dla loga
// znaleziono
// zapisz nowy adres procedury w IAT
pNewProc = Hook_MessageBox ;
WriteProcessMemory(GetCurrentProcess(),ppOrgProc ,&pNewProc,
sizeof(pNewProc),NULL);
WriteFile(hLog,info_Proc,strlen(info_Proc),&buf,NULL);
WriteFile(hLog,AddrProc,strlen(AddrProc),&buf,NULL);
WriteFile(hLog,info_Return,strlen(info_Return),&buf,NULL);
return true ;
}
}
WriteFile(hLog,info_Error_NoProc,strlen(info_Error_NoProc),&buf,NULL);
WriteFile(hLog,info_Return,strlen(info_Return),&buf,NULL);
return false ;
}
Uwaga :
Biblioteka była testowana na Notepad.exe (z XP) plik nie posiada
informacji o sekcji importu w IMAGE_SECTION_HEADER ,
a jedynie wpis w IMAGE_DATA_DIRECTORY .
Skoro jednak funkcja 'ImageDirectoryEntryToData' zwraca wartość różną od NULL
to znaczy że potrafi trafić do symboli importowanych.
Testowana na WinRar.exe ( Poszukiwanie MessageBoxA ) i też lipa .
WinRar posiada "normalny" opis sekcji importu i sekcję.
Biblioteka zostaje wyrzucona z pamięci.
Aplikacje testowe napisane w C++ Builder i wołające Funkcję
MessageBoxA i MessageBoxW napisane aby sprawdzić bibliotekę
nie chcą załadować 'imagehlp.dll' poprzez 'test.dll'.
A jeśli dołączę statycznie 'imagehlp.dll' do 'test.dll' to niechcą
w ogóle załadować biblioteki 'test.dll'
Normalnie to jakaś kicha(ku..ca mnie już bierze).
Sposób użycia 'ImageDirectoryEntryToData' i poszukiwanie
importowanych symboli zaczerpnąłem z "Programowanie aplikacji dla Ms Windows"
Jeffrey'a Richtera ....