본문 바로가기

2. Reversing (리버싱)/1) Write UP

[2021.11.06] Codeengn 11,Nag 창 없애기

OEP 찾으시오. Ex) 00401000 / Stolenbyte 찾으시오.
Ex) FF35CA204000E84D000000
정답인증은 OEP+ Stolenbyte
Ex ) 00401000FF35CA204000E84D000000

 

StolenByte ?

프로그램의 어떤 부분의 코드를 다른 부분으로 옮긴 코드이다. 조금 더 쉽게 말하면 옮겨지는 코드들은 대부분 OEP 위에 코드들이 JMP 구문으로 OEP에 도달하기 전 코드들이다. 주로 패킹과 동시에 이루어지는 것 같다.

 

이제 프로그램을 실행시켜보겠다.

프로그램이 잘 작동된다.

 

 

이제 올리디버거에 프로그램을 올려 분석해주겠다.

 

코드들을 실행시켜줘도 큰 변화가 일어나지 않고 무엇보다 주석,힌트 등 코드들이 수상하게 생겼다.

 

이제 ExeinfoPE 프로그램에 이 파일을 올려 패킹이 된게 맞는지 확인해주겠다.

 

아래쪽 두 줄을 확인해보면 이 파일이 UPX로 패킹되어있기 upx.exe -d 명령어로 언패킹을 진행해줘야 한다는 것을 알 수 있다. 어차피 언패킹을 진행해줘도 코드가 완전하지 않아 제대로 된 프로그램이 실행되지 않을 걸 알기에 이 부분은 패스하겠다.

 

이렇게 프로그램이 제대로 실행되지 않는다.

 

ollydbg에 다시 파일을 올려 분석을 진행해주겠다.(OEP를 찾는 게 급하다.)

OEP를 찾는 방법은 아래 블로그 포스팅에 잘 나와있으니 참고하셨으면 한다.

https://honorlog.tistory.com/5

 

오른쪽 마우스 -> Search for -> All commands -> popad 입력 후 검색을 통해 pushad에 인접한 popad 주소로 이동해주겠다.

 

popad 명령어 주소에 BP를 걸고 거기까지 실행시키면 아까 뜬 오류 문자열이 나타난다. 좀 이상한 점이 있다면 메시지 박스 함수가 보이지 않고 문자열만 떡하니 있다는 것이다. 

 

코드 가장 마지막 줄을 확인해보면 JMP 명령어가 있다는 것을 알 수 있다. JMP 명령어로 이동하는 주소가 OEP이다. OEP로 이동해보겠다.

 

이동하니 이곳에도 수상한 주소가 보인다. 0040100E 주소와 메시지 박스를 호출하는 다른 주소들과의 차이점을 보면 push로 인자를 한 개 밖에 받지 않았다. 기본적으로 MessageBox를 호출할 때는 파라미터 4개를 받아준다. 앞에서 수상했던 코드들의 주소들을 다시 확인하면 push 명령어로 3개의 값들을 스택에 넣어주고 12바이트라는 것을 볼 수 있다. OEP위에 붕 뜨는 주소들의 바이트 값을 확인하면 12바이트라는 것을 알 수 있다. 그래서 JMP 명령어 전에 있던 push 명령어로 구성된 3 주소가 stolenbyte라고 추측할 수 있다.

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa

 

JMP 명령어 전에 있던 push 명령어를 쓰는 주소 3줄을 긁어오겠다. 기계어 코드를 긁어와 오른쪽 마우스 -> Bianry -> Edit에 기계어 코드를 붙여주면 된다.

 

이제 수정된 코드들을 덤프로 저장해주겠다.(덤프는 따로 다운받아 plugin 폴더에 넣어주어야한다.)

 

엔트리포인트가 새롭게 바뀌었으니 1000으로 수정해준다. 덤프를 눌러 새로운 파일로 저장해주고 정상적으로 작동하는지 실행시켜보겠다.

잘 실행된다.

 

따라서 답 OEP + StolenByte 는 04010006A0068002040006812204000 이다.

 

리버싱 입문 4. 리버싱, 좀 더 깊숙이 – 2. Nag 창 없애기

2.1 프로그램 동작 방식

 Nag

 ->Exit

 Nag

 

2.2 콜 스택(스택)

콜스택이란 프로그램에서 사용하는 서브루틴에 대한 정보를 저장하기 위한 자료구조.

 

사용 목적 : 서브루틴 간 호출 순서를 추적할 수 있는 정보를 저장하는 것.

서브루틴 A는 실행하는 도중에 특정 기능이 필요할 때 서브루틴 B를 호출 -> 서브루틴 B가 가진 모든 명령어 수행이 종료됐을 때 다시 서브루틴 A로 돌아와서 나머지 명령어를 수행

명령어 4 : 복귀 주소 (서브루틴 B를 호출하기 전에 스택이라는 자료구조에 넣어두고 B의 동작이 끝날 때 복귀 주소를 사용해서 복귀)

 

프레임 포인터와 스택 포인터 사이에 있는 값을 스택 프레임이라고 부름.

스택 포인터는 현재 사용하는 서브루틴의 최상위 스택 값을 가리키고 있음.

서브루틴을 호출하기 전 ESP 레지스터 값은 프레임 포인터에 저장 -> 하나의 서브루틴이 종료되고 복귀 주소로 돌아갈 때는 프레임 포인터 값을 ESP 레지스터로 복구.

[Called from] : 호출하는 코드를 의미

[Procedure] : 호출되는 서브루틴

-> 맨 위에 있는 ‘ReverseMe.NAGs.exe’ 모듈에서 호출하는 코드가 Nag 창을 여는 서브루틴인 경우가 많다.

 

콜 스택 창에서 서브루틴을 호출하는 부분을 찾은 경우

 

사용자 코드에서 서브루틴을 호출하는 코드를 못 찾은 경우 -> 스택 영역

콜 스택 창 : 서브루틴 호출 구조에 대한 요약 자료

스택 영역 : 스택에 대한 모든 정보를 보여줌.

 

1. 스택 영역의 맨 위에 보면 콜 스택 창의 맨 윗부분에 있는 정보와 일치한다는 것을 알 수 있음.

2. 콜 스택 창 두번째 줄과 같은 정보임을 확인할 수 있음.

서브루틴을 호출하는 모듈 찾기. (주소 0018BFA4)

-> 코드 영역으로 따라가기

복귀주소에 스택에 나와있는 서브루틴이 호출된 것을 확인할 수 있음.

코드 캐이브 : 작은 공간에 큰 코드를 집어넣으려고 사용하는 기술

사용하지 않는 코드 영역에 필요한 코드를 입력하고, 수정해야 할 부분에는 새로운 코드가 입력된 메모리로 점프하는 코드를 넣기 -> 코드 영역에 입력된 새로운 코드 마지막 부분에 다음에 실행되어야 할 코드로 점프하는 코드를 넣기 -> 내가 필요한 시점에 원하는 코드 실행 가능

 

 

1. 주소 0042039A에서 Nag 창을 여는 서브루틴을 호출.

2. 주소 00420377에서 EAX 레지스터 값이 ‘0’인지 확인해서 ‘0’이면 제로 플래그를 ‘1’로 설정.

3. 제로 플래그가 ‘1’이면 주소 004203BA로 이동하고 제로 플래그가 ‘0’이면 점프하지 않고 아래에 있는 Nag 창을 열어주는 서브루틴을 호출.

메모리 맵 : 운영체제가 PE 파일을 메모리에 로딩에서 어떻게 저장하고 있는지 한눈에 볼 수 있다.

[Address] : 메모리에서 시작 주소

[Size] : 데이터의 크기 -> address에서 시작해서 size만큼 데이터가 들어가 있다.

[Section] : PE 파일의 구성 요소.

[Access] : 메모리 맵에 접글 할 수 있는 특성

- ‘R E’ : 읽고 실행

- ‘RW’ : 읽고 씀

 

코드 영역의 마지막 주소와 ‘.text’ 영역에 마지막 데이터의 주소는 같음.

마지막 주소에 ‘00000000’ 모두 4바이트가 들어 있기 때문에 메모리 영역의 데이터는 주소 00447000까지 들어 있음.

‘.data’ 영역의 데이터는 주소 00447000 역역까지 들어 있게 됨.

 

캐이브 코드 -> ‘.text’ 영역(access 영역에 따라)

임시로 사용하기 위해 저장하는 데이터 -> ‘.data’ 영역(access 영역에 따라)

 

1. 코드 영역에서는 주소 00437D6A에 코드를 넣음.

2. 메모리 영역에서는 주소 00445E90에 임시로 사용할 숫자를 집어넣음.

 

1. 주소 00420377에 브레이크포인트 설정

2. 스페이스 바를 누르면 어셈블 할 수 있는 창이 뜸.

3. ‘Keep size’는 새로 들어가는 명령어가 선택한 명령어 크기를 넘을 수 없다는 의미 -> 체크 X

4. ‘Fill rest with NOPs’는 나머지 영역을 NOP 명령어로 채움. (NOP 명령어 : 아무 동작도 하지 않고 다음 명령어를 실행) -> 체크 O

5. 선택된 ‘TEST EAX,EAX’ 명령어를 ‘JMP 00437D6A’로 교체.

세 줄의 명령어가 한 줄의 명령어로 바뀜.

 

1. 특정 메모리 영역에 1바이트 단위 덧셈

2. 특정 메모리 영역에 2가 저장되었는지 확인

3. 두 번째 창이 아니면 창을 띄우지 않는 로직으로 이동

4. 점프 명령어 입력을 위해 삭제된 원본 코드 입력

5. 두 번째 창이면 창을 띄우는 로직으로 이동

 

 

번경된 내용을 영구적으로 실행 파일에 기록하기 위한 방법

1. 메뉴 -> [Edit] -> [Copy all modifications to executable]

2. 메뉴 -> [Save file…]