윈도우 95는 DLL에서 익스포트된 함수를 실행하는 16비트, 32비트 Rundll.exe과 Rundll32.exe 커맨드-라인 유틸리티를 가진다. 그러나, Rundll과 Rundll32 프로그램이 모든 DLL로 부터의 모든 익스포트 함수에 대해 실행되지는 않는다. 예를 들어 시스템 DLL에서 익스포트되는 Win32 API (Application Programming Interface) 는 콜할 수없다. 작성한 DLL에 존재하는 익스포트 함수에 대하여만 가능하다. 여기에서는 윈도우 NT와 95하에서 Rundll과 Rundll32 사용법을 다룬다. 원래 Rundll과 Rundll32 유틸리티는 마이크로소프트 내부용의로 설계되었다. 그러나 그 기능이 일반적이므로 현재는 공개되었다.
주 : 윈도우 NT 4.0은 Rundll32만 포함되며 Rundll32만 지원한다.
* Rundll 과 Rundll32 비교
Rundll은16-비트 DLL을 로드하고 실행하며, 반면 Rundll32는32-비트 DLL을 로드하고 실행한다. 잘못된 DLL을 Rundll 나 Rundll32에 사용하는 경우, 오류 메시지 없이 실행에 실패한다.
* Rundll 커맨드 라인
RUNDLL.EXE <DLL 명>,<엔트리 포인트> <옵션 아규먼트>
다음은 예이다:
RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF
다음은 위 명령어 라인에서 주의해야한 3가지 문제이다:
- Rundll 이나 Rundll32은 주어진 DLL 파일명을 LoadLibrary() 함수가 사용하는 표준위치에서 찾는다. 정확을 기하기 위해서는 DLL의 풀-패스를 기술하고, 유효한 파일명이 되기 위해서는 긴 파일명 대신 짧은 파일 명을 기술한다. 즉 "C:\Program Files" 폴더는 반드시 짧은 폴더 명으로 변환되어야 한다.
- <DLL 명>에는 스페이스, 콤마, 따옴표등이 포함될 수없다. 이것은 Rundll 커맨드 분석기의 한계이다.
- 위 커맨드 라인에서, <DLL 명>과 <엔트리 포인트>사이의 컴마(,)는 매우 중요하다. 만약 컴마가 없다면, Rundll이나 Rundll32는 어떤 오류 메시지 없이 실패한다. 또한 <DLL 명>, 컴마와 <엔트리 포인트> 함수 사이에는 스페이스도 없어야만 한다.
* Rundll 동작 방법
- 커맨드 라인을 분석한다.
- LoadLibrary()로 명시된 DLL을 로드한다.
- GetProcAddress()로 <엔트리 포인트> 함수의 어드레스를 얻는다.
- <옵션 아규먼트>를 <엔트리 포인트> 함수로 패스하면서 콜한다.
- <엔트리 포인트> 함수 리턴시 Rundll.exe는 DLL을 언로드하고 종료한다.
* DLL 작성법
작성하는 DLL에서, 다음같은 함수 원형 <엔트리 포인트> 함수를 만든다:
16-비트 DLL:
void FAR PASCAL __loadds
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
32-비트 DLL:
void CALLBACK
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
엔트리 포인트 함수는 다음을 고려해야 한다.
- "EntryPoint"는 반드시 실제 엔트리 포인트 함수명 이어야 한다. Rundll32의 엔트리 포인트는 프로세스와 쓰레드 어태치/디태치 통보(notifications)를 처리하는 32비트 DLL의 DllEntryPoint함수와 완전히 별개이다.
- Rundll32의 엔트리 포인트 함수는 반드시 _stdcall(CALLBACK은 디폴트로 _stdcall 속성을 사용한다)을 정의해야만 한다. 만약 _stdcall이 없으면, 함수는 디폴트로 _cdecl를 사용하며, 이때 Rundll32은 함수 호출 후, 비정상적으로 종료한다.
- 반드시 함수 선언에 _stdcall 를 사용해야 하며, 비주얼 C++ 컴파일러는 DLL이 C로 쓰여진 경우는 _EntryPoint@16으로, C++로 쓰여진 경우는 함수명을 장식한다. 그러므로 장식돤 이름을 사용하지 않으려면, .DEF 파일을 사용하고, 이름으로 엔트리 포인트 함수를 익스포트해야 한다.
Rundll 엔트리 포인트의 매개변수는 다음과 같다:
hwnd - DLL에서 사용할 오너 윈도우의 윈도우 핸들
hinst - DLL의 인스턴스 핸들
lpszCmdLine - DLL이 분석해야할 ASCIIZ 커맨드 라인
nCmdShow - DLL의 윈도우를 디스플레이할 방법
다음은 예이다:
RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF
Rundll은 Setupx.dll 내의 InstallHinfSection() 엔트리 포인트 함수를 다음의 매개 변수로 콜한다:
hwnd = (모 윈도우 핸들)
hinst = SETUPX.DLL의 HINSTANCE
lpszCmdLine = "132 C:\WINDOWS\INF\SHELL.INF"
nCmdShow = (CreateProcess에 전달되는 nCmdShow)
주 : 엔트리 포인트 함수(예제에서는 InstallHinfSection())는 커맨드 라인 (여기에서는 lpszCmdLine)을 분석한다. Rundll.exe는 커맨드 라인에 패스되는 아규먼트중 옵션 아규먼트까지 분석하고 나머지 분석은 엔트리 포인트 함수에 의존한다.
* 윈도우 95와 윈도우 NT간의 차이점
윈도우 NT에서의 Rundll32.exe동작은 유니코드 커맨드 라인에 적합하도록 되어있다. 윈도우 NT는 먼저 <엔트리 포인트 함수명>W의 GetProcAddress를 얻어내어 엔트리 포인트가 있는 경우 함수 원형을 다음으로 간주한다:
void CALLBACK
EntryPointW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow);
이것은 lpszCmdLine이 유니코드 문자열인 점만이 ANSI 엔트리포인트 함수와 다른 점이다.
만약 <엔트리 포인트 함수명>W이 없으면, 윈도우 NT는 <엔트리 포인트 함수명>을 위하여 <엔트리 포인트 함수명>A의 GetProcAddress를 실행하고 이를 ANSI 엔트리 포인트로 여겨 윈도우 95와 동일하게 처리한다. 그러므로, 만약 작성한 DLL이 윈도우 95에서는 ANSI 지원, 윈도우 NT에서는 UNICODE지원하게 한다면 반드시 두개의 함수: EntryPointW 와 EntryPoint를 익스포트한다. 윈도우 NT에서 EntryPointW 함수는 유니코드 커맨드 라인을 사용하고, 윈도우95에서는 EntryPoint 함수는 ANSI 커맨드 라인을 콜하게 될 것이다.