삽질 하나: rundll32.exe와 ~RunDLL 시리즈 함수들

닷넷 프레임워크에서 DLL을 호출하고 다루는 방법은 2.0에 들어와서부터는 사실상 완전해졌다. 1.0/1.1때부터는 종전의 Visual Basic 6.0과 비슷한 방식으로 함수의 시그니처를 제어하는 방식으로 외부 DLL에 대한 링크를 걸 수 있었고 2.0에 와서는 드디어 GetProcAddress와 같은 함수가 노출하는 함수 포인터 주소를 직접적으로 대리자로 치환하거나 반대의 일도 할 수 있게 되었기 때문이다. 그리고 같이 추가된 기능이 있다면 MDA 에이전트가 있다는 점이다. 닷넷 프레임워크의 입장에서보기에 “이건 좀 어폐가 있는게 아니냐”는 불평이 MDA 에러 방식으로 나타난다.

서버 관리 도구를 작성하는 도중 종전의 제어판 모듈과 몇 몇 숨겨진 위저드 DLL 모듈을 호출할 일이 있어서 구글에게 물어보니 ~RunDLL 시리즈 함수들에 대한 호출법은 열의 아홉이 rundll32.exe를 사용하는 방식이었다. 사실 이런 함수들은 프로그래밍 언어에서는 직접 연결할 수가 없다. 그저 Shell 명령어 해석기를 통해 간접적으로 rundll32.exe에게 호출을 의뢰하는 것 밖에는 방법이 없다. 하지만 rundll32.exe를 통하여 대리 실행하는 방법말고 좀 더 빠른 방법을 찾아보고 싶었다. 즉, 직접 해당 DLL의 해당 함수에 연결하는 방법이다.

특별한 명시가 없어도 대부분의 Windows용 DLL의 노출된 함수들은 호출자 시그니처에 WINAPI 어트리뷰트가 붙는다는 것을 “가정”해 보고 작업을 시작해보았지만 생각보다 일이 어려웠다. 진짜 문제는 닷넷 프레임워크의 P/Invoke가 너무 관대하다는데에 있었는데, 함수 시그니처까지 정확히 검사하지는 않고 있었고 그저 함수 진입점만 찾을 수 있었다고 하면 일단 들어가고 보는 것이었다. 들어가는 것은 좋지만 나올때가 문제인데, 시그니처가 정확하지 않기 때문에 스택이 함수 호출 전과 후의 모습이 상이하게 달라지게 되었기 때문이다.

일단은 rundll32.exe를 가지고 호출하는 방법으로 아쉽게 넘어갔지만 좀 더 시간을 내어 한 번 살펴볼 생각이다.

댓글 남기기