제가 만들어본 리버싱 기초를 설명한 PPT입니다.

부족한 점이 많을것입니다.   많이 지적해주세요.


아 그리고 쓰실때 출처만 제대로 밝혀주세요.






Posted by Dakuo

dakuo reversing lecture 1편이 장장 6시간  40여차례 이상의 NG 끝에 완성되었습니다.  목도 아프고 눈도 아프네여.

완성본은 13분짤...... ㄷㄷㄷㄷ

이런 강의제작이 처음이라 너무 설레고 오글오글 거려서 

시작도 늦게 했고(준비는 지난주에 다됐지만)

오늘 하면서 발음도 엄청 버벅이고, 말도 꼬이고, 설명할 내용이 머리속에 떠오르지 않아 멍때리고 해서

수많은 NG끝에 드디어 완성되었네요.  머 여러사람들에게 많은 도움이 됬으면 좋겠습니다.


p. s. 유튜브를 이용해서 올렸는데 유튜브가 2GB 용량제한에  10분 길이제한이네요.....

제껀 37.8메가에 13분짜리라 ....... 눈물을머금고  2개로 짤랐습니다..... ㅠㅠㅠㅠ 다음엔 분량 맞춰서할께요 ㅠㅠㅠ

720P로 보시면 잘보입니다 ㅎㅎㅎ



문제파일 :



리버싱 1-1 :

 


리버싱 1-2 :

Posted by Dakuo


올리디버거 창들 중에 Executable Modules 창이 있다.

현재 불러온 프로세스에서 실행중인 모듈들을 보여준다.

한 프로그램에서 여러개의 모듈(ex. DLL 등)을 사용할 경우

올리디버거는 하나의 모듈만을 트레싱할 수 있기 때문에 제대로 분석할수가 없다.

따라서 Executable Modules 창을 이용해 실행 가능한 모듈을 골라서 중요한 코드에

BreakPoint 를 걸어놓음으로써 해당 코드가 실행될 때에 제어권을 올리디버거로 받아 문제를 해결할 수 있다.


일단 해당문제를 실행시켜보자.

Ezbeat 문제 패스워드 찾기
올바른 패스워를 찾으시오!
난이도 : ★☆☆☆☆

위의 메시지 박스가 뜨며 확인을 누르면

콘솔창 하나가 뜨며 Input Password : 를 입력하라고 뜬다.


올리디버거로 프로그램을 오픈한다.

메시지 박스가 뜨므로 back to user mode 를 이용한다.

Run(F9)을 한다. 메시지 박스가 뜨면 pause(F12)를 한다.

back to user mode(Alt + F9)를 한 후 확인창을 누른다.


그러면 다음과 같은 코드로 이동한다.

00401149  |.  57            PUSH EDI                                    ; /Style
0040114A  |.  68 5CD34000   PUSH CrackMe_.0040D35C       ; |E
0040114F  |.  68 80D34000   PUSH CrackMe_.0040D380        ; |Text = "올바른 패스워드를 찾으시오!.
                                                                                     난이도 : ★☆☆☆☆"
00401154  |.  51            PUSH ECX                                  ; |hOwner
00401155  |.  FF15 4CC14000 CALL DWORD PTR DS:[<&USER32.MessageBoxW>>; \MessageBoxW
0040115B  |.  6A 03         PUSH 3                                     ; /ShowState = SW_SHOWMAXIMIZED
0040115D  |.  68 40D34000   PUSH CrackMe_.0040D340        ; |c:\solve.exe
00401162  |.  FF15 18C04000 CALL DWORD PTR DS:[<&KERNEL32.WinExec>]  ; \WinExec

위의 코드를 보면 WinExec 라는 WinAPI 가 보인다.

이 WinExec 함수는 CreateProcess 와 같이 프로세스를 생성하는 함수이다.

따라서 위의 3줄을 해석해보면 

WinExec 함수를 사용하여 최대창으로(SW_SHOWMAXIMIZED) c:\solve.exe 를 실행시켜라라는 뜻이다.

즉, 우리는 분석하던 CrackMe_2.exe 프로세스가 아니라 solve.exe 프로세스를 분석해야 한다.


따라서 WinExec 함수까지 실행을 한후에 solve.exe 가 실행되면

Attach 로 solve.exe 프로세스를 올리디버거로 불러온다.

E창을 눌러 Executable Modules 창을 연다.


맨 위의 solve 를 클릭한다. 실행영역에 올라온 코드들이다.

조금 아래로 가서 살펴보면

0040105C   .  68 3CD34000   PUSH solve.0040D33C                      ;  ASCII "Input Password : "
00401061   .  E8 28020000   CALL solve.0040128E
00401066   .  83C4 08       ADD ESP,8
00401069   .  E8 2F030000   CALL solve.0040139D
0040106E   .  50            PUSH EAX
0040106F   .  6A 63         PUSH 63
00401071   .  8D55 90       LEA EDX,DWORD PTR SS:[EBP-70]
00401074   .  52            PUSH EDX
00401075   .  E8 69070000   CALL solve.004017E3
0040107A   .  83C4 0C       ADD ESP,0C
0040107D   .  6A 0E         PUSH 0E

정답으로 보이는 값이 보인다.

입력하면 congratulation~!   가 출력된다.

Posted by Dakuo

아 슬럼프가..

Essay 2010.01.25 06:04

저랑은 상관없는 크리스마스에 괜히 들떠서 공부가 안되서

걍 이때 팍 놀고 마음잡고 공부하자

그랬는데 벌써 한달이 훌쩍 지나갔네요..ㄷㄷㄷㄷ

그동안 너무 놀았으니까 이제 다시

몰아치기로 열공해야죠 ㅋㅋ

아 그리고 UltraISO 라는 프로그램이 있는데 아마

USB 를 어떻게든 활용해볼려고 하시던 분들이나 ISO 이미지 에 대해 찾던분들은 잘아실겁니다.

네이버에서 다운받아서 쓸려는데 정식버전으로 등록하라고 나오더군요 그냥쓸수도 있지만 제한이 걸려있네요 근데 이걸 한번 리버싱해보다가

정식버전으로 쓰는법을 우연히 찾았네요 ㅎㅎ

궁금하신분들은 메일주세요 ㅎ.

dakuo@naver.com 입니다.

'Essay' 카테고리의 다른 글

hellSonic  (1) 2010.03.07
2010년 공부 계획  (0) 2010.02.08
아 슬럼프가..  (1) 2010.01.25
기말고사가....  (1) 2009.12.12
2009년에 한일들 -  (0) 2009.11.27
IGRUS 배 내부 해킹대회 후기.  (0) 2009.11.26
Posted by Dakuo

요즘 저의 근황...

Essay 2009.11.17 22:06
지난주부터 코드엔진과(http://www.codeengn.com/)과 심플스(http://simples.kr/)에서
리버싱 문제를 푸느라 정신없이 하루하루를 보내고 있네요 학업과 병행하려니까 장난이 아니네요 ㅠ.

그래서 요새 블로그 업데이트도 못하고 있고... 여러모로 바쁘네요 .

조만간 두사이트의 리버싱 문제 풀이에 대해서 포스팅하도록 하겠습니다. 그리고 리버싱 분야도 마저 정리하도록 하고요. 리빌더 설명하다가 중간에 끈겼네요 ㅠ 죄송합니다.

그리고 이것이 끝나면 이제 웹해킹쪽으로 올드좀비 문제를 풀어볼생각입니다.

아 물론 이론에 대해서도 포스팅하겠습니다.

부족한 제 블로그를 방문해주시는 여러분들에게 항상 감사하고 있습니다.

이만 줄이겠습니다,...


'Essay' 카테고리의 다른 글

2009년에 한일들 -  (0) 2009.11.27
IGRUS 배 내부 해킹대회 후기.  (0) 2009.11.26
요즘 저의 근황...  (0) 2009.11.17
천재에 대한 나의 생각  (0) 2009.11.07
리버싱 관련 포스팅  (0) 2009.11.04
SBS 스페셜 최악의 시나리오 3부 - 사이버 아마겟돈  (0) 2009.10.29
Posted by Dakuo

C언어로 if문을 컴파일한 것을 IDA로 분석해보자.

#include <stdio.h>

void main()
{
         int a = 3;
         int b = 5;

         if( a > b)
         {
                 printf(" a 가 크다 ");
         }

         else
         {
                printf(" b 가 크다 ");
         }
}


IDA 그래프 기능으로 본 해당 소스의 흐름이다.


가운데 지점에서 빨간선과 초록선으로 분기하고 각각의 일을 실행한 후 하나로 합쳐지며 프로그램이 종료된다.

.text:00411390                 push    ebp 에 breakpoint를 설정한다.

디버그 모드로 전환(F9)하여 분석을 해보겠다.

다음은 Main함수이다.

.text:00411390 main proc near                          ; CODE XREF: j_mainj
.text:00411390
.text:00411390 var_D8= byte ptr -0D8h          // 변수 선언
.text:00411390 var_14= dword ptr -14h          // 변수 선언 : int b; 
.text:00411390 var_8= dword ptr -8               // 변수 선언 : int a;
.text:00411390
.text:00411390 push    ebp
.text:00411391 mov     ebp, esp
.text:00411393 sub     esp, 0D8h
.text:00411399 push    ebx
.text:0041139A push    esi
.text:0041139B push    edi
.text:0041139C lea     edi, [ebp+var_D8]
.text:004113A2 mov     ecx, 36h
.text:004113A7 mov     eax, 0CCCCCCCCh
.text:004113AC rep stosd
.text:004113AE mov     [ebp+var_8], 3           // 3을 [ebp+var_8]에 대입 : a = 3;
.text:004113B5 mov     [ebp+var_14], 5          // 5을 [ebp+var_14]에 대입 : b = 5;
.text:004113BC mov     eax, [ebp+var_8]       // [ebp+var_8]을 eax에 대입 : eax = 3;
.text:004113BF cmp     eax, [ebp+var_14]     // eax와 [ebp+var_14]를 비교 : (3 : 5 비교)
.text:004113C2 jle     short loc_4113DD     // eax값이 [ebp+var_14]보다 작거나 같으면 점프
                                                              :  3 - 5 < 0  작거나 같으므로 점프

분기 1 :

.text:004113C4 mov     esi, esp
.text:004113C6 push    offset aABI                     ; " a 가 크다 "
.text:004113CB call    ds:__imp__printf
.text:004113D1 add     esp, 4
.text:004113D4 cmp     esi, esp
.text:004113D6 call    j__RTC_CheckEsp
.text:004113DB jmp     short loc_4113F4         // 합쳐지는 코드로 점프
.text:004113DD ; --------------------------------------------------------------------

분기 2 :
.text:004113DD
.text:004113DD loc_4113DD:                             ; CODE XREF: main+32j
.text:004113DD mov     esi, esp
.text:004113DF push    offset aBBI                     ; " b 가 크다 "
.text:004113E4 call    ds:__imp__printf
.text:004113EA add     esp, 4
.text:004113ED cmp     esi, esp
.text:004113EF call    j__RTC_CheckEsp
.text:004113F4

분기후 합쳐지는 코드 :

.text:004113F4 loc_4113F4:                             ; CODE XREF: main+4Bj
.text:004113F4 xor     eax, eax
.text:004113F6 pop     edi
.text:004113F7 pop     esi
.text:004113F8 pop     ebx
.text:004113F9 add     esp, 0D8h
.text:004113FF cmp     ebp, esp
.text:00411401 call    j__RTC_CheckEsp
.text:00411406 mov     esp, ebp
.text:00411408 pop     ebp
.text:00411409 retn
.text:00411409 main endp

몇가지 구문을 C언어로 제작하고, 그것을 역으로 IDA에 넣어서 분석해보며
분석실력과 어셈실력을 익혀놓으면 리버싱 실력향상에 도움이 된다.


Posted by Dakuo
C언어로 for문을 컴파일한 것을 IDA로 분석해보자.

#include <stdio.h>

int main(void)
{
      int i = 0;
      int result = 0;

      for ( i ; i < 5 ; i++ )
      {
                result = i;
      }
}


IDA 그래프 기능으로 본 해당 소스의 전체적인 흐름이다.


가운데 지점에서 빨간선과 초록선으로 분기를 하고 초록선으로 이동하면 일을 수행후 종료가 되며 빨간선으로 이동하면 일을 수행한 후 다시 돌아온다.

.text:00411360                 push    ebp 에 breakpoint를 설정한다.

 (Tip : 디어셈블된 상태에서 분석할 때 마우스로 함수를 더블클릭(Enter)하면 함수 안으로 들어갈수 있다. 함수를 선택후 Alt+Enter을 누르면 새 창이 뜨면서 그래프로 함수의 내용을 보여준다)

디버그 모드로 전환(F9)하여 분석을 해보겠다.

다음은 Main함수이다.

.text:00411360 main proc near                          ; CODE XREF: j_mainj
.text:00411360
.text:00411360 var_D8= byte ptr -0D8h        // 변수 선언
.text:00411360 var_14= dword ptr -14h        // 변수 선언 :     int result;    
.text:00411360 var_8= dword ptr -8             // 변수 선언 :     int i;
.text:00411360
.text:00411360 push    ebp
.text:00411361 mov     ebp, esp
.text:00411363 sub     esp, 0D8h
.text:00411369 push    ebx
.text:0041136A push    esi
.text:0041136B push    edi
.text:0041136C lea     edi, [ebp+var_D8]
.text:00411372 mov     ecx, 36h
.text:00411377 mov     eax, 0CCCCCCCCh
.text:0041137C rep stosd
.text:0041137E mov     [ebp+var_8], 0        // [ebp+var_8] 에 0을 대입 : i = 0
.text:00411385 mov     [ebp+var_14], 0       // [ebp+var_14]에 0을 대입 : result = 0
.text:0041138C jmp     short loc_411397      // loc_411387로 점프

: int i = 0; , int result = 0;

.text:0041138E ; --------------------------------------------------------------------

.text:0041138E
.text:0041138E loc_41138E:                             ; CODE XREF: main+43j
.text:0041138E mov     eax, [ebp+var_8]    // [ebp+var_8]값을 eax에 대입
.text:00411391 add     eax, 1                     // eax+=1
.text:00411394 mov     [ebp+var_8], eax     // eax값을 [ebp+var_8]에 대입

: i++

.text:00411397
.text:00411397 loc_411397:                             ; CODE XREF: main+2Cj
.text:00411397 cmp     [ebp+var_8], 5             // i와 5를 비교
.text:0041139B jge     short loc_4113A5  // [ebp+var_8]이 5보다 크거나 같으면 4113A5 점프
.text:0041139D mov     eax, [ebp+var_8]        // [ebp+var_8]값을 eax에 대입
.text:004113A0 mov     [ebp+var_14], eax      //  eax값을 [ebp+var_14]에 대입
.text:004113A3 jmp     short loc_41138E         // 41138E로 점프

: i < 5 비교 만족하면 result = i; 만족하지 않으면 4113A5로 점프

for()문이 있는 프로그램을 디버깅했다. while()문도 for()문과 같은 작동을 하는 코드를 작성하여 IDA로 열면 비슷한 디어셈블 결과를 볼 수 있을 것이다.

#include <stdio.h>

void main()
{
        int i = 0;
        int result = 0;

        while(i<5)
        {
               result = i;
               i++;
        }
}

Posted by Dakuo

리버싱 쪽은 아무래도 분석이 많아서 화면을 보면서 해야하기에 포스팅을 할때 스샷을 많이 찍다보니 시간이 오래 걸리네요 .ㅠㅠ

빨리 리버싱쪽을 끝내고 윈도우 프로그래밍이나 언어(C, C++, Asm, 자바), 웹(html, php, jsp, mysql, mssql)쪽으로 포스팅 방향을 옮겨야겠어요

'Essay' 카테고리의 다른 글

2009년에 한일들 -  (0) 2009.11.27
IGRUS 배 내부 해킹대회 후기.  (0) 2009.11.26
요즘 저의 근황...  (0) 2009.11.17
천재에 대한 나의 생각  (0) 2009.11.07
리버싱 관련 포스팅  (0) 2009.11.04
SBS 스페셜 최악의 시나리오 3부 - 사이버 아마겟돈  (0) 2009.10.29
Posted by Dakuo

IDA의 디버깅을 통한 스택의 Stack 분석

분석해볼 프로그램은 IDA의 사용법을 알아보기 위해 예제로 썻던 것을 계속 쓰겠다.

다시 한번 설명하면 func( ) 함수에 세 개의 값을 파라미터로 전달하고 그 값들의 합을 리턴하는 프로그램이다.


#include <stdio.h>

 func(int a, int b, int c)
{
           return a+b+c;
}

int main(void)
{
           int sum;
           sum = func(1, 2, 3);
           return sum;
}


프로그램이 실행되기 전의 Stack이다. ESP, EBP의 위치를 살펴본다.


.text:00401060 push    ebp :
EBP가 가리키는 곳이 SFP(Saved Frame Pointer)로 변하고, 그 윗부분이 RET로 바뀌며 스택에 EBP값 12FFC0h값을 넣고 ESP는 한 칸 내려간다.
(참고 : EBP는 함수 시작전의 기준점이 되며. 이 최초의 EBP가 할당된 값을 스택에 저장한다. SFP(SavedFramePointer) : 스택에 저장된 EBP, RET : 함수 종료시 점프 할 주소 값을 저장)

.text:00401061 mov     ebp, esp :
EBP가 ESP가 가리키는 곳을 가리키게 된다. 즉 EBP와 ESP가 같은 지점을 가리킨다.

.text:00401063 sub     esp, 44h :
EBP가 가리키는 곳이 SFP로 변하고 바로 밑에 RET가 있다. 또한 ESP에서 44를 뺀다. 즉 ESP는 var_44변수를 가리키게 된다.

.text:00401066 push ebx :
ESP가 한 칸 내려가면서 현재 EBX값 7FFDA000이 스택에 들어간다.

.text:00401067 push    esi :
ESP가 한 칸 내려가면서 현재 ESI값 01B26D97이 스택에 들어간다.

.text:00401068 push    edi :
ESP가 한 칸 내려가면서 현재 EDI값 01B26CF8이 스택에 들어간다.
       
.text:00401069 lea     edi, [ebp+var_44] :
[ebp+var_44]의 주소를 EDI에 넣는다.

.text:0040106C mov     ecx, 11h :
11을 ECX에 넣는다.

.text:00401071 mov     eax, 0CCCCCCCCh :
CCCCCCCC를 EAX에 넣는다.

.text:00401076 rep stosd :
기본 할당 공간(ECX값 11)을 EAX값으로 채운다, EDI는 반복할 때마다 한 칸 올라간다.
                                    
.text:00401078 push    3 :
ESP가 한 칸 내려가면서 3값이 들어간다.
                       
.text:0040107A push    2 :
ESP가 한 칸 내려가면서 2값이 들어간다.

.text:0040107C push    1
ESP가 한 칸 내려가면서 1값이 들어간다.

.text:0040107E call    j_func :
j_func를 call한다.
call j_func의 내부로 추적해 들어가겠다.(Step Into)


stack

       .text:00401020 push    ebp :
       EBP가 가리키는 곳이 SFP(Saved Frame Pointer)로 변하고, 그 윗부분이 RET로
       바뀌며 ESP는 다음 주소를 가리킨다.

      .text:00401021 mov     ebp, esp :
      EBP가 ESP가 가리키는 곳을 가리킨다.

      .text:00401023 sub     esp, 40h :
       EBP가 가리키는 곳이 SFP로 변하고 바로 밑에 RET가 있다. 또한 ESP에서 40을
       뺀다. 즉 ESP는 var_40변수를 가리킨다.

      .text:00401026 push    ebx : 
      ESP가 한 칸 내려가면서 현재 EBX값 7FFDB000h이 스택에 들어간다.
      
      .text:00401027 push    esi :
      ESP가 한 칸 내려가면서 현재 ESI값 01B26D97이 스택에 들어간다.

      .text:00401028 push    edi :
      ESP가 한 칸 내려가면서 현재 EDI값 12FF80h이 스택에 들어간다.

      .text:00401029 lea     edi, [ebp+var_40] :
      [ebp+var_40]의 주소를 EDI에 넣는다.

      .text:0040102C mov     ecx, 10h :
      10을 ECX에 넣는다.

      .text:00401031 mov     eax, 0CCCCCCCCh :
      CCCCCCCC를 EAX에 넣는다.

      .text:00401036 rep stosd :
      기본 할당 공간(ECX값 10)을 EAX값으로 채운다, EDI는 반복할 때마다 한 칸 올라 간다.

      .text:00401038 mov     eax, [ebp+arg_0] :
      [ebp+arg_0]의 값인 1을 EAX에 넣는다.

      .text:0040103B add     eax, [ebp+arg_4] :
      [ebp+arg_4]의 값인 2를 EAX에 더한다. (EAX = 1+2 = 3)

      .text:0040103E add     eax, [ebp+arg_8] :
      [ebp+arg_8]의 값인 3을 EAX에 더한다. (EAX = 3+3 = 6)

      .text:00401041 pop     edi :
      스택의 값(0012FF80)을 꺼내서 EDI에 넣는다. ESP는 한칸 내려간다.

      .text:00401042 pop     esi :
      스택의 값(01B26D97)을 꺼내서 EDI에 넣는다. ESP는 한칸 내려간다.

      .text:00401043 pop     ebx :
      스택의 값(7FFDB000)을 꺼내서 EDI에 넣는다. ESP는 한칸 내려간다.
      
      .text:00401044 mov     esp, ebp :
      EBP가 ESP가 가리키는 곳을 가리킨다.

      .text:00401046 pop     ebp :
      스택의 값(12FF80h)을 꺼내서 EBP에 넣는다. ESP는 한칸 내려간다.

      .text:00401047 retn :
      ESP는 한칸 위를 가리킨다.


.text:00401083 add     esp, 0Ch :
ESP에 0Ch를 더한다.

.text:00401086 mov     [ebp+var_4], eax :
EAX의 값인 6을 ebp+4에 위치에 넣는다.

.text:00401089 mov     eax, [ebp+var_4] :
의미없는 명령으로 ebp+4의 값인 6을 eax에 넣는다.

.text:0040108C pop     edi :
스택의 값(01B26CF8)을 꺼내서 EDI에 넣는다. ESP는 한칸 내려간다.

.text:0040108D pop     esi :
스택의 값(01B26D97)을 꺼내서 ESI에 넣는다. ESP는 한칸 내려간다.

.text:0040108E pop     ebx :
스택의 값(7FFDB000)을 꺼내서 EBX에 넣는다. ESP는 한칸 내려간다.

.text:0040108F add     esp, 44h :
ESP에 44를 더한다. EBP가 가리키는 곳을 가리킨다.

.text:00401092 cmp     ebp, esp :
EBP와 ESP값을 비교한다. (값이 같다)

.text:00401094 call    __chkesp :
__chkesp를 call한다.
건너뛰겠다.(StepOver)

.text:00401099 mov     esp, ebp :
EBP의 주소를 ESP에 넣게 되어 ESP는 현재의 EBP주소를 가리킨다.

.text:0040109B pop     ebp :
EBP는 이전의 EBP인 12FFC0h을 가리키게 되고 ESP는 한칸 내려간다.

.text:0040109C retn :
ESP가 가리키는 4011D9h주소로 이동하고(call명령 다음의 코드) ESP는 한칸 위를 가리킨다.
(참고 : 즉 처음 EBP값을 스택에 넣어 함수의 시작주소를 저장하고 RET로 함수가 끝난 후 메인루틴의 call 함수 다음의 코드로 리턴하여 메인루틴을 실행한다)

Posted by Dakuo

아이다(IDA) 사용법

Tool 2009.11.02 17:20

디스어셈블러 : 바이너리 파일을 역으로 어셈블리어로 재구성해주는 툴

IDA가 거의 독보적인 자리를 차지하고 있고, 기능도 다양하다.
 


(토렌토 사용법 : http://dakuo.tistory.com/entry/토렌토torrent-사용하기)



아이다(IDA)의 장점 :

1. 거의 모든 CPU를 지원

2. FLIRT(Fast Library Identification and Recognition Technology)는 기계어의 코드로부터 컴파일러 특유의 Library 함수를 산출해낼 수 있는 강력한 기능

3. 각종 플러그인 지원

4. Obfuscation(난독화) 코드도 해석이 잘됨

IDA 설정 :

IDA의 설정 파일은 ..\IDA\cfg 경로에 있으며 세부 설정을 할 수 있다. 단축키(idagui)를 재설정할 수 있고 disable된 설정을 enable시킬 수도 있다.



디스어셈블 상태와 디버깅 상태에서 특정 어셈블리어 코드를 고치고 싶을 때는 고칠 부분을 클릭하고 Alt+F2를 누르거나 메뉴에서 edit->Other->Manual Intruction을 누르고 바꾸고 싶은 어셈블리어 구문을 넣고 OK를 누른다.
(참고 : 프로그램 파일이 수정되는 것은 아니고 분석 화면에서만 바뀐다)




IDA 메뉴 :

IDA의 메뉴 구성에 대해서 알아보기 위해 C언어로 코드를 작성하고, 그 프로그램을 분석해보겠다. Stack에서 일어나는 흐름을 쉽게 알아보기 위해서 func()함수에 세 개의 파라미터를 전달하고, 그 값들을 합친 결과를 리턴해주는 간단한 코드를 작성했다.

#include <stdio.h>

 func(int a, int b, int c)
{
           return a+b+c;
}

int main(void)
{
           int sum;
           sum = func(1, 2, 3);
           return sum;
}


(저는 Visual 6.0으로 빌드를 하였습니다. 다른 버전으로 빌드하신분들은 컴파일러 차이에 의해 IDA로 오픈하셨을때 디어셈블된 코드가 다를수 있습니다)

컴파일한 후 파일을 drag해서 작업 창에 올려놓거나 File->Open을 이용해서 불러온다.

Stack_basic_CL.exe를 열어본 화면이다.


(참고 : IDA에서 파일을 Open하면 분석 과정을 통해 id0, id1, nam, til 파일이 생성되고, 종료하면 id0, id1, nam, til 파일이 지워지고 idb 파일이 새로 생성된다.
idb 파일은 실행 파일이 Database 파일이며, 분석 과정에서 주석을 달면 idb 파일에 저장이 된다.  idb 파일만 열면 실행했던 파일이 없어도 다시 디어셈블 과정없이 디어셈블된 코드들과 주석들을 볼 수가 있다)

IDA 5.0부터 Graph overview 기능이 있어서 처음 디어셈블하면 바로 각 함수들의 관계와 분기점들을 Graph 화면으로 보여준다. Spacebar로 Text view 화면과 Layout Graph 화면으로 전환할 수 있다.


IDA에서 스크롤을 맨 위로 올려보면 Open한 파일의 MD5정보, Open한 파일의 경로, 해당 파일의 Format 정보, ImageBase 정보, Sectjion의 size, OS 정보등이 나와 있다.


다음은 프로그램 시작점(Entry Point)으로써 프로그램이 시작되면 이 부분부터 시작이 된다.
각 변수들의 위치를 보려면 빨간박스 안에 변수를 더블클릭하여 stackframe를 확인한다.   


stackframe     
                                       
                                                  
IDA View나 Hex View 창에서 프로그램 실행의 어디에 있든 Ctrl+p를 누르면 가고 싶은 함수로 이동할 수 있다.(Functions창과 같음)


G를 누르면 'Jump to address'라고 해서 창이 뜨는데 이동하고 싶은 주소를 넣고 OK를 누르면 해당 주소로 이동한다. 디버깅을 하거나 분석을 할 때, 특정 부분을 바로 찾아갈 때 유용하다.


Ctrl+l을 누르면 이름으로 검색을 할 수 있다.


Alt+t를 누르면 Text 검색을 할 수 있다. 검색하려는 어셈블리어 구문을 넣으면 된다.


Shift+F12를 누르면 Strings window(사용되는 API 정보들과 문자열을 보여줌)를 볼 수 있다. String을 더블클릭하면 해당 지점으로 이동한다.


MessageBoxA를 더블클릭하여 따라가보자.


(참고 : xref operand는 원래의 함수 본체로 이동하는 것이고 xref reference는 해당 함수를 호출한 곳으로 이동하는 것이다)
ESC를 누르면 전단계로 돌아간다.(뒤로가기)

디어셈블 화면에서 F12를 누르면 IDA의 그래프 기능이 나온다.




IDA 화면 :


1. 메뉴바

2. 툴바 :
취향에 맞게 추가 · 삭제를 할수 있다. 빈 공간에 마우스 우클릭으로 아이콘을 추가할 수 있다.

3. Subview :
View->OpenSubviews->보고싶은 Subviews

4. 분석할 때 가독성을 위해 자주 사용하는 Subview를 오른쪽에 배치할 수 있다.

5. 함수의 분기점이나 코드에서 Jump가 있으면 그곳으로 방향을 표시해주고 코드가 어디로 분기되는지, Jump되는지 보여준다.

6. Virtual Address

7. Stack Pointer

8. 해당 어셈블리어 명령의 OPCode

9. Code Location :
코드의 흐름 중에 분기점이 발생했을 때 그 해당되는 location으로 분기할 수 있다.

10. Code Reference :
더블클릭을 하면 현재 location 부분에서 분기점이 발생된 부분으로 이동하고 ESC를 누르면 다시 전화면(뒤로가기)으로 이동한다.

11. Open한 프로그램의 디어셈블코드

12. 마우스나 키보드로 선택된 위치의 디어셈블된 코드의 위치 정보 :

왼쪽은 Virtual Address, 오른쪽은 Virtual Address와 현재 location의 시작된 곳(location으로 분기하기전 코드의 시작점)에서의 offset
ex. VA = 00001423, offset = 93    _CrtDbgReport = 00401423-93 = 00401390 (hex)

13. 현재 하드디스크의 남은 용량을 표시

14. IDA의 마지막 명령이나 정보들을 Log형태로 보여준다.

15. IDA의 현재 상태



IDA 디버깅모드 :

IDA로 Debugging을 하려면 먼저 BreakPoint(F2)를 설정해야 한다.


그 후 메뉴 Debugger->Start process (F9)를 하면 Debugging 상태로 바뀌게 된다.


1. Breakpoints :
현재 설정된 Breakpoints 목록을 보여준다.

2. IDA View-EIP :
프로그램의 실제 Code 부분이다.

3. Registers :
Registers 상태를 보여준다.

4. Flags :
Flags 상태를 보여준다.

5. Threads :
Threads 목록을 나타낸다.

6. IDA View-ESP :
Stack의 흐름을 보여준다. ESP와 EBP가 가리키는 곳을 자세히 살펴봐야 한다.

7. 메뉴바


Debugging할 때 쓰는 단축키 :

 Breakpoint  F2
 Debugging 시작  F9
 Debugging 종료  Ctrl + F2
 Step Into  F7
 Step Over  F8
 계산기  Shift + /

'Tool' 카테고리의 다른 글

디컴파일러(Decompliers)  (0) 2009.11.07
아이다(IDA)에 MS 심볼 서버 연동하기  (9) 2009.11.06
아이다(IDA)에 Hex-Ray 연동  (9) 2009.11.06
아이다(IDA) 사용법  (46) 2009.11.02
시스템 모니터링 툴  (0) 2009.11.01
올리디버거(OllyDBG) 사용법  (12) 2009.10.24
Posted by Dakuo

시스템 모니터링 툴

Tool 2009.11.01 02:11
파일과 레지스트리 변화와 네트워크 상태, 프로세스의 상태를 분석하는 툴들을 소개한다.
(2010. 11. 15. 월요일 확인결과 Filemon 이 없어지고 Process Moniter 가 생겼네요.
사용법은 똑같으니 다운받아서 아래처럼 사용하세요 ㅎㅎ)

ProcessMonitor : 
어플리케이션이 파일들을 어떻게 사용하는지 실시간으로 모니터링해서 오픈, 읽기, 쓰기, 삭제 등의 상황을 정확히 출력해준다.

Filemon.exe를 실행하면


돋보기 모양 : 모니터링(Ctrl+E), 모리시계모양 : 필터링(Ctrl+L)

돋보기 모양의 모니터링 버튼(Ctrl+E)을 이용하여 모니터링 시작 · 중지를 할수 있다.
프로그램을 켜놓기만 하면 이벤트 정보가 로그로 쌓이지만 그 양이 너무 많아서 옵션을 주어야 한다.

먼저 어떤 파일들을 모니터링할지 선택한다.


Volumes에서 원하는 하드디스크와 네트워크 파일을 체크할 수 있다.폰트 조절은 Option->Font 에서 가능하다.

모니터링된 파일 리스트 중 하나를 더블클릭하면 사용된 디렉터리를 열어서 내용을 확인할 수 있고, 모니터링 내용들은 파일(.LOG)로 저장해서 나중에 다시 열어 검토할 수 있으며 특정 문자의 검색 기능도 갖추고 있다.


필터링 버튼을 눌러서 notepad.exe 프로세스가 저장하는 파일을 찾도록 해보겠다.


필터 옵션의 Include에는 파일의 변화를 보고 싶은 프로세스명을 적고, Exclude에는 보고 싶지 않은 프로세스명을 적는다.

ex. Include 값에 별(*)을 넣으면 전체가 다 나온다. 때문에 Exclude 값에 보고 싶지 않은 값을 넣으면 되고, 그 값들이 여럿이라면 세미콜론(;)으로 구분해서 넣으면 된다. 하단의 원하는 로그 종류 옵션을 체크박스로 구분해두면 보기 편하다.

이툴은 어떤 인증을 key 파일로 하는 경우에 어떤 파일을 필요로 하는지 찾는데 리버싱에서 유용하게 쓰이거나 악성 코드를 분석할 때에 무슨 파일들을 만들어내는지 분석할 때 편하다.



Regmon :
레지스트리를 검사하는 툴로써 어플리케이션이 어떤 레지스트리들을 사용하는지 실시간으로 모니터링한다.

사용법은 Filemon과 거의 동일하며 레지스트리를 보여준다는 것만 다르다.


탐지된 레지스트리 로그를 더블클릭 하면 윈도우에 기본적으로 있는 regedit.exe의 해당 위치로 이동한다. 주요 기능인 필터를 지정한 후에 Filemon과 동일하게 사용하면 된다.


FIlemon과 동일한 화면 구성을 가지고 있다. 특정 프로그램을 분석할 때 실시간이므로 특정 시점의 변화를 알려고 할 때 좋다.



TcpView :
윈도우에서 네트워크 관련 프로세스가 어떤 포트를 열어서 사용 중인지 모니터링한다.

윈도우의 콘솔 명령어인 netstat 명령어와 비슷하지만 Update 시간을 조절해서 보거나 프로세스의 변경되는 상태를 색으로 구분해주어 더 편리하다.


어떤 포트가 어떤 프로그램에 의해서 열려있는지 확인할 때 주로 쓰며, 색으로 구분이 확실하게 되므로 실시간으로 변경되는 상태를 볼 때 주로 사용된다.



Procexp :
ProcessExplorer는 프로세스의 세부적인 정보를 보여주고, 실시간으로 새로 생성하고, 없어지는 프로세스를 색으로 표시해준다.

Option->Replace Task Manager를 선택하면 Windows 작업관리자를 대체해서 사용 가능하다.


View->Lower Pane View->DLLs를 선택하면 하단에 선택한 프로세스가 사용중인 DLL 모듈 목록들이 나타난다. 프로세스에 DLL 파일들이 사용되었다가 없어졌다가 하는 모습을 색으로 구분해서 실시간으로 보여준다.


프로세스의 정보를 보고 싶으면 프로세스를 선택하고 우클릭 하여 Properties를 선택해주고, 프로세스를 종료하고 싶으면 Kill Process를 누르면 된다.


표시된 아이콘을 프로그램 화면에 드래그 앤 드롭하면 해당 프로세스를 찾아준다.


View->Select Columns 을 선택하면 프로세스 정보를 나타낼 항목을 지정할 수 있는데, 서버들을 모니터링해야 할 일이 있을 때 원하는 항목을 지정해서 보면 편리하다.

'Tool' 카테고리의 다른 글

디컴파일러(Decompliers)  (0) 2009.11.07
아이다(IDA)에 MS 심볼 서버 연동하기  (9) 2009.11.06
아이다(IDA)에 Hex-Ray 연동  (9) 2009.11.06
아이다(IDA) 사용법  (46) 2009.11.02
시스템 모니터링 툴  (0) 2009.11.01
올리디버거(OllyDBG) 사용법  (12) 2009.10.24
Posted by Dakuo
리버싱을 위해서 툴을 사용하는 기본적인 순서이다.

1. 바이너리 분석
2. 문자열 분석 및 Api와 Dll, Event 분석
3. 모니터링을 통한 파일 및 레지스트리, 네트워크 패킷 분석
4. 디스어셈블러나 디버거를 이용한 분석


1. 바이너리 분석, 컴파일러 확인, 패커 여부를 파악한 후에 어떤 언어로 코딩되어 있는지 확인한다.
사용되는 툴 : PEID, HEX Workshop

2. 어떠한 문자열들이 들어있는지 대략적으로 살펴보고,
어떤 Api를 사용했는지, 어떤 Dll을 로딩하는지 주요 이벤트 시점의 위치에 대해서 분석한다.
사용되는 툴 : Dependency Walker,  Dumpbin, Strings

3. 모니터링을 해본다. 외부의 시스템과 어떤 패킷이 오가는지도 확인한다.
사용되는 툴 : ProcessMoniter, RegMon, TcpView
 
4. 디스어셈블링을 통해 얻어진 어셈코드를 분석하거나 디버거로 로드하여 실시간으로 분석해본다.
사용되는 툴 : OllyDbg, IDA


대체로 이와 같은 기본 순서에서 몇가지를 더 추가하거나 바로 디버깅하는 형태로 진행한다.

리버싱을 위해서는 다각적인 분석이 필요하기 때문에 여러 가지 툴을 사용하게 된다.
Posted by Dakuo
레나(Lena)라는 제작자가 리버싱 플래시 강좌 40강 중에 3번 강좌에 있는 RegisterMe.exe와 RegisterMe.Oops.exe파일을 풀어보겠다. 강좌 파일을 다운로드 받으면 연습 문제와 강의 파일이 모두 들어 있다.

참고로 관심이 있으신 분들은 1강부터 40강까지 순서대로 모두 보는 것을 추천한다. 자료는 모두 영문이다. 조만간 풀이를 올리도록 하겠다.



문제의 설명을 보면 nag를 제거하고, 헤더 문제를 해결이라고 되있다. nag는 경고창 정도를 의미한다.

#03.tutorial 폴더의 files 폴더에 RegisterMe.exe 문제를 올리디버거로 실행해보면


nag 창이 떴다. 확인을 누르면 메인 폼이 뜬다.


종료를 하면 또 nag 창이 뜬다.


처리해야 할 부분은 실행할 때 1번, 종료할 때 1번 총 두 곳이다.

대부분 Strings를 검색해보기 마련인데, 패킹이나 암호화 프로텍터가 있거나, 함정이 숨겨져 있는 경우가 많기 때문에 올리디버거로 재시작하고, 초반부터 F8로 StepOver해 보겠다.


GetModuleHandleA를 통해서 얻어진 값을 비교한 후에 JE 구문을 만나 첫 nag 창이 뜬다.
강제로 jump를 시켜서 진행해보면, 종료할 때에 창이 또 뜨게 된다. 모든 nag 창을 강제로 jump시켜버려도 되지만, PE 구조를 이용하기 위해 EP 주소를 변경하여 해당 nag가 실행되지 않도록 해보겠다.

(윈도우 PE 구조 참고 : http://dakuo.tistory.com/entry/Windows-PE-구조)

M(Memory Map)을 클릭해서 PE 헤더 부분을 확인해보면


00400000주소부터 사이즈인 0x1000h까지가 PE 헤더이다. 해당 라인에서 더블클릭하면 DUMP창이 나타나고, DOS 헤더 구조를 볼 수 있다.


DOS 헤더를 지나 PE 구조 부분까지 내려보면 PE signature 부분을 시작으로 해서 PE 구조가 나타난다.


004000E8    00100000    DD 00001000          ;  AddressOfEntryPoint = 1000

ImageBase 값에 OEP 값을 더해서 시작하므로 00401000 주소에서 코드가 실행된다.

시작되는 지점을 수정해서 첫 번째 nag 창을 제거할 것이므로 Memory Map 창에서 PE 덤프를 하여 나타난 OEP 주소지(004000E8)로 Hex dump 창에서 이동(Ctrl+G)한다.


덤프된 hex 값 00 10 00 00 을 확인하고 24 10 00 00 으로 수정한다. 수정할 곳을 블록잡고, 우클릭을 하여 Binary -> Edit를 선택하여 수정하고 저장하자.
Hex dump에서 24 10 00 00으로 수정하면 리틀엔디안에 의해서 00 00 10 24로 처리된다.

004000E8    24100000    DD 00001024          ;  AddressOfEntryPoint = 1024


저장한 파일을 실행해보면 첫 번째 nag는 해결되었다.



종료시에 나타나는 nag 창은 프로그램을 종료할 때 나타나는 것으로 Messagebox 부분을 Nop(No Operation) 처리하면 된다. 종료할 때에 나타나는 nag 창은 어떻게 찾는 것이 좋을까?
1. nag 창에 나타나는 문자열을 추출하여 검색.
2. Back To User 모드 기능 사용
3. Commandline or Commandbar 플러그인 사용 bpx MessageboxA로 검색.

각각 이미 서술한 방법이니 3가지 방법중에 마음에 드는 것으로 골라 해당 코드 부분을 찾자.


PUSH 0부터 Call MessageBoxA까지 블록 선택하고 Binary -> Fill with NOPs를 선택한다. 수정후 저장한다. 실행해보면 nag 창이 하나도 안뜨며 문제 풀이가 끝났음을 알 수 있다.



이번에는 RegisterMe.Oops.exe파일을 풀기 위해 올리디버거로 열어보자. 그러면 화면과 같은 잘못된 실행 포맷이라는 에러 문구가 나타난다.

확인을 누르면 이상한 주소지가 선택되어 디버거가 실행될 것이다. 이문제는 기존 문제에서 PE 구조만 꼬아놓은 경우로, 수작업으로 수정하거나 자동으로 PE 구조를 보정해주는 플러그인을 이용하는 방법을 소개할 것이다.

먼저 PE 구조를 살펴보고, 어떤 문제가 있는지 확인해보자.
M(MemoryMap)을 선택한 후 PE header 부분을 더블클릭하여 Dump 창을 연다.


일반적인 PE Header의 길이는 1000인데, 5000으로 되어 있는 것을 체크하고 더블클릭하여 덤프된 창에서 내려가면서 PE 구조를 확인한다.


AddressOfEntryPoint = 1000, ImageBase = 400000. EP(시작되는 부분)는 00400000 + 1000 = 00401000이다. 직접 CPU 창에서 00401000 주소지로 이동(Ctrl+G)하고, BreakPoint(F2)를 걸면 올리디버거가 혼란스러워 하며, 다음과 같은 경고를 낸다.


~~~~~~~~~~~~~~

'예(Y)' 버튼을 눌러 Breakpoint(F2)를 설정하고, Run(F9)을 하면 00401000에서 정지된다.

PE 구조가 잘못되었더라도 시작 지점까지 로드가 되었기 때문에 M(Memory Map)을 열어서 다시 PE 구조를 확인해보면 아까와는 다르게 나타난다.


PE 사이즈는 5000이고 text 섹션은 없어져 있는 상태이다. PE 구조를 DUMP에서 보면 더 확실하게 우리가 알고있는 일반적인 PE 구조와 어떻게 다른지 알 수 있다.


이상한 부분과 수정해야 할 값을 정리하면 다음과 같이
NumberOfRvaAndSize를 제외하고 사이즈 값을 크게 늘려놓은 것을 복원하는것 뿐이다.

004000DC    00040040    DD 40000400          ;  SizeOfCode = 40000400 (1073742848.)
: 40000400 -> 400

004000E0    000A0040    DD 40000A00          ;  SizeOfInitializedData = 40000A00 (1073744384.)
: 40000A00 -> A00

004000EC    00100040    DD 40001000          ;  BaseOfCode = 40001000
: 40001000 -> 1000

004000F0    00200040    DD 40002000          ;  BaseOfData = 40002000
: 40002000 -> 2000

00400134    04000040    DD 40000004          ;  NumberOfRvaAndSizes = 40000004 (1073741828.)
: 40000004 -> 10 (이 값은 옵셔널 헤더의 디텍터리 엔트리 개수로 일반적으로 10이며, 이 값을 변경함으로써 올리디버거가 오작동하게 만들 수 있다고 알려져 있다.)

00400138    00005000    DD 00500000          ;  Export Table address = 500000
: 500000 -> 0

0040013C    00000500    DD 00050000          ;  Export Table size = 50000 (327680.)
: 500000 -> 0

이문제는 문제 제작자가 사이즈 값들이 400이면 40000을 앞에 붙여 PE 구조를 바꾸어놓거나 특별한 값으로 변경하여 올리더버거가 잘못 작동하도록 해둔 것이다.
수정을 할 때에는 NumberOfRvaAndSzies 값의 경우 hex dump 창에서 00400134 주소로 이동(Ctrl_+G)하여 , 기존의 값인 40000004를 10으로 변경하면 된다. 리틀엔디안 값으로 표시되어 04 00 00 40으로 나타나 있으니 거꾸로 뒤집어서 10 00 00 00 으로 수정해서 정상적인 값으로 복원시키면 된다. 나열한 항목들을 모두 수정한 후에 바이너리를 저장하고 올리디버거로 다시 열어 PE 구조를 확인하면 text 색션도 나타나며, 기존의 nag 창이 뜨는 문제와 동일하게 나타나게 된다.

참고로 Hex Dump에서 Binary -> Edit 기능을 사용할 때는 PE 구조 부분을 한꺼번에 블록을 씌워서 수정을 하도록 하고, 아니면 헥스에디터를 이용하여 수정하는 것이 더 편할 수도 있다.



Tip : 올리디버거의 플러그 인 중 Olly_Advanced_v1.27.rar을 소개한다. 이것은 설치하여 옵션을 조절하는 것만으로 자동으로 fake된 ExportTable을 수정해주거나 Copy to Exe 메뉴에서 에러나는 버그를 수정해주고, 그 외에도 anti debugging을 우회할 수 있는 기능 등을 사용할 수 있다.


다운받아서 advancedolly.dll 파일만 올리디버거의 plugin 폴더에 넣어주면 된다.
다음은 Olly Advanced 1.27의 옵션창이다.


Bugfixes 탭에는 올리디버거의 버그를 고치는 옵션들이 있다.

Additonal Options 탭에는 여러 기능들이 있는데 잘 생각해서 체크하기 바란다. 나중에 플러그인을 많이 설치하다 보면 플러그인들끼리 기능상 충돌이 생기게 된다 따라서 필요할때만 켜놓는것이 좋다.

Anti-Debug 탭에는 디버그하는 것을 막는 루틴들이 여러 가지 있는데 그런 부분들을 우회할 수 있도록 해준다.


마지막에 풀었던 PE 헤더를 꼬아놓은 문제는 이 플러그 인을 설치한 후에 열면 모두 정확한 값으로 수정되어 열리기 때문에 풀이에서처럼 수작업을 해줄 필요가 없었다.

Posted by Dakuo

KeyFile : 인증을 위해서 시리얼키를 원하는 것과 비슷하게 키값을 파일에 저장하거나 어떤 파일 이름이 같은 위치에 있는 것을 확인하는 인증을 할 때 사용되는 파일을 의미한다.

파일과 관련된 문제에서는 파일이나 레지스트리 사용하는 것을 확인하기 위해서 모니터링툴을 사용하는데, Filemon을 주로 사용할 것이다.
         
                                       (Filemon 사용법 참고 : http://dakuo.tistory.com/22)


CrackMe 15 문제를 풀어보도록 하겠다.
다운로드 하여 Project1.exe을 실행해보면


올리디버거로 열어서 스트링에 참고할 만한 내용이 있는지 찾아본다.
스트링 추출을 하고 살펴보면 solved라는 문자열을 보인다.


이상한 점은 File Monitor라고 해서 Sysinternals 홈페이지 표시되어 있다는 것이다.
아마도 문제 제작자가 파일을 모니터링 해보라고 힌트를 준것 같다. 프로그램을 실행해 놓고 Filemon을 실행해보도록 하겠다.


Filemon을 실행하고 문제 파일의 이벤트만 볼수 있게 Incude에 Project1.exe를 넣고 OK 버튼을 누른다.


Filemon을 켜놓은 상태에서 문제 파일을 실행하면 화면과 같은 이벤트를 볼 수 있다.
C:\challneges-crackme15\kernel32.dll을 찾고 있다. 따라서 해당 위치에 kernel32.dll이라는 이름으로 파일을 만들어둔다. 파일을 만들어도 문제 파일에서는 A 문자열만 나타난다.

올리디버거를 열어서 solved 위치 근처를 분석해보면


mov 명령으로 solved 문자열을 넣고 뭔가 call을 하는 것을 알수 있다.
이 명령이 시작되는 부분을 보면 분기점이 존재하고, 이 분기점의 점프 위치는 solved의 다음 위치이다.

00442514  |. /E9 8E000000   JMP Project1.004425A7

여기서 분기를 못하도록 JMP 구문을 NOP 처리한다.

JMP 구문이 작동하지 않고 다음 명령들이 진행되는데, 그 후에 점프 구문을 또 만나게 된다.

00442574  |. /74 51         |JE SHORT Project1.004425C7

이 부분을 한번 더 NOP 처리해주면 문제는 해결되었다고 표시된다.




또 다른 풀이로는 처음 점프 구문을 solved 문자열이 mov되는 곳으로 바로 이동시켜도 같은 결과를 낼 수 있다.

00442514     /EB 7A         JMP SHORT Project1.00442590

이번에는 어셈코드를 직접 수정하지 않고 hex dump 창에서 바이너리를 직접 수정하는 방법을 설명하겠다. 일단 Ctrl+F2를 눌러 문제 파일을 재시작하고 두 번째 풀이 위치인 00442514로 이동(Ctrl+G)을 한다.

00442514     /E9 8E000000   JMP Project1.004425A7

현재 이렇게 되어있는 것을 다음처럼 변경하려고 한다.

00442514     /EB 7A         JMP SHORT Project1.00442590
00442516     |90            NOP
00442517     |90            NOP
00442518     |90            NOP

스페이스바를 눌러서 어셈코드 수정 창에서 바꿔주어도 되지만, hex dump 부분의 바이너리 를 수정해보겠다.

(참고 : 어셈블리어를 수정하고 그것을 취소하려고 할 때는 수정된 라인에 커서를 둔 상태에서 Alt+BackSpace를 누르면 된다)


기존에 있는 값은 E9 8E 00 00 00 이고, 수정해야 하는 값은 EB 7A 90 90 90 이다.
블록을 씌운 다음에 우클릭 메뉴에서 Binary -> Edit 를 선택한다.


바이너리를 수정해준다.


저장한 파일을 실행해보면 문제 풀이가 완료됨을 알 수 있다.



이와 같은 리버싱 과정들을 보면 간단한 인증 절차는 점프문 한 개 수정하는 것으로도 우회가 가능하다.

Posted by Dakuo
키젠 문제는 프랑스의 haiklr라는 아이디를 쓰는 사람의 홈페이지에서 다운받았다.
문제를 다운로드 받아서 압축을 풀어보면 ReadMe.txt 파일이 있다.


Type : Keygenme
Level : Newbie
Langage : C (console)
Packed : Non

시리얼키들을 생성해내는 문제고, 난이도는 쉬운 편이며, C언어 콘솔어플리케이션이고, 패킹은 하지 않았다고 설명되어 있다.

문제를 실행해보자.


Name과 Serial을 입력하라고 나타난다.
입력을 하니까 '잘못된 패스워드'라는 문자열이 출력된다.

올리디버거로 열어서 어떤 알고리즘에 의해서 잘못된 패스워드로 판단했는지 확인해보고 정확한 시리얼값을 찾아보겠다.


문제 파일을 열고, 마우스 우클릭 메뉴에서 Search for -> All referenced text strings를 선택하여 문자열을 추출한다.


시리얼키가 일치했을 때 나타날 "Yeah, c'es" 부분에서 더블클릭하여 해당 위치로 이동한다.
어셈블리 코드를 보면서 프로그램을 분석해보면 성공 메시지 부분에서 위로 이동하면 Name을 입력받는 부분이 나타난다.


'[x] Name : '이 출력되고, scanf로 입력값을 받고, strlen을 통해서 이름의 길이를 체크한다.


어셈블리 코드를 보면 CMP를 이용해서 조건이 '3 < Name 길이 < 15'와 같은지 비교하고
맞으면 JMP구문에서 004014B0주소로 점프하고, 맞지 않으면 점프해서 printf하고 system으로 pause명령을 실행하게 된다.

004014B0주소로 가면 시리얼키를 넣는 부분이 나타나고, 입력한 값이 반복문을 통해서 변경된다.


시리얼값을 입력받은 다음에 반복되는 형태로 JMP를 하여 위쪽으로 이동되는 것을 볼 수 있다. 시리얼값이 들어온 부분 다음을 Breakpoint(F2)설정하고 StepOver(F8)을 누르면서 Value창을 확인하면서 반복되는 과정을 보면 Name값의 문자열이 한 개씩 들어오면서 중간에 공백 문자가 들어가는 것을 볼 수 있다.

Name에 'test'을 입력하고 값이 변경되는 과정을 주요 어셈블리 코드들을 보며 체크해보겠다.

StepOver(F8)해가면서 하단의 Value창과 우측 상단의 레지스터 값들을 체크하면서 봐야한다.
(Hex dump창의 아래 나온 변수의 주소값으로 이동해서 확인을 해보면 값들이 어떻게 바뀌어 가는지를 볼 수 있다)

004014E0   > /8B45 E8       MOV EAX,DWORD PTR SS:[EBP-18]
// [EBP-18]에는 test의 길이인 4가 들어가 있고, 그것을 EAX에 저장

004014E3   . |89C2          MOV EDX,EAX
// EAX값을 EDX에 저장

004014E5   . |8D0412        LEA EAX,DWORD PTR DS:[EDX+EDX]
// [EDX+EDX]는 EDX의 값을 곱하기 2 하여 8이 된 주소를 EAX에 저장

004014E8   . |3945 FC       CMP DWORD PTR SS:[EBP-4],EAX
// EAX와 [EBP-4]를 비교한다. for문을 언제까지 할지 결정한다.

004014EB   . |7C 03         JL SHORT Babylon_.004014F0
// CMP에 의해 값이 같지 않으면 점프한다.(반복문 진행)

004014ED   . |EB 31         JMP SHORT Babylon_.00401520
// 반복이 완료되면 반복 구문 밖으로 점프하여 반복을 종료한다.

004014EF     |90            NOP
// 아무일도 하지 않는다.

004014F0   > |8D85 A0FDFFFF LEA EAX,DWORD PTR SS:[EBP-260]
// [EBP-260]의 주소를 EAX에 저장

004014F6   . |8B55 FC       MOV EDX,DWORD PTR SS:[EBP-4]
// EDX = 0

004014F9   . |8D8D E0FEFFFF LEA ECX,DWORD PTR SS:[EBP-120]
// 이름의 주소를 ECX에 저장

004014FF   . |8B5D F8       MOV EBX,DWORD PTR SS:[EBP-8]
// EBX = 0

00401502   . |8A0C0B        MOV CL,BYTE PTR DS:[EBX+ECX]
// 이름의 첫번째 값의 아스키 코드를 CL에 저장, test의 t가 먼저 저장

00401505   . |880C02        MOV BYTE PTR DS:[EDX+EAX],CL
// CL의 값을 [EDX+EAX]에 저장

00401508   . |8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
// EAX = 0

0040150B   . |40            INC EAX
// EAX를 INC로 1증가 EAX = 1

0040150C   . |8D95 A0FDFFFF LEA EDX,DWORD PTR SS:[EBP-260]
// [EBP-260]의 주소를 EDX에 저장

00401512   . |C60410 20     MOV BYTE PTR DS:[EAX+EDX],20
// [EAX+EDX]에 16진수로 20 -> 0x20 아스키값으로 공백이다.

00401516   . |FF45 F8       INC DWORD PTR SS:[EBP-8]
// [EBP-8]값에 INC로 1증가

00401519   . |8345 FC 02    ADD DWORD PTR SS:[EBP-4],2
// [EBP-4]값에 2를 더함

0040151D   .^\EB C1         JMP SHORT Babylon_.004014E0
// 다시 반복을 시도한다.

이해를 돕기 위해 위의 어셈블리 코드들을 C언어로 재구현했다. C언어와 비교해보면서
어셈블리 코드들을 다시 한번 분석해보자.

char str[5] = "test";  // 4 = [EBP-18] (test의 길이) ,
                             // 'test' 문자열의 인덱스(str[0])주소 = [EBP-120]
char str1[8] = {0};   // 변경된 문자열을 저장할 배열의 인덱스(str1[0])주소 = [EBP-260]

for( int i =0 , int j = 0 ; i < 8 ; i+=2, j++ )  // i = [EBP-4], j = [EBP-8]
{
            str1[i] = str[j];                                  // str[j] = CL -> str1[i]에 대입.
            str1[i+1] = 0x20;
}

이렇게 반복문을 지나고 나면 SS:[EBP-260]에는 "t e s t "가 들어가게 된다.
그 후에 이상한 값들이 추가되는데, 위치와 값을 체크해보면


이상한 값이 들어가고 길이를 체크하며, 반복문을 통해 문자열들의 길이만큼 반복을 하면서 BL에 한 글자씩 넣고 00401564   .  FEC3          INC BL 을 통하여 값을 변경한다.
이 반복문을 C언어로 재구현하면,

char str2[35] = "-[#]]=}&&&+(=$*,,)&.*/+++[][;/..?" [EBP-160]

for( int i = 0 ; i < 34 ; i++ ) // i = [EBP-4]
{
            str2[i] = str2[i]+1;
}

아래로 내려오면 또 반복문이 나오면서 XOR연산을 한다.
004015C9   .  321C37        XOR BL,BYTE PTR DS:[EDI+ESI]
이 반복문을 C언어로 재구현하면,

char str2[35] = ".\$^^>~''',)>%+--*'/+0,,,\^\<0//?" [EBP-160]
char str1[8] = "t e s t ";                                          [EBP-260]

for( int i = 0 ; i < 8 ; i++ ) // i = [EBP-4]
{
            str2[i] = str2[i]^str1[i];                   // '^' 는 XOR 연산
}

아래로 내려오면 또 반복문이 나온다.
이 반복문을 C언어로 재구현하면,

char str2[35] = "Z|A~-'',)>%+--*'/+0,,,\^\<0//?" [EBP-160]
char str3[35] = {0};                                             [EBP-360]

for( int i = 33, int j = 0 ; i >= 0 ; i--, j++ ) // i = [EBP-4], j = [EBP-C]
{
             str3[j] = str2[i];
}

아래로 내려오면 또 반복문을 만난다.
이 반복문을 C언어로 재구현하면,

char str2[35] = "Z|A~-'',)>%+--*'/+0,,,\^\<0//?" [EBP-160]
char str3[35] = "1?/0<\^\,,,0+/'*--+%>),''-~A|Z" [EBP-360]
char str4[35] = {0};                                              [EBP-460]

for( int i = 0, int j = 0, int k = 0 ; i < 34 ; j++, k++ ) i = [EBP-4], j = [EBP-10], k = [EBP-14]
{
           str4[i] = str3[j];
           i++;
           str4[i] = str2[k];
           i++;
}

아래로 내려오면 또 반복문을 만난다.
이 반복문을 C언어로 재구현하면,

char str4[35] =  "1Z?/A/~0-<\.^\',',,,)0>+%/+'-*-" [EBP-460]

for(int i = 0 ; i < 34 ; i++ )
{
        if(str4[i]<=1F)
        {
                     str4[i]=0x36;
        }
        
        if(str4[i]>'z')
        {
                     str4[i]=0x36           
        }
}

분기문을 만났다.
여기까지 정리를 하면 (이표에 나와있는 문자열값은 정확하지 않다.
올리디버거에 Hex dump창의 아래 나온 변수의 주소값으로 이동해서 확인을 해보자)

 [EBP-160] = "-[#]]=}&&&+(=$*,,)&.*/+++[][;/..?"
                                    ↓
 [EBP-160] = ".\$^^>~''',)>%+--*'/+0,,,\^\<0//?"
                                    ↓
 [EBP-160] = "Z|A~-'',)>%+--*'/+0,,,\^\<0//?"
                                    ↓ 
 [EBP-360] = "1?/0<\^\,,,0+/'*--+%>),''-~A|Z"
                                    ↓
 [EBP-460] = "1Z?/A/~0-<\.^\',',,,)0>+%/+'-*-"
                                    ↓
 [EBP-460] = "1Z66/A/60-<6\6^6\',',,,)0>+%/+'-*-"

004016E3   .  3B45 E8       CMP EAX,DWORD PTR SS:[EBP-18]  // [EBP-18] = 4
004016E6   .  7C 08          JL SHORT Babylon_.004016F0
004016E8   .  EB 4B         JMP SHORT Babylon_.00401735

JL구문에서 점프를 하지 않으면 JMP를 만나 성공 메시지가 있는 곳으로 간다.

마지막 반복문을 진행하여 성공 or 실패 메시지로 점프하는데 이 반복문을 C언어로 재구현하면,

char str5[5] = "1234";                                                    [EBP - 560]
char str4[35] = "1Z66/A/60-<6\6^6\',',,,)0>+%/+'-*-";    [EBP - 460]

for ( int i = 0 ; i < 4 ; i++ ) // i = [EBP-4]
{
        if(str5[i]!=str4[i])
        {
                    실패메시지 호출;
        }
}
성공메시지 호출;


여기까지의 분석을 통해 우리는 Name : test 를 입력한 경우에 시리얼값은 1Z66 이라는 것을 찾아냈다.


이제 시리얼값이 어떻게 만들어지는지 정리해보겠다. 이러한 알고리즘을 프로그래밍하면 그것을 키젠이라고 한다.

1. Name 입력 : "test"

2. [EBP-160]에 "-[#]]=}&&&+(=$*,,)&.*/+++[][;/..?"값이 들어간다.

3. [EBP-160]에 값을 INC한다. ".\$^^>~''',)>%+--*'/+0,,,\^\<0//?"

4. Name 문자열 사이에 공백을 추가한다. "t e s t "

5. 공백이 들어간 Name의 길이만큼 반복하면서 INC된 [EBP-160]값과 XOR 연산한다.

6. [EBP-360]에는 INC된 [EBP-160]값이 거꾸로 뒤집혀서 들어간다.

7. [EBP-460]에는 [EBP-360]값과 [EBP-160]값을 번갈아 가며 넣는다.
    ex. [EBP-460][1] = [EBP-360][1]
          [EBP-460][2] = [EBP-160][1]

8. [EBP-460]의 문자중에 'z'보다 크거나 0x1F보다 작거나 같으면 6으로 변경한다.

9. [EBP-18](Name의 길이)만큼 [EBP-460]을 앞에서부터 잘라낸다.

다음 내용들을 정리하여 짜본 소스를 첨부한다.
이해가 안되는 부분은 질문을 해주시기 바랍니다.


키젠 문제를 풀어보았는데, 일반 CrackMe 문제보다는 더 꼼꼼히 정리하고, 값들이 어떻게 변화되는지를 살펴봐야 한다. 문제 자체가 중요한 것이 아니라 문제를 풀면서 어느 정도 어셈블리어에 익숙해지고, 분석하는 방법을 배워가는게 중요하다.

(참고로 아스키 값과 10진수, 16진수 코드 값은 여기에 정리된 것이 있다
                                         
                                           http://www.asciitable.com/)

Posted by Dakuo
이번에 풀어볼 문제는 upx로 패킹이 되있는 문제로 upx -d 옵션으로 압축을 풀어도 되지만 메뉴얼 언패킹하는 방법을 간단하게 설명하기 위해서 올리디버거의 덤프 플러그인을 사용하여문제를 풀어보도록 하겠다.
다음을 다운받아 Plugin 폴더에 넣는다.


올리디버거의 메모리 덤프의 리빌드 기능만으로도 upx 압축은 풀리기 떄문에 쉽게 따라할 수 있는 문제이다.


먼저 PEID로 바이너리를 확인해본다.
               (PEID 사용법 참고 : http://dakuo.tistory.com/entry/바이너리-분석)


upx 압축되어 있는 문제 파일인 CrackMe2.exe를 올리디버거로 열어본다.


코드가 압축되었으며, 분석을 더할 것인지 묻는다. 예를 누른 후 아래쪽으로 내려가다 보면 압축이 모두 풀려서 메모리에 올라가 있는 초기 상태인 OEP(Original Entry Point)부분으로 가는 JMP문이 나타난다.


upx 같은 경우는 프로세스를 보호하기 위해서 압축하는 것이 아니기 때문에 OEP를 찾는 것이 어렵지 않다.
JMP구문에서 Breakpoint(F2)를 설정하고, Run(F9)을 하면 이 주소에서 Paused가 된다.
Step Over(F8)을 한 번 해주면 OEP(Original Entry Point) 위치로 이동한다.

PUSH EBP 위치에서 올리디버거의 plugin의 덤프를 하면 된다.


마우스 우클릭 후 Dump debugged process를 선택하거나 플러그인 메뉴에서 선택을 해도 된다.



올리디버거의 덤프 플러그인에 import 테이블을 리빌드하는 옵션이 있다. upx로 된 경우에는 옵션을 체크한 후에 덤프 버튼을 누르면 메모리상의 프로그램이 덤프가 되어 압축이 풀린다. 파일을 저장하고 정확하게 되었는지 PEID로 확인해보면


upx 압축이 풀리고 제작 툴인 볼렌드 델파이라고 탐지해주는 것을 확인할 수 있다.

upx가 패킹을 하는 원리는 기존의 소스 코드 부분들을 모두 새로 만든 upx 섹션에 압축하여 저장을 해놓고, 실행 부분에서는 upx 섹션에 저장해놓은 부분을 풀어서 메모리에 올리게 된다. 이런 원리로 압축이 다 풀려서 OEP(Original Entry Point)로 가게되는데, 이 부분에서 메모리상의 프로그램을 덤프받는 것이다. 그냥 덤프받으면 IAT 정보가 정확하지 않으므로 덤프 플러그인의 옵션에서 Rebuild Import를 체크하는 것이다. 저장한 파일을 올리디버거로 열어서 Run(F9)을 눌러 프로그램이 어떤 문제인지 확인해보면


실행 후 시리얼을 넣는 editbox가 있으며 시리얼을 넣고 check the serial 버튼을 누르면 Wrong Serial이라는 타이틀의 메시지 창이 나타난다.


스트링 검색을 해서 이벤트 시점을 찾아도 되지만 새로운 방법으로 풀어보겠다. 메시지 창이 나타나는 경우 더 빠르게 이벤트를 찾을 수 있는 방법이다.


Back to user mode : 
특정 이벤트를 일어나기 전에 설정해두고 Call 명령이 일어난 바로 다음 위치를 잡을 수 있다.

사용순서 :

1. 프로세스 attach(open)
2. Run(F9)
3. 프로그램을 메시지 창과 같은 정지된 상태로 만든다.
4. paused(F12)
5. back to user mode(Alt+F9) 설정
6. 프로그램에서 이벤트 발생(메시지 창에서는 확인 버튼 클릭)
7. 올리디버거에서 해당 부분에 커서가 설정된다.

(주의할 점 : back to user mode 기능은 브라우저나 내부 스레드가 작동하는 프로그램의 경우에는 내부 이벤트가 수시로 일어나서 해당 모드가 풀려버리니 사용하려면 메시지 박스와 같이 프로세스가 멈추는 상태에서 사용한다)

Wrong Serial 창이 뜬 상태에서 올리디버거에서 일시정지(F12)를 시킨 후에 back to user mode 설정키인 Alt + F9를 눌러준다.
Debug 메뉴에서 Excute till user code를 선택해도 된다.


일시정지(F12)를 하면 Paused라고 표시가 되고,


Alt + F9를 누르면 back to user mode가 표시된다.


이런 상태에서 CrackMe 문제의 메시지 창의 확인 버튼을 눌러준다.

보이는 것과 같이 MessageBoxA 함수가 호출된 다음의 위치가 선택된다.
틀렸다는 메시지 창이 나타나는 곳은 찾았으니 그 메시지 내용이 설정되는 곳을 찾기 위해 파라미터를 확인한다.

MessageBoxA를 Winapi 확인을 해보면 다음과 같다.


메시지 내용인 "You are a bad cracker!"가 어디에서 입력됬는지 어셈블리 코드에서 Text 부분이 입력되는 곳을 확인한다.


PUSH ESI를 통해서 파라미터가 들어갔음을 알 수 있다.
올리디버거의 CPU 레지스터값을 보면 우리가 찾는 Text가 있다.


Ctrl+G 단축키를 이용하여 ESI가 가리키고 있는 주소인 00442C68를 입력하면 다음과 같은 곳으로 이동한다.


문자열들이 보인다. 이 부분에서 한 페이지만 위로 올려보면 값들이 구분되는 부분이 보인다.


첫 줄에서 Value 창을 확인하면서 Breakpoint를 잡아놓고 StepOver하다 보면 내가 입력한 값이 들어가는 것을 볼 수 있다.



1234라고 입력한 값이 Value창에 찍히는 것을 볼 수 있다.


다음 줄에서 시리얼같은 값이 EDX에 저장되고, CALL 명령이 실행되면서 StepInto(F7)을 하여 내부로 들어가서 확인해보면 CMP를 통해 입력한 값과 시리얼 키를 비교하는 부분이 나타난다.



결정적으로 JNZ 구문에서 "Congrats! You were successful!"과 "You are a bad cracker!"가 구분된다.

이 문제 같은 상황에서는 back to user mode 기능을 사용하면 보다 빠르게 분석을 할 수 있다.

이제 "12011982" 숫자 값을 넣어서 확인해보자.

Posted by Dakuo
커맨드 명령을 사용하려면 특정 상황별로 유용한 api를 알고 있어야 한다.


파일 생성하거나 열기(Open)
16bit : CreateFile
32bit : CreateFileA
wide : CreateFileW

파일 입출력(Read&Write)
ReadFile : 읽기
WriteFile : 쓰기

파일 접근(Access)
SetFilePointer

시스템 디렉터리를 얻어오는 함수
16bit : GetSystemDirectory
32bit : GetSystemDirectoryA
wide : GetSystemDirectoryW

.ini 파일과 관련된 함수 : ini 구성 설정에 관련된 함수들
16bit : GetPrivateProfileString, GetPrivateProfileInt, WritePrivateProfileString, WritePrivateProfileInt
32bit : GetPrivateProfileStringA, GetPrivateProfileIntA, WritePrivateProfileStringA, WritePrivateProfileIntA
wide : GetPrivateProfileStringW, GetPrivateProfileIntW, WritePrivateProfileStringW, WritePrivateProfileIntW

레지스트리와 관련된 함수 : 레지스트리의 키를 생성 혹은 삭제할 때
16bit : RegCreateKey, RegDeleteKey
32bit : RegCreateKeyA, RegDeleteKeyA
wide : RegCreateKeyW, RegDeleteKeyW

현재 열린 레지스트리 키를 읽을 때
16bit : RegQueryValue
32bit : RegQueryValueA
wide : RegQueryValueW

레지스트리 키를 열 때
16bit : RegCloseKey, RegOpenKey
32bit : RegCloseKeyA, RegOpenKeyA
wide : RegCloseKeyW, RegOpenKeyW

객체에서 문자열을 읽을 때
16bit : GetWindowText, GetDlgItemText
32bit : GetWindowTextA, GetDlgItemTextA
wide : GetWindowTextW, GetDlgItemTextW

객체의 텍스트를 지정
16bit : SetWindowText, SetDlgItemText
32bit : SetWindowTextA, SetDlgItemTextA
wide : SetWindowTextW, SetDlgItemTextW

메시지 박스
16bit : MessageBox, MessageBeep
32bit : MessageBoxA, MessageBoxExA
wide : MessageBoxW, MessageBoxExW

메시지 관련
16bit : SendMessage
32bit : SendMessageA
wide : SendMessageW

날짜와 시간 : 날짜와 시간을 구할 때
GetSystemTime
GetLocalTime
SystemTimeToFileTime

윈도우를 생성하거나 제거할 때
16bit : CreateWindow, DialogBoxParam, CreateWindowEx, DestroyWindow, EndDialog, Showwindow, bitblt
32bit : CreateWindowA, CreateWindowExA, DialogBoxParamA
wide : CreateWindowW, CreateWindowExW, DialogBoxParamW
Posted by Dakuo
1. 진수 변환 :

2진수, 10진수 16진수의 뜻과 자유롭게 변환하는 법을 소개한다.

10진수를 기준으로 해서 2진수와 16진수를 설명하겠다.

2진수는 0과 1로만 이루어져 있어서 1 다음이 한 자리 올림을 한 10이 된다. 2진수가 영어로 binary이기 때문에 뒤에 b를 붙인다.

16진수는 1부터 9, 그리고 A부터 F까지 순차적으로 사용하고, 10진수로 16이 되면 그때 자릿수를 올려 10이 된다. 16진수를 표현할 때는 영어로 hexadecimal이기 떄문에 뒤에 h를 붙인다.
그리고 구분을 더 편하게 하기위해서 앞부분에는 0을 붙인다.

 10진수  2진수   16진수  10진수  2진수  16진수
 1  1  1  10  1010  A
 2  10  2  11  1011  B
 3  11  3  12  1100  C
 4  100  4  13  1101  D
 5  101  5  14  1110  E
 6  110  6  15  1111  F
 7  111  7  16  10000  10
 8  1000  8  17  10001  11
 9  1001  9  18  10010  12

이러한 진법 계산은 윈도우 계산기를 이용하면 편리하다.
윈도우 실행(Win키+R) calc.exe 혹은 cmd 창에서 calc.exe 혹은 보조프로그램에서 계산기를 실행하고 공학용 옵션을 활성화시켜준다.


계산기의 공학용 옵션을 켜면 Hex(16진수), Dec(10진수), Oct(8진수), Bin(2진수) 버튼이 나타난다.
변환하는 방법은 Dec를 선택한 상태에서 숫자를 십진수로 적고, 변환하고 싶은 진수버튼을 누르면 변환이 되어 표시된다. 각 진수간의 변환도 가능하다.



2. CPU 레지스터 :

CPU(Central Processing Unit)는 메모리로부터 명령어를 가져와서(fetch) 어떤 명령어인지 해석하고(decode) 실행하는(execute) 동작을 한다.

레지스터는 CPU 내부에 존재는 작은 고속의 메모리이다. 레지스터의 종류로는 범용 레지스터, 세그먼트 레지스터, 상태 플래그 레지스터, 명령 포인터 레지스터 등이 있다.
다음은 올리디버거에 나타나는 레지스터 정보이다.



범용 레지스터

EAX(Extended Accumulator Register)
곱셈과 나눗셈 명령에서 자동으로 사용되고 함수의 리턴값이 저장되는 용도로 사용된다.

EBX(Extended Base Register)
ESI나 EDI와 결합하여 인덱스에 사용된다.

ECX(Extended Counter Register)
반복 명령어 사용시 카운터로 사용된다. ECX 레지스터에 반복할 횟수를 지정해 놓고 반복 작업을 수행한다.

EDX(Extended data Register)
EAX와 같이 쓰이며 부호 확장 명령 등에 쓰인다.

ESI(Extended Source Index)
데이터 복사나 조작시 Source Data의 주소가 저장된다. ESI 레지스터가 가리키는 주소의 데이터를 EDI 레지스터가 가리키는 주소로 복사하는 용도로 많이 사용된다.

EDI(Extended Destination Index)
복사 작업시 Destination의 주소가 저장된다. 주로 ESI 레지스터가 가리키는 주소의 데이터가 복사된다.

ESP(Extended Stack Pointer)
하나의 스택 프레임의 끝 지점 주소가 저장된다. PUSH, POP 명령어에 따라서 ESP의 값이 4byte씩 변한다.

EBP(Extended Base Pointer)
하나의 스택 프레임의 시작 지점 주소가 저장된다. 현재 사용되는 스택 프레임이 소멸되지 않는 동안 EBP의 값은 변하지 않는다. 현재의 스택 프레임이 소멸되면 이전에 사용되던 스택
프레임을 가리키게 된다.


명령 포인터 레지스터

EIP(Extended Instruction Pointer)
다음에 실행해야 할 명령어가 존재하는 메모리 주소가 저장된다. 현재 명령어를 실행 완료한 후에 EIP 레지스터에 저장되어 있는 주소에 위치한 명령어를 실행하게 된다. 실행 전 EIP 레지스터는 다음 실행해야 할 명령어가 존재하는 주소의 값이 저장된다.


세그먼트 레지스터

CS(Code Segment)
실행 가능한 명령어가 존재하는 세그먼트의 오프셋이 저장된다.

DS(Data Segment)
프로그램에서 사용되는 데이터가 존재하는 세그먼트의 오프셋이 저장된다.

SS(Stack Segment)
스택이 존재하는 세그먼트의 오프셋이 저장된다.


플래그 레지스터

CF(Carry Flag)
부호 없는 연산 결과가 용량보다 클 때 세트(1)된다.

ZF(Zero Flag)
연산 결과가 0일 때 세트(1)된다. 연산 결과가 0이 아닐 때 해제(0)된다.

OF(Overflow Flag)
부호 있는 연산 결과가 용량보다 클 때 세트(1)된다.

SF(Sign Flag)
연산 결과가 음수가 되었을 때 세트(1)된다. 연산 결과가 양수가 되었을 때 해제(0)된다.

DF(Direction Flag)
문자열 처리에서 연속되는 문자열의 처리 방향에 따라 세트된다.


부동 소수점 데이터 레지스터

ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7)
범용 레지스터는 레지스터 이름 첫 글자가 'E'인 것을 알 수 있다. '확장되었다(Extended)'
라는 의미로 32bit 컴퓨터 환경이 되면서 16bit 레지스터인 AX, BX, CX, DX 등의 레지스터를 32bit로 확장한 것이라고 보면 된다. EAX, EBX, ECX, EDX 레지스터는 32bit, 16bit, 8bit로
사용할 수 있다.

 32bit  16bit  High 8bit  Low 8bit
 EAX  AX  AH  AL
 EBX  BX  BH  BL
 ECX  CX  CH  CL
 EDX  DX  DH  DL

ESI, EDI, EBP, ESP 레지스터는 32bit, 16bit로 사용이 가능하다.

 32bit  16bit
 ESI  SI
 EDI  DI
 EBP  BP
 ESP  SP
Posted by Dakuo

crackme author : abex
type                 : cdrom check
level                 : easy
tute author         : HaQue


Ollydbg.exe 실행해서 abexcm1.exe를 open한다.
프로그램이 어떻게 작동되는지 보기 위해 Run(F9)을 한다.


첫 번째 메시지박스가 나타나고, 확인을 클릭하면 두 번째 메시지박스가 나타난다.


확인을 클릭하고 올리디버거를 보면 프로그램이 종료되었음을 알 수 있다.


첫번째 메시지박스에는 CD-ROM을 체크하는 루틴을 우회하라고 나오고
두번째 메시지박스에는 CD-ROM이 아니라고 하며 프로그램이 종료되었다.


이 문제를 푸는 방법에는 메모리 주소 흐름을 바꾸는 방법과, CD-ROM을 체크하는 함수의
리턴값을 변경해서 푸는 방법 2가지 방법이 있다.


1번 방법 풀이(메모리 주소 흐름 변경) : 

취약한 프로그램 리버싱 순서 :
1. 프로그램 흐름 분석
2. 문자열을 이용한 특정 이벤트 시점 찾기
3. 성공이었을 경우의 문자열 위치를 찾아 무조건 성공하도록 흐름 변경

프로그램의 흐름을 파악했으니 문자열을 통해 특정 이벤트 시점을 찾아보겠다.
프로그램이 종료되어 있는 상태니 Restart한다.(Ctrl + F2)  어셈블리코드가 보이는 화면에서 우클릭후 Search for -> All referenced text strings 를 선택후 문자열을 확인해본다.


문자열 목록을 보면, CD-ROM이 인식되었을때는 00401044 주소의 값이 출력되는 것을 예상
할수 있다. 해당 문자열을 더블 클릭하여 해당 주소지로 이동하자.


위에 GetDriveTypeA라는 드라이브의 유형을 리턴해주는 API가 보인다.(두번째 풀이는 이 API를 이용한다)
또 JE문에 의해 점프를 할때에는 성공 메시지박스가 점프를 안할 때는 실패 메세지박스가 뜬다. 실패메시지박스가 뜬 뒤에는 JMP구문에 의해 프로세스가 종료된다. 그러므로 JE문을 JMP문으로 바꿔준다면 ZF플래그와 상관없이 무조건 성공메시지박스만이 뜰것이다.

                  (어셈블리어 참고 : http://dakuo.tistory.com/entry/기초-어셈블리어)


수정을 하고 나서 Run(F9)을 하면 문제가 풀어진 것을 알수 있다.
수정한 내용을 파일로 저장을 하기 위해 수정한 부분에서 우클릭 후 Copy to executable -> All modifications를 선택한 후 Copy all을 클릭한다.


수정된 어셈블리어들이 나타난 창에서 우클릭 후 Save file을 선택한다.




2번 방법 풀이(WinAPI함수의 리턴값 변경) :

E 버튼을 눌러서 Executable modules창을 연다.
실행중인 문제 파일인 abexcm1.exe 항목에서 우클릭 후 View Names를 선택한다.


사용되고 있는 api함수 목록을 볼수 있다.
GetDriveTypeA라는 함수가 드라이브의 유형을 리턴해줄것 같다. 원형을 보기 위해서 우클릭후 Help on symbolic name을 선택한다. 기존에 연결시켜 놓은 헬프 파일에서 해당 api이름을 검색해서 보여준다.


레퍼런스를 확인하면 목적, 파라미터, 리턴값을 알 수 있다.
그런데 리턴값에서 0, 1 다음에는 문자열로 지정되어 있다. 정확한 값을 알기 위해 MSDN에서 검색해보면 CDROM은 5가 리턴된다. 이제 Breakpoint를 설정하여 해당 api가 실행되는 과정을 분석하고, 리턴 값을 수정해주면 된다. 해당 api함수에 우클릭 후 Set breakpoint on every reference 메뉴를 선택한다. Command Line이라는 플러그인에서 bpx 함수명으로 명령을 주는 것과 비슷한 기능이다.(이플러그인은 기본플러그인이다) plugin메뉴 -> Command line -> Command line을 선택해주면 창이 생긴다. 여기서 bpx GetDriveTypeA라고 명령어를 치면 해당 api에 모두 브레이크 포인트를 설정해준다. 익숙해지면 디버깅 속도를 단축시킬수 있어서 편리하며, 찾고 싶은 api를 미리 알고 있다면 특정 시점을 찾기가 쉬워진다.


(참고로 Command Bar(cmdbar.dll)라는 플러그인을 사용하면 올리디버거 하단에 붙어있어서 자주 커맨드 명령을 사용할 경우 Command Bar를 사용하는것이 효율적이다. 올리디버거 플러그인이 잘 정리된 곳으로는 OpenRCE가 있다)

 

CPU창에서 Run(F9)을 해보면 GetDriveTypeA에서 멈추게 된다. Step Over(F8)시켜서 api를 실행시킨다.


위부분은 api가 실행된 후부터 (성공or실패)메시지박스를 만나기 위한 분기점까지의 어셈코드이다. 이부분을 해석하면


마지막에 DEC EAX 구문만 없으면 CMP EAX ESI 에서 2 : 2로 똑같아져서 JE문에서 점프를 하게 된다. DEC EAX 를 NOP로 바꾸자. 변경을 한 후에 Run(F9)를 해보면 문제를 푼 것을 확인 할수 있다. 변경한 코드를 저장하면 모든 풀이가 끝이 난다.
Posted by Dakuo

리버싱을 하기 위해서 이용되는 툴중에 디버거라는 것이 있다.
이 디버거들 중에 가장 대표적인 것은 올리디버거(OllyDebugger)이다.



odbg110.zip를 다운로드 받아서 odbg110 폴더에 압축을 풀고 Plugin폴더와 UDD폴더를 생성한다.
Win32_Programmers_Reference.rar로 압축을 풀어 wn32.hlp 파일을 obdg110 폴더에 넣는다. BOOKMARK.dll과 cmdline.dll은 Plugin폴더에 넣는다.

Ollydbg.exe를 실행하고  Option -> Appearance ->Directories를 열고 그림과 같이 경로 설정을 하고 다시 실행을 해준다.


이외에 설정해 주면 좋은 옵션은
작업관리자의 프로세스 목록에서 바로 디버깅 연결이 가능한 Jit(Just-in-time Debugging)
탐색기에서 파일 우클릭으로 바로 연결 가능한 Add explorer이 있다.


Help메뉴에서 Select API help file 선택을 해서 win32,hlp을 열어주면 자동으로 winapi도움말과 연결이 된다.


그리고 디버깅 옵션의 Event탭에서 프로그램을 열었을 때 시작할 위치를 Entry point of main module로 시작 지점을 잡아주도록 수정하는것이 좋다.


자 이제 마지막으로 점프위치를 화살표로 보기 좋게 표현하도록 고쳐보자.
ini파일을 메모장으로 열어서 [Settings]섹션을 다음과 같이 수정한다.

이렇게 바꿔주면 왼쪽처럼 화살표가 없던것이 오른쪽과 같이 화살표가 생긴다.

다른 옵션들은 자기에 맞게 변경하면 되고 그 옵션값들은 ollydbg.ini에 저장이 된다.
따라서 파일을 직접 수정해서 고치는것도 가능하다.

(참고로 TUTS4YOU 사이트에는 여러 형태의 리버싱 연습 문제들과 강좌도 많으므로
리버싱 공부를 위해 참고하면 좋다. : http://www.tuts4you.com/)



// ps. 추가로 한글판도 올립니다.



올리디버거로 notepad.exe를 열었을때의 화면이다.


1. 어셈블리코드
2. 레지스터 상태
3. Dump
4. 스택

3. Dump창에는 Heap이나 FileMap, Text 영역의 값들이 올 수 있다. 주소 부분을 16진수로 보여준다.

MENU :

[File] : 파일을 디버거로 불러오는 Open, 실행중인 프로세스를 디버거로 붙이는 Attach(해당 프로세스는 정지상태가 된다), 디버거를 종료하는 Exit가 있다.

[View] : 보여주는 기능. Memory를 선택하면 현재 Memory의 모습을 보여주고, Call Stack(Alt + K)을 선택하면 어디서 어떤 함수가 호출되었는지를 보여준다. 각 기능을 실행해보고 파악하자.

[Debug] :
Run : 디버거로 불러온 프로그램을 실행시킨다. Breakpoint를 만나거나 Exception이 발생해서 프로그램이 정지할때까지 실행한다. (단축키 : F9)
Restart : 프로그램을 처음부터 실행시키기 위해 재실행한다. Run을 해야 프로그램이 실행된다. (단축키 : Ctrl + F2)
Step into : 코드를 한줄씩 실행한다. Call(함수호출)나 Rep (반복문) 명령어를 만나면 함수내부로 들어가고 조건을 만족할때까지 계속 수행한다. (단축키 : F7)
Step over : 코드를 한줄씩 실행한다. Call(함수호출)나 Rep(반복문) 명령어를 만났을때 함수내부로 추적하지 않고 실행하며 반복문도 한번에 처리한후 다음줄로 넘어간다. (단축키 : F8)
Execute till return : 추적할 필요가 없는 함수 내부로 들어갔을때 그 함수의 ret명령 지점까지 한번에 실행하고 함수를 나올수 있다. (단축키 : Ctrl + F9)

[Plugin] : 올리디버거에서 사용하는 여러 플러그인 기능들이 있다. 다운받아 사용한다.

[Options] : 올리디버거의 설정 사항을 조정할수 있다.
Appearance에서는 Udd폴더나 Plugins폴더를 설정할 수 있고, 폰트도 변경할 수 있다.
Debugging options에서는 디버깅과 관련된 여러가지 설정을 변경할 수 있다.

[Windows] : 올리디버거 내부 윈도우들의 정렬 방식을 바꿀수 있으며, 원하는 윈도우를 활성화시킬 수도 있다.

1. 어셈블리코드 부분에서 우클릭시에 나오는 메뉴다.


Comment : 어셈블리코드 옆에 주석을 달아 놓을 수 있는 기능이다. 주석을 달아 놓음으로써 프로그램 분석을 보다 편리하게 할 수 있으므로 주석을 자주 달자.

Breakpoint : 디버거로 대상 프로그램을 실행시켰을 때 Breakpoint를 만나면 실행을 멈추고
사용자에게 제어를 넘겨준다.

Breakpoint에는 크게 두 가지가 있다.

 Software Breakpoint
CPU는 인터럽트를 이용하여 운영체제에게 특정 이벤트를 알려주며 CC(int3)라는 인터럽트가 발생되면 프로그램의 동작이 멈추게 되며 디버거에게 넘겨지게 되고 제어가 된다.
 Hardware Breakpoint
디버그 레지스터인 DR0, DR1, DR3, DR6, DR7을 이용하며 DR0~DR3은 Breakpoint를
걸어줄 대상의 주소 또는 범위를 설정할수 있으며 DR6은 인터럽트가 발생했을때의 결과를 알려주며 DR7은 Breakpoint의 속성을 설정할수 있다. 이것을 이용하면 특정 메모리 주소에 Write, Read, Excute가 발생했을 때 어떤 주소에서 실행이 되었는지 알수가 있다.

Search for :


All intermodular calls 기능은 Import된 함수들의 목록을 볼 수 있다.
All referenced text string 기능은 사용되는 문자열 값을 보여준다.

어셈블리코드가 있는 부분에서 더블클릭할 시에 직접 어셈블리 코드를 수정할 수 있다.
나머지 메뉴는 직접 실행해보며 파악하자.


2. 레지스터창에서 우클릭시 나오는 메뉴이다.


레지스터 상태창의 레지스터를 더블클릭하면 레지스터에 설정된 값을 변경할 수 있다.


3. Dump창에서 우클릭시 나오는 메뉴이다.



4. 스택창에서 우클릭시 나오는 메뉴이다.


Lock stack : 스택이 표시되는 윈도우가 ESP의 값에 따라서 변하는 것을 막아 표시되는 부분이 변하지 않도록 하여 스택의 특정 부분을 감시한다.
Go to EBP : 현재 EBP 레지스터가 가리키고 있는 주소로 스택 윈도우를 바꿔준다.
Follow in Dump : 스택에 들어있는 주소값에 어떤 데이터가 존재하는지 확인한다.

올리디버거의 화면을 세부적으로 설명하겠다.


1. 메모리 주소 : 프로그램을 디버깅하는 동안에 표시되는 주소지로 Ctrl + G 단축키로 특정
위치로 이동할 수 있다.

2. Opcode : 오퍼레이션 코드로 어떤 작동을 하는 코드들이 1byte로 정리되어 있다.
(1opcode == 1byte/2bytes == 1word/2words == 1dword)

3. Assembler Code : 디스어셈블된 코드들이다.

4. Olly가 분석한 내용 : api 함수들이나 문자열, 함수 파라미터들을 올리디버거가 보기 좋게 정리해서 보여준다.

5. 사용자가 입력한 주석 표시 : 세미클론(;)을 누르면 임시로 구분해 놓기 위한 내용들을 적을 수 있다.

6. 변수값 출력창 : 디버깅 중에 주요 변수들에 어떤 값들이 들어갔는지 표시해주는 창으로 자주 확인해야 한다.

7. Hex Dump창 : 16진수로 덤프를 하여 표시해주는 영역으로 바이너리 파일을 직접 수정할 때에 쓰인다.(hex값은 두 자리가 1byte이며, 1byte는 8bit가 된다)

8. 레지스터와 플래그 값 : CPU가 필요할 경우 사용하는 레지스터와 플래그의 값이 어떻게 변화하는지 보여준다. 레지스트리는 특별한 메모리 공간으로써 data를 저장하고 이용 가능하다.



다음은 OllyDBG 110의 단축키이다.

Pop-up menus display only items that apply. Frequently used menu functions:  

Function

Window

Menu command

Shortcut

Edit memory as binary, ASCII or UNICODE string

Disassembler, Stack Dump

Binary|Edit

Ctrl+E

Undo changes

Disassembler, Dump Registers

Undo selection Undo

Alt+BkSp

Run application

Main

Debug|Run

F9

Run to selection

Disassembler

Breakpoint|Run to selection

F4

Execute till return

Main

Debug|Execute till return

Ctrl+F9

Execute till user code

Main

Debug|Execute till user code

Alt+F9

Set/reset INT3 breakpoint

Disassembler Names, Source

Breakpoint|Toggle Toggle breakpoint

F2

Set/edit conditional INT3 breakpoint

Disassembler Names, Source

Breakpoint|Conditional Conditional breakpoint

Shift+F2

Set/edit conditional logging breakpoint (logs into the Log window)

Disassembler Names, Source

Breakpoint|Conditional log Conditional log breakpoint

Shift+F4

Temporarily disable/restore INT3 breakpoint

Breakpoints

Disable Enable

Space

Set memory breakpoint (only one is allowed)

Disassembler, Dump

Breakpoint|Memory, on access Breakpoint|Memory, on write

 

Remove memory breakpoint

Disassembler, Dump

Breakpoint|Remove memory breakpoint

 

Set hardware breakpoint (ME/NT/2000 only)

Disassembler, Dump

Breakpoint|Hardware (select type and size!)

 

Remove hardware breakpoint

Main

Debug|Hardware breakpoints

 

Set single-short break on access to memory block (NT/2000 only)

Memory

Set break-on-access

F2 

Set break on module, thread, debug string 

Options

Events

 

Set new origin

Disassembler

New origin here

 

Display list of all symbolic names

Disassembler, Dump Modules

Search for|Name (label) View names

Ctrl+N

Context-sensitive help (requires external help file!)

Disassembler, Names

Help on symbolic name

Ctrl+F1

Find all references in code to selected address range

Disassembler Dump

Find references to|Command Find references

Ctrl+R

Find all references in code to the constant

Disassembler

Find references to|Constant Search for|All constants

 

Search whole allocated memory

Memory 

Search Search next

Ctrl+L

Go to address or value of expression

Disassembler Dump

Go to|Expression Go to expression

Ctrl+G

Go to previous address/run trace item

Disassembler

Go to|Previous

Minus

Go to next address/run trace item

Disassembler

Go to|Next

Plus

Go to previous procedure

Disassembler

Go to|Previous procedure

Ctrl+Minus

Go to next procedure

Disassembler

Go to|Next procedure

Ctrl+Plus

View executable file

Disassembler, Dump, Modules

View|Executable file

 

Copy changes to executable file

Disassembler

Copy to executable file

 

Analyse executable code

Disassembler

Analysis|Analyse code

Ctrl+A

Scan object files and libraries

Disassembler

Scan object files

Ctrl+O

View resources

Modules, Memory

View all resources View resource strings

 

Suspend/resume thread

Threads

Suspend Resume

 

Display relative addresses

Disassembler, Dump, Stack

Doubleclick address

 

Copy

Most of windows

Copy to clipboard

Ctrl+C



Frequently used global shortcuts:
 

Ctrl+F2

Restart program

Alt+F2

Close program

F3

Open new program

F5

Maximize/restore active window

Alt+F5

Make OllyDbg topmost

F7

Step into (entering functions)

Ctrl+F7

Animate into (entering functions)

F8

Step over (executing function calls at once)

Ctrl+F8

Animate over (executing function calls at once)

F9

Run

Shift+F9

Pass exception to standard handler and run

Ctrl+F9

Execute till return

Alt+F9

Execute till user code

Ctrl+F11

Trace into

F12

Pause

Ctrl+F12

Trace over

Alt+B

Open Breakpoints window

Alt+C

Open CPU window

Alt+E

Open Modules window

Alt+L

Open Log window

Alt+M

Open Memory window

Alt+O

Open Options dialog

Ctrl+T

Set condition to pause Run trace

Alt+X

Close OllyDbg



Frequently used Disasembler shortcuts:
 

F2

Toggle breakpoint

Shift+F2

Set conditional breakpoint

F4

Run to selection

Alt+F7

Go to previous reference

Alt+F8

Go to next reference

Ctrl+A

Analyse code

Ctrl+B

Start binary search

Ctrl+C

Copy selection to clipboard

Ctrl+E

Edit selection in binary format

Ctrl+F

Search for a command

Ctrl+G

Follow expression

Ctrl+J

Show list of jumps to selected line

Ctrl+K

View call tree

Ctrl+L

Repeat last search

Ctrl+N

Open list of labels (names)

Ctrl+O

Scan object files

Ctrl+R

Find references to selected command

Ctrl+S

Search for a sequence of commands

Asterisk (*)

Origin

Enter

Follow jump or call

Plus (+)

Go to next location/next run trace item

Minus (-)

Go to previous location/previous run trace item

Space (  )

Assemble

Colon (:)

Add label

Semicolon (;)

Add comment



'Tool' 카테고리의 다른 글

디컴파일러(Decompliers)  (0) 2009.11.07
아이다(IDA)에 MS 심볼 서버 연동하기  (9) 2009.11.06
아이다(IDA)에 Hex-Ray 연동  (9) 2009.11.06
아이다(IDA) 사용법  (46) 2009.11.02
시스템 모니터링 툴  (0) 2009.11.01
올리디버거(OllyDBG) 사용법  (12) 2009.10.24
Posted by Dakuo

Reverse Engineering이란 역으로 분석하는 것이라고 정의할 수 있다. (줄여서 Reversing)
즉, 개발자가 소스 코드를 작성하고 그것을 실행 가능한 바이너리를 만들기 위해 원하는
컴파일러를 선택하여 컴파일시킨다. 이 바이너리의 원래 소스를 파악하기 위해 여러가지 방법을 통해 원래 소스의 구조와 원리를 분석하는데 이러한 과정이 리버싱(Reversing)이다.


또 리버싱은 완성된 프로그램의 수정, 디버깅, 호환과 프로그램의 분석 등 다양하게 쓰이고 있다.

Posted by Dakuo