TH3 6R3@T H@CK
Assembly 본문
· 옵코드 opcode: 명령어
- ex) mov, push
· 오퍼랜드 operand: 인자, 명령어 다음에 "어떤 장소로 값을 넣을 것인지" 또는 "명령어에 해당하는 값"
- 오퍼랜드가 2개인 경우 → 앞의 오퍼랜드: destination / 뒤의 오퍼랜드: source
· EAX: Accumulator
- 산술 계산을 하며, 리턴값을 전달
· EDX: Data
- EAX와 역할은 같되, 리턴 값의 용도로는 사용되지 않음
· ECX: Count
- 루프문을 수행할 때 카운팅하는 역할
- 미리 루프를 돌 값을 넣어놓고 감소시키며 루프 카운터가 0이 될 때까지 카운팅
· EBX: Base
- 레지스터가 하나쯤 더 필요하거나 공간이 필요할 때 등 적당한 용도를 프로그래머나 컴파일러가 알아서 만들어서 사용
· ESI: Source Index
· EDI: Destination Index
· AX: 16bit / 2byte
· AH, AL: 8bit / 1byte
32bit | 16bit | 상위 8bit | 하위 8bit |
EAX | AX | AH | AL |
EDX | DX | DH | DL |
ECX | CX | CH | CL |
EBX | BX | BH | BL |
· PUSH, POP
- 순서대로 스택에 값을 넣는 것 / 스택에 있는 값을 가져오는 것
- PUSHAD, POPAD: 모든 레지스터를 PUSH하고 POP하라는 명령어
- 오퍼랜드는 1개만
· MOV
- 단지 값을 넣는 역할
· LEA
- 주소를 가져옴 (*MOV는 값을 가져옴)
- 가져올 src 오퍼랜드가 주소라는 의미로 대부분 []로 둘러싸여 있음
예시)
가정: 레지스터와 메모리에 다음과 같은 값이 들어있다.
esi : 0x401000 (esi에는 0x401000이라는 값이 들어있다)
*esi : 5640EC83 (esi가 가리키는 번지에는 5640EC83라는 값이 들어있다)
esp+8 : 0x13FF40
*(esp+8) : 33
lea eax, dword ptr ds : [esi]
esi가 0x401000이므로 eax에는 0x401000이 들어온다
mov eax, dword ptr ds : [esi]
esi가 0x401000이므로 eax에는 0x401000 번지가 가리키는 5640EC83이라는 값이 들어온다
lea eax, dword ptr ss : [esp+8]
esp+8은 스택이며, eax에는 0x13FF40라는 값이 들어온다
mov eax, dword ptr ss : [esp+8]
esp+8은 스택이며, eax에는 0x13FF40가 가리키는 값인 33이 들어온다
· ADD
- src에서 dest로 값을 더하는 명령어
· SUB
- ADD와 반대되는 뺄셈 명령어
· INT
- 인터럽트를 일으키는 명령어
· CALL
- 함수를 호출하는 명령어
- CALL 뒤에 오퍼랜드로 번지가 붙음
- 해당 번지를 호출하고 작업이 끝나면 CALL 다음 번지로 되돌아옴 (CALL로 호출된 코드 안에서는 반드시 RET를 만나게 되어 다시 호출한 쪽으로 돌아오기 때문)
· INC, DEC
- 순서대로 i++; / i--;
· AND, OR, XOR
- dest와 src를 연산
- XOR은 dest와 src를 동일한 오퍼랜드로 처리 가능
ex) XOR EAX, EAX → EAX는 0
· NOP
- 아무것도 하지 말라는 명령어
· CMP, JMP
- 비교해서 점프하는 명령어
· 리버스 엔지니어링에 필요한 스택
1. 함수 호출 시 파라미터가 들어가는 방향
2. 리턴 주소
3. 지역 변수 사용
예시)
push ebp
ebp 레지스터를 스택에 넣음
mov ebp, esp
현재 esp 값을 ebp에 넣음
→ ebp와 esp가 같아지면서 이 함수에서 지역변수는 ebp에서부터 얼마든지 게산 가능 (ebp를 기준으로 오프셋을 더하고 빼는 작업으로 스택을 처리할 수 있음)
sub esp, 50h
esp에서 50h만큼 뺌 → 50h만큼 지역변수 사용
예시) HelloFunction이라는 함수, DWORD 타입으로 3개의 인자를 받는 함수 타입
DWORD HelloFunction(DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
HelloFunction 호출
main()
{
DWORD dwRet = HelloFunction(0x37, 0x38, 0x39);
if (dwRet)
// .....
}
push 39h
push 38h
push 37h
call 401300h
- 함수의 인자는 스택에 값을 LIFO 순서대로 넣기 때문에 실제로 소스 코드에서 호출한 것과는 반대로 들어감
- 파라미터를 push로 넣어 놓았기 때문에 이 값들에 접근하려면 ebp에서 오프셋을 더하는 방식으로 계산해야 함 → ebp+x 형태- ebp+8: 첫 번째 인자인 37h / ebp+0xc: 두 번째 인자인 38h / ebp+0x10: 세 번째 인자인 39h