따라만들어보는 VCP - 상상만 하던걸 드디어..!

2017. 12. 5. 08:400x03 Reversing Theory

728x90

가상화 코드를 공부하고 싶어 둘러보다가 이 분 블로그가 좋아보여서 공부 할 겸 따라 적으면서 필요한 부분은 추가하거나 내가 이해한 대로 재해석해서 작성하였다.


출처: http://revsic.tistory.com/4


VCP는 VM과 가상화 된 명령어로 이루어져 있다. 

설계를 할 때 명령어 가상화 모델 설계 + VM 모델 설계, 바이너리 설계로 나뉘어지게 된다. 


VM모델의 경우 세부적으로 들여다보면 VM의 실행 루틴과 에뮬레이션 과정에서 참조하는 메모리 영역의 설계로 이루어진다고 한다.


[설계 시나리오]


<1> 전가상화


1. 소스를 메모리에 적재 

2. 소스 해석을 전부 VM에게 인가


<2> 반가상화

1. 소스를 메모리에 적재

2. 소스 해석 일부분만 VM에게 인가


가상화를 이렇게 이해하면 편하다고 한다.

(아는동생의 기가막힌 설명이어따..)


가상화 코드(영어)  -> 가상화 CPU(통역사) -> 실제 CPU(나) -> 프로그램(영어를 통해 말하고자 하는 것을 한글로 알아듣고 수행)


내가 적어본 것은 다음과 같다.

가상화는 게씽으로 만들어두는게 아니다. 가상화도 엄연히 로직이 적용되어야 한다.

쉽게 말하면 VM이 연산한 eax 레지스터의 값이 VM이 종료 된 이후(즉, cpu에게 권한을 인가)에 CPU의 EAX 레지스터에도 적용이 되어야 한다. 만약 적용이 되지 않았다면, printf의 인자값 push eax에 제대로 된 값이 들어가지 않아 printf 기능을 수행할 수가 없다. 아마 엉뚱한 기능을 진행할 것이다.

VM이 실행 될 때는 cpu의 레지스터와 스택정보를 VM에게 넘겨야 하고

cpu가 다시 실행 될 때는 VM의 레지스터와 스택정보를 cpu가 가지고 가야한다. 


[위의 내용을 참고해서 적어본 인라인어셈블리어]

#include <stdio.h>


int main(int argc, char *argv[])

{

  // 예시일 뿐. 프롤로그는 무시했다

  __asm{

      mov eax, esp

      mov ebx, 4

      mul ebx, 5     // 여기까지 가상화가 진행된다면 실제 CPU로 반환 값을 옮겨야 하기 때문에 EAX애 일치하는 값을 반환시켜야 한다.

      push eax

      push 0x8000000

      call   printf 

   }

}


VM과 CPU는 연산에서 사용되는 변수와 자료구조가 같아야 한다.

기계어와 1대1 매칭으로 가상화 된 명령어는 형태는 다르지만, 본질은 같아야 한다.! 


차츰 차츰 가상화에 대한 재미있는 개념이 머리에 쌓이기 시작한다..


이어서 이제 이러한 가상화를 어떻게 설계하는지 공부해보았다.


패턴을 만들기 위해 먼저 해야하는 일은? 

    >> 어셈블리어를 꼼꼼히 분석하라 !   


어셈블리어는 명령어부분인 opcode와 명령어의 인자 부분인 operand로 이루어진다.

intel CPU에서는 무려 150개의 opcode가 존재한다고 한다. 그에 대응 되는 operand의 종류와 갯수는 다르다.


VM에서 바이트코드를 해석하여 본래 어셈블리어의 의미를 알기 위해서는 opcode, operand의 정보, operand 들이 바이트코드에 녹아 있어야 한다고 한다. 


코드 가상화 예시를 다른 사람의 블로그를 참조하였다.

mov $0x0, 0x1c(%esp) 


이는 기계어로 

 C7 44 24 1C 00 00 00 00 


이를 가상화 하면 

00 80 07 00 00 00 0A 00 00 00 01 90 1C 00 00 00 0A 00 00 00 00 91 00 00 00 00 0A 00 00 00  

이렇다고 한다.


첫 바이트는 opcode

다음 바이트는 operand의 정보를 나타낸다.

그다음 4byte는 operand들이 operand info에서 제시한 갯수 만큼 들어온다고 한다. 

아직 정확하게 이해가 되지 않는다. . . 


공식은 opcode 1byte + operand + operand 's information operand 4byte * n


실제 cpu opcode 

http://ref.x86asm.net/coder32.html


분석자가 분석하기 어렵게 하려면 "opcode"를 새로 만들어야 한다.

이 때 주의해야할 점은 해당 opcode를 가지고 mov 명령어라면 vm_mov함수를 

jmp 명령어라면 vm_jmp 함수를 호출해야 하기 때문에, 0x0 부터 명령어를 차례로 하나씩 대응 시키는 것이 좋다고 한다.


으악 어떻게 만드는걸까.. 


가상화에서 사용하는 instruction은 7개만 사용하기로 하자.


하지만, 여기에 추가되어야 하는 사항은 VM을 종료시키는 instrcution이다.


반가상화는 아까 설명했듯이 일부는 VM, 일부는 CPU에서 실행한다. 

따라서 VM에서 CPU로 권한을 넘겨주기 위해서는 VM을 종료하는 명령이 존재해야 하는 것이다.


VM 종료를 위한 instruction end를 만들 것이며, end instruction은 VM이 사용한 스택을 할당 해제하고, 가상화 된 코드를 실행하기 이전에 이용하던 스택으로 복구시켜야한다. 스택의 기본 사항이다. 

또한 VM에서 사용하던 레지스터 데이터를 CPU에 옮김으로써, 실행권한을 넘기게 해야한다.


[이런식으로 테이블을 우선 세팅해야한다]

[ Operand Info ]

bit 7,6 : Ref_Size 

bit 5,4,3 : Op1_Info

bit 2,1,0 : Op2_Info


[ Ref_Size ]

0 0 : 8bit operand

0 1 : 16bit operand

1 0 : 32bit operand

1 1 : 64bit operand


[ Op Info ]

0 0 0 : register

0 0 1 : register

0 1 0 : constant

0 1 1 : constant

1      : relocation


언젠가는 스스로 직접 만들어보는 날이 오겠지 라고 생각하면서 배껴 써보고 있다. 


1. Operand Info 

-> operand의 크기와 operand의 종류를 나타낸다.

Operand Info의 경우 1byte 내에서 정보들을 나타내야 하기 때문에 비트 단위로 의미를 부여하게 된다.

bit 0 ~ 7 까지 8개로 나타냈다.

최상위 두 비트의 경우는 operand의 크기를 위해 쓰려고 한다.


VM의 입장에서는 operand만 봐서는 해당 오퍼랜드가 레지스터인지, 상수인지, 포인터인지, 재할당이 필요한지 알 수가 없다.

그렇기 때문에 Operand의 정보를 나타낼 비트가 따로 필요하다.


책의 저자가 설계한대로에 의하면 가상화 opcode에서 필요한 최대 operand의 수가 2개 이기 때문에, 

2개의 operand 정보를 나타낼 수 있게 해두었다. 

bit 5 4 3 : 첫번째 operand의 정보

bit 2 1 0 : 두번째 operand의 정보



실습을 따라 하고자 하는 '가상화 시킬 어셈블리어'는 at&t 형식이기 때문에 

상수를 주소로 직접 참조가 불가능 하다고한다. 

at&t형식은 상수를 주소로 직접 참조가 불가능하군.. 


0 1 1 constant 는 무의미 하다고 하고, VM의 편의를 위해 메모리의 주소를 고정시키기 때문에 reloc 비트도 필요하지 않다고 한다.


이렇게 정보를 만들 것이다.


0 0 0 : 레지스터일 때


0 0 1 : 레지스터를 주소로 메모리에 참조 할 때


0 1 0 : 상수 값일 때


[실제 intel register]

0x0 : eax


0x1 : ebx


0x2 : ecx


0x3 : edx


0x4 : esi


0x5 : edi


0x6 : ebp


0x7 : esp


0x8 : eip 


0x9 : eflags 


0xa: tmp 

이걸 적다보니 디버거에 UI적용되어있는 순서와 같지는 않다. 


연습을 한 번 해보자 

1) mov %esp, %ebx 


mov는 opcode로써 1byte를 차지하니까 [0x00]


%esp 는 레지스터 이면서 2바이트를 차지하니까 [0x00 0x07]


%ebx 는 레지스터 이면서 2바이트를 차지하니까 [0x00 0x01] 


little endian 적용해서 


mov %esp , %ebx는 [07 00]  [00]      [00 01]   [00 00 00] 이 되는데 뒤에 3바이트는 register를 나타내는 정보이다.

                           [esp]    [mov]    [ebx]      [register임을 나타내는 정보]



2) sub $0x5, %eax


sub는 opcode로써 1byte를 차지하니까 [0x03]

그렇다면 상수값은?? 그냥 [0x00 0x05]일까? 


%eax는 레지스터이면서 2바이트 차지하니까 [0x00 0x00]


지금 가지고 있는 정보는 레지스터 정보 + 상수 정보니까  0 0 0  || 0 1 0 하게 되면 0 1 0 인 것 같다.


little endian 적용해서 


sub $0x5, %eax는 [0x05 0x00] [0x03] [0x00 0x01 0x00] 이 될 것 같다.




IF, mov 0x18(%esp), %eax라는 어셈블리어가 있다면 

VM은 0x18을 이해하기 버겁다고 한다 ㅠㅠ 

왜냐하면 operand info의 크기를 늘려야 되기 때문이라고 한다. 

그래서 mov 0x18(%esp), %eax를 가상화 하고 싶으면 0xa(즉, %tmp)를 적극적으로 이용하는 습관을 기르자.


mov %esp, %tmp

add $0x18, %tmp

mov (%tmp), %eax


또 하나 중요한 사항이 있다. 만약에 call 또는 jmp계열을 이용하고 싶다면? 

예시를 printf를 들어줬더라. printf는 공유라이브러리에서 가져와서 plt -> got를 거쳐서 사용하는 함수 중의 하나다.

즉, 외부의 함수를 불러오기 때문에 VM은 해석을 할 수가 없다. 

그렇기 때문에 VM을 CPU와 동기화 시켜둔 후, 일반 CPU로 잠시 실행 권한을 넘겨 printf를 수행하고 printf의 행위가 

끝나게 되면 stub code를 삽입하는 형태로 해야한다.


printf가 종료 되었다면 printf에서 eax레지스터에 반환 값을 담아올 것이고, 이 때는 CPU가 "실행 권한"을 소지하고 있을 것이다. 

그리고 CPU는 VM코드를 해석하려고 한다. 이것을 방지하기 위해 STUB CODE를 삽입해주는 것이다. 


stub code는 VM의 호출과 유사하게 다음 실행해야 하는 가상화된 명령어의 주소를 push하면서, vm의 "restart"로 점프해서 

CPU와 VM을 동기화 시키게 된다.


VM과 CPU의 동기화가 성공하면 CPU는 VM에게 실행권한을 넘겨주게 되고, VM은 가상화 된 명령들을 해석, 실행하게 된다.


다시 한번 어느 블로그님이 적은 예시를 가져왔다.

(사실상 그 분의 블로그를 보고 조금 내가 이해하기 쉽게 단어를 바꿔서 공부 할 겸 적어보고 있다.)


 05 90 F0 82 04 08     call 0x80482f0

 68 55 ad 04 08         push $vcode_addr

 b8 f3 ad 04 08          mov $vm_restart, %eax

 ff  e0                      jmp %eax


위의 코드는 실제 가상화 때 사용하였던 코드라고 한다.

call로 접근할 수 있는 주소 0x80482f0은 printf함수의 plt이다. 

외부함수이기 때문에 가상화가 적용될 수가 없다. 그러므로 해당 call문의 instrcution을 가상화 한 vm_call 함수에서는 CPU, VM을 동기화하여 CPU에게 실행권한을 부여하고 CPU는 명령으로 외부의 주소로 이동할 수 있게 한다. 그 후 CALL에서 호출 된 주소 0x80482f0의 역할을 다 하게 되면은 반환값을 가지고 나오게 되며, CPU의 EIP는 call 다음 주소를 가리키게 된다. 이때 push $vcode_addr 으로 되어있는데 보다시피 $vcode_addr은 가상화코드이다. CPU에서 가상코드를 실행할 수 없기 때문에 VM에게 가상화 코드를 실행 할 수 있는 실행권한을 넘겨주어야 한다. 이때 stub code를 이용하여 VM을 재시작할 수 있는 루틴으로 이동시킨다. 

가상화 코드의 주소를 push하고 vm_restart로 이동하게 된다.


그렇다면 이제 VM 모델의 메모리는 어떻게 설계하는지 알려주길래 공부하였다.



일반적인 프로그램 즉, CPU가 관여하는 프로그램은 스택이 1개 이지만, VM의 메모리 내부에는 스택이 무려 2개가 있다.

VM이 사용하는 레지스터 블럭 공간과 인스트럭션을 구현한 함수 (vm_mov, vm_call, vm_jmp)가 사용하는 스택 등이 존재한다. 

두 스택이 확장되고, 해제되는 과정에서 서로 충돌을 할 수 있다.

특정한 경계선이 없는 것 같다. 하지만 이러한 충돌을 예방할 수 있다.

그것은 바로 메모리를 미리 예약해 놓는 것 

만약에 가상화 된 코드의 스택이 미리 예약해 놓은 영역을 넘는다면, 예약한 스택의 크기를 늘리고, VM 데이터를 가상화 스택 아래로 복사해야 할 것이다.


< VM 호출의 예 >

push $vcode_addr

mov $vm_start, %eax

jmp %eax 


반 가상화에서는 CPU가 일반적인 기계어들을 실행하다가 VM을 요청하게 된다. VM의 호출은 위의 코드로 진행되게 되는데, 여기서 vcode_addr은 가상화 된 명령어의 시작주소를, vm_start는 VM의 시작주소를 나타낸다. 

push $vcode_addr을 통해서, VM이 해석해야하는 가상화 된 명령어의 주소를 스택에 저장 할 수 있다

그 이후 eax 레지스터에 vm의 시작주소 값 $vm_start를 저장하고 eax를 가지고 점프 명령을 수행하게 된다. %eax를 점프에 이용하여 eip를 바꾸는 행위는 "절대주소"로 jmp문을 시행하기 위함이다.

하지만, 상대주소가 불가능 한 것은 아니라고 한다. 

jmp문을 수행 후 VM이 시작되게 되고, 스택에 저장된 vcode_addr을 가지고 가상화 된 바이트 코드를 해석, 실행하게 된다.


[스택의 모형]

 main stack 

 Virtual Code Addr

 Stack Frame Pointer

 Reserved Stack

0x300 bytes

  Virtual Machine Stack

0x100 bytes

위의 모형을 임시로 설계했다고 한다. 

내 진정 가상화를 하여도 태초부터 가상화를 진행하진 않았을 터이니 제일 첫번째 스택은 일반적인 CPU에서 관여하는 스택이 될 것이니라. 라고 이해하면 쉽지 않을까 한다.

그 후 VM을 호출하기 위해 vcode_addr을 스택에 push 하게 된다. 

vcode_addr 즉, 가상화 코드의 주소를 스택에 쌓았기 때문에 이제 우리는 CPU와 VM의 동기화가 이루어진 상태가 만족되고 VM이 실행권한을 얻게 된다. 하지만 이때 VM이 해야할 첫 번째 과업은 "VM이 끝나고 나서 돌아갈 수 있는 실제 CPU를 사용하는 주소를 PUSH %EBP를 이용하여 Stack Frame Pointer를 저장해 두어야 한다.

그 후에는 VM에서 실행되는 명령어가 사용할 스택을 예약 ->VM의 레지스터나 다른 기타 정보가 저장 될 영역을 확보하게 된다.


새벽에 배운 내용을 떠올리면서 본격적으로 VM 을 설계 해보자.


우선 공부하면서 알게 된 핵심가치 2가지

1. VM은 반드시 CPU와 동기화가 이루어져야 한다.

2. VM은 바이트 코드를 읽어들여 실행할 수 있어야 한다.


해당 예시 역시 타 블로그 님의 멋진 예시다.


start:

push %ebp

sub $0x300, %esp ; reserved_stack

mov %esp, %ebp

sub $0x100, %esp ; vm_data


mov %eax, (%esp)

  mov %ebx, 0x4(%esp)

  mov %ecx, 0x8(%esp)

mov %edx, 0xC(%esp)

mov %esi, 0x10(%esp)

mov %edi, 0x14(%esp)

  mov 0x300(%ebp), %eax

mov %eax, 0x18(%esp) ; ebp

mov 0x150(%ebp), %eax

mov %eax, 0x1C(%esp) ; esp

mov 0x304(%ebp), %eax

mov %eax, 0x20(%esp) ; eip

mov $0x804aca5, 0x30(%esp) ; opcode table

mov $0x8004acc1, 0x34(%esp) ; spc - tpc pointer


jmp decode


위의 코드가 뭔가...싶은분들이 많을 것이다. 나도 처음엔 뭔가..싶었다 왜냐하면 타 블로그에 게시 되어있던 테이블과 달랐기 때문이다. 그럼 여기서 알 수 있는 점!! 

"규칙은 자신이 만들면 된다" 이지 않을까?


VM의 시작부분을 어셈블리어로 짜놓은 형태다. 

VM은 레지스터 자체를 직접 다루거나, 메모리를 직접 참조하는 부분이 있기 때문에 어셈블리어로 작성을 하였다. 

VM의 시작은 cpu와의 동기화로 시작되게 된다. 계속 언급하는 이유는 이보다 중요한 말은 없다고도 볼 수 있기 때문이다. 시작이 반이라는 말이 있지 않는가 !! 

CPU의 레지스터는 VM 구동에 이용되기 때문에 VM의 레지스터는 메모리에 존재하게 된다. CPU의 레지스터 정보를 메모리에 차곡차곡 쌓을 수 있다.


VCP 단계에서는 mov instruction을 VM에서 실행하기 위해 vm_mov라는 함수를 구현하게 된다. 계속 언급하는 부분이다. 아주아주 중요하다고 볼 수 있다.


VM은 가상화 된 명령어에서 opcode를 가지고 vm_mov와 같은 가상 함수를 실행해야 한다. 


opcode table은 이러한 가상 함수들의 주소를 모아두는 테이블이다. 

예를 들어 mov의 주소가 0x804892a7이라면 little endian적용 되어 

테이블에 a7 92 48 80 이 저장되게 되는 것이다.


꼭 기억해야 하는 것

[opcode_table_addr + 4 * opcode]


ex) sub의 opcode가 2이다. 

mov의 주소를 조금전에 0x804892a7으로 하기로 했으니 

0x804892a7 + 4 * 2 =  0x‭804892AF‬가 된다.

그렇다면, 0x‭804892AF‬가 sub함수의 주소가 된다. 

단순화를 위해 ! opcode는 mov, sub, add 뭐 이런거...

0x00~0xXX까지 순차적으로 설계를 해둔 것이다.! 



기본적으로 코드를 가상화하게 되면, 문자 하나당 10bytes 정도의 바이트 코드로 변환이 된다.  기존 기계어 코드의 크기가 커봐야 6byte 이기 때문에, 가상화 코드는 기존코드보다 당연히 더 커질 수 밖에 없다. 


이렇게 되면 jmp나 call을 하는 메모리 영역 부분의 주소가 바뀔 수 있게 된다. 

spc-tpc 테이블은 이렇게 바뀌어 버린 주소를 매핑해주는 역할을 진행한다. 


ex) mov $0x4, -0x8(%ebp) 문장이 0x80484d9에서 위치한다고 가정.


가상화가 진행되어, 길어진 바이트 코드에 의해 주소가 밀려 0x8048523으로 바뀌었다고 가정한다. 만약에 주소를 변경하는 루틴이 존재하지 않는다면 프로그램은 엉뚱한 지점으로 이동하게 되며, VM은 해석을 하지 못하고 오류를 발생시키게 된다.

BOF의 원리와 동일한 것이다. 버퍼에 너무 많이 값이 들어와서 ret영역을 파괴하면 프로그램은 내가 어디로 점프를 해야하는지 갈팡질팡하다 결국 오류를 발생시키고 죽어버린다. 


그래서 spc-tpc는 가상화로 인해 엉뚱해진 주소가 있으면 그것을 바로 잡아주는 부모님과 같은 역할을 한다. 자식이 불량학생이면 부모는 그 자식을 올바른 길로 잡아줄 필요가 있다. 여기서 길어진 바이트가 불량학생, 잘못된 방향(나쁜 짓)은 엉뚱한 주소, 부모는 spc-tpc가 되는 것이다. 

그렇다면 spc-tpc는 가상화 된 코드영역 내에서의 주소만을 반환하면서 바이트코드의 잘못된 행동을 저지하는 역할을 맡은 것이다.


그리고 이해를 돕기 위해 억지로 예시를 만들어보자면 남의 자식에게 까지 굳이 신경 쓸 필요가 없다. 남의 자식을 일반 기계어 영역, 나의 자식을 가상화 된 코드 영역이라고 생각하게 되면, 남의 자식까지 굳이 신경 쓸 필요가 없으니 spc-tpc는 일반 기계어 코드 영역은 신경쓸 필요가 없는 것이다.


실제로 jmp와 call을 구현할 때는 spc-tpc 테이블을 참조하여, 외부 주소인지 VM주소인지를 확인 후 실행하는 방식을 사용한다고 한다.


decode를 어떻게 할까?

decode:

mov 0x30(%esp), %ebx ; opcode table


xor %eax, %eax

mov 0x20(%esp), %ecx ; eip

mov (%ecx), %al

mul $0x4

add %ebx, %eax

mov %eax, %ecx

mov %ebp, %eax

sub $0x100, %eax

call (%ecx)

add $0x4, %esp

jmp decode 


한줄 한줄 다시 쓰면서 공부해보자.

mov 0x30(%esp), %ebx 

opcode table의 시작주소를 %ebx에 저장 


 mul $0x4 

그 후 opcode 값과 4를 곱한다

Q : 왜 4를 곱해요~? 다른 거 곱하고 싶은데...?

A : 지금 구현하고자 하는 바는 32비트 ELF 이기 때문에 주소가 4바이트로 이루어져 있기 때문


add %ebx, %eax

opcode Table 시작주소에 곱한 결과를 더함 -> 명령어의 함수를 알아냄  


call (%ecx)

ecx 블럭을 인자로 함수를 실행 시킴  


jmp decode 

end 명령어 만날 때 까지 decode로 분기  


<바이너리 설계>


실제 VM의 실행코드와 가상화 된 명령어, 가상화 환경을 구성하는 곳은 바이너리이다.


가장 먼저, 데이터들을 저장할 구역을 만들어야 한다.

당연히 데이터를 사용하려면 '방'이 존재해야 하는 것이다. 


ELF는 Segment 단위 -> Section 단위  


ELF는 Segment 단위로 데이터를 메모리에 적재한다. 

ELF 파일 내에서 메모리에 적재되는 구역을 정의하고, 데이터를 쓰기 위해서는 Segment를 추가해야 한다. 

하지만, Segment를 추가로 만들 경우, Program Header Table에 새로운 값이 추가되어야 하고, 그 결과 Program Header Table 이 후의 데이터들이 밀려나게 된다.


그림은 퍼왔다.


ELF 파일을 보면 Note Segment가 존재함을 볼 수 있다.

Note 는 말 그대로 Note 이기 때문에 프로그램 정보만 저장하지 프로그램 실행에 

전혀 영향을 미치지 않는다. 


이제 부터 머리를 아주아주 많이 굴려야 할 때가 왔다. 

Note Segment를 메모리에 적재되는 LOAD Segment로 타입을 변경 후 업로드 되는 주소와 파일 내의 오프셋 정보를 변경하여, 데이터 업로드에 이용한다.


세그먼트 변경은 구조체를 이용한다.


지금부터 Hello World를 처음 봤을 때의 쾌감을 다시 한번 느낄 수 있는 시간이 왔다...


코드가상화의 예시를 직접 따라 써본다.


내 인생 처음 코드가상화 구현 모듈이다.

물론. 예시니까 책의 내용을 그대로 배꼈지만, c언어도 처음에는 코드 그대로 배끼면서 하지 않는가 !! 


설계 


.text 

...

push vcode_addr

jmp vm.start

...

end

--------------------------------------------------------------------------------------

.venv

opcodeTable

spc-tpcTable

tmp storage


--------------------------------------------------------------------------------------

.vcode

00 08 07 00 00 00 0A 00 00 00

01 90 1C 00 00 00 0A 00 00 00

00 91 00 00 00 00 0A 00 00 00


...


--------------------------------------------------------------------------------------

.vm

void vm_mov(int *regs){


이 모양은 이번 바이너리의 기본 모형이 된다. 

현재 .venv, .vcode, .vm 은 영역을 나누기 위해 붙인 이름 (alias라고 봐도 되나?)

실제로는 재 정의된 하나의 세그먼트 내에 쓰여지고, 메모리에 적재된다.

.text 영역에서는 .vcode의 시작주소를 push하고 .vm으로 이동하는 역할을 한다.


그 이후 .vm에서 VM 실행권한을 가지고 프로그램을 실행해나간다. 


VM 환경에 필요한 구성

1. Opcode Table

2. SPC-TPC Table

3. Register 

  --> 만약, 이 3가지로 구성으로도 해결 할 수 없는 부분이 나오게 되면 

.venv에 임시 저장소를 설정할 수 있다.


c코드로보면 완전 간단한 반복문이지만, 분명 우리는 이 반복문도 처음 배울 때는 와 이게 뭔가 싶었었다. 지금도 분명히 이게 뭔가.. 싶겠지만 포기하지 않고 달려본다 ~~ 


Positive _Mind _Hack이다 항상


우선 c코드

#include <stdio.h>


int main(int argc, char* argv[])

{

int i;

for(i=0; i<5; ++i)

printf("%d\n",i);


return 0;





'0x03 Reversing Theory' 카테고리의 다른 글

개인공부  (0) 2017.12.11
GCC Asembler  (0) 2017.12.06
기초 공부 Code Virtualization  (0) 2017.12.05
ELF 기초 공부중  (0) 2017.12.05
installing xv6 in ubuntu  (0) 2017.10.19