DLL 로딩하기 추가 내용

@codemaru · September 04, 2007 · 4 min read

이번 달 원고에 빠진 부분과 잘못된 부분이 있어서 올립니다.

재배치 섹션 부분에 보시면 "블록 크기 ? 8) / 2"라는 부분이 있습니다. 갑자기 쌩뚱맞은 ?표죠. 빼기(-) 기호 입니다. 재배치 섹션에 포함된 재배치 주소의 개수는 (블록크기 - 8) / 2를 해서 구할 수 있다는 이야기죠.

리스트 4에 사용된 코드에 주석인 "임포트한 DLL 이름을 출력한다"는 잘못된 내용입니다. 그 부분은 임포트한 함수들의 실제 주소를 기록하는 부분이죠. 지난 번에 연재한 코드에서 붙여넣기를 하면서 주석을 지운다는게 실수했네요. ㅠㅠ

분량 관계상 원고에서 소스 코드 세 개 정도가 빠져 있더군요.
이달의 디스켓 받아서 소스 보기 귀찮으신 분들을 위해서 올려 둡니다.
리스트 7, 8, 9에 사용된 소스 부분입니다.

여담으로 시스템 프로그래밍에 관심 있는 분들을 위한 소식을 하나 알려드리자면,
지난 달부터 마소에 권용휘님네이티브 애플리케이션과 관련된 연재가 진행되고 있습니다.
악성코드 탐색 프로그램에서는 불필요한 파일을 지우기 위한 용도로 사용되기도 하죠.
관심있으신 분들은 꼭 읽어보시고 내공 향상에 도움이 되셨으면 합니다.

리스트 7: FreeLibrary 함수 구현

void CDllLoader::FreeDll(CDllInfo \* dll)  
{  
  InterlockedDecrement((LONG \*) &dll->ref);  
  
  if(dll->ref == 0)  
  {  
    dll->DllMain(DLL\_PROCESS\_DETACH);  
  
    for\_each(dll->modules.begin()  
        , dll->modules.end()  
        , ::FreeLibrary);  
  
    UnloadFile(dll);  
  }  
}  
  
bool CDllLoader::FreeLibrary(PVOID base)  
{  
  CDllInfo \* dll = GetDll(base);  
  if(!dll)  
    return false;  
  
  FreeDll(dll);  
  
  if(dll->ref == 0)  
  {  
    EnterCriticalSection(&m\_csLoadDlls);  
    m\_loadDlls.erase(base);  
    LeaveCriticalSection(&m\_csLoadDlls);  
  }  
  
  return true;  
}

리스트 8: GetProcAddress 구현 부분

FARPROC CDllLoader::GetProcAddress(PVOID base, LPCSTR name)  
{  
  CDllInfo \* dll = GetDll(base);  
  if(!dll)  
    return NULL;  
  
  PIMAGE\_NT\_HEADERS nt = dll->NTHeader();  
  IMAGE\_DATA\_DIRECTORY edd = dll->DataDirectory(IMAGE\_DIRECTORY\_ENTRY\_EXPORT);  
  if(!edd.VirtualAddress || !edd.Size)  
    return NULL;  
  
  PIMAGE\_EXPORT\_DIRECTORY ied;  
  ied = (PIMAGE\_EXPORT\_DIRECTORY) GetPtr(dll->Base(), edd.VirtualAddress);  
  
  char \*funcName;  
  DWORD \*funcs = (DWORD \*) GetPtr(dll->Base(), ied->AddressOfFunctions);  
  DWORD \*names = (DWORD \*) GetPtr(dll->Base(), ied->AddressOfNames);  
  WORD \*ordinals = (WORD \*) GetPtr(dll->Base(), ied->AddressOfNameOrdinals);  
  
  if(HIWORD(name) == 0)  
  {  
    WORD ordinal = LOWORD(name) - ied->Base;  
    if(ordinal < ied->NumberOfFunctions && funcs[ordinal])  
      return (FARPROC) GetPtr(base, funcs[ordinal]);  
  }  
  else  
  {  
    for(DWORD i=0; i<ied->NumberOfNames; ++i)  
    {  
      funcName = (char \*) GetPtr(base, names[i]);  
      if(strcmp(funcName, name) == 0 && funcs[ordinals[i]])  
        return (FARPROC) GetPtr(base, funcs[ordinals[i]]);  
    }  
  }  
  
  return NULL;  
}

리스트 9: CDllLoader 사용 프로그램

typedef void (\*PrintMsgFunc)(const char \*msg, DWORD len);  
typedef int (\*PlusFunc)(int , int);  
int \_tmain(int argc, \_TCHAR\* argv[])  
{  
  CDllLoader loader;  
  PVOID base = loader.LoadLibrary(\_T("dummydll.dll"));  
  if(base)  
  {  
    PrintMsgFunc PrintMsg;  
    PrintMsg = (PrintMsgFunc) loader.GetProcAddress(base, MAKEINTRESOURCEA(2));  
    PrintMsg("Hello", 5);  
  
    PlusFunc Plus;  
    Plus = (PlusFunc) loader.GetProcAddress(base, "Plus");  
    int a = Plus(3, 4);  
    printf("%d\n", a);  
  
    loader.FreeLibrary(base);  
  }  
  return 0;  
}
@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중