스템 프레임이란?

 -ESP(스택 포인터)가 아닌 EBP(베이스 포인터) 레지스터를 사용하여 스택 내의 로컬 변수, 파라미터, 복귀 주소에 접근하는 기법

 

ESP레지스터의 값은 프로그램 안에서 수시로 변경되기 때문에 스택에 저장된 변수, 파라미터에 접근하고자 할 때 ESP 값을 기준으로 하면 프로그램을 만들기 어렵고, CPU가 정확한 위치를 참고하기 힘듭니다.

그래서 함수 시작의 ESP값을 EBP에 저장하고 이를 함수 내에서 유지해주면, ESP값이 아무리 변하더라도 EBP를 기준으로 안전하게 해당 함수의 변수, 파라미터, 복귀 주소에 접근할 수 있습니다. 

 

 

 

스택 프레임의 구조

PUSH EBP        ;함수 시작(EBP를 사용하기 전에 기존의 값을 스택에 저장)

MOV EBP,ESP   ;현재의 ESP를 EBP에 저장

 

...                   ;함수본체; 여기서 ESP가 변경되도, EBP는 변경 X; 안전하게 로컬 변수와 파라미터 엑세스 가능

 

MOV ESP, EBP  ;함수 시작했을 때의 값으로 복원

POP EBP         ;리턴되기 전에 저장해 놓았던 원래 EBP값으로 복원

RETN             ;함수 종료

 

 

스태겡 복귀 주소가 저장된다는 점이 보안 취약점으로 작용할 수 있습니다. buffer overflow 기법을 사용하여 복귀 주소가 저장된 스택 메모리를 의도적으로 다른 값으로 변경할 수 있습니다.

 

 

 

반응형

'보안 > 리버싱' 카테고리의 다른 글

2. abex' crackme 1  (0) 2019.07.29
1. 문자열 패치  (0) 2019.07.19

파일을 실행하면 이렇게 뜹니다. 어떻게 크랙을 하는 것인지 분석해볼게요.

 

옆쪽에 보면 저희가 띄워야 되는 구문은 ok, I really thing that your HD is a CD-ROM! :p 구문을  띄워야 되는 것을 알 수 있어요.

 

옆에 주석을 보면서 어셈블리어를 분석해볼게요.

push: 스택에 값 입력

call  : 지정된 주소의 함수 호출

inc   : 값 1 증가

dec  : 1감소

jmp  : 지정된 주소로 점프

cmp : 주어진 두 개 operand 비교

je    : 조건 분기

 

 

cmp eax,esi 를 비교합니다.

JE SHORT 0040103D 는 두 값이 같으면 40103D로 점프하고 아니면 그대로 진행합니다.

 

 

 

저희가 원하는 값으로 나오게 할려면 JE ~~~ 구문을 JMP 0040103D로 바꿔주면 됩니다. 그러면 바로 저희가 원하는 쪽으로 점프 하겠죠?

 

 

저희가 원하는 값이 잘 나오네요~

 

 

아 그리고 알아야 될 것이 있습니다. 함수 호출 시 스택에 파라미터를 전달하는 방법에 대해 살펴볼게요.

MeesageBoxA() 함수를 호출하기 전에 필요한 파라미터를 거꾸로 입력하고 있습니다.

 

MessageBoxA(NULL, "Make me think your HD is a CD_Rom.", "abex' 1st crack me", MB_OK|ME_APPLMODAL);

 

파라미터의 순서가 역순으로 입력되는 이유는 스택 메모리 구조이기 때문입니다.

파라미터를 거꾸로 넘겨주면 함수에서는 올바른 순서로 꺼낼 수 있습니다.

반응형

'보안 > 리버싱' 카테고리의 다른 글

스택 프레임  (0) 2019.08.02
1. 문자열 패치  (0) 2019.07.19

이 소스를 실행하면 Hello World 라는 문자를 출력하는 메세지 박스 창이 뜹니다.

 

이 메세지를 다른 메세지로 패치해볼게요.

 

우선 ollydbg를 실행해서 이 exe파일을 엽니다.

 

 

메인함수를 찾아보도록 합시다.

우클릭 눌러서 search for 에서 name in all modules를 누릅니다.

그리고 messageboxw를 타이핑 하면,

이렇게 찾을 수 있습니다. 여기에 f2를 눌러 브레이크포인트를(bp) 설정하고, f9를 눌러 실행합니다.

 

오른쪽 아래에 보면 이런 내용이 있습니다.

 

첫 번째는 address , 두 번째는 value, 3번째는 comment 입니다.

 

meesageboxw는 0D1758 에서 호출 되었고, 함수 실행이 종료되면 0D175E주소로 리턴한다는 뜻입니다.

 

 

 

이제 패치해보도록 할게요.

위에서 Hello World 의 주소와 meesageboxw가 호출되는 주소를 찾았습니다.

main 함수 시작 주소(0D174A)까지 실행합니다. (bp설정하고 실행하면 됩니다.)

 

문자열을 패치하는 방법에는 2가지 방법이 있습니다.

 - 문자열 버퍼를 직접 수정

 - 다른 메모리 영역에 새로운 문자열을 생성하여 전달

 

1) 문자열 버퍼를 직접 수정

덤프 창(왼쪽 아래)에서 문자열의 주소인 0D7B58주소로 찾아갑니다.(컨트롤+g)

 

선택하고 컨트롤 + e키를 눌러 edit 다이얼로그 창을 띄웁니다.(유니코드는 한 글자당 2바이트가 필요합니다. null도 고려해야되요)

여기서 unicode의 문자열을 hello reversing으로 수정할게요. keep size 체크 풀어주세요! 그리고 유니코드에선 null을 입력할 수가 없어요. 그래서 그 아래에 hex창에서 00 00 을 끝에 입력해줍시다.

메인함수로 다시 돌아가서 실행해보면,

성공적으로 수정됬습니다. 

 

뒤에 reversing의 길이가 world보다 더 깁니다. 보통 원본 문자열 뒤에 다른 데이터가 있을 수 있기 때문에 원본 길이를 넘는 문자열로 덮어 쓰는 것은 위험합니다.

 

이 방법의 장점은 간단하지만, 단점은 기존 문자열 버퍼 크기 이상의 문자를 입력하기 어렵습니다.

 

 

파일로 생성하기

위에서 한 것은 메모리에 임시적으로 한 것이라 디버거가 종료되면 패치했던 내용은 사라집니다.

영구히 보존하려면 별도의 실행파일로 저장해야 됩니다.

 

변경된 내용(hello reversing)을 선택하여 마우스 우측 버튼을 누르고 copy to executable file 메뉴를 선택하고, 다시 우측 버튼을 눌러 save file 버튼을 눌러 저장 할 수 있습니다.

 

 

2) 다른 메모리 영역에 새로운 문자열을 생성하여 전달

위의 경우처럼 원본 문자열보다 더 긴 문자열로 패치해야 될 경우에는 위의 방법은 알맞지 않습니다.

이런 경우 사용할 수 있는 방법을 알아보겠습니다.

 

컨트롤 + f2로 다시 실행 후, 아까 설정한 main 함수(0D174A)로 갑니다.

아래 사진처럼 MessageBoxW가 호출 되는 지점으로 가면, 주소 수정해도 안되요!

 

0D1751 주소의 push 명령은 0D7B58의 hello world 문자열을 파라미터로 전달합니다.(MessageBoxW() 함수)

 

이 함수는 파라미터로 입력된 주소의 문자열을 출력 해줍니다. 만약 이 문자열 주솔르 변경해서 전달하면, 메시지 박스 에는 변경된 문자열이 출력됩니다.

 

적당한 메모리 영역에 패치하고 싶은 긴 문자열을 적고, 그 주소를 파라미터로 넘겨줍니다. (지금은 임의의 영역을 고를게요. 더 자세한 방법은 더 공부하고 올릴게요)

 

dump 창에서  hello world 문자열 주소로 이동합니다. 스크롤을 밑으로 내리다 보면 NULL padding 으로 끝납니다.

 

이곳은 프로그램이 사용하지 않는 NULL padding 영역입니다.

적당 한곳에 패치 문자열을 씁시다.

이 새로운 주소를 이제 파라미터로 전달 해야겠죠? 

 

아까 코드에 마우스를 올리고 우클릭 누른 뒤 assemble 명령을 사용해주세요.(단축기 space)

 

그리고 코드를 변경해줍시다.

문자열을 새로 쓴 주소를 파라미터로 전달해줍시다.

 

 

반응형

'보안 > 리버싱' 카테고리의 다른 글

스택 프레임  (0) 2019.08.02
2. abex' crackme 1  (0) 2019.07.29

+ Recent posts