본문 바로가기

개인 공부/리버싱

Reverse Engineering-004(C++)

 C++ 분서의 난해함

  • C 코드의 경우 함수, 조건문, 반복문 등 일정한 규칙이 있다(절차지향)
  • C++ 에서는 클래스(멤버 변수, 멤버 함수, 생성자, 소멸자), 캡슐화, 상속등이 추가(객체지향)
  • C++와 어셈블리는 1:1 매칭이 되지 않으므로 직관적으로 파악하기 쉽지 않다
  • 가장 필요한거는 리버서의 풍부한 코딩 경험!!!

분석 할 간단한 C++ 코드

#include <iostream>
#include "windows.h"
#include "tchar.h"
// namespace : 함수나 구조체 혹은 변수 이름등의 소속을 정해주는 것
using namespace std; // std::cout, std::cin 등을 해당 파일에서 std:: 때고 사용! 

class Employee {	// 직원의 정보에 대한 C++ 클래스
public :	// Public : 클래스 외부에서도 접근 가능!!
	int number;	// 직원의 번호
	char name[128];	// 직원의 이름
	long pay;	// 직원의 월급
	void ShowData();	// 직원의 데이터를 출력해주는 함수 
	void Test();	// Test 함수
};

void Employee::ShowData() {	
	cout << "Employee Number : " << number << endl;
	cout << "Employee Name :" << name << endl;
	cout << "Employee Pay : " <<  pay << endl;
	Test();

	return;
}

void Employee::Test() {
	cout << "TEST Function!!!" << endl;
	return;
}

int main() {
	Employee ename;

	cout << "Size : " << sizeof(Employee) << endl;
	ename.number = 0x0101;
	_tcscpy(ename.name, _T("EmName"));
    // _tcspy(buf1, buf2) : buf2를 buf1에 덮어쓴다 -> 직원의 이름 설정 
	ename.pay = 0x0100;

	ename.ShowData();

	return 0;
}

0x401000 번호에서 시작하는 것은 ShowData 함수라고 추측

ShowData() 추측

  • 0x401004는 ShowData()에 [ cout << "Employee Number : " << number << endl; ] 라고 추측
    • [ebp-4] = ecx  --> eax = [ebp-4] --> ecx = &eax 순서로 진행되는 것을 확인
    • ecx 레지스터에 저장된 0019FEA4를 덤프로 들어가서 확인해 본 결과 0101이 저장된것을 확인 (회원번호 0101)
    • 0x403150에 "Employee Number : " 출력 되는 것을 확인

  • 0x401038은 ShowData()에 [cout << "Employee Name :" << name << endl;] 라고 추측
    • eax = [ebp-4] -> eax + 4 -> push eax  순서로 진행 되는 것을 확인
    • 0x19FEA8에 사용자 이름이 저장, EAX에 사용자이름이 저장되는 것을 확인
    • 0x403164에 "Employee Name : " 출력되는 것을 확인

※ 한글은 깨지고 영어로 작성시 0x19FEA8에 회원 명이 저장되는 것을 확인


  • 0x401075는 ShowData()에 [ cout << "Employee Pay : " <<  pay << endl; ] 라고 추측
    • edx = [ebp-4] -> eax = [edx+84] -> push eax 순서로 진행 되는 것을 확인
    • edx = [ebp-4] 실행 후 edx에 값(0x19FEA4)에  84를 더한 0x19FF28 주소를 덤프에 들어가서 확인
    • 0x19FF28에 0100이 저장된 것을 확인, 사용자 월급인 것을 확인
    • 0x403174에 "Employee Pay : " 출력되는 것을 확인

  • 마지막으로 0x4010A2에서 0x401080주소의  함수가 호출 되는 것을 확인

--> 0x401000은 ShowData()인것을 확인

0x403150 ~ 0x403174


0x401080 번호로 시작하는 것은 Test()함수라고 추측

0x401080

  • 가장 의심스러운 0x4010BC에서 0x403184를 호출하는 것을 확인
  • 0x403184를 덤프로 확인 한 결과  덤프에 "Test Function!!!"이 저장된 것을 확인

--> 0x401080은 Test()함수 인것을 확인

0x403184


0x4010E0이 메인함수라고 추측

0x4010E0

  • 0x4010F3에서 0x403198을 push하는 것을 확인(0x403198에는 Size : 가 들어있다)
  • [ebp-88] = 0x101, [ebp-84]에는 사용자이름 저장, [ebp-4] = 0x100
  • 0x40114E에는 0x401000을 호출하는 것을 확인
  • 0x401000보다 0x4010E0이 먼저 시작되고 이 함수에서 ShowData를 호출하는 것을 확인

--> 0x4010E0은 main함수 인것을 확인

EmployeeClass.cpp


객체의 동적 할당과 해제 분석

 

#include <iostream>
#include "windows.h"
#include "tchar.h"
using namespace std;

class Employee {
public:
	int number;
	char name[128];
	long pay;
	void ShowData();
	void Test();
};

void Employee::ShowData() {
	cout << "Employee Number : " << number << endl;
	cout << "Employee Name :" << name << endl;
	cout << "Employee Pay : " << pay << endl;
	Test();

	return;
}

void Employee::Test() {
	cout << "TEST Function!!!" << endl;
	return;
}

int main() {
	Employee *jisu;
	jisu = new Employee;	// 객체 생성
	cout << "Size : " << sizeof(Employee) << endl;

	// -> : 주소(포인터)를 통해 접근
	jisu->number = 0x1111;	
	_tcscpy(jisu->name, _T("JeonJisu"));
	jisu->pay = 0x0100;
	jisu->ShowData();
	delete jisu;	// 객체 해제
	return 0;
}

이전 코드에서 main함수에서 객체 할당하는 것만 수정!

이전에 한글은 깨지는 것을 확인해서 회원의 이름은 영어로 수정!

0x4010E0 main()

이전 코드와 달라진 점은 메모리나 스택에 직접 값을 넣지 않고 new로 객체를 생성(heap 메모리 할당)해서 값을 넣는다

0x4010EB에 new 객체 할당하는 것을 확인

0x40112D에 [edx] = 0x1111에 주소로 값을 넣는 것을 확인 할 수 있다

([register] = 값을 넣는 것은 register 주소에 값을 넣는다는 의미) 


 

'개인 공부 > 리버싱' 카테고리의 다른 글

Reverse Engineering-006 PE-01  (0) 2023.04.17
Reverse Engineering-005  (0) 2023.04.13
Reverse Engineering-003(구조체 & API)  (0) 2023.04.12
Reverse Engineering-002(문법)  (0) 2023.04.10
Reverse Engineering-001(Assembly)  (0) 2023.04.09