What does the 'TEST' instruction do

TL;DR

어셈블리어에서 TEST 명령어는 eax의 값이 0이냐 아니냐를 판단하기 위해서 사용한다. 만약 eax의 값이 0이라면 (zf가 세팅되어) 뒤에 JEJZ 명령어가 온다면 jump한다.

TEST 명령어

문제를 풀다가 언제 jump하는지 항상 헷갈려서 블로그에 정리하려고 한다..

아래는 예시 어셈블리어이다.

1
2
3
4
5
6
7
8
9
.text:0000131E
.text:0000131E loc_131E:
.text:0000131E lea eax, (var - 4000h)[ebx]
.text:00001324 mov edx, [eax+38h]
.text:00001327 mov eax, [eax+34h]
.text:0000132A xor eax, 11h
.text:0000132D or eax, edx
.text:0000132F test eax, eax
.text:00001331 jnz short loc_1347

간단하다.

test eax, eax 에서 eax가 0인지 판단하고, 만약 0이라면 zf가 1로 세팅된다. jnz(=jump not zero) 명령어는 이름 그대로 0이 아닐 경우 jump하기 때문에 eax가 0이라면 jump하지 않는다.

하지만 문제 풀 때 의외로 많이 헷갈렸으므로 이 로직을 조금 더 뜯어보자.

1.

1
2
text:00001324 mov     edx, [eax+38h]
.text:00001327 mov eax, [eax+34h]
  • 이 연산은 edxeax 주소에 값을 저장하는 연산이다.
  • 사용자 인풋은 eax 주소에 저장된다. bss영역 정의된 배열에 값을 쓰는데 어째선지 배열의 사이즈를 모르는 상황이다.
  • edx에 배열 밖의 값이 저장된다는 사실을 파악해보자.

2.

1
.text:0000132A xor     eax, 11h
  • xor 연산을 진행한다. eax가 0x11라면 0으로 초기화가 되겠고, 0이라면 eax에 0x11가 저장될 것 이다.
  • 앞 부분 분석을 해보면 eax에 무조건 0x11을 넣고 싶어질 것이기 때문에 이 연산 값은 0이 되고 eax에 0이 담긴다.

3.

1
.text:0000132D or      eax, edx
  • or 연산을 진행한다. 두 값 중 어느 하나라도 0이 아니면 0이 아닌 수가 eax에 담길 것이다.
  • 현재 eax은 0으로 고정이므로 edx 값에 집중하여 분석해보자.
  • edx가 0이라면? 0 | 0 = 0, eax의 값은 0이 된다.
  • edx가 X라면? 0 | X = X, eax의 값은 X이 된다.

4.

1
.text:0000132F test    eax, eax
  • eax가 0인지를 검사한다. 실제로 eax에 값을 쓰지는 않는다.
  • eax가 0인 경우: edx의 값이 0인 경우
  • eax가 X인 경우: edx의 값이 X인 경우

5.

1
.text:00001331 jnz     short loc_1347
  • jnz = jump not zero
  • eax가 0이 아니면 jump한다.
  • 참고로 loc_1347은 실행하고 싶은 로직이 아니다.
  • 결론적으로 jump를 하면 안되고, eax가 0이어야 한다. eax가 0이려면 edx가 0이어야 한다.
  • overflow때문에 edx에 값을 입력할 수 있지만 배열 크기 검사를 진행했기 때문에 값을 쓰면 안된다는 결론을 얻을 수 있다.