농소

asm 형변환, 관계연산, 제어문 본문

Security/System Hacking

asm 형변환, 관계연산, 제어문

농소 2018. 1. 18. 03:05

형변환


1). 큰 -> 작은 저장소   ( 큰 문제는 없다. )


  int a = 10

  short b =a


ex) eax -> ax -> al


별다른 명령어가 필요하지않고 해당 레지스터 크기를 줄여서 사용

하지만 줄이는과정에 상위비트의 값의 손실이 발생할 수 있음.


2). 작은 -> 큰


  short a =10

  int b = a


예를들어 8비트 크기의 레지스터인 dl 값을 16비트인 ax로 옮길려고 할시 컴파일 에러가 발생한다. 

바로 8비트를 채우고 나머지 8비트를 무엇으로 채워야 할지 모르기 때문이다.

그것을 해결하기 위해선


 [ movzx ( zero extend - 나머지를 0으로 채우겠다.)  ]

 [ movsx ( sign extend - 부호가 있는경우 음수일 때 나머지 빈공간을 1로 채우겠다. ]


이 두 명령어가 필요한데 movzx는 나머지 비트들을 0으로 채우고

movsx는 만약 값이 음수일때 부호까지 신경써서 나머지 비트를 채운다


< mov 와 movzx 비교 >


< mov    eax,    dl 을 했을때 에러가 발생하는 모습 >


< -10일때 부호까지 신경써주는 movsx명령어를 사용 >



만약 movzx명령어를 사용하면 나머지 비트에 0을 채우게 되므로 -10이 아닌 값이 246이 나오게 된다.

즉, 0으로 채워서 0000 0000 1111 0110 = 246이 나오게 된다.

그러니 부호까지 신경쓰는 movsx를 쓰면 나머지 8bit도 1로 채우므로 1111 1111 1111 0110 = 10이 나온다





3). 논리쉬프트 shl, shr



        xor     edx,    edx


        mov     dl,     -2

        shl     dl,     2

        shr     dl,     2


-2가 나와야하지만 62가 출력됨

그래서 산술쉬프트 sal, sar 연산을 해야함




비교연산


  - cmp : compare



  - cmp vleft, vright -> eflags register


연산과정을 보면 Sub명령어와 구조가 매우 흡사하다.

여기서 vleft, vright의 뺄셈을 통해 부호가 정수이면 SF = 0 ZF =0

            음수      SF = 1 ZF =0

            같다면   SF = 0 ZF  =1이 된다.



여기서 SF, ZF란? FLAG REGISTER의 여러 FLAG중에 하나이다.


SF는 Sign Flag의 약어로 비교연산을 했을시 부호가 변하면 1 아니면 0 으로 표현되고

ZF는 Zero Flag의 약어로 비교연산을 했을시 값이 같다면 1 다르다면 0으로 표현된다.



cmp는 sub과 구조가 매우 흡사하나 차이점이 존재한다 cmp는 sub과는 다르게


  - 1. 특정 메모리나 레지스터의 값을 변경하지 않는다.

  - 2. [ 플래그 레지스터 ] 에 반영한다!!


즉, sub명령어는 레지스터값에 영향을 주고 cmp는 영향을 주지 않는다. 

오로지 cmp는 flag 레지스터에만 영향을 줌.


이 해당 SF,ZF만 확인할수 있는 방법은 nasm에서 명령어로 존재하지 않아.

eflags register 전체를 볼 수 있는 명령어를 통해서 확인 해보겠다.


<pushfd 명령어로 flag 상태를 확인함>


< 10진수로 flag의 상태를 보여줌 >


< 2진수로 변환한 모습 >


자 flag register의 구조를 보면 하위7비트에 ZF 하위 8비트에 SF가 위치해 있다.

10 과 5를 비교할때 연산과정을 보면 10 - 5 = 5 (양수)가 나온다 양수일때는 SF = 0 , ZF = 0이 되므로

2진수를 봤을때 0000     0010     [00]00     0110 으로 표현된다.

 만약 음수였으면 00이 아니라 10이 되었을 것이다.



제어문: if, case


  - if, case는 기계어로보면 동일하게나옴.

  - 그래서 어셈블 코드를 분석할 때 if인지 case인지 구분할 수 없음.

  - 즉, if, case는 아무 차이없고, for,while도 차이없음.


1). 무조건 분기: jmp(jump) 강제 이동한다.


C언어로 치자면 goto문으로 생각하면된다


  - jmp 주소 - [ 지금은 이것을 이용 ]

  - jmp offset


주소를 설정하여 해당 주소로 강제로 이동시킬수 있는 표현방법이다.



강제로 end주소로 이동하게 되어 print문을 건너뛰게 된다.



2). 조건 분기  : 조건을 확인하고 이동한다


  - j<조건>


.

.

.


등 여러 조건이 많지만 외워서 쓸 필요는 없고 직관적으로 표현되어서 쉽게 사용할 수 있다.

jg(great) = 크다 je = 같다(equal) jl = 작다(less)



실습 - c언어로 표현한것을 어셈블로 표현하라.


c언어

if ( a < 10 ) {

   printf("less then 10\n");

} else {

  printf("bigger then 10\n");

}





3). 다중조건


실습2 - and와 or가 섞여있는 경우


if( ( a < 10 && b > 1 ) || c == 5) {

   printf("correct\n");

}