0. 개요

  여기서는 EFLAGS에 대해서 알아본다. 먼저 기본적인 구조를 알아본 후 Ollydbg, Windbg, GDB 같은 디버거들에서 어떤 식으로 보여지는지를 설명한다. 그리고 이것이 사용되는 방식과 기타 사항들을 설명하기로 한다.





1. 구조

  eflags는 상태 레지스터이며 x86에서는 32비트, x64에서는 64비트의 크기이다. 여기서는 기본적으로 사용되며 중요한 부분만 설명하기로 하고 하위 12비트만 보겠다. 참고로 x64에서 확장된 32비트는 모두 Reserved이며 기본 32비트에서도 일반적으로 사용되는 부분은 하위 16비트이기 때문에 이것만 살펴보기로 한다.


  여러 디버거에서 디버깅을 하다보면 eflags는 0x00000246, 0x00000212 등의 값을 갖는 것을 볼 수 있다. 하위 12비트를 제외한 나머지 상위 비트들은 보여줄 때 무시되는 것인지 아니면 0의 값을 갖는 것인지는 알아보지 않았다.


OF DF IF TF    SF ZF 0 AF    0 PF 1 CF


  0과 1로 적은 것은 Reserved된 것으로서 기본적으로 위와 같이 0 또는 1의 값을 갖는다. 각각 Overflow Flag, Direction Flag, Interrupt Flag, Trap Flag, Sign Flag, Zero Flag, Auxiliary Carry Flag, Parity Flag, Carry Flag이다.


  TF는 뒤에서 설명할 것이며 어쨌든 디버거들 입장에서는 기본적으로 0으로 보여주는것 같은데 이것까지 고려해서 불필요한 부분을 x로 표시하면 다음과 같다.


000x    00x0    x0x0


  이제 이것을 기본으로 예제를 통해 살펴보겠다. 먼저 0x00000246의 12비트를 2진수로 보겠다. 활성화된 것은 IF, ZF, PF이다.


OF DF IF TF    SF ZF 0 AF    0 PF 1 CF

0010    0100    0110

001x    01x0    x1x0


  다음으로 0x00000212를 보겠다. IF, AF가 Set되었다.


OF DF IF TF    SF ZF 0 AF    0 PF 1 CF

0010    0001    0010

001x    00x1    x0x0





2. 디버거에서

  먼저 Windbg부터 살펴보겠다. Windbg에서는 Single Step이나 r 명령어로 레지스터를 볼 때 eflags 관련 부분은 다음과 같이 보여준다.


nv up ei pl zr na pe nc

efl=00000244


  살펴보면 먼저 TF를 제외하고 8가지만 보여준다는 것을 알 수 있다. 위의 약자들을 정리하면 다음과 같다. 아래에 정리된 것을 숙지하면 efl 값을 통해가 아닌 이렇게 일일이 직접 확인할 수 

있다.


--------------------------------------------------------------------

FlagName        Set                        Clear

Overflow         ov (Overflow)             nv (No Overflow)

Direction         dn (Direction Down)     up (Direction Up)

Interrupt          ei (Interrupts Enabled)   di (Interrupts Disabled)

Sign              ng (Sign Flag negative)  pl (Sign Flag positive)

Zero              zr (Zero)                  nz (Not Zero)

Auxiliary Carry   ac (Auxiliary Carry)       na (No Auxiliary Carry)

Parity             pe (Even Parity)          po (Odd Parity)

Carry              cy (Carry)                 nc (No Carry)

--------------------------------------------------------------------


  다음으로 GDB에서 어떻게 보여지는지 알아보겠다. GDB에서는 i r 명령어가 레지스터를 보여주는 명령어이다. 어떻게 보면 더 직접적으로 보여준다.

efl = 0x246    [ PF ZF IF ]


  마지막으로는 OllyDbg에서 어떻게 보여지는지 알아보겠다. 지금까지 살펴본 것과는 많이 다른 것을 볼 수 있다. 사실 어떤 면에서는 디버거를 사용하는 입장에서 이것이 가장 좋은 방식이 아닐까 생각한다.


EFL  00000246  ( NO, NB, E, BE, NS, PE, GE, LE )


  OllyDbg도 어떤 플래그가 Set 되었는지 여부를 보여주며 이 플래그들을 이용하는 조건 점프문들 중에서 어떤 것들이 활성화되는지 또한 보여준다. 예를들어서 위의 사항들 중에서 "E"가 보인다. 이 말은 현재 eflags 상태에서 만약 JE 명령어를 만나게 된다면 이것이 활성화될 것이라는 것을 보여준다. 또는 JLE 명령어의 경우에도 마찬가지이다. 이러한 사항들은 다음 항목에서 따로 정리한다.





3. 플래그의 사용

  앞에서 우리는 각각의 플래그들이 어떻게 보여지는지에 대해서 배웠다. 여기서는 OllyDbg를 설명하면서 다 설명하지 못한 부분인 어떻게 사용되는지에 대해서 정리하겠다. 만약 어떤 수를 비교하거나 해서 같은 경우에 ZF 즉 Zero Flag가 1이 되는데 이 상태에서 JE (Jump if equal) 명령어가 존재한다면 그것이 활성화된다. JNE 명령어는 ZF가 0인 상태에 활성화되는 조건 점프문이다.


  이러한 조건 점프문들의 활성화 여부는 각각의 플래그 값을 알고 있어야 예상할 수 있다. 물론 OllyDbg는 활성화된 플래그가 아닌 활성화된 조건을 직접 보여주므로 매우 좋은 인터페이스를 가지고 있는것 같다. 다음은 각각의 플래그에 맞는 조건들을 정리하였다. 참고로 각 조건에 따라 어셈블리 명령어가 2개씩 존재하는데 처음 조건은 OllyDbg에서 보여주는 조건이며 두 번째 ''로 표시한 부분은 OllyDbg에서 보여주는 것은 아니지만 동일한 명령어이므로 다른 디버거에서 볼 때 같은 것으로 여기면 된다.


--------------------------------------------------------------------

Mnemonic    Condition Tested For             Status Flags Setting


O             Overflow                            OF == 1

NO            No overflow                        OF == 0


B             Below                               CF == 1

NAE          Neither above nor equal            ''

NB            Not below                          CF == 0

AE            Above or equal                     ''


E             Equal                            ZF == 1

Z             Zero                                  ''

NE            Not equal                           ZF == 0

NZ            Not zero                             ''


BE   Below or qual                      CF == 1 || ZF == 1

NA          Not above                          ''

A             Above                               CF == 0 && ZF == 0

NBE          Neither below nor equal           ''


S             Sign                                  SF == 1

NS            No sigh                              SF == 0


PE            Parity even                          PF == 1

P             Parity                                 ''

PO            Parity odd                           PF == 0

NP            No parity                             ''


GE            Greater or equal                    SF == OF

NL            Not less                              ''

L              Less                                 SF != OF

NGE          Neigher greater nor equal          ''


LE            Less or equal                         ZF == 1 || SF != OF

NG           Not greater                           ''

G             Greater                               ZF == 0 && SF == OF

NLE          Neither less nor equal                ''

--------------------------------------------------------------------





4. 기타

  참고로 디버거는 Trap Flag를 이용한다. 즉 Single Step을 위해 이것을 활성화시켜서 각 명령어 실행 시 디버거에게 제어가 가게 되는 원리이다. 이 말은 이것이 안티 디버깅에도 사용될 수 있다는 것이다. 일반적인 실행에서 트랩 플래그는 사용되지 않는데 이것을 설정하고 이 예외를 받는 예외 핸들러를 설치한 경우 일반적인 실행에서는 예외 핸들러가 호출된다. 하지만 디버거의 입장에서는 이것을 구분할 능력이 없다. 왜냐하면 자체적으로 이미 사용하고 있기 때문인데 디버깅 시에 이 트랩 플래그는 당연히 무시되고 예외 핸들러가 호출되지 않을 것이다. 이것을 이용해 예외 핸들러에 현재 디버깅 당하는 중인지를 검사하는 루틴을 삽입할 경우 성공적인 안티 디버깅 기법이 될 수 있다.


  트랩 플래그를 설정하는 어셈블리 명령어는 없지만 트릭을 이용해 설정하는 루틴은 다음과 같다.


--------------------------------------------------------------------

PUSHFD

OR DWORD PTR SS:[ESP], 100

POPFD

--------------------------------------------------------------------


Posted by SanseoLab

블로그 이미지
Malware Analyst
SanseoLab

태그목록

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.4
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

최근에 올라온 글

최근에 달린 댓글

글 보관함