AES 소스

AES 암호화 방식은 예전에 DES 암호화 방식을 보안한 방식입니다. 흔히 블록 암호화 방식을 쓰고 있는데
16바이트 특정 키와 블록 할 바이트 영역(16,24,32) 를 설정한뒤 암호화 하는 방식입니다.

이 알고리즘은 오픈 소스이므로 누구나 갖다 쓸 수 있습니다.

코드 사용법은 이러합니다

#define Key "1234567890123456"

이렇게 16바이트 키를 설정한뒤(테스트 해본 결과 굳이 16바이트를 맞춰 주지 않아도 됩니다)

////////////////////////////슈도 코드///////////////////////////////////////////////////////
char *szHeader = new char[1024000]; //1mb정도 설정
//visual c++에서는 char buf[1024000];이런식으로 크게 버퍼를 할당하면 런타임시 에러가 납니다.
//유닉스에서는 그렇지 않다고 하네요...그래서 위처럼 동적할당으로 잡아줘야 합니다 ㅠ_ㅠ
 
hFile_Header=CreateFile(m_szFilePath,GENERIC_READ,0,
        NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if(hFile_Header != INVALID_HANDLE_VALUE){
  ReadFile(hFile_Header,szHeader,HEADER_SIZE_OFFSET,&dwRead_Header,NULL);
  CloseHandle(hFile_Header);
 }
 CRijndael oRijndael;                                               //AES 클래스 객체 할당
oRijndael.MakeKey(Key,CRijndael::sm_chain0,16,16);
oRijndael.ResetChain();
memcpy(szHeader_In,szHeader,HEADER_SIZE_OFFSET);
oRijndael.Decrypt(szHeader_In,szHeader_Out,Size,CRijndael::CBC);

여기서는 szHeader 버퍼에는 특정 파일을 읽었을때의 값입니다
Decrypt 할때 주의점은 세번째 아규먼트의 Size값이 MakeKey에서 할당한 4번째 인자 값과
바이트 수가 일치 하여야지 블록 암호화가 이루어 집니다.


가령 위에서는 16으로 설정되어 있으면 16배수로 블록사이즈를 잡아줘야 합니다.
또한 어떤것은 512바이트 마다 키값을 재할당하여 encrypt한 경우도 있으니 그 바이트 영역마다
키값을 설정하여 decrypt를 수행해야 합니다.
PS. AES 암호화 소스코드를 첨부 파일로 올려 놓습니다.(사실 제가 필요할때마다 갖다쓰기 위해서 ...-_-;)Rinjdael.zip

by 홍텐 | 2008/07/29 16:51 | c++ | 트랙백

How to MFC Reverse Engineering

비도오고 그냥 즉흥적으로 쓴글이므로 양해를 바랍니다...
물론 오덕후급의 리버서들에게는 이미 100년전에 알고 있거나 지루한 애기입니다.
그냥 그런 애기 입니다.

MFC 프로그램에 대한 리버싱

mfc 를 리버싱 하기란 어떻게 보면 간단하면서 어려운 것이다.
일단 왜냐면 첫째로 mfc함수가 wrapper함수 라는 것이다.
API와는 다른것이다. API경우 특정 함수 콜부분에 콜을 하거나..(절차지향적 프로그래밍 기법을 말한다)
물론 윈도우프로그래밍은 항상 메시지에 의존한 프로그래밍 기법을 이용하여서
절자지향적인 리버스와는 그 본질 부터가 다르다.
하지만 정확한 지점의 부분 가령 사용자로 부터 어떤 요청이 이루어지면
그요청이 이루어지는 부분은 한 부분씩 이루어 진다. 하지만 이 한부분을 찾기가 애매하다.

기본적으로 디버거로  mfc류의 프로그램을 열면 대체로 pdb(심볼을 의미)를 이용하여 기본적인 함수 오버라이드에 대한
함수 이름을 출력해준다. 하지만 프로그래머가 기존의 오버라이드 함수를 쓰는 경우도 있지만
대부분 새롭게 정의한 클래스에서 오버라이드를 한다 .이는 디버거가 제대로 함수 네임을 들고 오지 못한다.

여기서 간단한 센스로 리버싱을 진행해야한다.
가령 지금 생각나는 간단한 프로그램을 생각해보자
프로그램에서 어떤 트레이의 메뉴중 사용자 정보를 클릭했다고 가정해보자.

그리고 그 보여주는 부분에는 사용자의 정보라던지가 출력된다.여기서 리버서는
간단히 출력되는 부분을 바꿔보고 싶다고 생각해보자.


먼저 어떤 함수를 breakpoint를 걸며 추적을 할것인가이다..
물론 메뉴에서 클릭을 한 행위는 윈도우에서 OnCommand라는 함수로써 오버라이드 함으로써 제공 되고있다.

하지만 수많은 클래스중 특히 프로그래머가 정의해놓은 클래스의 OnCommand의 이벤트를 찾기란 불가능하다
여기서 한가지 팁이 있다. C++의 상속성의 특징을 이용하는 것이다.

즉 여기서 팝업되는 화면의 기능은 CWnd(윈도우에 관련된 기능) 등을 정의한 클래스인데 주로 여기서의 함수를
오버라이딩을 하여 프로그래머의 자신의 클래스에서 함수를 오버라이딩해서 땡겨 쓴다.
그렇다면 결국 프로그래머가 정의한 함수를 찾지 못하더라도 디어셈블러에서 보여주는 CWnd의 OnCommand의 함수를
먼저 호출한다는 애기이고 이 말 즉슨 CWnd OnCommand의 함수 호출은 프로그래머가 오버라이딩한 함수를 호출한다는
애기가 된다.
기본적으로 mfc가 정의하는 클래스들은 이렇다.(상속순으로 나열...)
CObject //거의 모든 MFC 클래스의 기반 클래스
CCmdType //이벤트를 받는 기능
CWinAPP //프로그램을 구동시키는 기능
CDocument // 데이터를 저장하고 처리하는 기능
CWnd //윈도우에 관련된 기능(눈에 보이는 오브젝트)
CFrameWnd  //윈도우 프레임(외곽)을 관리하는 기능
CView //데이터를 보여주는 기능

물론 OnCommand를 브레이크 포인트 걸어봤자 결국에는 윈도우 함수들이 주루륵 호출 될것이다 이것은 역시 C++의
특징이다. 즉 그 이벤트에 대한 처리루틴들만이 우리는 trace하게 될것이다. 이것은 우리가 의도한 바는 아니다.

결국 거기서 데이터를 조작하건 사용자의 컨트롤을 제한하던 그 특정 처리를 위한 호출을 찾아야 한다.
그건 결국 경험에 의해서 이루어 지는데 다음과 같은 프로그램이 있다고 보자.
화면에서 보듯이 특정 기준점에 의해서 edit박스의 컨트롤을 활성화 하거나 비활성하는 기능이다.
우린 그쪽 위치에서 trace를 하기를 원한다.

위의 그림에서 기혼을 체크하면 밑의 배우자 정보의 오브젝트들이 활성화 되며 해제하면 비활성화 된다.


위의 그림에서 어떤 함수를 브레이크를 걸지를 알 수 있겠는가?
위의 그림의 루틴은 다음과 같이 작성 되어 집니다.

void CProfileDlg::OnCheck1()
{
 // TODO: Add your control notification handler code here
UpdateData(TRUE); //UpdateData 의 인자값을 TRUE로 주면 사용자 컨트롤로 값이 멤버변수로  
       //UpdateData 의 인자값을 FALSE로 주면 Value형 멤버 변수에 설정 되어 있는 값이 컨트롤 전송

 m_ctrName.EnableWindow(m_bMarried);
 m_ctrlAge.EnableWindow(m_bMarried);
}

위의 코드는 디어셈블에서 찾기는 사막에서 바늘정도의 수준입니다.(조금 덩치큰 프로그램에서 혹은 그렇지 않더라도
mfc가 기본적으로 함수를 정의하는 코드를 비교 해봤을때..)
 물론 엄청난 시력의 눈을 가진 리버서에게는 소용 없는 일인가요 ? :(

이는 어떻게 보면 CWnd함수중 어떤 기능을(함수)를 쓰는가에 초점을 맞춰진다.물론 정통한 C++프로그래머는
분명 바로 눈치를 채게된다. EnableWindow함수를 썻다는 것에 대하여...물론 다른 함수들도 있을수 도 있다
하지만 이부분은 분명 리버서의 재량이거나 혹은 경험에 의해서 컨트롤 되어짐을 명심해야한다.

이 함수주소를 찾아서 breakpoint를 걸게 된다면 우린 우리가 원하는 루틴속에 빨려 들어갈수 있다.


PS.좀더 Row한 흐름속에 명백히 그것을 찾을려면 API를 줄줄 익히고 있으면 된다.
혹은 윈도우의 콜체인을 안다면 그것은 더이상 문제거리가 되지 않는다. mfc의 수많은 콜 처리 중에
결국 호출되는 함수는 같은것이니깐...하지만 이것은 별로인걸라 생각이 든다. 
다만 하나의 진실을 보는 방법은 수만가지일 뿐이라고 생각하네요.

커널레벨로 내려가기위해서 eax에 enableWindow 함수를 호출하기위한 인덱스값이 0x113f로군요

 Sysenter를 이용하여 커널과 통신을 하게 됩니다..

이상 비오는날 잡설이였습니다....~_~(글의내용은 다소 두서가 없지만 c++에 관한 디어셈 코드 복원 시도중이라 할까요 -_-)
좀더 다른 방법이나 괜찬은 방법있으시면 저한테 가르침을 주소서~

by 홍텐 | 2008/07/20 16:43 | Reverse | 트랙백 | 핑백(1) | 덧글(2)

[열혈강의c++]8장 상속과 다형성

음...C++에서 중요한건 클래스의 확장성을 고려해서 만들어야 된다..
이럴려면 제목처럼 상속과 다형성에 대해서 알아봐야하는데 ...밑에 그림을 보자.

저기서 보면 간단한 클래스를 상속의 개념을 덧붙여 그리고 있다
어떠한 문제냐면 간단히 Department라는 클래스가 일용직이든 고용직이든 모든 기능을
수행하는 클래스이고 일용직이나 고용직 클래스는 그것을 상속하고 있다
하지만 회사가 커져버려서 판매직이라던지 마케팅 등등 여러 부서가 만들어지고
클래스를 확장을 해야한다 하지만 위처럼 구현된다면 부서가 만들어 질때마다
Department class를 변경해야하는 수고스러움이 있다 그래서
가령 일용직이나 고용직의 공통된 분모를 뽑아 Employee라는 클래스를 만들고
이 클래스는 두개의 고용직을 상속당하는 형태이고 이 Emplyee클래스는
Department에 상속이 되어진다...
그리고 객체를 만듬에 있어서 포인터 값으로(참조...)형태를 만든다 코드는 아래와 같다..
#include <iostream>

using std::cout;
using std::endl;

class Employee
{
protected:
 char name[20];
public:
 Employee(char *_name);
 const char *GetName();

};
Employee::Employee(char *_name)
{
 strcpy(name,_name);
}
const char *Employee::GetName()
{
 return name;
}
/* Permanet class 급여관리 */
class Permanent:public Employee
{
private:
 int salary;
public:
 Permanent(char *_name,int sal);
 int GetPay();
};

Permanent::Permanent(char *_name,int sal)
: Employee(_name)
{
 salary=sal;
}
int Permanent::GetPay()
{
 return salary;
}
/* Tmeporary class */
class Temporary : public Employee
{
private:
 int time;
 int pay;
public:
 Temporary(char *_name,int _time,int _pay);
 int GetPay();
};
Temporary::Temporary(char *_name,int _time,int _pay)
: Employee(_name)
{
 time = _time;
 pay = _pay;
}
int Temporary::GetPay()
{
 return time*pay;
}
class Department
{
private:
 Employee *empList[10];
 int index;
public:
 Department():index(0){};
 void AddEmployee(Employee *emp);
 void ShowList();
};
void Department::AddEmployee(Employee *emp)
{
 empList[index++]=emp;
}
void Department::ShowList()
{
 for(int i=0; i<index ;i++){
  cout<<"name : "<<empList[i]->GetName()<<endl;
  cout<<"sal : "<<empList[i]->GetPay()<<endl;//error
  cout<<endl;
 }
}

int main()
{
 Department department;

 department.AddEmployee(new Permanent("KIM",1000));
 department.AddEmployee(new Permanent("LEE",1500));
 department.AddEmployee(new Temporary("HAN",10,200));
 department.AddEmployee(new Temporary("JANG",12,1000));

 department.ShowList();
 return 0;
}
소스코드중 cout<<"sal : "<<empList[i]->GetPay()<<endl;//error
여기 부분은 에러가 된다 이유는 이 empList라는 배열은 employee클래스의 포인터들을 담고있다
이 employee클래스의 포인터들은 결과적으로 일용직,고용직의 클래스들을 포함하는 형태(맨위 그림참조)
이므로 멤버함수를 쓸수 있지 않을까?라고 하지만...
이것은 8장 앞에서 애기 했듯이 상속하는 클래스는 결과적으로 상속된 모든 멤버들을 가져오므로
객체크기를 비교했을때 제일 나중에 상속 받는 클래스는 크게 된다.
이때의 과정은 간단히 말하면
A->B->C (화살표는 상속되는 순서)
이것은 메모리상으로 A가 가장 작은 녀석이고 B가 그담 C가 젤크다...
클래스를 포인터로 했을때 접근을 보자면
C의 클래스 포인터는 A,B,C의 멤버함수를 쓸수 있고 B의 클래스 포인터는 A,B의 멤버함수를 쓸수 있으며
A의 클래스 포인터는 자신의 멤버함수만을 쓸수 밖에 없어서
empList[i]->GetPay()는 에러가 나게된다..
이에 해결책은 다음 시간에...~_~

by 홍텐 | 2008/04/24 00:48 | c++ | 트랙백 | 덧글(2)

[열혈강의c++]6장 static멤버와 const멤버

const맴버

const double PI=3.14;
PI=3.1415;//compile error

const int val;
val =20; //compile error

int n =10;
const int *pN=&n;
*pN=20; //compile error
이경우는 pn포인터가 가리키는 n값이 상수화된것임

int n1=10;
int n2=20;
int *const pN=&n1;
*pN=20;
pn=&n2; //compile error
이경우는 pn포인터(주소값)이 상수화된거임..

그렇담 c++에서는 어떻게 될까?

가령
class A
const int a;
public:
    void test(int _a)
    {
        a=_a;
    }

이경우에서 main에서 객체를 생성했다고 가정하면
일단 객체를 생성할때 맴버들에 대한 메모리를 구성해준다..(스택작업)
이때 const선언된 녀석은 쓰레기값이 초기화 되므로 컴파일단에 에러가 난다

이럴때는 void test(int _a):a(_a)
이런식으로 해주면 해결 이건 걍 const쓸때 초기화 하고 싶을때 위와같이
쓰면 된다...그리공...함수의 const
c++에서는 함수 const할때 중간에 선언한다 이런식으로
void test(int _a) cont 이렇게 하면 함수가 상수화 된것이다...

그런데....두가지 유의사항이 있다
첫번째는 저렇게 상수화된 함수에서 멤버 변수를 조작하면
컴파일 에러가 나는것과

void test(int _a) const
{
    show();
}
void show()
{
    cout<<"babo"<<endl;
}
이렇게 하면 에러일까 아닐까?
(응 ? 멤버변수도 안건드리는데?)
그래도 컴파일 에러이다...왜냐면
test함수에서 show를 부를때..컴파일단에서는
어떻게 체크하냐면 show라는 함수가 const선언 되었냐 안되었냐를 판단한다..
즉 show란 함수 안에서 멤버변수를 조작체크하는게 아니라
만약 show란 함수가 const되있다면이라는 식이다...
위를 컴파일 단에서 고칠려면
void show() const 이렇게 하면 된다는 뜻이다...

static 일반적으로 사용할땐
지역변수를 전역으로 만들때 사용한다...
주로 이런식으로 씀
class AAA
static int a=1;
어쩌고 저쩌고
int AAA:a=1;  //static변수 초기화...

여기서 클래스내에서 static을 선언했다면 객체 생성시 static변수가 할당되므로
이렇게 클래스 외부에서 초기화를 한다는 의미는
static특성상 main함수 호출이전에 메모리에 초기화 한다는 의미이다..

새로운 키워드 explicit,mutable
explicit는  명시적 호출만 허용한다는 의미이다

일반적으로 객체를 생성할때
AAA a1=10; //이것은 C스타일이다
AAA a1(10); //이것은 C++스타일이다
C++스타일은 묵시적으로 C스타일을 내부적으로 호출하게 된다...
여기서 맴버 함수에
가령 생성자 함수를
explicit AAA를 선언하게 되면 첫번째 C스타일은 에러를 발생하게된다..

mutable 이건 자주 쓰지말라고 하던데...일단 간략하게
const한 함수에서는 멤버변수의 조작을 할수 없다 하지만
멤버변수에 mutable을 선언하게 된다면 조작을 할수 있다..

이렇게 조작하기 보다는 const를 이용하는 함수 따로
아닌 함수 따로 분리하는게 더좋단다...-_-;

by 홍텐 | 2008/04/21 00:52 | 트랙백

[열혈강의C++]5장 복사생성자

음 한마디로 생성자에 대입연산자를 써서 생성자의 멤버들을 모두 mov하겠다는 의미인데...
여기서 문제되는것은 동적할당을 했을경우이다

밑에 소스를 보면 알겠지만
처음 생성자를 호출하면 디폴트 생성자가 호출이 된다 여기서 동적으로 맴버들을 할당해주고
틸드 생성자에서 메모리 해제를 하면 되는데...
가령 하나의 생성자에 또다른 생성자를 대입해주면
이미 두번째(스택 상황상 생성자는 꺼꾸로 소멸) 생성자에서 동적할당된 멤버들이 사라진뒤
첫번째 생성자의 멤버들을 없앨려고 하니깐 런타임 에러...
이런걸 디폴트 생성자에서 다시금 동적으로 정의 해줘야 한다...

복사생성자 호출 형태 3가지
case1
-기존에 생성된 객체로 새로운 객체 초기화
case2
-함수 호출 시 객체를 값에 전달
case3
-함수 내에서 객체를 값에 의해 리턴
사실 case2와 case3는 거의 같은말
밑에 소스는 case1에 해당
/*
 CopyCon4.cpp
*/

#include <iostream>
using std::cout;
using std::endl;

class Person
{
 char *name;
 char *phone;
 int age;
public:
 Person(char *_name,char *_phone,int _age);
 Person(const Person &p){
  name=new char[strlen(p.name)+1];
  strcpy(name,p.name);
  phone = new char[strlen(p.phone)+1];
  strcpy(phone,p.phone);
  age = p.age;
 }
 ~Person();
 void ShowData();
};

Person::Person(char *_name,char *_phone,int _age)
{
 name = new char[strlen(_name)+1];
 strcpy(name,_name);
 phone = new char[strlen(_phone)+1];
 strcpy(phone,_phone);

 age = _age;

}
Person::~Person()
{
 delete []name;
 delete []phone;
}
void Person::ShowData()
{
 cout<<"name : "<<name<<endl;
 cout<<"phone : "<<phone<<endl;
 cout<<"age : "<<age<<endl;
}
int main()
{
 Person p1("KIM","013-333-5555",22);
 Person p2=p1;

 p2.ShowData();
  return 0;
}

by 홍텐 | 2008/04/20 22:35 | c++ | 트랙백

◀ 이전 페이지다음 페이지 ▶