2010-05-27 5 views
9

DLL을로드하는 프로그램이있어서 포함되지 않은 내 보낸 함수 중 하나를 호출해야합니다. 디버거 또는 다른 방법으로 검색하여이 작업을 수행 할 수있는 방법이 있습니까? 누구나 물어보기 전에, 예, 저는 프로토 타입과 기능들을 가지고 있습니다.DLL에서 내보낼 수없는 함수 호출

답변

0

참조 된 라이브러리가 명시 적으로 해당 객체 (클래스/함수)를 내보내는 경우 "안전한"방법이 없기를 두려워합니다. 코드 메모리에 매핑되는 필수 개체가 어디에 있는지 알 수 없기 때문입니다.

그러나 RE 도구를 사용하면 라이브러리 내에서 관심있는 개체의 오프셋을 찾아 알려진 내 보낸 개체 주소에 추가하여 "실제"메모리 위치를 얻을 수 있습니다. 그런 다음 함수 프로토 타입 등을 준비하고 사용을 위해 로컬 구조에 캐스트합니다.

+0

RE 도구 란 무엇입니까? – Nilbert

+0

디스어셈블러, 어셈블리 해석 기능을 제공하는 사람을 찾는 것이 좋습니다. (PE는 좋은 것입니다.) – YeenFei

10

예, 적어도 일종의 있지만, 그것은 좋은 생각이 아닙니다.

C/C++에서 모든 함수 포인터는 메모리의 주소입니다. 그래서 당신이 어떻게 든이 함수의 주소를 찾을 수 있다면 당신은 그것을 부를 수 있습니다.

몇 가지 질문을하겠습니다.이 DLL에이 기능이 있다는 것을 어떻게 알 수 있습니까? 소스 코드가 있습니까? 그렇지 않으면이 기능이 있는지 또는 전화를 걸면 안전한지 알 수 있습니다. 그러나 소스 코드를 가지고 있다면 함수를 노출하십시오. DLL 작성자가이 함수를 노출하지 않은 경우에는 호출자가 호출 할 것을 기대하지 않으며 언제든지 구현을 변경/제거 할 수 있습니다.

경고 기호 외에 디버그 기호가있는 경우 함수 주소를 찾을 수 있으며 MAP file이면 DLL에서 오프셋을 찾을 수 있습니다. DLL 이외의 것이 없으면 DLL에 해당 함수가있는 위치를 알 수있는 방법이 없습니다. DLL 자체에 저장되지 않습니다. 당신은 당신이 다음과 같이 코드에 그를 삽입 할 수 있습니다 오프셋하면

는 :

const DWORD_PTR funcOffset = 0xDEADBEEF; 
typedef void (*UnExportedFunc)(); 

.... 
void CallUnExportedFunc() { 
    // This will get the DLL base address (which can vary) 
    HMODULE hMod = GetModuleHandle("My.dll"); 
    // Calcualte the acutal address 
    DWORD_PTR funcAddress = (DWORD_PTR)hMod + funcOffset; 
    // Cast the address to a function poniter 
    UnExportedFunc func = (UnExportedFunc)funcAddress; 
    // Call the function 
    func(); 
} 

는 또한 DLL이 재건 될 때마다 변경됩니다이 기능의 오프셋을 실현 그래서 이것은 매우 허약하고하자 다시 말하지만 좋은 생각은 아닙니다.

+0

아아, 문제는 DLL에서 주소를 찾는 것이 었습니다. 예, DLL이 모두 있지만 확실합니다. 그 안에 기능이 존재합니다. "DLL 이외에 아무것도없는 경우 DLL에 해당 함수가있는 위치를 알 수있는 방법이 없습니다. DLL 자체에 저장되지 않습니다." – Nilbert

+0

내가 말하고자했던 것은 DLL에 해당 코드가있는 DLL 내부의 주소와 함수 이름 간의 매핑이 포함되어 있지 않다는 것입니다. 함수 자체의 이름은 DLL 내부 어디에서도 찾을 수 없습니다. – shf301

+1

OllyDBG에서 DLL을보고 기능이 어디에 있는지 알 수는 있지만 매우 어려울 수 있습니다. –

1

원하는 기능을 내 보내지 않은 경우 내보내기 주소 테이블에 없습니다. Visual Studio를 사용하여이 DLL을 생성하고 관련 PDB (프로그램 데이터베이스) 파일을 가지고 있다고 가정하면 Microsoft의 DIA (디버그 인터페이스 액세스) API를 사용하여 원하는 기능을 이름 또는 대략적으로 서명으로 찾을 수 있습니다.

PDB에서 기능 (심볼)을 얻으면 RVA (상대 가상 주소)도 갖게됩니다. 로드 된 모듈의 기본 주소에 RVA를 추가하여 함수가 저장되는 메모리의 절대 가상 주소를 결정할 수 있습니다. 그런 다음 해당 주소를 통해 함수 호출을 만들 수 있습니다. 이것은 당신이해야 할 단지 일회성 일 경우


또는, 당신은 당신의 프로세스에 연결하는 Debugging Tools for Windows 툴킷에서 WINDBG.EXE 사용할 수 있습니다 (즉, 당신은 프로그래밍 솔루션을 필요로하지 않습니다) 관심있는 기능의 주소를 확인하십시오. WinDbg에서 x 명령을 사용하여 모듈의 "검사"기호를 사용할 수 있습니다.

예를 들어 x mymodule!*foo*을 사용하면 이름에 "foo"가 포함 된 모든 기능을 볼 수 있습니다. 모듈에 대한 심볼 (PDB)이로드되어있는 한 내보내기 이외의 함수도 표시됩니다. 을 사용하여 x 명령에 대한 도움말을 얻으십시오.

+0

나는 단지 .DLL이 있고 .pdb가 아니라면 그게 끔찍한 것 같아? – Nilbert

+0

예, PDB 정보없이 내보내기되지 않은 기능을 찾는 것은 매우 어려울 것입니다. 디스 어셈블러를 사용하여 x86 프롤로그/에필로그를 찾고 추측 및 확인 접근법을 사용하여 위치를 추측 할 수 있습니다 (http://www.smidgeonsoft.prohosting.com/pebrowse-pro-file-viewer.html 참조). –

0

이것을 수행하는 가장 일반적인 방법은 다른 모든 사람들이 이미 지적했듯이 런타임에 DLL 코드가로드 된 후이를 검사하여 알려진 고유 한 코드 섹션을 찾습니다. 함수를 호출 한 다음 shf301의 응답과 비슷한 코드를 사용하여 호출하십시오. DLL이 변경되지 않는다는 것을 알고 있다면 DLL의 오프셋을 결정하는 모든 솔루션이 작동해야합니다.

고유 한 코드 섹션을 찾으려면 어셈블러 니모닉에 기계 코드를 표시 할 수있는 디스어셈블러를 사용하여 DLL을 분해하십시오 (나는 그렇게하지 않을 것이라고 생각하지 않습니다) 호출 및 jmp 명령.

DOS EXE에 바이너리 패치를 적용하려면 실제로 한 번 비슷한 작업을해야했습니다. 그것은 버그 수정이었고, 코드는 개정 통제하에 있지 않으므로이를 수정하는 유일한 방법이었습니다.

나는 왜 당신이 이것을 필요로하는지 정말로 알고 싶어합니다.

7

나는이 질문이 오래되었다는 것을 알고 있지만 shf301은 올바른 생각을 가지고 있습니다. 내가 추가 할 수있는 유일한 방법은 대상 라이브러리에서 패턴 검색을 구현하는 것입니다. IDA 또는 OllyDbg이있는 경우 함수를 검색하여 해당 함수의 시작 주소를 묶는 이진/16 진수 데이터를 볼 수 있습니다.

대부분의 경우 거의 변경되지 않는 일종의 이진 서명이 있습니다. 서명에는 빌드간에 변경 될 수있는 와일드 카드가 포함될 수 있지만 빌드간에 극단적 인 변경이 발생하지 않는 한이 패턴을 검색하는 중에 궁극적으로 성공한 히트가 하나 이상 있어야합니다 (어떤 지점에서 그 새 서명을 알아낼 수 있습니까? 특정 버전). 당신은 바이너리 패턴 검색을 구현하는 것이


방법은 그렇게 같다 :

bool bCompare(const PBYTE pData, const PBYTE bMask, const PCHAR szMask) 
{ 
    for(;*szMask;++szMask,++pData,++bMask) 
      if(*szMask=='x' && *pData!=*bMask) 
        return 0; 
    return (*szMask) == NULL; 
} 

DWORD FindPattern(DWORD dwAddress, DWORD dwLen, PBYTE bMask, PCHAR szMask) 
{ 
    for(DWORD i=0; i<dwLen; i++) 
      if (bCompare((PBYTE)(dwAddress+i),bMask,szMask)) 
        return (DWORD)(dwAddress+i); 
    return 0; 
} 


사용 예제 :

typedef void (*UnExportedFunc)(); 

//... 
void CallUnExportedFunc() 
{ 
    // This will get the DLL base address (which can vary) 
    HMODULE hMod = GetModuleHandleA("My.dll"); 

    // Get module info 
    MODULEINFO modinfo = { NULL, }; 
    GetModuleInformation(GetCurrentProcess(), hMod, &modinfo, sizeof(modinfo)); 

    // This will search the module for the address of a given signature 
    DWORD dwAddress = FindPattern(
     hMod, modinfo.SizeOfImage, 
     (PBYTE)"\xC7\x06\x00\x00\x00\x00\x89\x86\x00\x00\x00\x00\x89\x86", 
     "xx????xx????xx" 
    ); 

    // Calculate the acutal address 
    DWORD_PTR funcAddress = (DWORD_PTR)hMod + dwAddress; 

    // Cast the address to a function poniter 
    UnExportedFunc func = (UnExportedFunc)funcAddress; 

    // Call the function 
    func(); 
} 


이 작동하는 방식은 전달입니다 로드 할 라이브러리의 기본 주소 GetModuleHandle을 통해 검색 할 길이 (바이트), 검색 할 2 진 데이터 및 ma sk는 바이너리 스트링의 어느 바이트가 유효한지 ('x'), 어떤 것들이 간과 될 것인가 ('?')를 지정한다. 이 함수는로드 된 모듈의 메모리 공간을 탐색하여 일치하는 항목을 찾습니다. 경우에 따라 둘 이상의 일치 항목이있을 수 있으며이 경우 일치 항목이 하나만있는 곳에 서명을 조금 더 발음하게하는 것이 좋습니다.

다시 해시 응용 프로그램에서이 서명이 무엇인지 알기 위해 초기 이진 검색을 수행해야하지만, 일단이 방법을 사용하면 매번 수동으로 오프셋 오프셋 함수 을 찾는 것보다 조금 더 잘 작동합니다 대상이 작성됩니다. 희망이 도움이됩니다.

0

함수 주소를 찾을 수있는 경우에도 일반적으로 "개인"내부 용 전용 함수라고 생각하는 컴파일러에서 만든 함수를 호출하는 것은 안전하지 않습니다.

link-time-optimization enabled의 현대 컴파일러는 특정 발신자가 필요로하는 기능을 수행하는 특수 버전의 기능을 만들 수 있습니다.

원하는 기능처럼 보이는 기계 블록이 실제로 표준 ABI를 따르고 소스 코드가 말하는 모든 것을 구현한다고 가정하지 마십시오.

gcc의 경우 인라인되지 않지만 특수한 경우 (예 : 상수 전파) 여러 호출자의 특수 버전의 함수에 특수 이름을 사용합니다.

42944c : E8가 CF (13) 0E 00 호 50a820 429,451 48 8B 7B 48 MOV의 RDI, QWORD PTR [RBX + 0x48] 429,455 (-C를 디맹 글링이다)이 objdump -drwC 출력 48 89 공학부 MOV의 중증도 rbp 429458 : e8 b3 10 0e 00 call 50a510

gcc는 두 개의 다른 컴파일 타임 상수에 특화된 같은 함수의 두 개의 다른 클론을 호출하는 코드를 내 보냅니다. (이것은 http://endless-sky.github.io/에서 필요합니다. XY 위치 클래스의 사소한 액세서 기능도 Point.h가 아닌 Point.cpp에 있으므로 LTO에서만 인라인 될 수 있으므로 LTO가 필연적으로 필요합니다.

LTO도 만들 수 있습니다 .lto_priv 데이터의 정적 버전 : 당신이 링크 - 타임 최적화를 이용했다 가정을 위반 수있는 새로운 장소에서 호출, 당신이 원하는과 같은 기능을 찾을 수 없더라도

mov rcx,QWORD PTR [rip+0x412ff7]  # 83dbe0 <_ZN12_GLOBAL__N_116playerGovernmentE.lto_priv.898> 

있다.