Assembly code에 대한 고찰 (jump 명령어 그리고, pointer 연산)

아래는 x module ttt 라는 함수에 대한 disassemble code이다. 아래를 보고 몇 가지 특징을 잡아 보자.

 

x!ttt:

77f82f35 8b4c2408        mov     ecx,dword ptr [esp+8]

77f82f39 8b442404        mov     eax,dword ptr [esp+4]

77f82f3d 56              push    esi

77f82f3e 668b11          mov     dx,word ptr [ecx]

77f82f41 8d7002          lea     esi,[eax+2]

77f82f44 668910          mov     word ptr [eax],dx

77f82f47 eb08            jmp     x!ttt+0x12 (77f82f51)

 

x!ttt+0x19:

77f82f49 668b11          mov     dx,word ptr [ecx]

77f82f4c 668916          mov     word ptr [esi],dx

77f82f4f 46              inc     esi

77f82f50 46              inc     esi

 

x!ttt+0x12:

77f82f51 41              inc     ecx

77f82f52 41              inc     ecx

77f82f53 6685d2          test    dx,dx

77f82f56 75f1            jne     x!ttt+0x19 (77f82f49)

 

x!ttt+0x23:

77f82f58 5e              pop     esi

77f82f59 c3              ret

 

번째는 jmp 의한 loop 보인다. 상위의 노란색 block 이다.

일단, jmp 명령어에 의해서 77f82f51 분기한다. 그리고, jne 명령어에 의해서 77f82f49 분기될 있다. 결국, 아래 그림과 같이 looping 된다.

 

77f82f47 -------> 77f82f51 -------> 77f82f56 ------+

                         ^                         |

                         |                         |

                         +------77f82f49 <---------+

 

Loop 대한 end 조건을 찾아보면, 녹색 Block 이다.

 

77f82f53 6685d2          test    dx,dx

77f82f56 75f1            jne     x!ttt+0x19 (77f82f49)

 

test dx, dx dx null여부를 Check 하는 알려진 명령어이다. test a,b a&b 같이 AND 연산을 의미한다. 그러므로, dx 0x0 아니면 결과가 0x0 예상할 없다. 이후에 jne 연산을 하여 dx값이 0x0이 아닐 경우에 looping 돌고, 0x0이면 해당 loop 빠지는 condition으로 이뤄져 있음을 있다.

 

번째는 Frame 기반의 code 아닌 보인다. 이유는 assembly code 초기에 ebp(frame pointer) 저장 코드가 존재하지 않는 . 또한, 초기 code 보면,

77f82f35 8b4c2408        mov     ecx,dword ptr [esp+8]

77f82f39 8b442404        mov     eax,dword ptr [esp+4]

 

Esp 기반의 data ecx, eax 전달하는 것으로 보이며, 이는 parameter assign 으로 보인다. 이는 kv command로도 확인된다. 이는 FPO 이다.

 

ChildEBP RetAddr  Args to Child              

0006d950 0100e654 00d19fb0 0006e3b0 00c67fe0 x!ttt+0x1c (FPO: [2,0,1])

//

2 parameters

0 local variables

1 cpu register (??) – push esi

//

번째는 pointer 연산이 존재한다.

 

77f82f35 8b4c2408        mov     ecx,dword ptr [esp+8]

77f82f39 8b442404        mov     eax,dword ptr [esp+4]

77f82f3d 56              push    esi

77f82f3e 668b11          mov     dx,word ptr [ecx]

77f82f41 8d7002          lea     esi,[eax+2]

77f82f44 668910          mov     word ptr [eax],dx

 

상위의 노란 색을 보면, ecx parameter 전달된 address pointer 갖고 있으며, 해당 pointer 번째 value dx 저장한다. 그리고, dx 값을 eax address copy한다. Eax 역시 pointer이다.

 

Debugging , 중요한 것은 data 살피는 것인데, 상위의 code 경우는 stack 존재하는 data 유심히 살펴볼 필요가 있다. 만일, 아래의 위치에 break 되어 있다고 가정하면,

 

77f82f4c 668916          mov     word ptr [esi],dx

 

0:000> ddp esp

0006d950  00d19fb0 0042007b  <---- esp

0006d954  0100e654 5914438b  <---- esp+4

0006d958  00d19fb0 0042007b  <---- esp+8

0006d95c  0006e3b0 0042007b  <---- esp+c

 

mov ecx,dword ptr[esp+8] 에서 해당 parameter 처음 위치, parameter address 어떻게 될까? 00d19fb0 아니고, esp+c, 0006e3b0 맞다. 이유는 중간에 push esi 라는 명령어가 존재하기 때문에 esp 1 decrement 되었기 때문이다. 그러므로, esp+8, 00d19fb0 처음 eax mov parameter 처음 address 된다. Push/pop 따라 esp 변경되기 때문에 이를 유의하여 data check해야 한다.

 

Loop block 안의 code 아래와 같다.

 

77f82f49 668b11          mov     dx,word ptr [ecx]

77f82f4c 668916          mov     word ptr [esi],dx

77f82f4f 46              inc     esi

77f82f50 46              inc     esi

 

x!ttt+0x12:

77f82f51 41              inc     ecx

77f82f52 41              inc     ecx

 

보면, ecx에서 esi dx register temp copy 이뤄지고 있음을 있다. 그리고, inc 번씩 발생하는 , 이는 word 연산이기 때문에 그렇다. Word type data copy되고 pointer 증가하기 때문에 pointer++ inc 발생할 밖에 없다. 이는 아래의 명령어에서도 동일하게 추측된다.

 

77f82f3e 668b11          mov     dx,word ptr [ecx]

77f82f41 8d7002          lea     esi,[eax+2]

77f82f44 668910          mov     word ptr [eax],dx

 

lea 명령은 esi=eax+2 같은 pointer연산이라고 보면 되는 , address +2했다는 것은 word type data dx copy 하고, 다음 word 위치시키기 위해서, word 연산이기 때문에 +2 된다는 것을 있다.

 

그러므로, 해당 function 2개의 pointer source destination으로 받아서 copy하는 operation으로 보인다. 그리고, source data 0x0 때까지 copy 이뤄지는 구조로 이해할 있다.

//참고로

Jump 명령어는 Condition code flag 연관이 있다.



 X86에서 Condition code flag 다음과 같다.

 

Flag

Name

Condition

CF

Carry Flag

Set from the most significant carry bit.

ZF

Zero Flag

Set if the result is zero.

SF

Sign Flag

Set if the sign bit of the result is set.

OF

Overflow Flag

Set on positive or negative two's complement overflow.

 

 

Instruction

Condition

Description

je label

ZF

equal

jne label

~ZF

not equal

js label

SF

negative

jns label

~SF

nonnegative

jg label

~(SF ^ OF) & ~ZF

greater (signed)

jge label

~(SF ^ OF)

greater or equal (signed)

jl label

SF ^ OF

less (signed)

jle label

(SF ^ OF) | ZF

less or equal (signed)

ja label

~CF & ~ZF

above (unsigned)

jae label

~CF

above or equal (unsigned)

jb label

CF

below (unsigned)

jbe label

CF & ~ZF

below or equal (unsigned)

 

그러므로, jump 명령어는 수행 condition code flag 어떤 값인지를 Check하는 것이 중요한데, 이러한 Flag 정보는 Dump register 보는 ‘r’ 명령에서 확인할 있다. 예를 들어, 아래의 녹색 block flag 대한 정보를 보여준다.

 

0:000> r

eax=00d19fb0 ebx=00c67fe0 ecx=0006e400 edx=007a007d esi=00d1a000 edi=00c67fe0

eip=77f82f4c esp=0006d950 ebp=0006d96c iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00010202

x!ttt+0x1c:

77f82f4c 668916          mov     word ptr [esi],dx

 

마치 기호로 되어 있는 하지만, 다음과 같은 의미를 갖고 있다.

The following table lists the x86 flags:

Flag
Code

Flag Name

Value

Flag
Status

Status Description

of

Overflow Flag

0
1

nv
ov

No overflow
Overflow

df

Direction Flag

0
1

up
dn

Direction up
Direction down

if

Interrupt Flag

0
1

di
ei

Interrupts disabled
Interrupts enabled

sf

Sign Flag

0
1

pl
ng

Positive (or zero)
Negative

zf

Zero Flag

0
1

nz
zr

Nonzero
Zero

af

Auxiliary Carry Flag

0
1

na
ac

No auxiliary carry
Auxiliary carry

pf

Parity Flag

0
1

pe
po

Parity even
Parity odd

cf

Carry Flag

0
1

nc
cy

No carry
Carry

tf

Trap Flag

If tf equals 1, the processor will raise a STATUS_SINGLE_STEP exception after the execution of one instruction. This flag is used by a debugger to implement single-step tracing. It should not be used by other applications.

iopl

I/O Privilege Level

This is a two-bit integer, with values between zero and 3. It is used by the operating system to control access to hardware. It should not be used by applications.

 

by 강세윤 | 2008/12/17 13:24 | Windows debugging | 트랙백 | 덧글(0)
트랙백 주소 : http://byung.egloos.com/tb/4771921
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]

:         :

:

비공개 덧글

< 이전페이지 다음페이지 >