2017-09-25 17 views
3

내가 해결하기 위해 노력하고 재미 학업 문제의 상징 스텁 사용하려면, 내가 많이 Facebook's fishhook repo처럼, 실행시에 동적으로 문자를 리 바인드하려고 C 코드에서기능 개재, 마크 C의 기능은 항상 대신 직접 전화

을하는 기능 심볼을 다시 바인딩합니다. 나는 주로 Mach-O 실행 파일의 __DATA.__la_symbol_ptr 섹션에서 참조 된 심볼을 참고한다. fishhook 구현을 사용하면 대체 할 함수를 나타내는 문자열과 원래의 대체 된 함수를 호출 할 전역 함수 포인터를 제공합니다. 낚시의 환매 특약의 README에서 가져온 예를 들어

, ...

static int (*orig_close)(int); 
int my_close(int fd) { 
    return orig_close(fd); 
} 

... 다음 main

rebind_symbols((struct rebinding[1]){{"close", my_close, (void *)&orig_close}}, 1); 

이 굉장하지만 완전히 전환 할 수 원하는에서 모든 호출은 이고 모든 호출은 close이고 그 반대의 경우는 내 모듈입니다. 예를 들어, 대신 원래 close를 가리키는 전역 함수 포인터, I는 다음과 같이 내 구현을 원하는 것 :이 심볼이 동일한 모듈에서 참조되기 때문에

int my_close(int fd) { 
    return my_close(fd); 
} 

불행하게도,이 기호가 얻을 것이다 기호 스텁 대신 직접 호출을 통해 호출됩니다. main

0x100001e00 <+0>: push rbp 
0x100001e01 <+1>: mov rbp, rsp 
0x100001e04 <+4>: sub rsp, 0x20 
0x100001e08 <+8>: xor eax, eax 
0x100001e0a <+10>: mov dword ptr [rbp - 0x4], 0x0 
0x100001e11 <+17>: mov dword ptr [rbp - 0x8], edi 
0x100001e14 <+20>: mov qword ptr [rbp - 0x10], rsi 
0x100001e18 <+24>: mov edi, eax 
0x100001e1a <+26>: call 0x100001da0    ; my_close at main.m:42 
0x100001e1f <+31>: xor edi, edi 
0x100001e21 <+33>: mov dword ptr [rbp - 0x14], eax 
0x100001e24 <+36>: mov eax, edi 
0x100001e26 <+38>: add rsp, 0x20 
0x100001e2a <+42>: pop rbp 
0x100001e2b <+43>: ret 

좋아, 충분히 쉬운 수정에서이 함수를 호출 할 때 다음 어셈블리가, 난 기능이 약한 표시 어셈블러 지시어를 사용하여 잠재적 인 스택 오버 플로우에 대해 컴파일러를 종료하기 위해 weakref를 사용할 수 있습니다. 에 my_close을 변경하면 :

static int f(int) __attribute__ ((weakref ("my_close"))); 

__attribute__((weak)) 
int my_close(int fd) { 
    return f(fd); 
} 

다음 main에서 다음 어셈블리를 생성합니다 :

0x100001df0 <+0>: push rbp 
0x100001df1 <+1>: mov rbp, rsp 
0x100001df4 <+4>: sub rsp, 0x20 
0x100001df8 <+8>: xor eax, eax 
0x100001dfa <+10>: mov dword ptr [rbp - 0x4], 0x0 
0x100001e01 <+17>: mov dword ptr [rbp - 0x8], edi 
0x100001e04 <+20>: mov qword ptr [rbp - 0x10], rsi 
0x100001e08 <+24>: mov edi, eax 
0x100001e0a <+26>: call 0x100001e5e    ; symbol stub for: my_close 
0x100001e0f <+31>: xor edi, edi 
0x100001e11 <+33>: mov dword ptr [rbp - 0x14], eax 
0x100001e14 <+36>: mov eax, edi 
0x100001e16 <+38>: add rsp, 0x20 
0x100001e1a <+42>: pop rbp 
0x100001e1b <+43>: ret 

그래서 나는 여기에 부착하고있는 부분 : my_close 내부 my_close를 참조 할 때, 항상 직접 호출을 초래한다. 예를 들어 : 여기 my_close

0x100001dd0 <+0>: push rbp 
0x100001dd1 <+1>: mov rbp, rsp 
0x100001dd4 <+4>: sub rsp, 0x10 
0x100001dd8 <+8>: mov dword ptr [rbp - 0x4], edi 
0x100001ddb <+11>: mov edi, dword ptr [rbp - 0x4] 
0x100001dde <+14>: call 0x100001dd0    ; <+0> at main.m:44 
0x100001de3 <+19>: add rsp, 0x10 
0x100001de7 <+23>: pop rbp 
0x100001de8 <+24>: ret 

의 조립 내가 my_close 내에서 호출 될 때 그루터기로 취급 할 my_close에게 (내가 놓친 것을)를 사용할 수있는 어셈블러 지시어가있다인가? 그래, 내가 원본을 얻을 수 dlsym을 사용할 수 있습니다 알고 있지만, 내가 고집하고 있습니다 :]

+0

그리고 다시 함수가 static으로 선언 될 필요가 있기 때문에 그 것을 한 번에 상관없이 작동하지 않을 수 있었던 것처럼 보인다'weakref''__attribute__'에서 찾고. 나는 그래도 질문을 떠날 것이다. –

+2

그냥 생각 ... 전역 함수 포인터 형식으로'my_call' 선언 (어쩌면'volatile' 속성을 사용하여 원자와 정렬이되어 있는지 확인하는 것이 좋습니다), 심볼에 대한 모든 참조는 실제로 전역 변수 (어느 순간에 업데이트 할 수 있습니다) ....? – Myst

+1

대체 경로는 https://stackoverflow.com/a/34120249/5329717 –

답변

0

내 의견에 따라, 여기 my_call이 전역 함수 포인터 타입으로 선언 된 하나의 가능한 구현이다.

이 접근 방식은 기호에 대한 모든 참조가 실제로 언제든지 쉽게 업데이트 될 수있는 전역 변수 (함수 포인터)에 대한 참조임을 의미합니다.

extern volatile int (*my_close)(int); 

void set_my_close(int (*func)(int)); 

및 프로젝트에 (대부분 검증되지 않은)이 my_call.c을 추가합니다 :

장소이 my_close.h

#if defined(__unix__) || defined(__APPLE__) || defined(__linux__) 
#ifndef _GNU_SOURCE 
#define _GNU_SOURCE 
#endif 
#endif /* __unix__ */ 

/* Select the correct compiler builtin method. */ 
#if defined(__has_builtin) 

#if __has_builtin(__atomic_exchange_n) 
#define EXCHANGE(...) __atomic_exchange_n(__VA_ARGS__, __ATOMIC_ACQ_REL) 

#elif __has_builtin(__sync_swap) 
#define EXCHANGE(...) __sync_swap(__VA_ARGS__) 

#else 
#error Required builtin "__sync_swap" or "__atomic_exchange_n" missing from compiler. 
#endif /* defined(__has_builtin) */ 

#elif __GNUC__ > 3 
#define EXCHANGE(...) __sync_fetch_and_or(__VA_ARGS__) 

#else 
#error Required builtin "__sync_swap" or "__atomic_exchange_n" not found. 
#endif 

volatile int (*my_close)(int); 

void set_my_close(int (*func)(int)) { EXCHANGE(&my_close, func); } 

이 쉽게 동적으로 다른 기능에 my_close 및 경로를 업데이트 할 수 있습니다 .

...

(아마도 더 휴대용) C11 원자 작업을 사용하는 또 다른 옵션, 아마 필요합니다 my_close.hmy_close를 호출하는 모든 소스 파일에 포함 할 (atomic_load 있는지가 호출되어 있는지 확인합니다).

다음

가 안된 :

#include <stdatomic.h> 

extern volatile _Atomic int (*my_close)(int); 

inline void set_my_close(int (*func)(int)) { atomic_store(&my_close, func); } 

#define my_close(fd) ((atomic_load(&my_close))(fd)) 

my_close.c에서 :

my_close.h

#include "my_close.h" 

#undef my_close 

volatile _Atomic int (*my_close)(int); 

내가 실행 정도, 내 컴퓨터에 어떤 코드를 보풀하지 않았다하시기 바랍니다 이것을 개요로 만 생각하십시오.

0

dyld 가져 오기 기능의 경우 런타임에 호출 된 주소를 바꿀 수 있습니다. 다음 코드는 __DATA 세그먼트의 시작 부분에 dyld 스텁 주소 다음에 전역 변수가 오는 것에 의존합니다. 여기서 코드 스 니펫은 전역 변수 주소에서 시작하는 역방향 검색을 수행합니다.

size_t (*orgStrlenPtr)(const char *__s); 
size_t myStrlen(const char *__s) 
{ 
    return orgStrlenPtr(__s); 
} 

int main(int argc, const char * argv[]) { 

    char *ptr = &orgStrlenPtr; 
    while (*(void**)ptr != strlen) { 
     ptr--; 
    } 
    orgStrlenPtr = *(void **)ptr; 
    *(void **)ptr = myStrlen; 
}