Debugger
ModR/M 바이트에서 Mod+R/M과 Reg와의 목적지(순서) 구분 & SIB 바이트 작성법
GuTTe
2018. 12. 15. 01:58
개꿀팁인데 Opcode에서 오퍼랜드와 오퍼랜드 사이의 목적지를 구별 짓는 것이 상당히 어려웠다.
어떤 블로그에선 Mod 비트부분에서 11이면 목적지가 레지스터라는데 테스트 결과 조금 개소리였다. (아닐수도)
구글링 결과 Mod부분이 11이면 R/M이 Register임을 알린다.
추가 적으로 Mod부분이 00이라면 뒤엔 Displacement가 따른다.
그래서 고민하다가 구글링 해보았는데 Opcode안에 d라는 비트와 s라는 비트가 숨겨져 있었다!
d비트는 전체 1번째 비트에
s비트는 전체 0번째 비트에...
┌──────────────────────────┐
│ │ │ │ │ │ │ d │ s │
├──────────────────────────┤
d비트는 이 Opcode에 의한 오퍼랜드가 어떤 방향으로 가야하는지 Direction을 결정 짓는다.
-
d비트가 1이라면 Memory에서 Register로
-
d비트가 0이라면 Register에서 Memory로
만약 오퍼랜드 2개다 레지스터면 어떡하냐 그럴땐 기본형은 ModR/M + Reg의 형태를 따르는 것 같다. (이건 내 피셜)
그리고 오퍼랜드의 크기도 조금 헷갈릴 수 있는데 그럴 땐 0번째 비트에 위치한 s비트를 비교하면 된다.
-
s비트가 0이라면 8-bit
-
s비트가 1이라면 16-bit or 32-bit
하지만 위의 내용중 NOT명령과 NEG명령은 먹히지 않는다! (오퍼랜드가 한개라서 그런가)
0: 8b 46 14 mov eax,DWORD PTR [esi+0x14]
3: 89 46 14 mov DWORD PTR [esi+0x14],eax
여기서 볼 수 있는 거처럼 Mov의 Opcode인 0x8b와 0x89를 보자
0x8b의 경우 (10001011)2로 표현된다.
반면,
0x89의 경우 (10001001)2로 표현된다. 딱 봐도 d비트의 차이가 보이는가
Q. 다음 목표는 SIB의 경우 어떤 식으로 배치 해야 할지 음...
=> 만약 ModR/M값이 2C라면 2C에 대응하는 Reg값은 그대로 써주고 SIB표에서 2C를 찾는다. 그리고 찾은 값을 [Base + Scale Index]의 형태로 작성하면 된다!
간단한 예시를 들어보자. 예를 들어
add ebp, [eax*2]는 => add ebp, DWORD PTR [eax + eax * 1] 이렇게 표현된다.
이를 기계어로 나타내면 "03 2c 00"이다. 하나 하나 분석해보자.
03 : add라는 Opcode의 Hex코드
2C : Reg field는 EBP를 의미하고 ModR/M Field를 보면 [--][--]이므로 SIB를 살펴보자. 00이니까 그럼 Base가 000인 eax와 SS Index 00인 [eax]다.
이를 열씨미 조합해보면 [eax + eax * 1]임을 알 수 있다.
자세한 내용은 이 사이트에서 보길 바람. (설명이 쩐다.)