2009-07-14 3 views

답변

41

dumpbin /exports은 원하는대로 할 수 있지만 개발자 도구는 Win32 API가 아닙니다. DONT_RESOLVE_DLL_REFERENCES

LoadLibraryEx 무겁게에 대해주의, 그러나이 특별한 경우 – 유용 될 일이되어 그것을 않습니다 (하지만 실제로 필요하거나 라이브러리에서 아무것도 사용하지 않음) 메모리에 DLL을 매핑하는 무거운 , 당신은 머리글을 읽는 것이 쉽다 : LoadLibraryEx에 의해 반환 된 모듈 핸들은 바로 그것을 가리킨다.

#include <winnt.h> 
HMODULE lib = LoadLibraryEx("library.dll", NULL, DONT_RESOLVE_DLL_REFERENCES); 
assert(((PIMAGE_DOS_HEADER)lib)->e_magic == IMAGE_DOS_SIGNATURE); 
PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS)((BYTE *)lib + ((PIMAGE_DOS_HEADER)lib)->e_lfanew); 
assert(header->Signature == IMAGE_NT_SIGNATURE); 
assert(header->OptionalHeader.NumberOfRvaAndSizes > 0); 
PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)((BYTE *)lib + header-> 
    OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 
assert(exports->AddressOfNames != 0); 
BYTE** names = (BYTE**)((int)lib + exports->AddressOfNames); 
for (int i = 0; i < exports->NumberOfNames; i++) 
    printf("Export: %s\n", (BYTE *)lib + (int)names[i]); 

완전히 테스트되었지만 정확하다고 생각합니다. (유명한 마지막 단어입니다.)

+0

이 (하는 ctypes와) 파이썬 내 빠른 포트가 잘 작동하는지 충분히 잘 작동했다. 감사! –

+10

** DONT_RESOLVE_DLL_REFERENCES 플래그로 로딩 한 후에 ** 함수를 호출하면 **로드 된 모듈에'DllMain'이 호출되지 않기 때문에 ** 쓸데없는 일이 될 수 있습니다 **. –

+0

왜 DONT_RESOLVE_DLL_REFERENCES 대신 파일을 직접 메모리 맵핑하지 않을까요? 심지어 더 빠를 수도 있습니다. – masterxilo

5

Microsoft 리서치로 이동하여 우회 라이브러리를 가져옵니다. 그 예 중 하나가 당신이 요구하는 것과 정확히 일치합니다. 전체 라이브러리는 기본적으로 win32 함수 호출을 우회/재 라우팅하는 것을 매우 쉽게 만듭니다. 그 멋진 물건.

Detours

편집 :은 또한 단지 수출 테이블을보고 싶은 경우에, 당신은 (적어도 비주얼 스튜디오에서) 엑스포트/임포트 테이블을 인쇄하는 프로젝트 속성을 설정할 수 있습니다. 나는 정확한 옵션을 기억할 수 없지만 쉽게 Google에 있어야합니다.

** Edit2가 : ** 옵션은 프로젝트 속성 -입니다> 링커 -> Debugging-> 맵 파일 생성 - 당신은 단지 어떤 기능을 찾을 수있는 방법을 찾고 있다면> 예 (/ MAP)

0

을 DLL에서 내 보낸 경우 Microsoft의 dependency walker (depends.exe)을 사용할 수 있습니다. 그러나 실제로 프로그래밍 방식으로 내보내기를 검색해야하는 경우에는 도움이되지 않습니다.

1

자신의 코드를 작성하는 데 문제가 없으며이 목적으로 이미 존재하는 DLL을 사용하려는 경우 PE File Format DLL을 권장합니다. 원한다면 수정할 수 있도록 소스 코드가 제공됩니다. 걱정할 GPL이 없습니다.

DLL을 사용하는 방법을 보여주는 GUI 응용 프로그램도 사용할 수 있습니다.

0

내가 틀릴 수도 있고 솔직하게 두 번 확인하지 않았지만 프로세스와 다른 아키텍처에서 빌드 된 모듈에서 ephemient의 코드를 사용하면 호환성 문제가 발생할 수 있습니다. (다시 말하면, 지금 당장은 완전히 내 엉덩이에서 말하고 있을지도 모른다.)같은 기술을 사용하는 github 프로젝트가있다. (하지만 파일을 메모리에로드하더라도) 바이너리의 아키텍처에 따라 내보내기를 찾을 위치를 확인합니다. 가장 관심이있는 코드는 this file입니다.

2

DONT_RESOLVE_DLL_REFERENCESLoadLibraryEx이 정확한 작업이므로이 작업을 간소화 할 수 있습니다. 대신 DLL의 내보내기 디렉토리를 찾고 열거하는 대신 SymEnumerateSymbols을 사용하여 기호를 나열 할 수 있습니다.

자신의 코드보다 약간 단순하지만 (어설 션 없이는 코드가 6 라인에 불과함) 이론적으로 Microsoft가 언젠가는 실행 파일 형식을 조금 변경하기로 결정할 경우 약간의 유연성을 제공합니다./또는 HMODULE이 무엇을 가리키는 지 정확하게 변경하므로 더 이상 작동하지 않습니다 (이러한 세부 사항 대부분은 공식적으로 문서화되지 않았기 때문에).

2

이 시도 :

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

void EnumExportedFunctions (char *, void (*callback)(char*)); 
int Rva2Offset (unsigned int); 

typedef struct { 
    unsigned char Name[8]; 
    unsigned int VirtualSize; 
    unsigned int VirtualAddress; 
    unsigned int SizeOfRawData; 
    unsigned int PointerToRawData; 
    unsigned int PointerToRelocations; 
    unsigned int PointerToLineNumbers; 
    unsigned short NumberOfRelocations; 
    unsigned short NumberOfLineNumbers; 
    unsigned int Characteristics; 
} sectionHeader; 

sectionHeader *sections; 
unsigned int NumberOfSections = 0; 

int Rva2Offset (unsigned int rva) { 
    int i = 0; 

    for (i = 0; i < NumberOfSections; i++) { 
     unsigned int x = sections[i].VirtualAddress + sections[i].SizeOfRawData; 

     if (x >= rva) { 
      return sections[i].PointerToRawData + (rva + sections[i].SizeOfRawData) - x; 
     } 
    } 

    return -1; 
} 

void EnumExportedFunctions (char *szFilename, void (*callback)(char*)) { 
    FILE *hFile = fopen (szFilename, "rb"); 

    if (hFile != NULL) { 
     if (fgetc (hFile) == 'M' && fgetc (hFile) == 'Z') { 
      unsigned int e_lfanew = 0; 
      unsigned int NumberOfRvaAndSizes = 0; 
      unsigned int ExportVirtualAddress = 0; 
      unsigned int ExportSize = 0; 
      int i = 0; 

      fseek (hFile, 0x3C, SEEK_SET); 
      fread (&e_lfanew, 4, 1, hFile); 
      fseek (hFile, e_lfanew + 6, SEEK_SET); 
      fread (&NumberOfSections, 2, 1, hFile); 
      fseek (hFile, 108, SEEK_CUR); 
      fread (&NumberOfRvaAndSizes, 4, 1, hFile); 

      if (NumberOfRvaAndSizes == 16) { 
       fread (&ExportVirtualAddress, 4, 1, hFile); 
       fread (&ExportSize, 4, 1, hFile); 

       if (ExportVirtualAddress > 0 && ExportSize > 0) { 
        fseek (hFile, 120, SEEK_CUR); 

        if (NumberOfSections > 0) { 
         sections = (sectionHeader *) malloc (NumberOfSections * sizeof (sectionHeader)); 

         for (i = 0; i < NumberOfSections; i++) { 
          fread (sections[i].Name, 8, 1, hFile); 
          fread (&sections[i].VirtualSize, 4, 1, hFile); 
          fread (&sections[i].VirtualAddress, 4, 1, hFile); 
          fread (&sections[i].SizeOfRawData, 4, 1, hFile); 
          fread (&sections[i].PointerToRawData, 4, 1, hFile); 
          fread (&sections[i].PointerToRelocations, 4, 1, hFile); 
          fread (&sections[i].PointerToLineNumbers, 4, 1, hFile); 
          fread (&sections[i].NumberOfRelocations, 2, 1, hFile); 
          fread (&sections[i].NumberOfLineNumbers, 2, 1, hFile); 
          fread (&sections[i].Characteristics, 4, 1, hFile); 
         } 

         unsigned int NumberOfNames = 0; 
         unsigned int AddressOfNames = 0; 

         int offset = Rva2Offset (ExportVirtualAddress); 
         fseek (hFile, offset + 24, SEEK_SET); 
         fread (&NumberOfNames, 4, 1, hFile); 

         fseek (hFile, 4, SEEK_CUR); 
         fread (&AddressOfNames, 4, 1, hFile); 

         unsigned int namesOffset = Rva2Offset (AddressOfNames), pos = 0; 
         fseek (hFile, namesOffset, SEEK_SET); 

         for (i = 0; i < NumberOfNames; i++) { 
          unsigned int y = 0; 
          fread (&y, 4, 1, hFile); 
          pos = ftell (hFile); 
          fseek (hFile, Rva2Offset (y), SEEK_SET); 

          char c = fgetc (hFile); 
          int szNameLen = 0; 

          while (c != '\0') { 
           c = fgetc (hFile); 
           szNameLen++; 
          } 

          fseek (hFile, (-szNameLen)-1, SEEK_CUR); 
          char* szName = calloc (szNameLen + 1, 1); 
          fread (szName, szNameLen, 1, hFile); 

          callback (szName); 

          fseek (hFile, pos, SEEK_SET); 
         } 
        } 
       } 
      } 
     } 

     fclose (hFile); 
    } 
} 

예 :

void mycallback (char* szName) { 
    printf ("%s\n", szName); 
} 

int main() { 
    EnumExportedFunctions ("C:\\Windows\\System32\\user32.dll", mycallback); 
    return 0; 
} 

출력 :

ActivateKeyboardLayout 
AddClipboardFormatListener 
AdjustWindowRect 
AdjustWindowRectEx 
AlignRects 
AllowForegroundActivation 
AllowSetForegroundWindow 
AnimateWindow 
AnyPopup 
AppendMenuA 
AppendMenuW 
ArrangeIconicWindows 
AttachThreadInput 
BeginDeferWindowPos 
BeginPaint 
BlockInput 
BringWindowToTop 
BroadcastSystemMessage 
BroadcastSystemMessageA 
BroadcastSystemMessageExA 
BroadcastSystemMessageExW 
BroadcastSystemMessageW 
BuildReasonArray 
CalcMenuBar 
.....etc