정보보안/리버싱

reverse_assembly SWITCH

오오렌지 2022. 9. 2. 13:58

29_어셈블리(switch)

 - 분석 환경 : Windows7(32bit)
 - 분석 도구 : OllyDbg, VS2008


1. 'switch' 구문

 - 조건에 만족하면 코드를 실행하는 조건문이다.
 - 대신, if 구문과 차이점은 변수 값에 따라서 다른 동작을 실시할 수 있다.
 - 또한, 'break' 제어문과 같이 사용하여 조건에 만족되면 코드를 실행하고 조건 검사를 종료할 수 있다.
 - switch 구문 형식은 다음과 같다.

switch (변수)
{
case 값1:
// 값이 '1'인 경우 실행하는 코드
break;

case 값2:
// 값이 '2'인 경우 실행하는 코드
break;

default:
// 위에 조건이 아닌 경우 마지막에 실행하는 코드
}


 1) VS 2008을 이용하여 'switch.exe' 파일을 제작한다.

 - 파일 -> 새로 만들기 -> 프로젝트 -> 빈 프로젝트 -> 위치(04_테스트) & 이름(switch) -> 확인
 - '소스 파일' 우클릭 -> 추가 -> 새 항목 -> 'C++ 파일(.cpp)' 선택 -> 이름(switch) -> 추가


 - 파일 -> 모두 저장 -> 닫기


 2) 'cl' 명령어를 이용한 최적화 컴파일 실시


2. 'switch.exe' 파일을 'IDA Pro'를 이용하여 고급 정적 분석을 실시한다.

일단 main함수 전체의 ida-view의 모습이다.

간략하게 설명하자면,

[ebp+var_8]은 switch 로 넘겨주는 3이라는 값이 들어있다.

[ebp+var_8]을 상수값과 비교하고, 비교결과값의 결과에 따라 점프하거나. 다음상수값과 비교하여 [ebp+var_8] 와 상수값이 같아질때까지 진행하는 흐름이다. 

첫 분기 직전의 모습이다. 함수 프롤로그가 수행되고 , 세번의 MOV끝에 [ebp+var_8]에는 결국 3이라는 값이 들어있다. 

비교결과값이 0이 아니므로 점프하지 않고 다음 코드가 실행될것이다. 

따라서 아래와 같이 빨간선을 타고 내려온 후, 2라는 숫자와 비교하게된다. 

 

이제 3과 2를 비교할것이다.

이 경우 또한 비교결과값이 0이 아니므로 점프하지 않고 빨간선을 타고 내려가 다음 코드가 실행될것이다.

 

 

이제 3과 3을 비교할 차례이다.

비교결과값이 0이 되므로 JZ에 의하여 401053으로 점프하게되고, 메세지박스를 실행해 ' switch구문(case 3:) ' 이라는 문구가 출력될것으로 예상된다. 

 

이렇게 아이다로 정적분석하여 case3 으로 분기하여 'switch구문(case 3:)' 이라는 메세지박스를 실행할 것이라는 결과를 도출하였다.

이를 올리디버거로 확인해보자.

 

3. 올리디버거를 이용한 'switch.exe' 분석


 - 메모리 주소, 레지스터 저장 값, 스택 내용, 메모리 덤프 내용, 비교 및 분기 내용 확인

 

1) Main함수 찾기(F8)

 

 Main함수를 call하기 직전의 모습이다. Main함수의 주소는 401000임을 확인할 수 있다.

2) Main함수 진입(F7) – 함수 프롤로그, 함수 본체, 함수 에필로그 확인

<  함수 프롤로그  >

 

00401000  /$  55            PUSH EBP
00401001  |.  8BEC          MOV EBP,ESP

___________________________________________________________________________________

 

< 함수 본체 >

 

00401003  |.  83EC 08       SUB ESP,8

    -    다음과 같이 지역변수 num1과 switch로 넘겨줄 파라미터를 위한 공간 4byte * 2 만큼 ESP 를 위로 올려 공간을 마련해주는 작업을 한다.

00401006  |.  C745 FC 03000>MOV DWORD PTR SS:[EBP-4],3

지역변수에 3이라는 값을 초기화하는 과정이다.

0040100D  |.  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]

    -    이 값을 위와 같이 EAX에 복사한다.


00401010  |.  8945 F8       MOV DWORD PTR SS:[EBP-8],EAX

스위치함수로 넘겨줄 파라미터 자리에 3을 복사해서 넣어준다.

그리고 나서 이 값을 상수와 비교하게 된다. 


00401013  |.  837D F8 01    CMP DWORD PTR SS:[EBP-8],1
00401017  |.  74 0E         JE SHORT switch.00401027                 

00401019  |.  837D F8 02    CMP DWORD PTR SS:[EBP-8],2
0040101D  |.  74 1E         JE SHORT switch.0040103D             

 

    -      위의 네개의 코드를 실행하면 [EBP-8]의 자리엔 3이라는 값이 들어있으므로, 비교결과값이 0이 아니므로 점프하지않고 계속 진행된다. 

 

0040101F  |.  837D F8 03    CMP DWORD PTR SS:[EBP-8],3

      -     3과 [EBP-8]를 비교하면, 비교결과값은 0이 되고 ZF 는 아래와 같이 1로 변한다. 

00401023  |.  74 2E         JE SHORT switch.00401053

JE에 의해 아래와 같이 401053으로 점프하게된다. 


<  00401053 _ case 3 >

 

00401053  |> \6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
00401055  |.  68 84814000   PUSH switch.00408184                     ; |Title = "switch 구문(case 3:)"
0040105A  |.  68 9C814000   PUSH switch.0040819C                     ; |Text = "num1 is 3"
0040105F  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
00401061  |.  FF15 E8804000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA

 

위와 같이 case 3 에 해당되는 코드들을 실행하고, 메시지박스가 실행되며 아래와 같이 " num1 is 3 " 이 출력된다.


00401067  |.  EB 14         JMP SHORT switch.0040107D

     -     그 후, 아래에는 default 관련 코드들이 있으므로 0040107D으로 점프하여 main함수를 종료하는 과정을 수행한다. 

 

0040107D  >

 

XOR을 통해 EAX를 0으로 초기화 시켜준 후, 함수에필로그가 수행되며 main함수는 종료된다.


00401046  |>  33C0          XOR EAX,EAX

________________________________________________________________________________________

 

<  함수 에필로그  >

0040107D  |> \33C0          XOR EAX,EAX
0040107F  |.  8BE5          MOV ESP,EBP
00401081  |.  5D            POP EBP

____________________________________          main함수 소멸 


00401082  \.  C2 1000       RETN 10        ---> main함수 다음주소로 리턴