본문 바로가기

[+] Information/[-] RCE

어셈블리어 정리.

[어셈블리어]
Push  : sp 레지스터를 조작하는 명령어중의 하나이다. 스택에 데이터를 저장하는데 쓰인다.

          ex:) Push eax : 스택에 Eax의 값을 스택에 저장한다.

          ex:) Push 20 : 즉석값인 20을 스택에 저장한다.

          ex:) Push 401F47 : 메모리 오프셋 401F47의 값을 스택에 저장한다.
 

Pop  : 이또한 sp 레지스터를 조작하는 명령어중 하나이다. 스택에서 데이터를 꺼내는데 쓰인다.

          ex:) Pop eax : 스택에 가장 상위에 있는 값을 꺼내애서 eax에 저장한다.

             * 주의점 : Push 의 역순으로 값은 스택에서 Pop 된다.


Mov  : 메모리나 레지스터의 값을 옮길 때[로 만들 때]쓰인다.

          ex:) Mov eax,ebx : ebx 레지스터의 값을 eax로 옮긴다[로 만든다].

          ex:) Mov eax,20 : 즉석값인 20을 eax레지스터 에 옮긴다[로 만든다].

          ex:) Mov eax,dword ptr[401F47] : 메모리 오프셋 401F47 의 값을 eax에 옮긴다[로 만든다]


Lea  : 오퍼렌드1의 값을 오퍼렌드2의 값으로 만들어준다.

          ex:) Lea eax,ebx : eax레지스터의 값을 ebx의 값으로 만든다.


Inc  : 레지스터의 값을 1증가 시킨다.

          ex:) Inc eax  : Eax 레지스터의 값을 1증가 시킨다.
 

Dec  : 레지스터의 값을 1 감소 시킨다.

          ex:) Dec eax : Eax 레지스터의 값을 1 감소 시킨다.


Add  : 레지스터나 메모리의 값을 덧셈할떄 쓰임.

          ex:) Add eax,ebx   :Eax 레지스터의 값에 ebx 값을 더한다.

          ex:) Add eax,50    :Eax 레지스터에 즉석값인 50을 더한다.

          ex:) Add eax,dword ptr[401F47]  : Eax 레지스터에 메모리 오프셋 401F47의 값을 더한다.
 

Sub  : 레지스터나 메모리의 값을 뻇셈할떄 쓰임.

         ex:) Sub eax,ebx   : Eax 레지스터에서 ebx 레지스터의 값을 뺸다.

         ex:) Sub eax,50
 

Eax  : 레지스터에서 즉석값 50을 뺸다.

        ex:) Sub eax,dword ptr[401F47] : Eax 레지스터에서 메모리 오프셋 401F47의 값을 뺸다.
 

Nop  : 아무동작도 하지 않는다. : 90
 

Call : 프로시저를 호출할떄 쓰인다.

        ex:) Call dword ptr[401F47]    : 메모리 오프셋 401F47을 콜한다.

DIV <Target> - Division. EAX를 <Target>으로 나누는 연산이다. 결과로 몫은EAX에 나머지는 ECX에 들어간다. 

                       ex :) MOV EAX, 64h

                               MOV ECX, 9h

DIV ECX       ; 64h(100) / 9h(9) = 몫 : 0Bh(11) , 나머지 1h이므로

                EAX = 0Bh, ECX = 1h가 저장된다.


IDIV <Target> - Integer Division. DIV와 똑같다. 하지만 다른점은 부호있는 정수를 다룬다는 점이다.


MUL <Target> - Multiplication. EAX와 <Target>을 곱하여 EAX에 저장한다.

                        ex:) : MOV EAX, 2h

MUL 4h       ; EAX에는 2h * 4h = 8h가 저장된다.


IMUL <Value> - Integer Multiplication. EAX와 <Value>를 곱하여 EAX에 저장한다.

IMUL <Destination>, <Value> - <Destination>과 <Value>를 곱하여 <Destination>에 저장한다.

IMUL <Destination>, <Value>, <Value> - 2개의 <Value>를 곱한 후에 <Destination>에 저장한다.

TEST <Target1>, <Target2> - 이 연산은 대부분이 <Target1>과 <Target2>가 같게 설정된다. 예를들면 TEST EAX, EAX. 이 연산은 논리회로의 AND연산을 수행하지만 결과값을 저장하지 않는다. 단지 EAX=0일경우 ZF=1이 되고 EAX!=0일경우 ZF=0이 된다. 그리고 OF, CF는 0이된다.

ex :) TEST EAX, EAX 

LODS, LODSB, LODSW, LODSD(Load String Byte, Word, DWord) - ESI가 가르키는 곳에서 지정한 크기(Byte, Word, DWord) 만큼 읽어와 EAX에 복사한다. ESI는 복사한만큼 이동한다.


STOS, STOSB, STOSW, STOSD(Store String Byte, Word, DWord) - EAX에 들어이있는 데이터를 지정한 크기만큼 EDI가 가르키는 주소에 복사한다. EDI는 복사된 만큼 이동한다.


CLD(Clear Direction flag), STD(Set Direction flag) - Direction Flag를 Set하거나 Clear할때 사용한다.


CMC(Complement Carry flag), CLC(Clear Carry flag), STC(Set Carry flag) - Carry flag를 순서대로 반전, Clear, Set시킨다.
 

SHL <Destination>, <Value> - Shift Logical Left. <Destination>에 <Value>만큼 Shift연산을 왼쪽으로 수행한다. 만약 <Destination>보다 커질경우 CF=1이 된다.


SHR <Destination>, <Value> - Shift Logical Right. SHL과 기능은 동일하며 Shift연산이 오른쪽으로 진행된다.


ROL <Destination>, <Value> - Rotate Left. SHL과 기능은 동일하다. 단지 자리수가 늘어날경우 해당 비트가 오른쪽 끝으로 이동한다.


ROR <Destination>, <Value> - Rotate Reft. SHR과 기능은 동일하다. 단지 자리수가 없어질경우 해당 비트가 왼쪽 끝으로 이동한다.  

Ret : 콜한 지점으로 돌아간다.
 

Cmp : 레지스터와 레지스터혹은 레지스터 값을 비교하기위하여 쓰인다. 

        ex:) Cmp eax,ebx : Eax 레지스터와 Ebx 레지스터의 값을 비교한다.

        ex:) Cmp eax,50 : Eax 레지스터와 즉석값 50을 비교한다.

        ex:) Cmp eax,dword ptr[401F47] : Eax 레지스터와 메모리 오프셋 401F47의 값을 비교한다.
 

Jmp : 특정한 메모리 오프셋으로 이동할떄 쓰인다.

        ex:) Jmp dword ptr[401F47] : 메모리 오프셋 401F47 로 점프한다. 
 

조건부 점프: Cmp나 Test 같은 명령어의 결과에 따라점프한다.
Je : Cmp나 Test 의 결과가 같다면 점프 

Jne : Cmp나 Text 의 결과가 같지 않다면 점프

Jz : 왼쪽 인자의 값이 0 이라면 점프

Jnz : 왼쪽 인자의 값이 0 이 아니라면 점프 

Jl : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작으면 점프(부호있는)

Jnl : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작지 않으면(크거나 같으면) 점프 (부호있는)

Jb : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작으면 점프(부호없는)

Jnb : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작지 않으면(크거나 같으면) 점프 (부호없는)

Jg : 왼쪽 인자의 값이 오른쪽 인자의 값보다 크면 점프

Jng : 왼쪽 인자의 값이 오른쪽 인자의 값보다 크지 않으면 (작거나 같으면) 점프

Jle : 왼쪽 인자의 값이 오른쪽 인자의 값보다 작거나 같으면점프 (부호있는)

Jge : 왼쪽 인자의 값이 오른쪽 인자의 값보다 크거나 같으면 점프
 

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

약 이정도의 명령어들이 가장 많이 나오는 것들임으로

최소한 위에 나온것들은 외워 두도록 하자.


이글에서는 5가지 논리연산에 대해서 쓸것이다.

논리연산자는 두 오퍼렌드의 값의 비트들을 대응시켜 명령에 따른 적절한 값을 구하여 첫번쨰 오퍼렌드의 값을 바꾸어 주는것이다.

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 

AND 연산 : 대응되는 비트가 둘다 1이면 결과는 1이고 그외의 결과들은 모두 0 이 된다.

 - AND EAX,10 : 이를 계산하기 위해 우선 두 오퍼렌드의 값을 2진수로 바꾸어 주면 8은 1000 이 되고 10은 1010 이 되고 AND 연산은 둘다 1이여야 1이 됨으로 결과는 1000 이 됩니다.


OR 연산 : 대응되는 비트중 하나가 1 또는 둘다 1이면 결과는 1이고 그외는 모두 0이 된다.

 - OR EAX,10 : 이를 계산하기 위해 두 오퍼렌드의 값을 2진수로 바꾸어 주면 8은 1000이 되고 10은 1010이 되고 OR 연산은 한쪽 또는 양쪽둘다 1이면 1이고그외는 모두 0 임으로 결과는 1010이 된다.

 

XOR 연산 : 대응되는 비트 중에서 한비트가 1이고 다른 비트가 0이면 1이 되고 두개의 비트가 1이면 0 이 되고 두개다 0 이어도 0이 된다.

XOR EAX,10 : 이를 계산하기 위해 두 오퍼렌드의 값을 2진수로 바꾸어 주면 8은 1000이 되고 10은 1010이 되고 XOR 연산은 한쪽만 1이어야 1임으로 결과는 10이 된다.


NOT 연산 : NOT 연산은 오퍼렌드의 값을 반대로 하여 준다.

NOT EAX : 이를 계산하기 위해 오퍼렌드의 값을 2진수로 바꾸어 주면 10은 1010이 되고 NOT 연산은 1 과 0을 반대로 하여 줌으로 결과는 0101 이 된다.

 * 참고 : Test 연산은 오퍼렌드에 영향을 주지 않으며 플래그만 세트 시키어 준다


[레지스터]

1. 범용 레지스터

 - EAX 레지스터 : 누산기인 EAX 레지스터는 입출력과 거의 모든 산술연산에 사용된다. 곱셋과 나눗셈, 변환 명령어등은 반드시 EAX 레지스터를 필요하게 된다.

EAX 레지스터는 32bit의 레지스터이고 16bit 의 레지스터로 AX가 있다. (AX는 왼쪽의 AH와 오른쪽의 AL로 이루어져 있다)

 

 - EBX 레지스터 : EBX는 주소지정을 확대하기 위한 인덱스로서 사용될수 있는 유일한 범용 레지스터 이며, 다른 일반적인 계산 용도로도 쓰인다.

EBX는 32bit 레지스터이고 16bit로 EB가 있다. (EB는 왼쪽의 BH와 오른쪽의 BL로 이루어져 있다)

 
 - ECX 레지스터 : ECX는 루프의 반복 횟수나 좌우방향의 시프트 비트 수를 기억한다. 그외의 계산에도 사용된다.

ECX는 32bit 레지스터이고 16bit로 CX가 있다. (CX는 왼쪽의 CH와 오른쪽의 CL로 이루어져 있다.)
 

 - EDX 레지스터 : EDX는 몇몇 입출력 동작에서 사용 된다.
 

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 

2. 플래그 레지스터

 - OF [Over Flow] : 산술연산후 상위 비트의 오버플로를 나타냄

 - DF [Direction] : 스트링 데이터를 이동하거나 비교할떄 왼쪽 또는 오른쪽으로의 방향을 결정한다.

 - SF [Sign] : 산술결과의 부호를 나타낸다[0=양수,1=음수]

 - ZF [zero] : 산술연산 또는 비교동작의 결과를 나타낸다[0=결과가 0이 아님,1=결과가 0임]

 - CF [Carry] : 산술연산후 상위 비트로부터의 캐리 그리고 시프트 또는 회전동작의 결과 마지막 비트 내용을 저장한다.

 - TF [trap] : 프로세서가 단일 스텝 모드(single-step mode)를 동작할수 있도록 해준다.


[참고]

1. 나눗셈 연산의 피젯수는(32bit의 나눗셈을 가정) 항상 edx:eax 이다.

2. cdq 는 나눗셈을 위해 피젯수의 사이즈를 확장하는 것이다.


나눗셈연산(div, idiv)은 eax와 edx에 의해서만 이루어집니다

- 피젯수(나눔을 당하는 수) 는 eax, edx에만 들어갈 수 있다는 얘기에요

16 / 5 연산을 한다고 가정해 봅시다.


16과 5 둘다 32bit data라고 가정하구요


그럼 일단 eax에 16을 넣습니다. 그 다음 ebx(다른레지스터나 메모리도 상관없음)에


5를 넣습니다. 그 다음 div 연산을 하면.........될것 같지만 안됩니다..


일반적으로 제수(여기서는 5)가 32bit이면 피젯수(여기서는 16) 는 64bit가 되어야


32bit 값을 가지는 몫을 얻을 수 있습니다.


그래서 피젯수의 bit를 확장 시켜주는것이 바로 cdq 연산입니다


32bit 크기의 eax의 값을 64bit의 값인 edx:eax로 만들어줍니다.


여기서 edx는 상위자리가되고 eax는 하위 자리가 되죠


자..그럼 cdq 연산까지 끝났으면 edx:eax에 16이 들어가있고 ebx에 5가 들어있겠네요


그럼 idiv연산을 해봅시다(div는 부호가없는 나눗셈 idiv 부호가 있는 나눗셈)


그럼 몫과 나머지가 나와야 하겠죠? 그 결과는 다시 eax와 edx로 들어가는데


eax에는 몫이, edx에는 나머지 부분이 들어갑니다~


 



LoadLibrary GetProcAddress (로드 라이브러리 겟프락어드레스) 후에 변하지 않는 레지스터는

EBX EBP ESI EDI 이다. EAX, ECX, EDX 가 변한다 


출처 : http://zerohz.tistory.com/61

'[+] Information > [-] RCE' 카테고리의 다른 글

Lena's Tutorial 4 상세분석  (0) 2011.10.08
Lena's Tutorial 3 상세분석  (0) 2011.10.08
Lena's Tutorial 1 상세분석  (0) 2011.10.06
Lena's Tutorial 분석 글을 쓸 예정  (0) 2011.10.06