2010-08-06 1 views
3

Windows 실행 파일을 리버스 엔지니어링하는 중입니다. 내가 실행 파일 (다른 스레드, 자신의 스택)에 주입 일부 코드에서 사용하고자하는 클래스를 발견. 메서드 주소와 멤버 변수 구조가 주어지면 어떻게 그런 클래스를 선언 할 것인가?C++에서 문서화되지 않은 클래스 사용

예를 들어, foo라는 클래스를 찾았고, 생성자는 @ 0x4012D30이고 doTheMario @ 40125D4라는 함수가 있다고 가정 해 봅시다. 또한 개인 데이터의 3 가지 DWORD를 보유한다는 것도 알고 있습니다.

이제
class GuessedFoo { 
    private: 
     int bar; 
     char *cafebabe; 
     float deadbeef; 
    public: 
     GuessedFoo(int a, int b); 
     void doTheMario(); 
}; 

, 이것은 완벽하게 멋쟁이 클래스입니다,하지만 지금은 컴파일러/링커에 클래스 메소드를 바인딩 할 수있는 방법이있다 : 방법 모두 _thiscalls이기 때문에, 그래서 내 코드에서 같은 클래스를 선언 내가 말한 두 이전 주소? 물론 나는 asm 래퍼를 써서 stdcall을 thiscall로 바꾸고 클래스의 대신에 구조체를 사용하는 모든 메소드를 사용할 수 있지만 더 좋은 방법이 있어야한다.

현재 gcc/g ++를 사용하고 있지만 VC++로 전환 할 수 있습니다 (gcc의 인라인 asm이 나에게 두통을 주므로).

+0

만약 메모리가 제공된다면 GCC에서 인텔 문법을'-intel_syntax noprefix'와 함께 사용할 수 있습니다 ... –

+0

네,하지만 puke-like GAS 문법은 fiddle C/C++ 코드의 스택 변수와 인수를 인라인 어셈블리와 연결할 때 유용합니다. VC++의'__asm ​​{}'블록을 사용하면 훨씬 쉽습니다. – Serge

답변

4

클래스에 vtable이없는 경우 원칙적으로 모든 함수 호출이 적절한 실제 구현을 호출하는 코드를 직접 작성할 수 있습니다. 실제 구현에 어셈블리 점프 명령어가 포함 된 naked functions과 같은 멤버 함수를 사용하여이 작업을 수행 할 수 있습니다.

클래스에 vtable이있는 경우 상황이 훨씬 더 복잡해질 수 있습니다. vtable을 함수 포인터의 구조체로 명시 적으로 만들고 함수 스텁을 함수 포인터로 호출해야 할 가능성이 높습니다. 이것은 더 복잡한 심 함수를 의미합니다. 점프가있는 단순한 알몸 기능만으로는 충분하지 않을 수도 있으며 실제 기능을 사용하는 것이 더 나을 수도 있습니다. 그러나 win32의 멤버 함수는 different calling convention을 사용합니다. 이는 일반 멤버 함수 호출이 작동하지 않는다는 것을 의미합니다. 은 포인터를 멤버 함수로 생성하는 데 도움을받을 수 있지만 해당 요소에 rather strange structure이 있다는 것을 염두에 두십시오.이 포인터를 vtable 포인터와 동일한 표현을 가진 무언가와 일치시켜야합니다. 행운을 빕니다!

+0

알몸 함수가 트릭을 수행합니다. 원래 코드의 대부분의 클래스는 상속되지 않으므로 가상 함수가 없으므로 vtable이 없습니다. Muchas gracias! – Serge

0

나는 당신을 올바르게 이해하고 있다고 확신하지는 못하지만 어쨌든 나는 "손을 놓는"방법에 대한 가장 쉬운 방법은 함수 포인터를 사용하는 것이라고 생각한다.

+0

네,하지만이 사람들이 이쪽입니다. 나는 그들 모두를 asm 래퍼 (stdcall)로 변환하는 것 (첫 번째 인자를 펑플하고 ecx로 이동하여 함수를 호출하는 것)을하고 싶지 않다. 나는 GuessedFoo f = new GuessedFoo (42, 18)를 선호한다. GuessedFoo_GuessedFoo ((void *) data, 42, 18) 대신; – Serge

0

C++는 모든 종류의 이진 인터페이스를 정의하지 않으므로 C++ 클래스에 대해 모든 종류의 동적 바인딩을 구현할 수 있습니다.

당신이 할 수있는 최선의 방법은 두 개의 구조체를 선언하는 것입니다. 하나는 각 메소드에 대한 c 함수 typedef를 포함하고 다른 하나는 클래스 데이터 레이아웃을 반영합니다.

물론 클래스 메서드의 __thiscall이 ecs 레지스터를 통해 'this'를 전달하기 때문에 실제로 동일한 효과를 갖는 명시 적 C 함수 선언을 만들 수 있다고 생각하지 않습니다. 따라서 모든 함수를 수행해야 할 수도 있습니다. 어셈블리에서 작성한 사용자 지정 "CallThisCallMethodWithParameters"를 통해 호출합니다.

+1

C++의 바이너리 인터페이스는 C 또는 다른 언어와 마찬가지로 정의되며 플랫폼에 따라 다르며 플랫폼 설명서에 정의되어 있습니다. C++을위한 동적 바인딩을 확실히 구현할 수 있습니다. 매개 변수 등에서 템플릿 유형을 처리해야 할 때 약간 복잡하기 때문에 전체 작업을 수행하지 않는 완전한 동적 바인딩 시스템은 거의 없습니다 (있는 경우). 결국 C++ 컴파일러. – bdonlan

1

당신은 여기에서 리버스 엔지니어링을하므로 기존 코드와 상호 작용할 때 더 낮아질 수 밖에 없습니다.

이 함수는 순수한 어셈블리 코드를 사용하여 호출합니다.
EXE의 기본 주소가 고정되어 있으면 더 쉽습니다.
예제 코드 :

void main() 
{ 
    int bar = 5; 
    int * cafebabe = &bar; 
    __asm 
    { 
     push [bar]; 
     push [cafebabe]; 
     mov eax, 123456; // address of the function 
     call eax; 
    } 
} 

단순히이 기능이있는 당신이 인수를 추진해야 할 주문보고 원래의 코드에 의해 호출되고 있는지 확인합니다. 레지스터를 통해 전달해야하는 인수가 있음을 잊지 마십시오!

+1

예, "this"는 개체 메서드를 호출 할 때 ecx에 의해 전달됩니다. 어셈블리와 C를 작성하여 원본 코드를 사용할 수있는 즐거운 환경을 만들 수 있지만 12 개의 클래스가 각각 12 개있을 때 지루해집니다. 어쨌든 고마워! – Serge