YeoPEVA

어셈블리어 - CMP, 그리고 JMP에 대해 알아보자! 본문

#Reversing/Reversing - 정리

어셈블리어 - CMP, 그리고 JMP에 대해 알아보자!

YeoPEVA 2017. 7. 23. 14:58

이번에는 저번에 코엔 basic 1번을 풀다가 cmp JMP 같은 분기 쪽 설명이 부족한 것 같아,

이렇게 포스팅을 올리러 왔습니다! [물론 안 쓸려다가 쓰는건 비밀]



[하라는 공략은 안하고, 영화나 보고 있어?!]


.... 이만 줄이고, 본 글로 들어가보도록 하겠습니다. 


+ 이 글은 여러 블로그와 일부 문서를 참고해서 작성된 글입니다.

만약 저작권 상 문제가 있다면 언제든지 글이 내려갈 수 있습니다.



1. CMP와 JMP, JMP 함수들? 그게 뭔가요?


[그러게영?]

일단, 오늘 포스팅 내용은 아시다시피, CMP와 JMP에 대해 다루는 내용입니다.


그러면 먼저 CMP와 JMP에 대해 간략하게 정리를 한 다음에 CMP 연산에 대해 알아보고, 

CMP와 JMP과 무슨 관계인지 알아보도록 하겠습니다 ^^



[무슨 관계인지 차-암 궁금한걸?] 

(알았으니까 들어가요)


먼저 CMP에 대해 알아보도록 합시다.


우선 CMP는 아래와 같은 문법으로 쓰이게 됩니다. 


CMP 인자1 | 인자2 

위와 같은 방법으로 말이죠! ^^


CMP는 두개의 인자를 비교하는 역할로 쓰이는 명령어이며, 혼자 쓰이는 일은 없고 다음으로는 JMP와 같은 명령어가 

같이 쓰이게 됩니다. 위와 같은 관계를 통해 분기문 그리고 if문과 같은 조건문 들이 이루어 지는 것이지요!

그래서 관계가 어떻게 되는거냐고요? .... 

3번에서 밝혀집니다! [^ㅇ^]


다음으로는 JMP에 대해서 알아볼껀데요!

JMP는 특정 지역으로 이동[점프]를 하게 해줍니다! 


근데 여기서 어떤 분들은 궁금증이 생길꺼에욥!

CALL 명령어랑 뭐가 다른지 궁금하신 분들이 있을꺼라 생각됩니다! 

[없으면 말고요.. 시무룩]


CALL의 경우 

인자 하나를 받아서, [주소] 해당 주소의 함수 or 문을 부르는 것입니다!

인자 값으로는 함수 주소나, 특정 주소 or api 또한 해당사항이 되겠지요!


부른다 -> 주소까지 갈 필요 없이 해당 위치에서 수행 


JMP 처럼 실행 흐름이 바뀌지만, JMP와 다른 점은, 

돌아올 주소 ,[RET]을 스택에다가 저장을 한다는 점이 JMP와 다른 점입니다!


그럼 이제 JMP와 그에 관한 관련 함수에 대해 좀 더 자세히 알아보도록 하겠습니다!



 2. JMP..? 에 대해 좀 더 삽질해봅시다!


그럼 이제 좀 더 세부적으로 파해쳐보도록 하겠습니다.


사실 그냥 JMP와 JMP 함수들과는 좀 차이가 있습니다.


JMP는 피연산자의 위치로 실행 흐름이 바뀌는 역할을 하지만 [조건 x],

이와 다르게 JMP 명령어와 다른 조건 점프 명령어 들이 있습니다.


아래를 한번 봐주세요 ^^



기억 나시나요? 코엔 basic 1번 문제 풀이시 등장했던 것 입니다.

여기서 주목할 점은 

CMP EAX,ESI 

JE SHORT 0040103D 입니다.


여기서 JE가 뜻하는 것은?

jump if equal 라는 의미이며, 부등호로는 ==를 뜻하죠, 결과로는 ZF 플래그가 1이 되야 

분기문을 통과하게 됩니다. 그리고 해당 주소로 점프하게 되지요.

[그 점에 관해서는 코엔 basic 1번에서 다뤘습니닷]


+ 또한 SHORT이 의미하는 것은 무슨 의미일까요?

우선.. SHORT | NEAR | FAR 이렇게 이루어져 있습니다.

분기를 어디까지 할 것인지, 범위에 대해 정하는 거라고 생각할 수 있을 것 같습니다..

[이 부분에 대해선 저도 좀 더 조사가 필요할 것 같습니다.]


+ 만약 더 정확하게 알게 된다면 보충 하도록 하겠습니다.

SHORT의 경우 매우 한정된 범위에서 분기를 한다고 합니다 [최대 128 바이트]

NEAR의 경우 무조건 / 조건 분기의 기본으로 지정된 형태 | 세그먼트의 어떠한 부분으로도 점프가 가능하다고 합니다.

FAR의 경우 다른 코드 세그먼트로 분기를 허용한다고 합니다. 


위와 같이 JE 말고도 다양한 JMP 함수..? 라고 할 수 있겠네요.

JMP 함수들이 존재합니다. 그럼 여기서 한번 간단하게 표로 둘러보도록 하겠습니다.


 명령어

의미 

부등호 

플래그 조건 

JA 

 Jump if (unsigned) above

> 

CF = 0 and ZF =0 

JAE  

Jump if (unsigned) above or eual  

>= 

CF =0 or ZF = 1 

JB

jump if (unsigned) below 

< 

CF = 1 

 JBE

jump if (unsigned) below or equal 

<= 

 

JC 

jump if carry flag set 

 

CF = 1 

JCXZ 

jump if CX is 0

 

CX =0  

JE 

jump if equal 

== 

ZF = 1 

JECXZ 

jump if ECX is 0 

 

ECX =0 

JG  

jump if (signed) greater 

> 

ZF = 0 and SF == OF

JZ 

Jump if zero 

== 

ZF =1 

 JNZ

 Jump if not zero 

 

ZF = 0 

JO

Jump if overflowflag is set 

 

OF = 1 

JNO 

Jump if overflowflag not set 

 

OF = 0 

 JS

Jump if sign flag is set 

 

SF = 1 

 JNS

Jump if sign flag not set 

 

SF = 0 

JNC

Jump if carryflag not set 

 

CF = 0 

JP 

Jump if parity flag set 

 

 PF = 1

JNP 

Jump if parity flag not set 

 

PF = 0 

[뭔가 엄청 많죠.. | ....]


저것 보다 더 많은 종류가 존재하지만, 현 포스팅에선 위 정도만 다루도록 하겠습니다.

더 많은 정보를 원하신다면 아래에 참고한 사이트 링크를 참고 해주시길 바랍니다.


어떻게 보면 위 3의 내용을 벌써 다뤄버린 것 같습니다.

맨 오른쪽에 보시면 플래그 레지스터와 범용 레지스터의 변화가 나와있는데,

해당 분기시에 위와 같이 플래그 레지스터와 범용 레지스터가 저렇게 값이 변하게 된다면,

분기문은 참으로 변하게 되고, 점프를 수행하게 됩니다. 

그럼 다음으로 넘어가서 이와 관련해서 좀 더 다뤄보도록 하겠습니다. 



 3.CMP 연산 및 분기 시 일어나는 일에 대해 좀 더 알아봅시다.


이번에는 CMP 연산 및 분기 시에 어떤 변화를 통해서 참이 되서 점프를 수행하고, 점프를 수행하지 않는지에

대해 좀 더 자세히 알아보도록 하겠습니다.

우선 CMP 연산의 경우 아시다시피, 두개의 인자 값을 받아서 값을 비교하는데 쓰인다는 것은

아실껍니다. 


+ 음..? TEST란 어셈블리어도 같은 역할을 하는데 차이는 뭔가요?


CMP의 경우 첫번째 인자 값에서 두 번째 인자 값을 빼는 식으로 비교합니다.

[ZF (zero flag) 에만 영향을 주며, 다른 곳에는 영향을 주지 않습니다.]


단, TEST의 경우 위와 다르게 첫 번째 인자와 두 번째 인자를 AND 연산을 하는 방법으로 비교합니다.

이 경우 위 CMP와 다르게, ZF에만 영향을 주는 것이 아니라, 다른 곳에 또한 영향을 주게 됩니다.


AND 연산과, 빼기 연산을 통해 비교하는 방법이 다르다는 것인데요..

CMP는 빼기 연산이니 100에서 100을 뺀다고 치면 0 이런 식으로 완전히 같은지 판단이 가능합니다.


다만, AND 연산의 경우 0이  아닌 경우에 사용하게 되면, 그 결과가 같게 되어 결과가 애매해집니다.


이제 CMP와 TEST의 차이에 대해 조금은 이해가 되시나요..?
[설명이 부족했다면 죄송합니다 | 추후 보충할 예정입니다.]


그렇다면 CMP는 어떠한 방법으로 비교를 하는 걸까요?

[그 점은 위에서 말했지만 다시 말하겠습니닷]

바로 빼기 연산을 통해 비교를 하며, 그 결과 값을 통해 플래그 값을 변경하게 되지요.


또한 부호 없는 정수의 경우에는 ZF, CF가 중요하게 작용하며,

부호 있는 정수의 경우 ZF, OF가 중요하게 작용합니다.


그 이유는? 

CF의 경우, 연산된 결과 값이 결과값이 들어갈 피 연산자의 크기보다 클 경우 1로 set,

OF의 경우, 보호 있는 정수 가정하에, 연산 결과 값이 결과값이 들어갈 피 연산자의 범위를 벗어났을 때 set 되므로...


CF와 OF는 산술 연산의 결과가 피 연산자에 완전히 표현할 수 없을 때 그 상황을 알리기 위해서 사용됩니다.

그러므로 위와 같이 작용을 하게 되지요. [부호 유무에 따라 부호 없는 쪽에서, 부호 있는 정수 쪽에서 일을 합네다]


이렇게 CMP와 관련해서 좀 더 다뤄보았습니다.


다음으로 JMP 관련 함수에 대한 마무리를 짓자면..


위 표에서 다뤘듯이 다양한 조건들을 통해 조건 을 수행하게 되며,

CMP를 통해 비교, 그 결과를 플래그에 기록하여, 해당 분기 조건의 조건에 맞는다면 [플래그 상태]

점프를 하게 되는 것 같습니다. 그 말 즉슨, 분기 쪽에서 위와 같은 플래그 값으로 설정을 해주게 된다면

실제로는 점프가 불가능 해도 점프가 가능해지겠지요.. 


이렇게 마지막으로 JMP 관련 함수에 대해 간략하게 제 생각을 정리해보았습니다.


이걸로 어셈블리어에서 CMP와 JMP [관련 함수] + TEST와 CALL 에 간략하게 다루어 보았습니다.


추후 어셈블리어와 메모리 구조에 대해 다시 한번 간략하게 정리 해둘 생각입니다.

메모리 구조 같은 경우 시스템 쪽에 정리를 해두었으나, 조금 미흡한 것 같아, 시간 잡아 재 포스팅 할 예정입니다.


여튼.. 긴 글 보시느라 수고 많으셨고, 더 좋은 글로 찾아오겠습니다. 


참고


http://csdit.tistory.com/entry/%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC%EC%96%B4-CALLCMPJMP-%ED%95%A8%EC%88%98

[상단 표 출처]


http://p3ace.tistory.com/41


[CALL | JMP | CMP]


http://3dmpengines.tistory.com/1671

[CMP 분기시, 비트 플래그 변화]


http://muse192.tistory.com/28

비교 연산 및 분기 명령어


문서 -> 코드엔진 풀이 일부 [deok9님] | deok9님 작성 - 어셈블리 | PC 어셈블리 언어


 

https://www.tutorialspoint.com/assembly_programming/assembly_conditions.htm

[같이 보면 좋은 문서..?] 


http://egloos.zum.com/dal4segno/v/438860

[CMP 연산 관련 | TEST 및 CMP 차이]