2014-12-04 5 views
0

알려진 주소에 위치한 함수 func이 있다고 가정 해보십시오. 이 함수가 얼마나 많은 인수 또는 어떤 종류의 데이터 형식을 기대하는지에 대해서는 알지 못합니다.C에서 저수준 함수 호출?

우리는 함수가 기대하는 적절한 바이트 수에 해당하는 데이터를 포함하는 배열이 제공됩니다. 예를 들어 함수가 func(uint8_t a, uint16_t b, uint8_t c)이고 배열이 0x0A, 0x0B, 0x0C, 0x0D이고 0x0Aa이고 0x0B0Cb이고 0x0D이 값이 c 인 경우를 가정 해 봅니다.

이 배열과 함수의 주소가 주어지면 C 또는 인라인 어셈블리에서이 함수를 어떻게 호출 할 수 있습니까?

편집 :이 코드는 ARM 프로세서에서 실행될 것이라고 언급해야합니다.

+0

전혀합니다. 문제는 스택과 레지스터에 넣는 방법을 모르는 것입니다. 또는 함수에서 알 수없는 호출 규칙이 무엇이든간에. – Deduplicator

+0

당신은 함수가 취하는 인수의 개수를 알지 못한다고 말하면서 3 개의 인자, 즉 byte, short, byte를 취한다. 함수에 대한 typedef를 선언 한 다음 함수의 주소를 해당 유형의 함수에 대한 포인터로 캐스팅하고 지정한 매개 변수를 사용하여 함수를 호출 할 수 있습니다. – rcgldr

+0

이것은 배열을 설명하는 예제 함수입니다. 배열과 함수의 주소 만 있으면됩니다. 이 함수가 얼마나 많은 인수 또는 어떤 종류의 데이터 형식을 기대하는지에 대해서는 알지 못합니다. –

답변

-3

여기 내 사진입니다. 컴파일하지만 테스트하지 않았습니다.

0x12345678은 함수의 알려진 주소입니다.

이 함수는 아무 것도 반환하지 않는다고 가정합니다.

'data'var은 전달 된 데이터입니다.

'data'var은 임의의 struct {}로 대체 될 수도 있습니다.

이 함수는 단일 포인터 arg가 가리키는 주소에서 데이터를 가져 오는 방법을 알아야합니다.

void (*fun)(void*) = (void (*)(void*))(0x12345678); 

int main(int argc, char *argv[]) 
{ 
    unsigned char data[] = {1, 2, 3, 4, 5}; 

    fun(data); 
} 

=========

+1

함수가 어떤 인수를 취하는 지 알 수 없기 때문에 void 포인터를 사용하도록 지정할 수 없습니다. 컴파일러는 단순히'data'의 주소를 함수에 넘겨 주어'void *'가 취할 인수라고 가정합니다. –

+0

질문의 요점은 당신이 제어하지 않는 임의의 매개 변수 집합으로 함수에 대한 호출 시퀀스를 작성하는 방법입니다. –

4

가 할 수있는 방법이 없습니다 그 함수 호출 규칙을 모른 채. 스택에 데이터를 덤프하고 함수가이를 처리 할 것으로 기대할 수는 없습니다. __cdecl 함수 인 경우 실행 후 스택을 지워야합니다. 그렇지 않으면 손상 될 수 있습니다. __fastcall 함수 인 경우 ecx/rcxedx/rdx 레지스터에 처음 두 개의 인수가 필요합니다. (또한 플랫폼에 따라 다름)! __thall 경우에는 ecx 레지스터 (플랫폼에 따라 다름)를 통해 객체 인스턴스에 대한 포인터를 제공해야합니다.

편집 :Procedure Call Standard for the ARM architecture에 따르면, 매개 변수는 스택과 레지스터 (페이지 18, 30)를 통과 할 수있다. 따라서 위의 모든 내용이 여전히 적용됩니다.

+0

이것이 ARM 아키텍처에서 실행될 것이라는 언급을하지 못했기 때문에 x86 레지스터 정의가 적용되지 않습니다. 그러나 기본 이론은 건전해야합니다. 인수와 스택이 어떻게 관련되는지에 대한 기사를 추천 해 주시겠습니까? –

+0

수정하십시오. 이전의 언급에서 언급했듯이 이론은 여전히 ​​건전해야합니다. 나는 프로그램의 분해 작업을하고 있고 적절한 레지스터를 늘리고 수동으로 스택하는 방법을 고안하고있다.컴파일러는 어느 레지스터에 인수를 할당 할 것인가에 대해 꽤 예측 가능합니다. 그래서 거의 완료 될 수 있습니다. –

0

최근 의견을 감안할 때 함수 호출 하나당 하나의 추가 인수 (함수의 "유형")를 전달하여 수행하려는 작업을 수행 할 수 있다고 생각합니다. 예를 들어, 발생할 것의 당신이 모든 기능 유형의리스트를 만들어 가정하자 :

enum funcType { 
    V_U8_U16_U8, // Means: void func(uint8_t, uint16_t, uint8_t) 
    V_U16_U16, // Means: void func(uint16_t, uint16_t) 
    U32_U32,  // Means: uint32_t func(uint32_t) 
    ... 
} 

그런 다음 호스트 측에, 당신은 다른 정보와 함께 funcType를 전송할 수 있습니다. 목표면에서 다음과 같이해야합니다.

type = GetFunctypeFromStream(); 
switch(type) { 
    case V_U8_U16_U8: 
    { 
     void (*func)(uint8_t, uint16_t, uint8_t) = GetFuncPointerFromStream(); 
     uint8_t arg1 = GetU8ArgFromStream(); 
     uint16_t arg2 = GetU16ArgFromStream(); 
     uint8_t arg3 = GetU8ArgFromStream(); 

     func(arg1, arg2, arg3); 
     break; 
    } 
    case V_U16_U16: 
    { 
     void (*func)(uint16_t, uint16_t) = GetFuncPointerFromStream(); 
     uint16_t arg1 = GetU16ArgFromStream(); 
     uint16_t arg2 = GetU16ArgFromStream(); 

     func(arg1, arg2); 
     break; 
    } 
    case U32_U32: 
    { 
     uint32_t (*func)(uint32_t) = GetFuncPointerFromStream(); 
     uint32_t arg1 = GetU32ArgFromStream(); 

     ret = func(arg1); 
     break; 
    } 
    ... 
} 

물론 위의 내용을 모두 손으로 쓰지는 않을 것입니다. 각 사례를 생성하는 스크립트를 작성하여 해당 코드를 자동으로 생성 할 수 있습니다.또한 함수를 호출하는 것과 관련하여 실제로는 중요하지 않기 때문에 서명 된 유형과 부호없는 유형을 하나의 유형으로 병합 할 수 있습니다.

이 솔루션은 함수 유형 수가 함수 수보다 훨씬 작은 한 도움이됩니다. 모든 함수가 다른 유형이라면 기본적으로 모든 함수를 switch 문으로 사용하기 때문에 (이 함수는 피하고 싶다고 말했던 것처럼) 도움이되지 않습니다.

+0

매우 철저한 설명에 감사드립니다. 불행히도,이 접근법은 이전에 언급 한 내용보다 훨씬 좋지 않습니다. 당신이 한 일을 따르면 꽤 긴 switch 문을 만들어야 할 것입니다. 당신이 이미 접했을 때 나는 피하려고합니다. 물론 각 함수에 대해 하나씩 작성하는 것보다 몇 가지 사례를 줄일 수 있지만 프로세스는 여전히 엄격하고 스크립트를 정확하게 생성해야합니다. @ Ari0nhh가 제안했듯이, 원래 생각 하듯이 스택을 조작하여 원하는 것을 얻을 수 있습니다. 나는 곧 후속 조치를 게시 할 것이다. –

0

문제점을 발견하고 시간을주었습니다. & 생각을 들었습니다. 질문을 반복하겠습니다. (임의의) 주소에서 함수를 호출 할 수 있기를 원하고 임의의 유형 및 길이의 인수 목록을 전달하려고합니다. 우리가 주소와 매개 변수 배열에 대한 포인터를 제공하는 "call_it"이라는 함수를 정의하자. 이 함수는 스택 관리 및 호출을 수행해야합니다. "call_it"을 순수한 C 함수로 사용할 수 있습니까? C에서 스택을 조작 할 수 없기 때문에 대답은 "아니오"입니다. 특히 호출 후 밀어 넣기 명령어와 스택 정리 명령어를 동적으로 생성 할 수 없습니다.

그러나 밀어 넣기 및 정리를 위해 어셈블러를 간단하게 종료 할 수 있습니다. 다른 답변의 대부분은/토론 참가자는 관련 측면과 예제를했다, 그래서 나는 단지 의사 코드 솔루션/예를 제공합니다

typedef struct PRM {int type; void *arg;}; 
#define T_INT 1 

int call_it(int (*address)(), struct PRM *prms, int n_prms) 
{ 
    int nbytes=0; 
    prms += n_prms-1; 
    for (;n_prms>0; n_prms--, prms--) { 
     switch (prms->type) { 
      case T_INT: 
       __asm mov ax,prms.arg 
       __asm push ax 
       nbytes += sizeof(int); 
       break; 
     } 
    } 
    address(); 
    __asm add sp, nbytes; 
} 

가 (미안, 난 단지 X86 말)