2008.09.01 01:00

구조체 확인하기

리버싱을 하면서 함수를 복구해야만 하는 경우가 있습니다.
물론 숙련된 리버서들은 보면 바로 나오죠..
하지만 초보자들에게는 쉬운 일이 아닙니다.
그래서 간단한(?) 프로그램을 가지고 리버싱을 해 보려고 합니다.

소스파일은 참고문헌 p.240 "중첩 구조체"를 참고했습니다.
visual studio 6.0 debug 버전으로 컴파일 하였습니다.

401010    PUSH EBP                 
401011    MOV EBP,ESP            // EBP = ESP = 0012FF80
401013    SUB ESP,48
401016    PUSH EBX
401017    PUSH ESI
401018    PUSH EDI
401019    LEA EDI,DWORD PTR SS:[EBP-48]
40101C    MOV ECX,12
401021    MOV EAX,CCCCCCCC
401026    REP STOS DWORD PTR ES:[EDI]

// malloc 함수를 사용하여 메모리를 할당합니다.
// push 8은 함수를 위한 argument가 되겠네요
401028    PUSH 8
40102A    CALL DoubleSt.malloc                      // EAX = 00430190
40102F    ADD ESP,4
401032    MOV DWORD PTR SS:[EBP-4],EAX    // [EBP-4] == [0012FF7C] = 00430190 값 저장
     EAX는 주소값을 가지고 있다. malloc 함수의 결과값을 가지고 있기 때문이다.
    [EBP-4] 역시 주소값이고, 이 값은 메모리 할당이 이루어진 곳을 가리키는 값이다.
    즉 지역번수 중 한개는 포인터 변수이다.
    grade *student;
    student = (grade *)malloc( sizeof(grade) );

401035    PUSH 8
401037    CALL DoubleSt.malloc        // EAX = 00430150
40103C    ADD ESP,4
40103F    MOV ECX,DWORD PTR SS:[EBP-4]    // ECX = 00430190
401042    MOV DWORD PTR DS:[ECX],EAX  
[EBP-4]에는 첫번째 메모리 할당 주소가 저장되어 있다.
    그 주소에 이번에 새로 할당한 메모리 주소를 다시 할당하고 있다.
    student->pri = (struct privates *)malloc( sizeof(struct privates) );

401044    PUSH 0C
401046    CALL DoubleSt.malloc        // EAX = 00430110
40104B    ADD ESP,4
40104E    MOV EDX,DWORD PTR SS:[EBP-4]    // [0012FF7C] = 00430190
401051    MOV DWORD PTR DS:[EDX+4],EAX    // [00430194] = 00430110
    student->score = (struct scores *)malloc( sizeof(struct scores) );

401054    MOV EAX,DWORD PTR SS:[EBP-4]    // EAX = 00430190
401057    MOV ECX,DWORD PTR DS:[EAX]    // ECX = [00430190] == 00430150
401059    MOV DWORD PTR DS:[ECX],OFFSET DoubleSt.??_C@_0BF@CBAC@Test?5For?5DoubleStruct?$AA@
student->pri->name = "Test For DoubleStruct";
    00420040 번지는 "Test For DoubleStruct"이라는 string값이 저장되어 있다.

// student->pri->age = 2008;
40105F    MOV EDX,DWORD PTR SS:[EBP-4]
401062    MOV EAX,DWORD PTR DS:[EDX]
401064    MOV DWORD PTR DS:[EAX+4],7D8

// student->score->eng = 80;
40106B    MOV ECX,DWORD PTR SS:[EBP-4]
40106E    MOV EDX,DWORD PTR DS:[ECX+4]
401071    MOV DWORD PTR DS:[EDX+4],50

// student->score->kor = 99;
401078    MOV EAX,DWORD PTR SS:[EBP-4]
40107B    MOV ECX,DWORD PTR DS:[EAX+4]
40107E    MOV DWORD PTR DS:[ECX],63
   
// student->score->mat = 95;
401084    MOV EDX,DWORD PTR SS:[EBP-4]
401087    MOV EAX,DWORD PTR DS:[EDX+4]
40108A    MOV DWORD PTR DS:[EAX+8],5F

// total = student->score->eng + student->score->kor + student->score->mat;
// 2번째 지역변수에 결과를 저장한다.
401091    MOV ECX,DWORD PTR SS:[EBP-4]
401094    MOV EDX,DWORD PTR DS:[ECX+4]
401097    MOV EAX,DWORD PTR SS:[EBP-4]
40109A    MOV ECX,DWORD PTR DS:[EAX+4]
40109D    MOV EDX,DWORD PTR DS:[EDX+4]
4010A0    ADD EDX,DWORD PTR DS:[ECX]
4010A2    MOV EAX,DWORD PTR SS:[EBP-4]
4010A5    MOV ECX,DWORD PTR DS:[EAX+4]
4010A8    ADD EDX,DWORD PTR DS:[ECX+8]
4010AB    MOV DWORD PTR SS:[EBP-8],EDX
   
4010AE    MOV EDX,DWORD PTR SS:[EBP-4]
4010B1    MOV EAX,DWORD PTR DS:[EDX]
4010B3    MOV ECX,DWORD PTR DS:[EAX]
4010B5    PUSH ECX
4010B6    PUSH OFFSET DoubleSt.??_C@_08EBKD@name?7?$CFs?6?$AA@    // 00420040
4010BB    CALL DoubleSt.printf
4010C0    ADD ESP,8

좀 더 쉬운 이해를 돕기 위해서 메모리를 살펴보면 다음과 같습니다.
(무척 엉성하지만 목적만 생각하세요 ^^;)
사용자 삽입 이미지


잠깐 정리해 보면
먼저 포인터 변수를 정의 합니다.
그 포인트 변수가 구조체로 구성되어 있고, 그 멤버는 2개 입니다.
형식은 다음과 같을 것입니다.
struct local_var {
    struct 1st *first;
    struct 2nd *second;
};

첫 번째 멤버는 구조체로 되어 있습니다.
형식은 다음과 같을 것입니다.
struct 1st {
    char *str;             // 다른 주소값이 저장되어 있으며, 그 주소값에는 문자열이 저장되어 있다.
    int a;
};

두 번째 멤버 역시 구조체로 되어 있습니다.
형식은 다음과 같을 것입니다.
struct 2nd {
    int a;
    int b;
    int c;
};


참고문헌
다시 체계적으로 배우는 C언어 포인터
신고
트랙백이 없고 Comment 2


티스토리 툴바