쉽게 쓴 dll

system/windows 2012. 2. 24. 16:33

  • 기초부터 가자~ DLL 이란 무엇인가
 dll이란 무엇인가. 대부분 .dll파일을 한번씩은 본적이 있을 것이다. 
 이 dll 파일이란 실행파일이 요구되는 변수 함수등을 공유하기 위해 외부적으로 만든 라이브러리 라고 보면 된다.(이해하기를)
 공통 부분의 함수를 공유하기가 용이하기 때문에 자주 사용되는 변수나 함수등의 내용을 dll로 작성하여 개발 시간이 단축될 수 있다. (나는 보통 cpp, h 파일로 작성하여 필요할때마다 파일을 카피 하여 프로젝트에 추가하곤 한다. 하지만 이 방법을 쓸 경우 굳이 파일을 포함시키지 않더라도pragma나 비쥬얼 스튜디오의 프로젝트 속성에 dll 파일을 링크하여 가져다 쓸 수 있다.)


  • DLL, 어떻게 가져다 써?
에잉~  중간에 내용 추가하려니까 더 귀찮네-_-;
깜빡하고 넘어간 것. DLL을 만드는건 그렇다 치고 어떻게 가져다 쓸것인가?

이 부분은 자세하게 풀이된 글이 있어 가져왔다.(많은 도움이 되었다 감동)
http://blog.naver.com/kyehwan2?Redirect=Log&logNo=10005701934
 삽질 해결을 위해 너무너무 많은 도움이 된 글이고 굳이 사견을 덧붙일 필요없이 예제까지 정리가 깔끔히 된 글이라 그대로 가져왔다.

호출하는 방법은 implicit 과 explicit 방법이 있는데
우선 여기선 조금쉬운 방법인 implicit방법을 먼저 하자
위에서 DLL을 만들때 같이 만들어 지는 lib를 이용한다.
 
여기서 lib에 대해 언급하면...
링크될때 링커는 이 lib파일을 표준 라이브러리 처럼 다루어 처리하지만, dll을 끌어오는
lib파일은 dll이 익스포트한 함수 각각에 대한 stub(함수 호출에 쓰이는 정보를 일컬음)만을 포함
 
함수 스텁은 사실 진짜 함수와 동일한 이름과 인수 리스트를 가진 pseudo 함수로서,
내부를 살펴보면 스텁에 필요한 모든 인수를 넘겨서 DLL에 들어있는 진짜 함수를 호출하는
짤막한 코드가 들어있다.
이렇게하면 DLL의 함수를 분리된 파일이 아니라, 애플리케이션 코드의 일부인 것처럼
다루게 된다
 
LIB 파일을 임포트 라이브러리라고 부른다.

(1)Implict 링킹
 
“DLL이 있어서 DLL이 바로 동적 링크되는데 LIB 파일이 왜 필요한가?” 

이렇게 물어보는 사람도 있을 것입니다. 이유는 메인프로그램을 컴파일하고 링크할 때 DLL 안에 있는 함수들은 메인프로그램에는 어느 것과도 링크되어 있지 않아 실행 파일로 만들 때 에러가 나오기 때문입니다. 예를 들어, PaintImage(LPSTR  filename);이라는 함수를 DLL로 만들어 놓고 메인프로그램에서 헤더에 extern "C"__declspec(dllimport)void PaintImage(LPSTR filename);이라고 정의하면 컴파일은 하지만 링크할 때 PaintImage 함수를 찾을 수 없다고 하며 에러를 리턴하고 실행 파일을 만들 수 없게 됩니다. 따라서, PaintImage라는 함수를 가상으로 만들어 그것을 0으로 설정해 주는 하나의 함수가 있어야 합니다.
void PaintImage(LPSTR  fileanem)=0;
 이렇게 만들어진 함수가 컴파일되어 LIB로 만들어집니다. 따라서, 메인프로그램에서는 실행 내용이 아무것도 들어 있지 않은 LIB를 프로젝트에 삽입하고 컴파일하는 것이죠. 그런 후 프로그램이 실행되면 LIB에 설정된 파일명에 따라 DLL을 로드하고 프로그램 메모리 안에 DLL에서 로드시킨 PaintImage 모듈을 삽입시키게 됩니다. 결국 우리는 DLL을 만들고 난 후 3가지의 파일을 이용해서 메인프로그램을 제작하게 되는 것입니다. 이 3가지 파일은 다음과 같습니다. 

① 실질적으로 프로그램이 실행될 때 로드되는 DLL 파일(*.DLL) 
② 컴파일할 때 설정해 주는 함수명이 들어 있는 헤더 파일(*.H) 
③ 링크할 때 메인프로그램에 빈 함수를 설정하는 LIB 파일(*.LIB)

(2)Explicit 링킹 
 Explicit 링킹 방법이란 Implict 링킹 처럼 3가지의 파일이 필요가 없이 단순하게 DLL를 이용하여 로드할수 있는 방법을 의미합니다. 이방법으로 DLL를 로드할경우 3개의 함수를 이용합니다. 
 제일 먼저 라이브러리를 로드하는 LoadLibrary함수입니다. 이함수의 형은 다음과 같습니다.

HINSTANCE LoadLibrary( LPCTSTR lpLibFileName );
 예를 들어서 ExRegularDll.dll이라는 함수를 로드하고자 한다면  다음과 같이 할수 있습니다. 

HINSTANCE hDll;

hDll=LoadLibrary("ExRegularDll.dll");

 LodadLibrary함수를 이용하로 로드하면 인스턴스 핸들을 리턴합니다. 이 인스턴스 핸들을 이용하여 필요한 함수의 포인터를 찾습니다. 예를 들어 ExRegularDll.dll이라는 함수에 현재 윈도우의 화면 크기를 가지고 있는 함수가 Factory라고 한다면 다음과 같이 할수 있습니다. 

typedef int (*FactoryFunc)(int num);

FactoryFunc lpFactoryFunc;

lpFactoryFunc=(FactoryFunc)GetProcAddress(hDll,"Factory");

GetProcAddress함수는 다음과 같은 형태입니다. 

FARPROC GetProcAddress(

HMODULE hModule, // DLL인스턴스

LPCSTR lpProcName //함수 이름

);

 GetProcAddress함수의 첫번째 인자는 로드한 DLL의 인스턴스 핸들이며 두번째 인자는 이 DLL안에 있는 함수이름입니다. GetProcAddress(hDll,"Factory"); 라고 하였을경우 “ExRegularDll.dll"함수안에서 Factory 함수를 찾아서 이 메모리 위치를 리턴하며 위의 예에서는 이 위치를 lpFactoryFunc 가 받는 것입니다. 이렇게 리턴된 lpFactoryFunc 함수를 실행하고자 한다면 다음과 같이 하면 됩니다. 
lpFactoryFunc(num)
 lpFactoryFunc();라고 실행하였을경우 DLL의 Factory 의 함수를 실행한것과 같습니다.  만일 Factory 함수의 안에 인자로 (int num)이 있기 때문에 위와 같이 int num의 인자를 설정한것입니다. 

 이와 같이 라이브러리에서 함수를 실행한후 DLL의 사용이 종료 되면 FreeLibrary함수를 이용하여 해제 하면됩니다.
FreeLibrary(hDll);
 이렇게 하였을경우 현재 DLL를 사용하는 프로그램이 전형 없다고 할경우 그 DLL은 메모리에서 해제되나 만일 다른 프로그래에서 사용하고 있다면 이 DLL 은 메모리에 그대로 있습니다. 메모리에서 DLL를 해제하지 않고 싶을경우 한개의 프로그램이 로드하면서 그DLL를 로드하고 아무것도 이용하지 않은채 해제를 하지 않으면 됩니다. 이렇게 되면 다른 프로그램에서는 언제나 메모리에 상주되어 있는 DLL 를 항상 이용할수 있습니다. 

그리하여 직접 사용해보기~
DLL 파일부로 부터 선언부 발췌

#pragma data_seg("Shared")
HINSTANCE g_Module = NULL;
HHOOK g_hook = NULL;
HWND g_hWnd = NULL;
#pragma data_seg() 

#pragma comment(linker, "/SECTION:Shared,RWS")

__declspec(dllexport) BOOL SetHook( HWND hWnd );
__declspec(dllexport) BOOL RemoveHook();
DLL을 링크한 CPP 파일로 부터 발췌

#pragma comment( lib, "test.lib" )

함수사용부
HINSTANCE hIns = LoadLibrary(_T("CatchDll.dll"));
if( hIns == NULL )
 MessageBox("Load Library fail\n");
typedef void (*defSetHook)(HWND hWnd);
defSetHook fSetHook; 
fSetHook = (defSetHook)GetProcAddress( hIns, "SetHook" );
fSetHook( this->GetSafeHwnd() );
FreeLibrary(hIns);
해당 부분은 직접 구현할 떄 사용한 방법/코드를 그대로 가져온 것이다.
이상하게 implict으로 하면 안된다 ..안습(이거때문에 하루를 날렸음)
  아. 예제 넣는것도 힘들다-_-; (tistory미워요)

pragma에 대한 자세한 사용은 아래의 글, "pragma의 용법"을 보자.

 비쥬얼 스튜디오에서 설정을 통하여 dll 파일을 linking 하는 부분이다.(순차설명)
Project(프로젝트:우클릭 혹은 드랍메뉴)>Property(속성)>Linker(링커)>input(입력)
제일 윗단의 추가종속성에 dll 파일의 경로와 이름을 넣어주면 된다. 상대경로든 절대경로든.
   한글버전의 비쥬얼 스튜디오가 깔려있어서 영문 이름은 정확하지 않다.


  • DLL, 변수를 공유하자
처음 시작은 dll을 링크한 외부에서 dll의 돌아가고 있는 상황을 알고자 함이었다.
  외부에서 DLL 파일의 변수에 접근하고 싶을 때 어떻게 해야할까?

dll에서 생성한 데이터(메모리)를 dll을 사용하는 프로세스(프로그램)에서 사용하는 방법에는 크게 두가지가 있다.
  1. #pragma data_seg의 사용
  2. 메모리맵 파일의 사용
 나는 이번 후킹예제에서 거의 대부분의 사람이 사용할 것이라고 생각하는(검색하였을 떄 양이 더 많다-_-;;) pragma data_seg를 사용하였다.
 따라서 메모리맵 파일의 사용법은 다른데서 찾아보세요- _-)y~

 용이한 자료가 매우 많은 pragma data_seg를 사용한 변수 공유는 사용법도 간편하다.
#pragma data_seg("SHAREDATA")
 int x;
 char y;
#pragma data_seg()
#pragma comment( linker, "SECTION:.SHAREDATA,RWS" )
   위의 pragma들의 자세한 사용에 대해 알고 싶으면 아래의 글을 참조.
 위와 같이 사용하면 된다. dll 파일을 링크하면 x, y의 데이터를 공유할 수 있게 된다.
 
쉽다.


 으흐흐 계속 쉬웠으면 좋겠다 ㅠㅠ
 이걸 위해 몇시간 삽질을 했는지 모름. 대체적인 예제들이 자세한 설명은 앞뒤로 떼먹고 코드만 보여주고 됐지? 타입이라 하나하나 정보를 수집해야만 했다. 특히 pragma 들에 대해-_-
 pragma의 자세한 내용은 아까 말했다시피 아래의 글을 참조.



  • 이제 변수의 공유가 되었으니 함수를 공유하자

이게뭐야-_-; tistory 편집기는 word를 따라가기엔 멀었다. 메뉴만 같이 하다니 밉다.
(글머리 기능&bold,color 사용을 위해 올렸다 내렸다 지웠다 달았다 난리 났다)

함수공유... ㅈㄱ..제일 삽질한 부분이다.

 dll 내부의 공유함수는 다음과 같이 "이~ 함수는~ 외부에서 사용할 것이다~" 라고 컴파일러에게 가르켜 주지 않으면 안된다. 자동인식...절때 그런거 없다 흑.

__declspec(dllexport) BOOL SetHook( HWND hWnd );
__declspec(dllexport) BOOL RemoveHook();

빨간 부분이 DLL 파일에서의 주 요점이다.

함수공유를 위해 프로그램에서 해주어야하는일이 있다.
링크와 선언.

implict방법
pragma 라던가 비쥬얼스튜디오를 사용해 링크해주던간에 일단 dll을 링크해주었다.
그럼 이제 dll내의 함수 사용을 위해 헤더나 파일의 상단에 dll 파일 내의 함수이름을 선언해주어야 한다. 그냥 다른 함수 선언하는 것과 마찬가지로

반환인자 함수이름( 매개변수 );
int testFunc( int name );

해주면 된다.
사용을 위해 이런게 있어 함 찾아봐 이러고, 선언해주는 것이다.
그럼 이제 컴파일시 해당 선언을 보고 linking된 dll 파일로부터 함수를 찾아 수행하게 된다.

explicit방법
좀 길지만 확실한 방법이다.
직접 dll이 컴파일되어있는 lib로 부터 불러들인다.

HINSTANCE hIns = LoadLibrary(_T("CatchDll.dll"));
if( hIns == NULL )
 MessageBox("Load Library fail\n");
typedef void (*defSetHook)(HWND hWnd);
defSetHook fSetHook; 
fSetHook = (defSetHook)GetProcAddress( hIns, "SetHook" );
fSetHook( this->GetSafeHwnd() );
FreeLibrary(hIns);

만세~
여기까지이다.
DLL 파일의 생성부터 자세한 설명까지

http://ccmc.knu.ac.kr/files/research/sdl_home/dll/subject1.htm
http://blog.naver.com/kyehwan2?Redirect=Log&logNo=10005701934
http://msdn.microsoft.com/library/default.asp


출처 : http://mayu.tistory.com/9

'system > windows' 카테고리의 다른 글

PE patch를 이용한 DLL loading  (0) 2012.06.15
가상 키 코드(스캔코드) 테이블  (0) 2012.03.06
관리자 권한 실행 - UAC 고려하기  (0) 2012.01.16
Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
: