무분기 로직

2015. 3. 9. 13:26Security ★ Development/Reversing

반응형

 컴파일러가 하이 레벨 언어를 로우 레벨 언어로 바꿀 때 파이프라인을 사용함에 따르는 분기에 의한 손실을 최소화 하기 위해 무분기 로직을 만들어냅니다.  

 파이프 라인의 끝에 다음 명령을 채울 때 분기가 있을 경우 어떤 분기된 명령들 중 하나를 쓸 수 밖에 없는데 이 때 예측이 틀리면 파이프라인을 비우고 새로 명령을 채워야 합니다.  그렇기 때문에 컴파일러는 분기가 있는 하이 레벨 언어를 분기가 없는 로우 레벨 언어로 바꾸는 작업을 합니다.


- 산술 구현

mov eax, [ebp-10]

and eax, 0x00001000

neg eax

sbb eax, eax

neg eax

ret

 위 작업은 분기문을 사용하지 않는데 어셈블리에 익숙하지 않다면 무슨 작업을 하는지 파악하기 어렵습니다.  eax와 0x00001000의 값을 and하고 neg를 하고 있습니다.  neg는 부호를 바꿔주는 명령으로 va=-va; 와 같은 연산입니다.

 sbb는 va-(va+CF);라는 의미인데 CF는 생소한 분들은 여기선 연산결과에 따른 어떤 상태플래그 정도로 알고 계시면 됩니다.  즉 여기서는 neg 연산의 결과 인자값이 0이면 CF는 0으로 설정되고 0이 아니면 1로 설정됩니다.  sbb연산은 eax=eax-(eax+CF)가 되는데 결국 eax는 CF에 의해 결정됩니다.  

 다시 neg연산을 하고 있는데 eax가 0(CF가 0일 경우)이면 0 그대로이고, -1이면(CF가 1일 경우) 1로 만들어 줍니다.

 if(va&0x00001000)

     return true;

 else

return false;

와 같은 작업입니다.

 하이레벨 언어의 분기문을 로우 레벨에선 분기명령을 사용하지 않았다는 것을 알 수 있습니다.


call SomeFunc

sub eax, 4

neg eax

sbb eax, eax

and eax, -52

add eax, 54

ret

 SomeFunc의 반환값에 4를 빼고 neg와 sbb연산을 하고 있습니다.

 4를 뺀 값이 0이면 sbb 연 산후 eax는 0이고 0이 아니면 -1이 됩니다.

 0인 경우에는 -52 and 연산을 해도 0이고 여기에 54를 더해 반환합니다.  -1인 경우는 0xffffffff이므로 and와 add연산을 거치면 2가 나오게 됩니다.  즉

if(SomeFunc()==4)

return 54;

else

return 2;

라는 분기문을 분기 명령을 쓰지 않도록 바꾼 결과입니다.



- 조건 실행

 분기문을 순수하게 산술로 구현하는 것은 제한이 있습니다.  복작한 분기 로직을 위해 프로세서에서는 무분기 로직을 가능하게 해주는 몇개의 명령을 제공해줍니다.

 return (result!=FALSE);

라는 하이 레벨 언어가 있을 경우 분기 로직을 포함한 로우 레벨 언어는 다음과 같습니다.

cmp [result], 0

jne NotEquals

mov eax, 0

ret

NotEquals:

mov eax, 1

ret

이를 IA-32 프로세서가 제공하는 setne 명령을 이용해 무분기 로직으로 바꿀 수 있습니다.

xor eax, eax

cmp [result], 0

setne eax

ret

setne 명령은 ZF플래그에 따라 값을 설정합니다.  ZF 플래그는 cmp 결과에 따라 둘이 같은 경우에 1로 설정되고 같지 않으면 0으로 설정됩니다.  즉, setne에 의해 ~ZF의 값이 설정되는데 result가 0과 같지 않으면 eax는 1이 설정되고 같으면 0이 설정되게 됩니다.  


mov ecx, 2000

cmp edx, 0

mov eax, 1000

cmove eax, ecx

ret

cmove 명령은 edx 레지스터의 값에 따라 작동합니다.  edx 레지스터의 값이 0이면 ecx의 값을 eax에 넣고 0이 아니면 그대로 놔둡니다.

if(va==0)  //edx의 값이 0이면

return 2000;  //ecx의 값을 넣고 리턴

else

return 1000;  //아니면 그대로